pax_global_header00006660000000000000000000000064145264617710014527gustar00rootroot0000000000000052 comment=198ebe2a4163129b0cb7e773c257ed48cafa73a4 hamster-3.0.3/000077500000000000000000000000001452646177100131755ustar00rootroot00000000000000hamster-3.0.3/.editorconfig000066400000000000000000000007541452646177100156600ustar00rootroot00000000000000# EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true # Matches multiple files with brace expansion notation # Set default charset [*.{js,py}] charset = utf-8 # 4 space indentation [*.py] indent_style = space indent_size = 4 trim_trailing_whitespace = true insert_final_newline = true # help pages [*.page] indent_style = space indent_size = 4 hamster-3.0.3/.flake8000066400000000000000000000043631452646177100143560ustar00rootroot00000000000000[flake8] exclude=wscript,waf,waflib builtins=_ # This just ignores everything that currently fails. Over time, most of these # should probably be fixed in the code and removed here. extend-ignore = E117, # over-indented E122, # continuation line missing indentation or outdented E124, # closing bracket does not match visual indentation E125, # continuation line with same indent as next logical line E127, # continuation line over-indented for visual indent E128, # continuation line under-indented for visual indent E129, # visually indented line with same indent as next logical line E131, # continuation line unaligned for hanging indent E202, # whitespace before ')' E203, # whitespace before ':' E211, # whitespace before '(' E221, # multiple spaces before operator E222, # multiple spaces after operator E225, # missing whitespace around operator E227, # missing whitespace around bitwise or shift operator E231, # missing whitespace after ':' E251, # unexpected spaces around keyword / parameter equals E261, # at least two spaces before inline comment E262, # inline comment should start with '# ' E265, # block comment should start with '# ' E271, # multiple spaces after keyword E272, # multiple spaces before keyword E301, # expected 1 blank line, found 0 E302, # expected 2 blank lines, found 1 E303, # too many blank lines (2) E305, # expected 2 blank lines after class or function definition, found 1 E306, # expected 1 blank line before a nested definition, found 0 E401, # multiple imports on one line E402, # module level import not at top of file E501, # line too long E502, # the backslash is redundant between brackets E701, # multiple statements on one line (colon) E703, # statement ends with a semicolon E711, # comparison to None should be 'if cond is not None:' E712, # comparison to False should be 'if cond is False:' or 'if not cond:' E722, # do not use bare 'except' E731, # do not assign a lambda expression, use a def F401, # 'xxx' imported but unused F811, # redefinition of unused 'xxx' from line 32 F841, # local variable 'xxx' is assigned to but never used W605, # invalid escape sequence hamster-3.0.3/.github/000077500000000000000000000000001452646177100145355ustar00rootroot00000000000000hamster-3.0.3/.github/workflows/000077500000000000000000000000001452646177100165725ustar00rootroot00000000000000hamster-3.0.3/.github/workflows/artifact-links.yml000066400000000000000000000026561452646177100222410ustar00rootroot00000000000000# This adds a comment to a PR with a link to any build artifacts. Because build # artifacts are not available until a workflow is completed, this is done in a # second workflow that triggers on completion of the workflow that builds the # artifacts. name: Linking to artifacts in PR on: workflow_run: workflows: ["Testing"] types: [completed] jobs: artifacts-url-comments: name: Add artifact links to PRs runs-on: ubuntu-20.04 if: ${{ github.event.workflow_run.event == 'pull_request' }} steps: # This uses a third-party action that handles figuring out the # pull request to comment on (which is no longer easily available # in a followup workflow) and formatting the comment. - name: Add artifact links to PR and issues uses: tonyhallett/artifacts-url-comments@v1.1.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: prefix: "Automatically generated build artifacts for commit ${{ github.event.workflow_run.head_sha }} (note: these links will expire after some time):\n" format: " - {name}: [:arrow_double_down: Download]({url})" # This adds a hline to terminate the artifact list, just # newlines should work, but it seems they are eaten # somewhere... suffix: "---\n\nTo test this PR, download and unzip the flatpak application above and then install with:\n\n flatpak install Hamster.flatpak\n" hamster-3.0.3/.github/workflows/testing.yml000066400000000000000000000112721452646177100207750ustar00rootroot00000000000000name: Testing on: [push, pull_request] jobs: test: # This runs the test suite. Since we need some system dependencies # (e.g. pygobject) that cannot easily be installed inside a # virtualenv using pip (that requires installing a dozen -dev # packages and building parts of pygobject from source, which makes # things way too complicated), this just runs with the Ubuntu system # python (e.g. not using the standard setup-python action, which # sets up a virtualenv). name: Run test suite strategy: # Complete all combinations, even if one fails fail-fast: false matrix: include: # This tests uses the oldest Ubuntu and its oldest Python # version, to get as close to our minimum required version as # possible. This does mean that we will not catch changes to # the code that unintentionally reaise the required python # version, but there's no easy way to run an older python # version (without having to install all or dependencies from # source) it seems. - os: ubuntu-20.04 python-version: 3.8 # On the latest ubuntu, just test the default 3.x version. - os: ubuntu-latest python-version: 3 runs-on: ${{matrix.os}} steps: - name: Prepare repo uses: actions/checkout@v2 - name: Install system packages run: | PACKAGES="" # Install a specific python version as configured PACKAGES="$PACKAGES python${{matrix.python-version}}" # Normal dependencies PACKAGES="$PACKAGES gettext intltool python3-gi python3-cairo python3-gi-cairo python3-distutils python3-dbus python3-xdg libglib2.0-dev libglib2.0-bin gir1.2-gtk-3.0 gtk-update-icon-cache" # For dbus-launch PACKAGES="$PACKAGES dbus-x11" sudo apt-get update sudo apt-get install ${PACKAGES} - name: Install hamster # This serves two purposes: # 1) Verify build and install still works and # 2) install the needed stuff (e.g. gsettings schemas) to allow # running the tests run: | ./waf configure build sudo ./waf install - name: Run tests run: | dbus-launch python${{ matrix.python-version }} -m unittest flake8: name: Run code linting and checks runs-on: ubuntu-20.04 steps: - name: Prepare repo uses: actions/checkout@v2 - name: Set up Python uses: actions/setup-python@v1 with: python-version: '3.7' - name: Install flake8 run: | pip install flake8 - name: Run flake8 run: | flake8 --count --show-source --statistics flatpak: # This job builds Hamster for flatpak, and runs its tests # inside the sandbox. name: Test the flatpak build runs-on: ubuntu-20.04 steps: - name: Prepare repo uses: actions/checkout@v2 # Fetch history, so we also fetch the previous tag for deriving # the version number with: fetch-depth: 0 - name: Install system packages # It would be good to cache the GNOME Sdk, as it # is rather big to download each time. env: DEBIAN_FRONTEND: noninteractive run: | PACKAGES="flatpak flatpak-builder dbus-x11" sudo apt-get update sudo apt-get install -yq ${PACKAGES} - name: Install GNOME SDK for flatpak run: | flatpak remote-add --user --if-not-exists --from flathub https://flathub.org/repo/flathub.flatpakrepo flatpak install --user -y flathub org.gnome.Platform//45 org.gnome.Sdk//45 - name: Build application run: | flatpak-builder --repo=build/flatpak/repo build/flatpak/tmp org.gnome.Hamster.yml - name: Run tests inside sandbox run: | dbus-launch flatpak-builder --run build/flatpak/tmp org.gnome.Hamster.yml python3 -m unittest - name: Export bundle and try to install it run: | mkdir -p dist # Note: For pull requests, this version includes the git hash # of the autogenerated *merge* commit, not the original # to-be-merged commit (because that's also what is tested). VERSION=$(python src/hamster/version.py) flatpak build-bundle --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo build/flatpak/repo "dist/Hamster-$VERSION.flatpak" org.gnome.Hamster flatpak --user -y install "dist/Hamster-$VERSION.flatpak" - name: Upload built artifact uses: actions/upload-artifact@v2 with: name: Flatpak application path: dist/*.flatpak hamster-3.0.3/.gitignore000066400000000000000000000005411452646177100151650ustar00rootroot00000000000000# backups (eg. glade) *~ *.pyc autom4te.cache/ m4/ config.* Makefile Makefile.in aclocal.m4 configure depcomp install-sh intltool-extract.in intltool-merge.in intltool-update.in libtool ltmain.sh messages missing mkinstalldirs py-compile stamp-h1 autom4te.cache m4 gnome-doc-utils.make hamster-time-tracker-*.tar.gz .lock-wscript .lock-waf* build *.deb hamster-3.0.3/AUTHORS000066400000000000000000000002161452646177100142440ustar00rootroot00000000000000Read the copylefts in files. Mainly it's code by Toms Bauģis and Patryk Zawadzki, but we also had some good contributions from other people. hamster-3.0.3/COPYING000066400000000000000000000772501452646177100142430ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. hamster-3.0.3/MAINTAINERS000066400000000000000000000001671452646177100146760ustar00rootroot00000000000000Whole projecthamster maintainer: Eric Goller E-mail: projecthamster.20.elbenfreund@spamgourmet.org Userid: elbenfreund hamster-3.0.3/NEWS.md000066400000000000000000001106411452646177100142760ustar00rootroot00000000000000## Changes in 3.0.3 (2023-11-19) After a long hiatus and slow development, finally a hamster release again! This version contains some usability fixes and makes hamster run on newer systems. Starting with this release, the hamster project also provides flatpak builds of all releases (and also of git development versions). This is now the recommended way of installing hamster, if your distribution does not provide (up-to-date) packages. One notable change is the parsing of the hamster cmdline (the "activity@category, description, #tag, #other tag" string when you enter or edit an activity as a single string), which is a bit simplified, but no longer accepts everything it did before. In particular: * Remove the need for using a double comma to start the description, a single comma can be used instead. Using double commas is still allowed for compatibility. This does mean that a comma can no longer be used in the activity or category. * The tags part must now be separated by a comma (previously, tags could be appended directly to the activity, category or description. This allows using # inside activity, category and description (without needing a double comma to force a possibly empty tags part at the end). For compatibility, the tags part can also be separated by a double comma. * Simple #hashwords are now extracted from the description as additional tags automatically (they can't start with numbers and can't contain spaces, but those can still be written in the "tags part" after a comma). This allows writing more natural descriptions with embedded tags, like Coding, fix #bugs in #hamster. * Limitations on the fields are more consistent. All fields can now contain any character, except: * The activity cannot contain @, since that would start the category. * The activity and category cannot contain ,, since that would start the description. * The description cannot start with # or contain the tag separator (one or two commas followed by optional whitespace followed by a hash, e.g. , #), since this would start the tags part. * Tags in the tag part cannot contain a # or , (since that would look like the start of the next tag). * Tags in the description part must start with a letter (upper or lowercase a-z) and cannot contain whitespace. Additional changes are: * A number changes to the overview screen: - Add daily total rows. (PR 596) - Remove lines previously shown for days without activity. (PR 650) - Refactor the range selection dropdown, preventing a problem where it would not be shown on systems using Wayland and some other systems. (issue 639, 645, PR 647) - Do not periodically scroll to the top, only when displaying a new set of facts.(issue 594, PR 648) - Fix overlapping texts with wide fonts (issue 698, PR 699) * On Wayland, fix the popup below the tag field when editing activities and the time field in the preferences window. (PR 652) * Fix exception when calling the dbus UpdateJSON method with a string argument (issue 671, PR 672). * Fix the start date picker in the update/add activity window. (issue 590, PR 674) * Allow resuming last activity with ctrl-space (issue 595, PR 678) * Added croation translation (PR 709) * Fix running on Python 3.11 by removing call to deprecated `bind_textdomain_codeset` gettext function (issue 715, PR 715) * Fix running on Python 3.12 by updating the waf build system to 2.0.26 (PR 732) * Improve HTML export: - Preserve newlines and special characters (PR 704) - Make checkboxes work (PR 665) * Updated and improved flatpak packagaging (issue 123, 456, PR 321, 111, 333, 610, 685) * Rework handling of tags in the cmdline, see below for details (issue 334, 657, PR 663) * Stop using pyxdg, GLib could already give the same information about XDG directories (PR 727) * Minor updates to documentation (but far from complete for now) ## Changes in 3.0.2 (2020-05-19) * Switch from deprecated xml2po to itstool for translating help files (issue 583). * Fix off-by-one-day error in CSV exports (issue 576). * Support Python3.5 again, this was >= 3.6 (issue 582). ## Changes in 3.0.1 (2020-03-01) * Fixed a rare crash in hamster-window-server (issue 571). ## Changes in 3.0 (2020-02-24) * Fixed dialogs placement (PR 549): - dialogs appear above their parent (the overview, if opened). - the window manager/compositer chooses the dialog position. * Fixed gnome window/application association (issue 242) * Fixed numpad Enter now works in the GUI cmdline (PR 540). * Fixed popups position in wayland (issue 339) * Fixed permissions in the source tree. * Fixed "Unsorted": no category (PR 502). * Fixed removal of tags from autocomplete (issue 238) * Fixed hamster-cli windows calls (PR 480) * Fixed font sizes on high DPI screens (PR 426) * Fixed installation process (PR 421) - Updated waf to 2.0.17. No longer need python2. - Default to --prefix=/usr. - Removed binary footer, to ease debian packaging (PR 569) * Fixed category color and tags spillout (PR 414) * Fixed multiline description height (PR 412) * Fixed adding overlapping activity (PR 410) * Fixed update activity window to be resizable (PR 403) * Fixed database file monitoring (PR 401). * Fixed dark theme colors (PR 391). * Fixed hamster-service failure when there is no hamster.db (issue 394). * New options for packagers (PR 565) * New 'version' or 'Version' command/methods available (PR 528). * New Gui is a Gtk.Application (PR 516) * New `*JSON` dbus methods to pass facts verbatim (PR 514). * New hamster.lib.datetime, customized replacement for python datetime (PR 510). * New `CheckFact` and `check_fact` methods available (PR 500). Check a fact validity, with detailed error messages. * New AddFact accepts -1 as start or end, to mean explicit None (PR 492). * Moved Fact to new fact.py * Changed basenames from hamster to org.gnome.Hamster.GUI (issue 547) - metainfo.xml (PR 558) - hamster.png icons (PR 542) * Changed i18n from from intltools to pure gettext (PR 497). * Changed from GConf to GSettings (PR 470) * Changed directory names from hamster-time-tracker to hamster (PR 485). * Changed parser: - Use Fact.parse() - Accept activity starting with hash '#' (issue ?) - Accept comma in activity (issue ?) - Breaking (sorry, really needed): Description delimiter is a double comma ',,' instead of a single comma. - Comma is forbidden in category (instead of silently swallowed) - Same parser for terminal, gui and D-Bus interface. Range is still searched at tail (terminal) or head position (gui, D-Bus). - Fact.range start/end are always datetimes any time given without date is attributed to a default hamster day. The default hamster day is usually today. In the gui, the default day is the day selected in the timeline. - start/end can be entered as +mmm or -mmm (<1-3 digits>), relative to a reference. The reference is usually now. - The fact duration can be given as mmm (<1-3 digits>, no sign), instead of the end. - hour/minutes separator can be colon, comma, dot, e.g. 9.30. No separator is allowed, but only with 4 digits: hhmm. * Changed install bash completion to /usr/share (PR 417) * Changed preselect time instead of activity (PR 415) * Removed trophies code (PR 408) * Used GLib.MainLoop instead of GObject.MainLoop (PR 404) * Added stop tracking button to header bar (PR 427) * Brought back the help system (PR 393). * Improved Add/Update activity window - fixed description input (PR 430) * Improved consistency in date/time handling (PR 429) by - switching to ISO date format (%Y-%m-%d) in `lib/*` to be consistent with hamster-cli usage - rounding (i.e. truncating) all activity start/end timestamps to the minute ** note that this only affects new and/or edited activities in the database * Improved keyboard handling: - Ctrl+Space to stop tracking. - Left/Right arrows change date. - Resume: start now a clone of the selected activity. Ctrl-+: clone or fallback to new if none selected. (same as pressing the + button) Ctrl-R: only Resume (clone) an existing fact. Ctrl-N: only new. - Up, down, Home, End, Page-Up, Page-Down, Return work straight from the overview (no need to click). - More info on PR 387. * Removed non-working stuff that will be developed elsewhere (issue 493): external, idle, ... ## Changes in 2.2.2 * Restore python3 < 3.6 compatibility. * Remove a PangoCairo warning. ## Changes in 2.2.1 * Activity can contain decimal numbers. * Add total duration to the `hamster list` output. * Base Fact comparison on main attributes. * Small improvements to suggestions. * A selected fact can be resumed (start now a clone) by pressing the `+` button. * Facts can be deselected by mouse click. * Still ongoing activities are shown, even if they started on a previous day. * Several export (reports) fixes. * Fact.delta (duration of the fact, as a timedelta) is a read-only property. * Tag list keeps the input order. * Better format of the stats area. Thanks to all contributors (either code or feedback) ! More information by looking for milestone:2.2 or by cloning and using the following command: gitk v2.1.1...v2.2.1 ## Changes in 2.1.1 Migration to python3 and minor usability fixes More details by cloning and using the following command: gitk --no-merges v2.0-rc1...v2.1.1 ## Changes in 2.0 This release marks the transition to Gtk3, and includes all the other feature additions and bugfixes that have been submitted since then and are too countless to list here. Thanks to all the contributors! Please check README.md for the current dependencies. ## Changes in 1.04 This version just packs all the contributed bugfixes of last 12 month (there were just a few) * bugfixes around talking to the notifications daemon * updating tags list in prefs wasn't doing anything * in some cases activity updates were failing when tags where provided ## Changes in 1.03.3 * fix exporting entries to file ## Changes in 1.03.2 * fix bug when trying to enter an activity with tags (mea culpa) ## Changes in 1.03.1 * fix silly bug with path ## Changes in 1.03 * fix issue 61 - installation was missing initial database for fresh installs * loosen backend dependencies so that hamster.client can be used outside the project see http://pypi.python.org/pypi/hamster-sqlite/ for details * desktop notification now once again correctly notifies of "No activity" * updated Bulgarian translation ## Changes in 1.02.1 * Drop gnome-keybindings as a dependency - not used anymore ## Changes in 1.02 This is the first release targetting GNOME v3+. The applet has been removed and recommended hamster remote is the shell extension, available on extensions.gnome.org (also ). * Project Hamster has detached from Gnome and thus we are resetting the versioning. The program name also has changed from hamster-applet to a more generic hamster-time-tracker * Improvements in the command line. hamster-cli has been renamed to simply "hamster" and without parameters launches the day view. Run "hamster --help" to get help on available commands. The executable also supports tab-completion to suggest actions as well as to look up activities and categories * desktop notifications are back * the notification tray interaction has been slightly improved (click to toggle) * ~20 bug fixes https://github.com/projecthamster/hamster/issues?state=closed ## Changes in 2.91.2 * experimental trophy support (to try out need to install the achievement service from https://github.com/tbaugis/gnome-achievements) * improvements in HTML reports Updated translations: * ar (Khaled Hosny) * bq (Damyan Ivanov) * ca (Gil Forcada) * ca@valencia (Gil Forcada) * cs (Adrian Guniš) * da (Kenneth Nielsen) * de (Christian Kirbach) * el (Michael Kotsarinis) * en_GB (Bruce Cowan) * es (Jorge González) * et (Ivar Smolin) * fr (Bruno Brouard) * gl (Fran Dieguez) * he (Yaron Shahrabani) * hu (Gabor Kelemen) * it (Milo Casagrande) * ja (Takayuki KUSANO) * ko (Changwoo Ryu) * lt (Žygimantas Beručka) * pl (Piotr Drąg) * pt_BR (Og Maciel) * pt (Duarte Loreto) * sl (Andrej Žnidaršič) * sr (Милош Поповић) ## Changes in 2.31.90 * maintaining selection on refresh in a more sane manner * self-monitor the database not only for updates but also for remove/create (solves problems with some synchronization tools) * documentation updates * fixed the global hotkey. require gnome-keybindings (gnome-control-center-dev) package as the hotkey is part of expected functionality Updated translations: * es (Jorge González) * nb (Kjartan Maraas) * ro (Lucian Adrian Grijincu) ## Changes in 2.31.6 * the top graph in overview is now interactive and allows zooming in and out * sqlite utf-8 case sensitivity workarounds for queries * hamster's docky helper installed together with hamster * using full text search in the overview window now * hopefully activity trees now behave better on refresh Updated translations: * de (Mario Blättermann) * es (Jorge González) * sl (Matej Urbančič) * ta (Dr.T.Vasudevan) * zh_CN (Tao Wang) * gl (Fran Diéguez) * he (Yaron Shahrabani) * zh_TW (Cheng-Chia Tseng) * zh_HK (Cheng-Chia Tseng) * nb (Kjartan Maraas) ## Changes in 2.31.5 * adjustments for custom widgets to better work with themes * if dialog windows are called from commandline, make sure they shut down properly Update translation * ee (Ivar Smolin) * es (Jorge González) * fr (Jean-Philippe Fleury) * gl (Fran Diéguez) Updated documentation translations * zh_CN (TeliuTe) ## Changes in 2.31.4 * overview gets a menu, drops toolbars and now supports date range browsing * adjustments to starts and ends graph in statistics (should be more accurate) * performance updates in graphics * html report was looking in the wrong place for the template Updated translations * es (Jorge González) * et (Ivar Smolin) * gl (Fran Diéguez) * he (Yaron Shahrabani) * lv (Anita Reitere) * nb (Kjartan Maraas) ## Changes in 2.31.3.2 * respecting SYSCONFDIR environment variable to determine where to store gconf schema (bug 620965) ## Changes in 2.31.3.1 * including generated help pages in the tarball so that they appear in library.gnome.org ## Changes in 2.31.3 * dropped in-house global hotkey management in favour to Gnome's global hotkeys * HTML report template now can be overridden from $HOME folder. instructions can be found in the report footer * remembering path of last saved report * moved build system from autotools to waf Updated translations * cs (Adrian Guniš) * es (Jorge González) * et (Ivar Smolin) * gl (Fran Diéguez) * he (Yair Hershkovitz) * nb (Kjartan Maraas) * sl (Matej Urbančič) * zh_CN (Ray Wang) ## Changes in 2.31.2 * optional integration with gtg (via preferences) * all kinds of bugfixes Updated translations * ee (Ivar Smolin) * en@shaw (Thomas Thurman) * es (Jorge González) ## Changes in 2.31.1.2 * hamster-service had not been packed in the tarball ## Changes in 2.31.1.1 * forgot to pull in translations ## Changes in 2.31.1 * application has been split up in back-end d-bus daemon and clients * edit activity preview widget got some love * minor bugfixes from 2.30 release Updated translations * es (Jorge González) * sl (Matej Urbančič) * gl (Fran Diéguez) ## Changes in 2.30.0 Updated translations * ca (Gil Forcada) * da (Kenneth Nielsen) * et (Mattias Põldaru) * eu (Iñaki Larrañaga Murgoitio) * fi (Tommi Vainikainen) * hu (Gabor Kelemen) * lt (Gintautas Miliauskas) * lv (Toms Bauģis) * pa (A S Alam) * pt (Duarte Loreto) * ru (Alexander Saprykin) * sv (Daniel Nylander) * uk (Maxim Dziumanenko) Updated documentation translations * el (Marios Zindilis) * fr (Claude Paroz) * zh_HK (Chao-Hsiung Liao) * zh_TW (Chao-Hsiung Liao) ## Changes in 2.29.92 Bug fixes * depend on gnome-python-desktop to fulfill wnck-python dependency * minor bug with screen refresh after deletion Updated translations * bg (Alexander Shopov) * de (Mario Blättermann) * el (Kostas Papadimas) * en_GB (Bruce Cowan) * es (Jorge González) * it (Milo Casagrande) * nb (Kjartan Maraas) * pl (Piotr Drąg) Updated documentation translations * en (Bruce Cowan, Milo Casagrande) * es (Jorge González) ## Changes in 2.29.91 * bug fixes - avoiding blank entries, not reusing fact ids; other details Updated translations * bg (Alexander Shopov) * cs (Adrian Guniš) * de (Mario Blättermann) * et (Ivar Smolin) * fr (Bernard Opic) * gl (Fran Diéguez) * pt_BR (Rodrigo Flores) * ro (Lucian Adrian Grijincu) * ta (Dr,T,Vasudevan) * zh_HK (Chao-Hsiung Liao) * zh_TW (Chao-Hsiung Liao) Updated documentation translations * cs (Adrian Guniš) * de (Christian Kirbach) ## Changes in 2.29.90 Updated translations * bn (Israt Jahan) * es (Jorge González) * sl (Matej Urbančič) * zh_CN (Ray Wang) Updated documentation translations * es (Jorge González) ## Changes in 2.29.6 * workspace tracking - switch activity, when switching desktops (Ludwig Ortmann, Toms Baugis, Patryk Zawadzki) * chart improvements - theme friendly and less noisier * for those without GNOME panel there is now a standalone version, accessible via Applications -> Accessories -> Time Tracker * overview window remembers position * maintaining cursor on the selected row after edits / refreshes (unimportant, but very convenient) * descriptions once again in the main input field, delimited by comma * activity suggestion box now sorts items by recency (Patryk Zawadzki) Updated translations * es (Jorge González) * eu (Iñaki Larrañaga Murgoitio) * nb (Kjartan Maraas) * sv (Daniel Nylander) * zh_CN (Tao Wei) ## Changes in 2.29.5 * searching * simplified save report dialog, thanks to the what you see is what you report revamp * overview/stats replaced with activities / totals and stats accessible from totals * interactive graphs to drill down in totals * miscellaneous performance improvements * pixel-perfect graphs Updated translations * es (Jorge González) * et (Ivar Smolin) * sl (Matej Urbančič) * sv (Daniel Nylander) * uk (Maxim V. Dziumanenko) ## Changes in 2.29.4 * overview window overhaul(still in progress) * more progress on tag front (now showing in lists) Updated translations * es (Jorge González) * et (Ivar Smolin) * he (Yair Hershkovitz) * sl (Matej Urbančič) * zh_CN (Funda Wang) ## Changes in 2.29.3 * partial tag support (adding to a fact and editing autocomplete list, no reports yet) * fixed glitches when editing ongoing task * improved save report dialog * better autocomplete for the entries Updated translations * en@shaw (Thomas Thurman) * es (Jorge González) * et (Ivar Smolin) * sl (Matej Urbančič) * zh_CN (Ray Wang) ## Changes in 2.29.2 * fixed bug 599343 - the charts are now back again (for those who had lost them) * hamster midnight is now a preference * when in panel, printing uncaugt errors to .xsession-errors * when looking for ongoing task, don't look into the future (causes some mad durations and is generally impractical) * new dbus method getCurrentActivity that returns just the name and category * fixed problems with hamster interfering with screensaver hibernation code * database MOVED to the xdg home (~/.local) * in reports inlude also activities without category * set start time to the end of the last activity if adding previous activity for today * fixes to the dropdown in compiz (not spanning over virtual desktops anymore) * in dropdown added end time and dropped the stripes (too much noise already) Updated translations: * ca (Gil Forcada) * en_GB (Bruce Cowan) * es (Jorge González) * et (Mattias Põldaru) * it (Milo Casagrande) * pl (Tomasz Dominikowski) * ro (Mișu Moldovan) * sl (Matej Urbančič) * sv (Daniel Nylander) * ta (Dr.T.Vasudevan ) * zh_CN (Ray Wang) ## Changes in 2.28.0 Updated translations: * as (Amitakhya Phukan) * bg (Alexander Shopov) * bn_IN (Runa Bhattacharjee) * da (Ask Hjorth Larsen) * de (Hendrik Richter) * en_GB (Bruce Cowan) * fi (Tommi Vainikainen) * gl (Antón Méixome) * gu (Ankit Patel) * hi (Rajesh Ranjan) * hu (Gabor Kelemen) * it (Milo Casagrande) * ja (Takeshi AIHANA) * kn (Shankar Prasad) * ko (Changwoo Ryu) * lt (Gintautas Miliauskas) * lv (Pēteris Caune) * mai (Sangeeta Kumari) * ml (പ്രവീണ്‍ അരിമ്പ്രത്തൊടിയില്‍) * mr (Sandeep Shedmake) * or (Manoj Kumar Giri) * pa (A S Alam) * pl (Tomasz Dominikowski) * sl (Matej Urbančič) * sr (Горан Ракић) * ta (I. Felix) * te (Krishna Babu K) * uk (Maxim Dziumanenko) * zh_HK (Chao-Hsiung Liao) ## Changes in 2.27.92 Updated translations: * ar (Khaled Hosny) * be (Alexander Nyakhaychyk) * bg (Alexander Shopov) * bn (Maruf Ovee) * bn_IN (Runa Bhattacharjee) * cs (Adrian Guniš) * en_GB (Philip Withnall) * es (Jorge González) * et (Mattias Põldaru) * eu (Iñaki Larrañaga Murgoitio) * fi (Tommi Vainikainen) * fr (Claude Paroz) * gl (Antón Méixome) * gu (Sweta Kothari) * kn (Shankar Prasad) * nb (Kjartan Maraas) * or (Manoj Kumar Giri) * pl (Tomasz Dominikowski) * pt (Duarte Loreto) * pt_BR (Fábio Nogueira) * sv (Daniel Nylander) * ta (I. Felix) * te (Krishna Babu K) * zh_HK (Chao-Hsiung Liao) ## Changes in 2.27.90 * Fixes to idle detection (now works with gnome screensaver 2.27+) * return of the day view * UI layout fixes to match HIG * now it is possible to add more than one applet to panel without crashing Updated translations: * ee (Ivar Smolin) * gl (Antón Méixome) * es (Jorge González) * hu (Gabor Kelemen) * zh_HK (Chao-Hsiung Liao) * sv (Daniel Nylander) ## Changes in 2.27.5 * Better autocomplete * More skeptic on parsing time * Legend in overview is sized proportionally to screen size, allowing larger labels Updated translations: * be (Alexander Nyakhaychyk) * es (Jorge González) * pa (Amanpreet Singh Alam) ## Changes in 2.27.4 * Now it is possible to copy/paste activities in the overview * mostly polishing and bug fixing the new stuff brought in in 2.27 cycle Updated translations: * bn_IN (Runa Bhattacharjee) * es (Jorge González) * et (Ivar Smolin) * fr (Claude Paroz) * sv (Daniel Nylander) * uk (Maxim V. Dziumanenko) ## Changes in 2.27.3 * A much better DBUS support (Felix Ontanon) * Switch days at 5am because humans tend to work late. Overlapping activities fall in day where the largest part of it is (Patryk Zawadski) * Now you can enter negatives minutes to start an activity in past. Example "-30 cookies" will start activity "cookies" 30 minutes before now * TSV, XML and iCal export * Ability to filter task by date and category * Overview has been improved by adding some nifty statistics for your pleasure Updated translations: * ta.po (Dr.T.Vasudevan) ## Changes in 2.27.2 * Now a reminder is displayed every configured amount of time also when no activity is being tracked. (Can be disabled in preferences) * Allow to switch to same task if description differs * Activity edit icon in dropdown is now keyboard accessible * Start time and end time can be specified when typing in task. Example: 00:04 Hamster * slightly smarter autocomplete with category suggestions when after @ symbol * fixes to edit activity dialog's end time field Updated translations: * el.po (Jennie Petoumenou) * et.po (Ivar Smolin) * ta.po (Dr.T.vasudevan) * uk.po (Maxim V. Dziumanenko) * ca@valencia.po (Gil Forcada/Miquel Esplà) ## Changes in 2.27.1 * Overview window graphs have been redone and now are less noisy * Tasks now can span over midnight, showing correct per-day totals in overview * Add earlier activity / edit activity has been overhauled and now is much easier to use. An experimental preview has been added * In preferences UI buttons have been added for editing and deletion * Glade files have been migrated to gtkbuilder format * now it is possible to start overview and other windows straight from command line using "-s [stats|edit|prefs]" switch Updated translations: * ca.po (David Planella) * cs.po (Petr Kovář) * da.po (Ask Hjorth Larsen) * de.po (Hendrik Richter) * el.po (Kostas Papadimas) * en_GB.po (Philip Withnall) * et.po (Ivar Smolin) * fi.po (Ilkka Tuohela) * fr.po (Claude Paroz) * gl.po (Ignacio Casal Quinteiro) * he.po (Yair Hershkovitz) * kn.po (Shankar Prasad) * lt.po (Gintautas Miliauskas) * lv.po (Toms Bauģis) * nl.po (Wouter Bolsterlee) * or.po (Manoj Kuamr Giri) * pl.po (Łukasz Jernaś) * pt_BR.po (Vladimir Melo) * ro.po (Mișu Moldovan) * ru.po (Nickolay V. Shmyrev) * si.po (Danishka Navin) * sl.po (Matej Urban) * sv.po (Daniel Nylander) * tr.po (Baris Cicek) * zh_CN.po (Aron Xu) ## Changes in 2.25.3 We were late for 2.25.1 and 2.25.2, so here we go - changes since 2.24.0! Applet - changes * Now it is possible to add description after activity, delimiting with comma: "watering flowers, begonias" will add activity "watering flowers" with description "begonias". Likewise you can go for cacti, and forgetmenots * Task category can be seen in dropdown and can be specified on fly to autocreate: working@new project - will create category "new project" and add activity "working" to it * Hamster now can remind of itself every once in a while, interval is set in preferences (George Logiotatidis) * Sending dbus signals on activity change (Juanje Croissier) Applet - love * Applet now again can be found in applet list by searching for 'hamster' * Get instant totals per category for today, in applet dropdown * Improvements in report - somewhat nicer look and there are also totals (Giorgos Logiotatidis) * Use vertical space if we have some on panel and show applet in two lines Updated translations * bg.po (Alexander Shopov) * el (Nick Agianniotis) * he (Yair Hershkovitz) * ku (Erdal Ronahi) * lv (Toms Bauģis) * sv (Daniel Nylander) * zh_CN (Ray Wang) ## Changes in 2.24.0 Applet * some more strings available for translation, but the main changes are the updated translations Updated translations * ar (Djihed Afifi) * bg (Alexander Shopov) * bn_IN (Runa Bhattacharjee) * ca (Gil Forcada) * cs (Petr Kovar) * da (Ask Hjorth Larsen) * de (Hendrik Richter) * el (Nikos Charonitakis) * en_GB (Philip Withnall) * es (Jorge González) * et (Ivar Smolin) * eu (Iñaki Larrañaga Murgoitio) * fi (Timo Jyrinki) * fr (Claude Paroz) * gl (Ignacio Casal Quinteiro) * gu (Sweta Kothari) * he (Yair Hershkovitz) * hi (Rajesh Ranjan) * hu (Gabor Kelemen) * it (Milo Casagrande) * kn (Shankar Prasad) * ko (Changwoo Ryu) * lt (Gintautas Miliauskas) * lv (Toms Baugis) * mk (Jovan Naumovski) * ml (പ്രവീണ്‍ അരിമ്പ്രത്തൊടിയില്‍ ) * mr (Sandeep Shedmake) * nb (Kjartan Maraas) * nl (Wouter Bolsterlee) * pa (Amanpreet Singh Alam) * pl (Tomasz Dominikowski) * pt (Duarte Loreto) * pt_BR (Vladimir Melo) * ru (Alexandre Prokoudine) * sl (Matej Urbančič) * sq (Laurent Dhima) * sr (Горан Ракић) * sr@latin (Goran Rakić) * sv (Daniel Nylander) * ta (Kannan Subramanian) * th (Theppitak Karoonboonyanan) * tr (Baris Cicek) * zh_HK (Chao-Hsiung Liao) * zh_TW (Chao-Hsiung Liao) ## Changes in 2.23.92 Applet * fixed code so that it works also with Python 2.4 * Fixed bug with tasks falling into unsorted category (bug 548914) * Fixed error when switching tasks with doubleclick Translations * ar (Anas Afif Emad) * bg (Alexander Shopov) * bn_IN (Runa Bhattacharjee) * ca (Gil Forcada) * cs (Adrian Guniš) * de (Matthias Mailänder) * en_GB (Philip Withnall) * es (Juanje Ojeda Croissier) * et (Ivar Smolin) * eu (Iñaki Larrañaga Murgoitio) * fi (Timo Jyrinki) * fr (Claude Paroz) * gl (Ignacio Casal Quinteiro) * gu (Sweta Kothari) * he (Yair Hershkovitz) * it (Stefano Pedretti) * lt (Gintautas Miliauskas) * lv (Toms Baugis) * mk (Jovan Naumovski) * mr (Sandeep Shedmake) * nb (Kjartan Maraas) * nl (Wouter Bolsterlee) * pl (Tomasz Dominikowski) * pt (Duarte Loreto) * pt_BR (Vladimir Melo) * ru (Sasha Shveik) * sl (Matej Urbančič) * sv (Daniel Nylander) * zh_HK (Chao-Hsiung Liao) * zh_TW (Chao-Hsiung Liao) ## Changes in 2.23.91 Applet * When adding earlier activity in current day, set default end time to now * In overview start week with monday/sunday depending on locale (bug 548102) * Respect theme colors for graph labels (bug 548840) patch by CJ van den Berg * Fixed fail on exit when there is no last activity Translations * ar (Anas Afif Emad) * ca (Gil Forcada) * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * et (Ivar Smolin) * fi (Timo Jyrinki) * fr (Claude Paroz) * gl (Ignacio Casal Quinteiro) * gu (Sweta Kothari) * he (Yair Hershkovitz) * it (Stefano Pedretti) * lv (Toms Baugis) * mk (Jovan Naumovski) * mr (Sandeep Shedmake) * nb (Kjartan Maraas) * nl (Wouter Bolsterlee) * pl (Tomasz Dominikowski) * pt (Duarte Loreto) * pt_BR (Vladimir Melo) * ru (Sasha Shveik) * sv (Daniel Nylander) * zh_HK (Chao-Hsiung Liao) * zh_TW (Chao-Hsiung Liao) ## Changes in 2.23.90 Applet * Changing name from "Hamster" to "Time Tracker" * Information on when computer becomes idle is now determined from screensaver * Fixes to focusing issues when calling applet with hotkey Translations * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * et (Ivar Smolin) * fr (Stéphane Raimbault) * gl (Ignacio Casal Quinteiro) * he (Yair Hershkovitz) * it (Stefano Pedretti) * lv (Toms Baugis) * nb (Kjartan Maraas) * nl (Wouter Bolsterlee) * pt (Duarte Loreto) * ru (Sasha Shveik) * sv (Daniel Nylander) ## Changes in 2.23.6 Applet * Follow GNOME version scheme * Properly integrate with Keyboard Shortcuts in gnome-control-center Translations * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * fr (Stéphane Raimbault) * it (Stefano Pedretti) * lv (Toms Baugis) * nl (Wouter Bolsterlee) * ru (Sasha Shveik) * sv (Kalle Persson) ## Changes in 0.6.2 Applet * Fixed the header info and updated the Spanish translations * Updated the Dutch translation by Wouter Bolsterlee (544975) * Disable keybindings if not supported by g-c-c * Properly integrate with GNOME's keyboard binding dialog * Fixed problems with simple report * Now you can edit facts in overview by double clicking * Updated French translation (Stephane Raimbaul) * Put icons back in overview window * Stock buttons for add / update fact * Fixed potential popup window positioning issue Translations * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * fr (Stéphane Raimbault) * it (Stefano Pedretti) * lv (Toms Baugis) * nl (Wouter Bolsterlee) * ru (Sasha Shveik) * sv (Kalle Persson) ## Changes in 0.6.1 Applet * Do not eat up middle-click * Fixed fact pushing on overlap * Correct orientation on vertical applets Translations * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * fr (Pierre-Luc Beaudoin) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.6 Applet * Simple reporting via Overview dialog Translations * de (Matthias Mailänder) * es (Juanje Ojeda Croissier) * fr (Pierre-Luc Beaudoin) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.5 Applet * Preferences are now editable via user interface * Added option to stop tracking on shutdown * Current activity is now showing up in totals Translations * es (Juanje Ojeda Croissier) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.4.1 Applet * Fixed lintian warnings, mentioned in bug 531965. Also, got rid of rest of them :) * Fixed rules as per bug 532711. Patch by Juanje Ojeda. Translations * es (Juanje Ojeda Croissier) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.4.1 Miscellanous * Fixed usage of spanish and italian translations Translations * es (Juanje Ojeda Croissier) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.4 Applet * Fact editing! Translations * es (Juanje Ojeda Croissier) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.3 Applet * Many small fixes to activity editing window (setting, focus, F2 for renames and others you would expect) Translations * es (Juanje Ojeda Croissier) * it (Stefano Pedretti) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.2 Applet * change days on midnight also when there is no current activity * option to stop tracking after certain minutes of idle * simplified versioning to three numbers Translations * es (Juanje Ojeda Croissier) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7.5 Applet * Fixed midnight crasher Translations * es (Juanje Ojeda Croissier) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7.4 Applet * Fixed licensing issues Debian * Packaging is back to per arch Translations * es (Juanje Ojeda Croissier) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7.3 Applet * In stats the top caption shows what can be actually seen (day / week / month) - geekout * remove hamster killname, since it breaks x86_64 * switching tasks on doubleclick in applet main window * some more thinking on accidental facts (forth and back to previous task within minute) * graphs now have fixed offset from left, long labels get ellipsized Debian * attempt to package with arch = all Translations * es (Juanje Ojeda Croissier) * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7.2 Applet * Fixed focus issues with global hotkeys Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7.1 Applet * Fixed regression with keys ignored in applet window Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.7 Applet * Fixed applet vertical sizing issues * Showing Evolution's active TODO's in activity lists * Drop down window now doesn't have double shadow on top of it * Fixed bug with situation, when activities get moved to newly created category Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.6.2 Applet * Stop at 12 different activities a day, 12th being total of others * Give more space to activity stats * Put back resize to both sizes, since we are now ellipsizing Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.6.1 Applet * Kind of fixed problem with gconf schema not appearing Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.6 Applet * Enhanced drag and drop behaviour in edit activities window * Added labels, tooltips, spacings, and other flags to enhance experience Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5.5 Applet * Fixed pysqlite dependency * Fixed area chart color Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5.4 Applet * Hamster now has a process name for killall, which enables us to kill it on install! Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5.3 Applet * Fixed antialiasing problems in bar chart Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5.2 Applet * Minor changes and slight adjustments to Swedish translation Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5.1 Applet * Fixed window icons Translations * lv (Toms Baugis) * sv (Kalle Persson) ## Changes in 0.1.5 Applet * Initial release hamster-3.0.3/README.md000066400000000000000000000232261452646177100144610ustar00rootroot00000000000000# Hamster - The Gnome Time Tracker Hamster is time tracking for individuals. It helps you to keep track of how much time you have spent during the day on activities you choose to track. This is the main repo. It is standalone (single module). All other repositories -`hamster-lib/dbus/cli/gtk`- are part of the separate rewrite effort. More context is given in the history section below. Some additional information is available in the [wiki](https://github.com/projecthamster/hamster/wiki). ## Installation ### Backup database This legacy hamster should be stable, and keep database compatibility with previous versions. It should be possible to try a new version and smoothly roll back to the previous version if preferred. Nevertheless, things can always go wrong. It is strongly advised to backup the database before any version change ! ##### Locate the latest db ```bash ls --reverse -clt ~/.local/share/hamster*/*.db ``` Backup the last file in the list. ### Kill hamster daemons When trying a different version, make sure to kill the running daemons: ```bash # either step-by-step, totally safe pkill -f hamster-service pkill -f hamster-windows-service # check (should be empty) pgrep -af hamster # or be bold and kill them all at once: pkill -ef hamster ``` ### Install from packages ##### Debian and Ubuntu Package status Debian: https://tracker.debian.org/pkg/hamster-time-tracker Package status Ubuntu: https://launchpad.net/ubuntu/+source/hamster-time-tracker Installation: ```sudo apt install hamster-time-tracker``` (or graphical package installer). ##### OpenSUSE https://software.opensuse.org/package/hamster-time-tracker ##### Fedora and EPEL Package status: https://src.fedoraproject.org/rpms/hamster-time-tracker As of November 2023, hamster has only been packaged up to fc30 (with hamster version 2.0). Installation (on releases with existing package): ```sudo dnf install hamster-time-tracker``` (or graphical package installer). For more recent releases, refer to compilation from sources above. ##### Snap Easy installation on any distribution supporting snap: https://snapcraft.io/hamster-snap ##### Flatpak [Flatpak](https://flatpak.org/) enables you to install Hamster in a versioned environment and then run it inside a sandbox. It is a method independent from your distribution-specific packaging system, ensuring that the application can always be reproducibly built, even without hunting down all of the dependencies yourself. Debugging is made easier as every user has the exact same environment at runtime. Permissions are limited to what the application really needs to function properly. You can install the Hamster Flatpak from [Flathub](https://flathub.org/apps/details/org.gnome.Hamster) via: ```bash flatpak install flathub org.gnome.Hamster ``` If you would like to install Hamster only for your user, simply pass the `--user` option to the above command. To invoke Hamster from the command line, use: ```bash flatpak run org.gnome.Hamster [args...] ``` ### Install from sources #### Dependencies Hamster needs python 3.6 or newer (not included in below install commands). Older versions are not supported. ##### Debian-based ###### Ubuntu (tested in 19.04 and 18.04) ```bash sudo apt install gettext intltool python3-gi python3-cairo python3-gi-cairo python3-distutils python3-dbus libglib2.0-dev libglib2.0-bin gir1.2-gtk-3.0 gtk-update-icon-cache # and for documentation sudo apt install itstool yelp ``` ##### openSUSE Leap-15.0 and Leap-15.1: ```bash sudo zypper install intltool python3-cairo python3-gobject-Gdk sudo zypper install itstool yelp ``` ##### Fedora ```bash sudo dnf install gettext intltool python3-pyxdg python3-cairo python3-gobject sudo dnf install python3-dbus itstool yelp ``` ##### Help reader If the hamster help pages are not accessible ("unable to open `help:hamster-time-tracker`"), then a [Mallard](https://en.wikipedia.org/wiki/Mallard_(documentation))-capable help reader is required, such as [yelp](https://wiki.gnome.org/Apps/Yelp/). #### Download source ##### Git clone If familiar with github, just clone the repo and `cd` into it. ##### Download Otherwise, to get the `master` development branch (intended to be quite stable): ```bash wget https://github.com/projecthamster/hamster/archive/master.zip unzip master.zip cd hamster-master ``` or a specific [release](https://github.com/projecthamster/hamster/releases): ```bash # replace 2.2.2 by the release version wget https://github.com/projecthamster/hamster/archive/v2.2.2.zip unzip v2.2.2.zip cd hamster-2.2.2 ``` #### Build and install ```bash ./waf configure build # thanks to the parentheses the umask of your shell will not be changed ( umask 0022 && sudo ./waf install; ) ``` The `umask 0022` is safe for all, but important for users with more restrictive umask, as discussed [here](https://github.com/projecthamster/hamster/pull/421#issuecomment-520167143). Now restart your panels/docks and you should be able to add Hamster! ##### Flatpak Alternatively, you can also build a sandboxed [flatpak](https://www.flatpak.org/) yourself. You might need to install the GNOME SDK beforehand (an error will notify you about it, if needed). Execute: ```bash flatpak-builder --force-clean --user --install \ build/flatpak org.gnome.Hamster.yml ``` This creates a temporary flatpack build folder in the ``build/flatpak`` directory. Once the app is installed, the whole ``build/flatpack/`` directory can be removed. #### Uninstall To undo the last install, just ```bash sudo ./waf uninstall ``` Afterwards `find /usr -iname hamster` should only list unrelated files (if any). Otherwise, please see the [wiki section](https://github.com/projecthamster/hamster/wiki/Tips-and-Tricks#uninstall) ##### Flatpak To remove the installed flatpak, just run: ```bash flatpak uninstall org.gnome.Hamster ``` #### Troubleshooting [wiki section](https://github.com/projecthamster/hamster/wiki/Tips-and-Tricks#troubleshooting) #### Development During development (As explained above, backup `hamster.db` first !), if only python files are changed (*deeper changes such as the migration to gsettings require a new install*) the changes can be quickly tested by ``` # either pgrep -af hamster # and kill them one by one # or be bold and kill all processes with "hamster" in their command line pkill -ef hamster python3 src/hamster-service.py & python3 src/hamster-cli.py ``` Advantage: running uninstalled is detected, and windows are *not* called via D-Bus, so that all the traces are visible. Note: You'll need recent version of hamster installed on your system (or [this workaround](https://github.com/projecthamster/hamster/issues/552#issuecomment-585166000)). #### Running tests Hamster has a limited test suite, that can be run using Python's builtin unittest module. From the top-level directory, just run: python3 -m unittest This will let unittest automatically find all testcases in all files called `test_*.py`, and runs them. To run a subset of tests, specify the import path towards it. For example, to run just a single test file, class or method respectively run: python3 -m unittest tests.test_stuff python3 -m unittest tests.test_stuff.TestFactParsing python3 -m unittest tests.test_stuff.TestFactParsing.test_plain_name ##### Flatpak To run the tests inside the flatpak, use: ```bash flatpak-builder --run build/flatpak org.gnome.Hamster.yml \ python3 -m unittest ``` #### Migrating ##### Migrating data to flatpak If you would like to retain your data from a non-flatpak installation, you can do so by running: ```bash gio copy -b \ ~/.local/share/hamster/hamster.db \ ~/.var/app/org.gnome.Hamster/data/hamster/ ``` After checking everything works, you can remove the original database. ##### Migrating from hamster-applet Previously Hamster was installed everywhere under `hamster-applet`. As the applet is long gone, the paths and file names have changed to `hamster`. To clean up previous installs follow these steps: ```bash git checkout d140d45f105d4ca07d4e33bcec1fae30143959fe ./waf configure build --prefix=/usr sudo ./waf uninstall ``` ## Contributing 1. [Fork](https://github.com/projecthamster/hamster/fork) this project 2. Create a topic branch - `git checkout -b my_branch` 3. Push to your branch - `git push origin my_branch` 4. Submit a [Pull Request](https://github.com/projecthamster/hamster/pulls) with your branch 5. That's it! See [How to contribute](https://github.com/projecthamster/hamster/wiki/How-to-contribute) for more information. ## History During the period 2015-2017 there was a major effort to [rewrite hamster](https://github.com/projecthamster/hamster-gtk) (repositories: `hamster-lib/dbus/cli/gtk`). Unfortunately, after considerable initial progress the work has remained in alpha state for some time now. Hopefully the effort will be renewed in the future. In the meantime, this sub-project aims to pursue development of the "legacy" Hamster code base, maintaining database compatibility with the widely installed [v1.04](https://github.com/projecthamster/hamster/releases/tag/hamster-time-tracker-1.04), but migrating to `Gtk3` and `python3`. This will allow package maintainers to provide new packages for recent releases of mainstream Linux distributions for which the old 1.04-based versions are no longer provided. With respect to 1.04, some of the GUI ease of use has been lost, especially for handling tags, and the stats display is minimal now. So if you are happy with your hamster application and it is still available for your distribution, upgrade is not recommended yet. In the meantime recent (v2.2+) releases have good backward data compatibility and are reasonably usable. The aim is to provide a new stable v3.0 release in the coming months (i.e. early 2020). hamster-3.0.3/data/000077500000000000000000000000001452646177100141065ustar00rootroot00000000000000hamster-3.0.3/data/art/000077500000000000000000000000001452646177100146745ustar00rootroot00000000000000hamster-3.0.3/data/art/16x16/000077500000000000000000000000001452646177100154615ustar00rootroot00000000000000hamster-3.0.3/data/art/16x16/org.gnome.Hamster.GUI.png000066400000000000000000000016561452646177100221170ustar00rootroot00000000000000PNG  IHDRasBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<+IDAT8u_h[uǿw͟Me5RTvȐ{)MIRe>eLAhB#L0tk,nYܴɽ;>t:x89>$"Lf@M:6H,E_Kֈ,W?c3e)&™h#d'A@i[XD0F j1ꌼ0Vkli4+;~XXitߪoeO#q8ouFho }'eכ`MvybXͥu=DG$Gav^}qكMkcA n$٘?7\J+|GW/(E49 B胈+D)!J` @Wb1PI۱)Vvo΃( A.}>=N }_Vr -%mkD< C@Rxa=Ey:Yq^= -{ D{b4D cl]"v?0J %Ef\E(MOg7G kSbdR2f (L$"-W7}?yamo7$7Da1|Xs΋]yގMϰ^P>xugݬ}DيiaaYd~r,?jQgcfX!o}[-GFoj~m-N`4pLFnurG0eznKeY4M6;ٓbTӅ[emϝWR4*IRYcd!t.*IENDB`hamster-3.0.3/data/art/22x22/000077500000000000000000000000001452646177100154535ustar00rootroot00000000000000hamster-3.0.3/data/art/22x22/org.gnome.Hamster.GUI.png000066400000000000000000000030251452646177100221010ustar00rootroot00000000000000PNG  IHDRĴl;sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAT8}[l\̙W]_'NQi L&u۠D6HQ%("!sKQ""RT" Z!(iB#aG8v'kgw=~e@oTGw؛`tLYsAgl- <2ˌ봐S|VAƐa!j-զ^9\p")[#ȌV4g6$g>kxW*N#óGNm w﻽`Xn$N/}.8Oo߹rfn녱%I:0uk?DsU;pKn/ ~z项vʼn| *;Ņ%AHc[#y 0;NCH`K +JTR`,S$/ $ɶR^$B`N%A?~aݙR7[hwl4 'ԦLiSTK~]xh^Kk w.^XyZx;y:u=PƢLpժN!^md!hWN+P oۯYm^KR,"R!>l8{TmbNv|FzθMKD~x*?7-?L0x8cNvYn!rc0zͥ"L )0 Bs[ Rۆ:+1iJ,nyZY$U &a|n"Uj#KL)o '?tbW6s l ɵOqsZk}/r_>C%i7ewM L{tTm~βM\znrH[?y^Z$%DLI I4~Iۆ28u! s~;FQzr8D^ itFIL3EdwtJE6%K瓒y|bXVK7򺨛q,0_w(rݷ0xQoy[vF˥z2 7:ң eO&Med^o %7 E+S٬n@_]t;GW! }osԽ*&vTް#R0ԛ{lGgKW} k`{߿e CiЛD.iz6,\_7M/̲ ` R OOo!GA&Χv3,w|%1B$zw{ >G$"ޔCIENDB`hamster-3.0.3/data/art/24x24/000077500000000000000000000000001452646177100154575ustar00rootroot00000000000000hamster-3.0.3/data/art/24x24/org.gnome.Hamster.GUI.png000066400000000000000000000031021452646177100221010ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATH[l\W{OlIBh$"T-U  > nB@J}jU&9Fv.sf̹7/ dKZp,8uv%8$ ă$q a1}'>|N)?@ȗuZ̪Z! mHh!-sjc Smzu+sgJdd>3/wYu-7G.Qn1%̾gz7v3K3?:L1 ;KFF@{ăFܩ9(2yö`\r9nj4]r`l,/.Gt ~?PCC:]\F dҵ/\]򬎍zŋ<}Z$YO0]t@E1 8go,W.GPEbVіkn+|\5 j4wy 8e#"$ tJ|1j7+_BZAi8)E"0o x2GQpO+֟@QPڐ1ٻod4]p [F 0rydI*2s.e<\jr?ƧW*ОzZ帢FT cjV`~cB$ @,$Pc[\^e1tE~_+ƆE%ݧi8ը$DZ:VRٔ<;N*"IBOg壟ڮ+'z3n4O.-7UhGa8NϥwQ亯Faf՛]||taİٴL䝙=S'N}7_wv GIN}St0 rnP +sdp b=EizIENDB`hamster-3.0.3/data/art/32x32/000077500000000000000000000000001452646177100154555ustar00rootroot00000000000000hamster-3.0.3/data/art/32x32/org.gnome.Hamster.GUI.png000066400000000000000000000052541452646177100221110ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< )IDATXŖk]U{syܹsg03ZB`Ap )1*J!o $bxƄTRZ MK_әG>=キ!vH ~$;de~{!I&_~ggJE!EvƄ%IĖ(- !xV^zs|ƍt{:J Y#es-:ҖCx*vcpQ`__,6lu/d羜9+9UcE i&=r-ͦ5(2= XvoO @wyn}c-9eî]^3]궏"$e/ІM=NmZE~wl6]oţ8zbWX1w遲F> 6OOfWؓVo= Id~E۴]k?ֽܧ+oء Ik>G|@^~Ck6DtE' πU9s\Ž-gG]|v@6n+ϼ mu< !X"b.1p!!yԘnBĶv]60ق{&>8FZDχxhi흝RJX nTjTZ\u9$3VI1JfLi_X#ndDܯmȿǺwvhL46F$XN&ߕbjH&$^ +ܪ?}Iбw8 򙼲/g!Pi+-յ*C6Z&Dܸ;_:K/x8D&OgJL -_XnA׏D;g  Ŋpx^t\Ap󾳒_rۯRGf*O {Qү?IG欸,[מy,ʥ5opQIAި5";K.[U~YqK&d*h*zˬ=>R'cLܪ(JxbЉ 8W]Bjk՚d\C&#=K2 {?<;B>U3kpa"0$InWGlKH*LMA Pi(UlK^:t\{dI066|رcGB!B߮S)RufAp]|>wx'; A |FNӇN,pV˓ء4 -u(,u Dx\XqppLg 0HLb攧*NGS#PМ3!Ħ:eʹ_bʲl 8@|XSOaFr +fؙcnZi?>(4PxIENDB`hamster-3.0.3/data/art/org.gnome.Hamster.GUI.png000066400000000000000000000111131452646177100213170ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAThՙiՙwݗ^fAQ4jT@8I$jTTԨ$1hCEf2Ɍ' рI[\ ʾHC7.~ .d:un[OV>|Pkv!MFHR)F)!C"M{n>|W̛W/8nԚhi㲉b #i1!$꾄zӮj5ѫ?|9̾ӻi1iΉMɱI(1P"RTJQ(% A)A{o+WEX}[wSɈ[KS6wީ##RdF;@"hˤbh)Z46M&qk{_΅8f&J.G='_c/|(g$kcg{J.^4Z1{c+a zd2bT5 D*<' c B>:n줐$PH8nHF{2)+oOjڐ^xh[Jɍc ) AFQ(& HmlQzZP;f!8C-``=ZԃwvIOxỳq@Й6'AP)dS&@N6lUJ^JU(^+v[ #TqJ[_H(ͦTGP#ihxƊW` #t +{Y}slʛǛo:x>a!F0FREu`߶?~CpF9%烒 0ap8ߜ½VvcG`rVظꏍ-ذ2F@0J^=ח^pi˹!64&WwH5ӏi>:HPO>8aٲK~9p̈́7+^}{de iG+vZ_|1:8}?@ZHS^9whȚגln^s0?08]tƱd5]KzY&G@epZ_ßsV)/q» 63L0" ! 5s6qg9-8}jC1,:b_[@ 9h]A[+RՁ!Z=sOy&w VPHɤJs4#ۻkzȉ0`rܯ=pD©cċ$z|Bݞ9BhjᗎFG\2+~2D.ۖ.0%kNXw '^d; {z]8~ɣ3ʗtΟԚ2?G"4g'm@ɆWvcHV&pE50IN)^慁onW?r=E27[dȔi|@k56cr=>Ds3a)-K'뮳QߓJ}飒{ɜ2 pw롆' 9ӯXrZ_6 V*%/HsD=jIYA0z\k2hrP @];sI3fV^C6aݩCc--ML$ -eRuJRH H V*8ⲏ (C2燈2vߴws9,̙v<%?EOPt)+a$Ű T~M_xn03 ޱL1٧ {3T\_9#0n8Jz7 ~(ȤqIXz[֬YO=v*عs-,:u%λEc:g4!! JM)!2xփT"Na {ގ8pHQOXR":)ؐd%%QEɧOuR?\,S"ZFT[n]9rPQ~Xj)EDvU٤P<oaP 4?*m+ Q:ے4JKw{raSN>廟Ifr!x}썓 S NQuC@G#[;*ahmJR6gH'ݺ Ef\F]yfմ~^]߉Wv?k̄e7}f,4~4tG!k-8~">MAѐƦj(47 4d2+%xپy˖-{Ϭq*pOutvxcÆh9IF _+{ܼ a_e]^ߺ] 5'G;$ <Գҋ +WpԲpg>4a„ ϟR}T5eԪU(1JOkD5N"ri agb ׏5{K)rc%]F9! t \Le1xG曻~}!0ˮ|> +j˨Vx0J*(3(9x:P D#V*"!H$PC(pPJA( aB:F6E*exMT.IF2f9c袋.L465XJ#1 {a "ıJ)H R)htJ`Q B((`3!8LÀiY,isB'@_?#/ΎNgݺuO;H&oUTZ2˶ )mHVj_05V>J (tHD)T*z;;.^]*tvtr.0R#|wc;GCw䡮pΑf)0yE4 GRO:x_Gj0)0|$"M7ߪbryPW2BH[6o$$$% ΑV0~P @ 0HD0,= C}G?;,&WIENDB`hamster-3.0.3/data/art/scalable/000077500000000000000000000000001452646177100164425ustar00rootroot00000000000000hamster-3.0.3/data/art/scalable/org.gnome.Hamster.GUI.png000066400000000000000000000111131452646177100230650ustar00rootroot00000000000000PNG  IHDR00WsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDAThՙiՙwݗ^fAQ4jT@8I$jTTԨ$1hCEf2Ɍ' рI[\ ʾHC7.~ .d:un[OV>|Pkv!MFHR)F)!C"M{n>|W̛W/8nԚhi㲉b #i1!$꾄zӮj5ѫ?|9̾ӻi1iΉMɱI(1P"RTJQ(% A)A{o+WEX}[wSɈ[KS6wީ##RdF;@"hˤbh)Z46M&qk{_΅8f&J.G='_c/|(g$kcg{J.^4Z1{c+a zd2bT5 D*<' c B>:n줐$PH8nHF{2)+oOjڐ^xh[Jɍc ) AFQ(& HmlQzZP;f!8C-``=ZԃwvIOxỳq@Й6'AP)dS&@N6lUJ^JU(^+v[ #TqJ[_H(ͦTGP#ihxƊW` #t +{Y}slʛǛo:x>a!F0FREu`߶?~CpF9%烒 0ap8ߜ½VvcG`rVظꏍ-ذ2F@0J^=ח^pi˹!64&WwH5ӏi>:HPO>8aٲK~9p̈́7+^}{de iG+vZ_|1:8}?@ZHS^9whȚגln^s0?08]tƱd5]KzY&G@epZ_ßsV)/q» 63L0" ! 5s6qg9-8}jC1,:b_[@ 9h]A[+RՁ!Z=sOy&w VPHɤJs4#ۻkzȉ0`rܯ=pD©cċ$z|Bݞ9BhjᗎFG\2+~2D.ۖ.0%kNXw '^d; {z]8~ɣ3ʗtΟԚ2?G"4g'm@ɆWvcHV&pE50IN)^慁onW?r=E27[dȔi|@k56cr=>Ds3a)-K'뮳QߓJ}飒{ɜ2 pw롆' 9ӯXrZ_6 V*%/HsD=jIYA0z\k2hrP @];sI3fV^C6aݩCc--ML$ -eRuJRH H V*8ⲏ (C2燈2vߴws9,̙v<%?EOPt)+a$Ű T~M_xn03 ޱL1٧ {3T\_9#0n8Jz7 ~(ȤqIXz[֬YO=v*عs-,:u%λEc:g4!! JM)!2xփT"Na {ގ8pHQOXR":)ؐd%%QEɧOuR?\,S"ZFT[n]9rPQ~Xj)EDvU٤P<oaP 4?*m+ Q:ے4JKw{raSN>廟Ifr!x}썓 S NQuC@G#[;*ahmJR6gH'ݺ Ef\F]yfմ~^]߉Wv?k̄e7}f,4~4tG!k-8~">MAѐƦj(47 4d2+%xپy˖-{Ϭq*pOutvxcÆh9IF _+{ܼ a_e]^ߺ] 5'G;$ <Գҋ +WpԲpg>4a„ ϟR}T5eԪU(1JOkD5N"ri agb ׏5{K)rc%]F9! t \Le1xG曻~}!0ˮ|> +j˨Vx0J*(3(9x:P D#V*"!H$PC(pPJA( aB:F6E*exMT.IF2f9c袋.L465XJ#1 {a "ıJ)H R)htJ`Q B((`3!8LÀiY,isB'@_?#/ΎNgݺuO;H&oUTZ2˶ )mHVj_05V>J (tHD)T*z;;.^]*tvtr.0R#|wc;GCw䡮pΑf)0yE4 GRO:x_Gj0)0|$"M7ߪbryPW2BH[6o$$$% ΑV0~P @ 0HD0,= C}G?;,&WIENDB`hamster-3.0.3/data/art/scalable/org.gnome.Hamster.GUI.svg000066400000000000000000002273461452646177100231210ustar00rootroot00000000000000 image/svg+xml hamster-time-tracker 20080331 Kalle Persson hamster-3.0.3/data/art/stock_calendar-view-day.png000066400000000000000000000006601452646177100221030ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<-IDATHJA;פQAAHaAl-mip;/ v*8=BuKř*씿vaEkόu %2=iϮ{jyJcu&=.n9sXG5=󘔖gU?٩dVF}N% @B;`?a1|4[9W!"ȹ0d 40 ;>b!F*EryEߋ6 y](I=4MDYˬ"D,BWIENDB`hamster-3.0.3/data/art/stock_calendar-view-month.png000066400000000000000000000010231452646177100224450ustar00rootroot00000000000000PNG  IHDRw=sBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org<IDATHݖ;N@[p $<::J h"EJ &QA EByq8^c(8" fͷ3NoϤTڅϱVőwGZ.{|ެ:<C*:S<aP*sNBBK9%s9Er@k)X#x6idXi( ~Z;{c GX4Z2M܁eYv [X4Z2'"jي$ҩױLK涽0B59~Df= PO=X5jZmYM43o=0}!Ѹ?|oyM<鷣 &=h> False True False 0 out True False 12 12 True False vertical 8 False True True True none True False 8 100 True False 1 Today: False True 0 True False 0 Jun 17 False True 1 True True 0 False True True True none True False 8 100 True False 1 Week: False True 0 True False 0 Jun 14 - 20, 2010 False True 1 True True 1 False True True True none True False 8 100 True False 1 Month: False True 0 True False 0 Jun 1-30, 2010 False True 1 True True 2 True False 4 True False 8 100 True False 1 0 7 Range: False True 0 True False vertical 8 True False 12 True False True True 2010 5 11 False True 0 True False 0 7 to False True 1 True False True True 2010 5 11 False True 2 True True 0 True False end Apply False True True True False False 1 False True 1 False True 1 True True 3 hamster-3.0.3/data/edit_activity.ui000066400000000000000000000576651452646177100173310ustar00rootroot00000000000000 0 0 False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 Add Earlier Activity True org.gnome.Hamster.GUI True True False vertical 5 True False True True True none True False go-previous-symbolic False True 0 70 True False True True 1 True True True none True False go-next-symbolic False True 2 False True 0 cmdline box True False vertical True False start cmdline False True 0 False True 1 True False vertical True False start description False False 0 True True never in 50 True True word-char False True True 1 True True 2 True False 4 True True False vertical True False start start False False 0 True False vertical False True 1 True True True True True True 2019 8 15 True False start date False True 2 True True 0 True False vertical True False start end False False 0 True False vertical False True 1 True True True True True True 2019 8 15 True False end date False True 2 False True 2 False True 3 True True True False vertical True False start category False False 0 True True edit-clear-all-symbolic Unsorted activity completion True True 1 True False True False 4 vertical True False start activity False False 0 True True edit-clear-all-symbolic category completion True True 1 True False False True 4 True False vertical True False start tags False False 0 False True 5 True False gtk-delete True True True True False False 0 True False 8 end gtk-cancel True True True True False False 1 gtk-save True True True True False False 2 True True 1 False True 6 hamster-3.0.3/data/hamster.db000066400000000000000000000460001452646177100160600ustar00rootroot00000000000000SQLite format 3@ &>-&>-% tablefactsfactsCREATE TABLE 'facts' (id integer primary key, activity_id integer, start_time timestamp, end_time timestamp, description varchar2)I!!]tablecategoriescategoriesCREATE TABLE categories (id integer primary key, name varchar2(500), color_code varchar2(50), category_order integer)?WtableversionversionCREATE TABLE version(version integer)0!!+tableactivitiesactivitiesCREATE TABLE activities(id integer primary key, name varchar2(500), work integer, activity_order integer, deleted integer, category_i     rF!!WtableactivitiesactivitiesCREATE TABLE activities(id integer primary key, name varchar2(500), work integer, activity_order integer, deleted integer, category_id integer, search_name varchar2)?WtableversionversionCREATE TABLE version(version integer)_!! tablecategoriescategoriesCREATE TABLE categories (id integer primary key, name varchar2(500), color_code varchar2(50), category_order integer, search_name varchar2)h 3tabletagstags CREATE TABLE tags (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, autocomplete BOOL DEFAULT true)  ^nP ++Ytablesqlite_sequencesqlite_sequence CREATE TABLE sqlite_sequence(name,seq)E ']indexidx_tags_nametags CREATE INDEX idx_tags_name ON tags(name)U {tablefact_tagsfact_tags CREATE TABLE fact_tags(fact_id integer, tag_id integer)\ 1windexidx_fact_tags_factfact_tags CREATE INDEX idx_fact_tags_fact ON fact_tags(fact_id)Y/sindexidx_fact_tags_tagfact_tagsCREATE INDEX idx_fact_tags_tag ON fact_tags(tag_id)}tablefactsfactsCREATE TABLE "facts" (id integer primary key autoincrement, activity_id integer, start_time timestamp, end_time timestamp, description varchar2) + g e R;p  c autocomplete BOOL DEFAULT true) () #%#%2010-02-12 10:47:14,671 DEBUG: CREATE TABLE tags (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, autocomplete BOOL DEFAULT true) () q #%#%7  #%#%X_7  P7 7 7 7 !7 E (-. 6 6 7 7 T7 #%#% P7 #%7 F 7 ULL,^7 |l7 ULL,b7 N @f7 W@f7 7 7 J7 ULL,cf7 7 7 Ў6 xZ7 UЎ6 x7 9XЎ6 @f7 Ў6 f7 Ў6 \7 Ў6 0b7 Ў6 XR7 Ў6 P7 Ў6 pe7 Ў6 `T7 increfacts }h9~9s9@0~7 :97 7 7 7 XR7 Ў6 7 38 8 8 8 8 8 i%%%%7 7 YrXЎ6 (S7 Ў6 S7 Ў6 +g47 EEE7 T7  #%7 7 P7 O7 P7 8vi }hT0;~W0; s`0;@0~7 :h0; \7  Q7 8 w7 8 C8 M7 8 q g7 4iZb DIi HW6 DD }h0;~0; s0;@0~7 :0;7 T7  p7 #%8 S7 S7 S7 Ў6 H8 3 8 8 8 8 8  8 Op7 #% + g  tc  start_time timestamp, end_time timestamp, description varchar2) ()iEX"2010-02-12 10:47:15,033 DEBUG: CREATE TABLE increment_facts (id integer primary key autoincrement, activity_id integer, start_time timestamp, end_time timestamp, description varchar2) () C Ў6 H8 3X-8 -8 -8 -8 -8 ACX-8 !C 7 #%  3"7"K//Etablefact_index_segdirfact_index_segdirCREATE TABLE 'fact_index_segdir'(level INTEGER,idx INTEGER,start_block INTEGER,leaves_end_block INTEGER,end_block INTEGER,root BLOB,PRIMARY KEY(level, idx))AU/indexsqlite_autoindex_fact_index_segdir_1fact_index_segdir!!tablefact_indexfact_indexCREATE VIRTUAL TABLE fact_index USING fts3(id, name, category, description, tag)'11ytablefact_index_contentfact_index_contentCREATE TABLE 'fact_index_content'(docid INTEGER PRIMARY KEY, 'c0id', 'c1name', 'c2category', 'c3description', 'c4tag')~33#tablefact_index_segmentsfact_index_segmentsCREATE TABLE 'fact_index_segments'(blockid INTEGER PRIMARY KEY, block BLOB)   #A2008-03-30 04:58:54.176736hamster-3.0.3/data/org.gnome.Hamster.GUI.desktop.in000066400000000000000000000006441452646177100220320ustar00rootroot00000000000000[Desktop Entry] Version=1.0 Type=Application Terminal=false Name=Hamster Comment=Your personal time keeping tool Icon=org.gnome.Hamster.GUI DBusActivatable=true Exec=@BINDIR@/hamster Categories=GNOME;GTK;Utility; Keywords=time tracking;time-log;personal productivity Actions=overview;add; [Desktop Action overview] Exec= @BINDIR@/hamster overview Name=overview [Desktop Action add] Exec= @BINDIR@/hamster add Name=add hamster-3.0.3/data/org.gnome.Hamster.metainfo.xml.in000066400000000000000000000041101452646177100223270ustar00rootroot00000000000000 org.gnome.Hamster CC0-1.0 GPL-3.0+ and CC-BY-SA-3.0 Hamster Your personal time keeping tool

Hamster is time tracking for individuals. It helps you to keep track of how much time you have spent during the day on activities you choose to track.

Whenever you change from doing one task to other, you change your current activity in Hamster. After a while you can see how many hours you have spent on what. Maybe print it out, or export to some suitable format, if time reporting is a request of your employer.

Features:

  • Fast and easy data entry with autocompletion of recent activities
  • Flexible grouping with @categories and #tags
  • Day, week, month or custom views with tallies by groups
  • Generation of html reports (can be customized)
  • Data export in text, xml and tsv formats
org.gnome.Hamster.GUI.desktop hamster.desktop The overview window https://raw.githubusercontent.com/projecthamster/hamster/master/screenshot.png The overview window with statistics https://raw.githubusercontent.com/projecthamster/hamster/master/data/screenshots/overview2.png hamster https://github.com/projecthamster/hamster/wiki hamster
hamster-3.0.3/data/org.gnome.hamster.gschema.xml000066400000000000000000000016341452646177100215770ustar00rootroot00000000000000 "" The folder the last report was saved to The folder the last report was saved to 330 At what time does the day start (defaults to 5:30AM) The hamster day of an activity is the civil date of start time, provided start time is after day-start. On the contrary, if start time is earlier than day-start, then the activity belongs to the previous hamster day. hamster-3.0.3/data/preferences.ui000066400000000000000000001044511452646177100167530ustar00rootroot00000000000000 False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 12 Time Tracker Preferences center 450 500 True org.gnome.Hamster.GUI True False vertical 8 True True True False 12 8 4 4 True False start start vertical 8 True False True False New day starts at False True 4 0 True False False True 1 False True 2 True False Tracking False True False 12 8 4 4 True False vertical 15 True True False 6 True True 150 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK vertical 4 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK _Categories True category_list 0 False True 0 True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK in True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False False Category list True True 1 True False 4 True True True True False list-add Add category False True 0 True True True True False list-remove Remove category False True 1 True True True True False gtk-edit Edit category False True 2 False True 2 False True True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK vertical 4 True False GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK _Activities True activity_list 0 False True 0 True False True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK in True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK False True False True Activity list True True 1 True False 4 True True True True False list-add Add activity False True 0 True True True True False list-remove Remove activity False True 1 True True True True False gtk-edit Edit activity False True 2 False True 2 True True True True 0 True False 0 none True False 8 12 True True in True True word-char 4 4 autocomplete_tags False True False Tags that should appear in autocomplete True True 1 1 True False Categories and Tags 1 False True True 0 True False end gtk-close True True True True False True 0 False True end 1 hamster-3.0.3/data/report_template.html000066400000000000000000000275301452646177100202110ustar00rootroot00000000000000 $title

$title

Show activity log

$activity_log_title

$header_date $header_activity $header_category $header_tags $header_start $header_end $header_duration $header_description
$date $activity $category $tags $start $end $duration $description

$totals_by_day_title

$show_prompt

Categories

Activities

Tags

$show_template. $template_instructions.

hamster-3.0.3/data/screenshots/000077500000000000000000000000001452646177100164465ustar00rootroot00000000000000hamster-3.0.3/data/screenshots/editor.png000066400000000000000000001143521452646177100204500ustar00rootroot00000000000000PNG  IHDRh6sBITO IDATxwXW3ݥ.{oy5jbo|IlX1K4PH^,e-3 4{|;Xw,ɲVea },˲,˽mBVpo7#j>^ S[RTȋ j57,AH$.V&zso#@!IR/H^x< (]OKI^*ǽJiT,*&f&fAP2Rlk(82*2?'G$Yvo#Q.AI\N$Y%YX%w %;GdGȽПzZ5uS?qj&*eIQ̪-#i@[C}iZCkj(8|Ss˜ $"#6L(G|/'ZDM0%0<eYx k RRRegL*"z\ ,75Je<ǝ5q|{9ZJQ]F!THڌNmMyH&B1i$A0A܌oZQ(Rrsr `i*27p4KWG Buu\Z.{x<g_`faD"5eSƧ&'ʋ )jj ׶#7k&fX"ХMIJԃygY j^׶w[ٷ[ϔY(N _:YiW`aaҿSI\\6򼝌R妦&ErZ#<@ܒHd$ l]*V?&B5G,CI<|մu6spoBMkb_5yreTkȰP Wg8k&j 26k(wg⏻ښ*TB z9Y7!^gY6;lYCw$5ӥ'޿KG7o)4"uj.EeD­_^9Wnޮ;NnjE }ŹiU_6k 5+,#wDE62Š,}ӷ)=l> dc)Ag{&{*% MNnS8H=)XSJHbnm3`YF(5KI 2O*5,V1xՊmH+vĚO-MZ&Z? ]i-'dO]i#u_=1,DgصqۯX0ИvÖ;;3bҪYE[fآvH'ߧswsb$GEBUw֯ibi;|?F֏f읔ٯ03+ʛ{'& mj~Qd3#~}mV_O+4 6} \_2^EĈS{ؚ8Y=ȟ _Wd g ʪZ/Dhhf)+*$@CG7_FfYO s(ihn(NPͪ_B('-aԭ|贖>{OdlB)t>,=}$"k`BasFZV)/(V_;Z\(/ ?/YalFbR4pԵ7 ɱB'Ly4Cbk+ݛQIk`1Q=$TWÒ(|,%z]\l]{dbۼI A/׷;_fZM×NoٛI/ם5IX`{ {|0 h+˖,,F˂^MeeYǾlXv%E]͜MصZ)LlJl満K~5izzWCZhhz3O6|^C]43×#lקǏouiJ,mj~Qk գ'Y:f՟w+T42RCAhrZ<əfXU sqp%NfZy^(5nS e嗘JP!ˑX9jg <@`kYO'z:q7wuӺ9`.)- Qӱ /4b#EC)PogZX +PoX Kcׯ1iͽhiW'eE[:ya`3cQܵSqKG|/t]ZJr NMK/3wU˼) ʂL6'r׽m̒2elcyF)?)fX squO}eq[EM'JUؚ sr5*Vj"+Pd+xE(활u UV[!TXFȳWΕv>pDgvuIOƔUKby%q2qbĨ]&4K ZZ RsG*Uzr?%LU/EnZ ϰlDbm@_4 Yx|x:ZzI<^еM?%L lu{uW88$.5aY :4s =t{3xGD/wRsqSKw"h`.12зZ(b+b;Zh+̀AMߨt4Jd,n祈b\@jY0oVzBh$E9ʙq9t7qȲ6s~5O3~0ii.4skˡe'N-}%&) $6WRp8;؂-z,7&`ʞ]/D80_ڀetPjk@Ȏa4JP*2wgԱU&򒵪"M jE)iy.`م'.iEBsGC.3QgX0NA2<3r|=)8`P+/ޭ Z)K('Ѫb<נcZ|>( >Va/U(,mp+(ȥ?w66 -$W]|B$aD6CJM KϛO%xmפ:U蔹+e -ዝ^>ՈVީT w3̋rÚeE+I 5i /- ޏՐ2;̗͜$\W3׋U?LrkoP/O+4,m ہ<<#;29K*`yc/%6c)# 2 *ѼAnC:+}bߡ P(+_ |00LRk>J ^mVRPNX!P j@^PFr QåuH0"L¬PT˯w6oROZ] D |"T{e R3!P=C7r#I^]w!HS{[G#BL$EQ~ffE!>x$1FuOBz׾~:W#3 lQQ<oiM\J}Y,diaW\,H^4.W'@VvvzFðM^@Rrr^<DzlxDBJjJL/OjZ6#3t4j>xG$xȨn4n BeWVQs1{Qwf3vQQ==k>DFG=mi&0ic?' ,;;9**݋:m3J h+99^˛5msrs%89:*ʒe?xaxJJNI+| '.>aY0qVN۷fMc!:L!P%`D!*'B!T 8BJQP 23z:B"cc}:ԴG8QлO.cԙ1cFBB0q"BsqvhXVݷO--<=9{yO(,,"yT"y]w&&\IFf溍xAASܼGB}}}[h^&ղŋƎV~63Zvݮ+''w͏ u%,[X.WY bb[Bggg{ƍ9s_~ϗ۹xUݣ/;w]e !܎{vcP-~>0loh4|>Z~8qTu] =7wdD;=Gmݺ8e2?ǏO8^59cG0770/gA}?~͞{5~A cF^{6BamQTk![޽z2 ܢA9EQMr ֬XaVX~o-r797f@^~~rJ{v &B}h-[nnnީSH=N|>ennVzMG7CC3m H4և`pSYӧV!͛6OGh|Y]6l$>ޣnl޽fϘևyЯϤRBJ=N.$Iܾ{נ\ݝ*prJkS&,a!>48q w/dzg IBbRɕu؄)_T(##.XjMEBQ ª!P}Tq"c>;aİ^2٥Wnޞ;suC+KecGHMM۹^=AYGM7oYfA5ν6 hZ{oqOӻk=Gͪ+6~е7wc['Qӆu?8[Γƍ]:^~7n߼C_jm7}H( hd?D5{RyAߩ!T33j׵8/^WϗXʢ(jOF̽ 4X{Žulu@۴,S{@:VVK-#"zHTS!֮Zvm#""rm^/**`yp82BR IDATyDxޣ{̚P+Oxqyw_.8ۼZ"G'CuۼMV~e<^§TX֯byW~}~5;&NBN`D!*'B!T ɓ'3 0;}]S]*dz|fXu Vj5sA^ +{8;FcddTk{g]?mx<aaaF lؒ++꺇!;d9E}8ϧ|>E!*'B!T 8BJĉBU&NB0q"B!L!P%`D!*'B!T 8BJĉBU&NB0q"B!L!P%`D!*'B!T 8BJxow<wp;v0 ;y*cN=zs!P-xg|SXlN$DDFqMBPu݁T4XN4a"{BqIIxw:q>MJf<=ZeB}'qqХ+ffeYZXt0aH ;q_LuOPTmQqqX]ry~׬ww~iE@l\?< \TT8l^ݻUB}P!qNjzJj*H$}/f.w[YNZ_RrYݾsWvm劯!/ܸy |_Ͳ,xËMyy%%%p)_^v%k4$aLlܒe+J>|BjXVl՚TwW׃xĈCի,r$ɩE}zv?{-"<_.:р~r987˭ hHeDD=OÆ,(,\|FSxdG>vB8Snݾ-8Ņ  |ַw4l`|>_$qA\\32N>h}{q8cb*!?nqd 4|Idĩ3 (ZK;RB}8#=zTypqvvwsJlml2!)iՒ-|>DFEم4mogפ?W0L\|< 4M@ݹ O;~b5W#ŹcG!8sLf͂Sc].T"Ox232eOj~0J3`ƌ`B}Zmǃ>8b1DDEefe4sos,Z:X8* XYqi5!1QP]m@tl\tLV].NbS^b)H8#ׇ [kk5Lj>2t䘉!+8vBZMtUg?yB4tH(,Q*y<ނysR./rBx1 H.Ɲm ]:u0c&M6 ;8 O+ݝ;Ǜ z9EK'4X +*##_~.8vB>OQTUg^[~\,X*2m}Ǝ|K_o$qD$Fn,۹퍍6m%\+}Eֿ n.%%<i^=woܲeBBFz:h4͠)ˆ-9;D!^{N|`Q?άU!Їg B!j8U{}eTFa !v">kLʅWPUM{nO=VژR$I&NB"$TZbEwVRT{X"hGFVҪqB&kO?.9tc sV>}|W)qy_ikJ4*qBe% ؒ?+[:K:TEejrFU BՎ^F tt*A4TjX`- -BJSXҊ!L!P%`DV5mѪ?q&&&7S,:4"";~7okMD~!ݻA)SH|A;w>s///Dbaajժ:G&"--MWB~ ݻwWA믕mzlyfppIwء+gY 211 ^~}qƍ뗼aK.?~Ν'O~Q``{>{C8;;7o޼*^ɦMΚ5Ӈ޾}{'NԩxȑSLٽ{Y,XY]:pAt%\? o߾*BWܹsƍMz7SڬHc_<K.;v;v,/ܮjӧO/a7l_F4iIFFD.{zzvu~_-]ʪ{Qr:YRRaggWXXȲ,M2LW'//YfVVV'O4hުU+ Ξ=˕YtuFUVo1رcG&[E4PMYzyJW3 t޺Y3ŋ8q :t… ä[n6l6lغuV^n:LfԩSÇ/=rvvѕq7FS;~wy"h ,7>x`֭\e.>|;jW^mܸȑ#333&44TwK. :… \Z~N7Bj*q\|?D\ѣ322nݺu=a飫kk'OΙ3GwBԞ={~o߾Ν;  <855UW_mٲI``?+'/uA>ccc6m\t€iӦ@Tڸq]v2 2o!7U9#-}e׮]`llqFQ8+;; !!!&Lؼyc.\8|~߿ٳ?ܽ{7$$D"GGG<ĉ_bפCݣif̘099Y Y+g& K.su#-}8b ]o''',;w\{RBI`ԨW.fp,ϝ;Dzlqqĉu{===ӦMJO?IJСC۴iòl~~>ۼy3˲#G433j:x [|q"TޫkUZP({СC=zصkWju>|DA^^^!!!ׯ_yRlݺu AAA ݻ\!CZspp077_|-[wմir޼ySV5@ĵk߯ ;Vّ>۷Zqt njh V)WeD{Ν;w]9ӦM^s7nlnn~me/_ܹsg033 ޾}m۶ܟ\رc~)IC y"}Ae|]I^^p¢ g͚Bom۶-,, 2dȐk~קN8pAXssrrvZbb"iƠmJJZ}611vҥKϟ_888;vϧ(aÆBT*X9iC6/'4M7Ν;-Z7nϞ=Ç)NB@TTTZZ͛7u6Ѯ]Јlm-]vݲeKNNN\\p쥿Ǐ_bի aPEEGXFCӥw 5x<ޜ3zOv5-ϏԕDGGMԩ9o|E 6ѣ{ &unQNzzfZZ5AEEE'߿?77|ҥKWZUN@;;;98Ž̑>=Mk9\=pDXfMXXئM7m|rn%D"iɓ'ܮu 믿çN١CÇ B]ڵkAA֭[Y]p쥿ϟ3gʕ+Ϟ=*B*|'OHD{ 4~|eM)wo߾=۷/wg'hm۶$*F?i?Ilݺ5JABYv_tM6-[$СCj۷o4H=zݻ<YfV+'`VH_b:tЙ3g;y$Q{nZh=Ԉ,YdI 0`Ҟ6mqUn_hQ||OGv5jԨ &kNC,n޼uֺmڴ122ڰaQPPPƮ&LЪUiӦW8LЛh<5W@ܡ]=:[o5kVNF1r7n/[lx0uy=SNuw,[ʕ+277]d ʉo:t6lgaakN>=goooh޼Ν;mllwmpcǎSL)**Zz_maa1q?<>>iӦwټy~jmm]y2l„ ӧO(QQQK.~]@kk>l̙ݻw[frH$?qDK/s1qy={E7nشiӴi R^IeǏOQJڍ7^panrppOW\GOj-2 =X[[gM*pڻk׮+WM(->!3Mmڤ$kV fhCOΟ?Y AF5jTJJӧOU*X,ێ!jܲdhh MuC̙3u݋P-#۷UKUX׽@(FC4iGu݅ZR-#^D# uBbZ1!*ܬ5M 6 $rR^Mt!F9Z`*d%)<`+[-Պ:*=@!jǩp%mïJRVU*mVv n&+Sۭb<ًBSV"ǁU ^V.hpE L[B&.=-≓'y$y[ |lxW ò8BR0SUP4] ttT\!(7/FTNJ!BRKZjB7@=!@tU"d2.qBwO.Roy' B!!pRZڟU;ۅ;_]-DZ;vԣ70!Ї@VcDj\g-GDdwD$+|[to!ЇS\...SUzpJ>^^|S&M0vH(|QQ$ߢ9BBhܸ1f¢"T +ӤdaӣbV kneW@صgѕjBԲU+X\PP@}7WظGB:Z޶cTjUVT qq{8(qQQ!{u5LKسefe[whvFFFPT\Ceia9Ä1cD"aFf校O]z?QTX]ryQl߼=0JG :o=xqGso=qk#"X`==??;5+~ݻEŝ:=cEU!Mϟ>zʋ:q劯!/ܸy |.^ѐ$!cb,[T*0R(<ϧ2KP,;;'7wWSRS@"gd0//7sA?kogkffvܓr| 2:໥2Zd+֬mxhޏG?oȨh%%%Kr:BJu~Sn^^II ;y{`U z2JYTX!6m࡝or+ӳpfCN}铭Z4;w+ w7gN^:}j=eȩS IDAT֤mS'F  ^eY<ɲlFf̜/pI"綡?xx<\rcc(w7Ayu+K˟7ore@IIsQ6NfFf[ B0$c۵O8q ,?ϣ;믣ĩ3 (ZK;R̬,H|t[h@_$%ܺ}[8 7p AA<'G_l?1У[O~ ^>#F+/<%5Ͽojڸ1th9iR~  4|Id!8?/nܺMӴ]\IAa!ui#ruq93rUӤ;wCV-W} |Fhkcӧ *&6F~2\5,rErJ ]W\EѻUFy؃Z$eK]b9:Ч O[?!P=BEEEŽ]ħOmg/\{;;DƎ0ft鶾>슍zK OCo߹~+4))XYqXz:MӍejgdpsA.Ep,LM Q)ش)˲qqlR$޻,'$fM ;[V-[L7H$MwlZήts{;m_) lб]}8+pbDqF1lR4~ߵCw2!zksω,{Ǚ5Nǣsu,XBEY+>!PM Y8G1 BՎz1|)gԣޡ*fMB|0=#*ϥqqB!T;;95MMihpqB!Zdiwr>ȺB󣢢(J4!z-Z}H$H$I BF1v>!L!P%`D!*'B!T 8BJĉBU&NBB!T8yG<g!P%`D!*O"Boٻή'&+uP(ŋ3`066\;^6e -(S6m~ܑ/o%MH 8=w\'q"BJ‰B) 'B!,!p"BJ‰B) 'B!,!!B q!RNBH X8B!%`D!!B4p dXljB) 'B!,!p"BJ‰B) 'B!,!TeTZƁB*N7B!"ZBH X8B!%`D!!RNBq3g,}X߽5} Ԓ qDzUUTwiPKҮorg)q `gkqT@ n.._z,$[NNN.B_$BHVZzDBӗ B-SVEEE٪>r!ĩ?_GGwy)U|S?vK~ͩSޖuhniZZ9CGqD[v^oB))'O>웾}@8oq+*{th\& BpBBBAK m-/F,:ff7nRC|~ b坿t_dS'GGswux)AL&d~ɹr:\q @.\+#K s{ = "hH$il䔠kjjJjv󖻛wlof߹wID$a6!vfh~p8)o@br20L'G1doRL$srsgLxz# )+/ڰI$1֕K!7;o\ qhnmNn.ڷ7=r(|[YUxeBJsqv!IR {yyhʎ&%&%=ŢZ% ދO+uu_l|X[ڳb6͍[|>Jg͕NK$k+997oKZ9o|:'B}v:uTC\<MSң=z;m^A=W ? {蘚H$twI)0n(iՄ G_@,_tEV8ߧQi$X,򤦖F+dj(ngNKNIzz7$}jZg#zvF"nz݆u/[~#tqvzP(oOid$kE@+S'M:qBIITxzS-1qqecm}eіs?,-,x2vT=}Cصqc'KZ[gegSgS<__G{Ĥ]#ͦhx6" u275KKK 8wq͚]Uů81qFѨĤd .\r}oF=Ng]t5 6sk@]+~[f= 7oc^P@w7W twsf;FtwWqD#ǬzlVMyǭ81qqWWI$?hjFW! U8W-]<~({;٦K/^wq Bbeap֮Zameq\]kh`99@w7"8TZ^vuqfY:~??8eeYY@}mb"+KKmm֭7 R-*2B$DynlσE!ߒܳݱbX,uBH X8B!%`D!8*+ U z4Bt:ehdҮfB*j4j,*+-*sg0*FCDDEYIvFieN~)Eɯ()*tnKzB0 =#-W1fBj!'˔9΢|k;gԂdZ:6b!FfT*J]}U" dWWUʶ`!^uLY*Nԇ`\Yz2e(!p"B*//‰B)D"!n 'Iڽf:$?`!vy111_pFDE=}{yjMR0B-RYRD"!NwU_v޾k΍v^fÍ7455LWZ5y? 00fٲel[n 4zmbb"mT0B-RYR9F FB!"'7;4m 4M\aaa#FԤZ&L D2p@iCVWW߹sFE_~lpjq>-B333kGKK gjZ36o۞ԟb8{7{FgLJJ"[BLNN622 餴4ww6 L&SWWWWWz+%?B-'gBH) cEM~f뿎uRXWdR000@AAѣ.\hjjիӧ@QQ\rʕo^NZO2 p$ɫ7n<\fС :444ehAhhh\tICCߟL:jT2'hy/\vmUf6m+..ްy˭ۍJ477iKqq1XZZWbccCCCfffO}q*fB4ڻCŻsuq8nl^=O=% ,+>>^ڒ666b͛7666@]Ӯ];Ǧz ! pFmbRҲU_znoktv.^tI[ZZvڕ` 4hҤIT;AwssH># eOЄӣVD"qsuU ;֭[˗/?t F3g͛7'Lp?~xǎ\ׯӧ1޺G@P=BjCGNOA$%G}5kFtС)SP-ZD/_GMȉPKz!ED"8p9!e[r:D/_ɩ #~ʃG_eTw[[2ԮV5j]ՃXb1Y,Vbӿo&] B_32>3|4B!,!p"BJ‰B) 'B! 'ΐ>!:  l fBU7˔RjiU{@BH)e%DfBU7˔R442H#bU (Xfhl"ۈY՛eRqS[W >EIQ!MB01!-; !eRAƦ Cdj> ,A,CHuL)jxWKRFɇYPѴϪkom?ms~H^~qǎА?;CN:#rxOB@T|qӺߚt0mң{1# O=&:13~gY1nzək}W^5|wO9_PrɢzNdaQ7ѿc/;IҕxBɡ9v6vbw?Б9JMH5aRAC.Z)b-k~ߍǞ}"Z3vTElulKQqqaaQπҖ^^,3-=C xW6MMؿ_aQQl\Kt/djbBP(߿u,]8ʎ5s*fBHEMr~hXuu͆Vk|ė%n޾#bh`מzM23ب֌~ʵh;I2lw6VI/]Ԙ>er=̲䔔3~ sQS6.!A$[ZgfJ$'G$G{rsuih.3S]J5VWW}_:wn.@?9KTwb323?GS3Éc@z;FfX&OM[I޽@GoR9sl(ةv UYҕ FN!N#yҕ+D= S{t[5 6.^"0deoL&s;}_$ O  hjjt)4!H$~{5xꚚLqݹ}ișK:m.?O ՉI_jZz@ҕ#g< Έ !tZ]'Л"add=e޹wܥˉIIzI{,^*+;;'7h@~v'O9{h!WTJWT%׷ԙCUUUZV&RSww~}z׍!ݝH}쨑_n7}D^qs9t:=&.^\~|lߑ:-=m}|* -] n..j>"BPsֵrth[;+׮$!ih?Ϟ `?ah--ުw;MС};֧~ݰYYp~ȝ!S'MptwcCNm҅ ɟk}CG]XTdfj!ǎ5tek<9h,C5!D"qA76!5N BFedf;~}^2+@!.Agw,`,EPX, ֹSS !п^,{& !T//n8&C!//\.B!UUy!p"BJ‰B) 'B!,5# /B‰W[{7@Dk% H=;jCũbq snklEHKv6< )6ǩS'MTzb"$8:|/$ Bc'07tuٞRgEe{S IDATsC<340mĉSg%--+362оݬSy?|^'<}6:&:po&DG Wշu o\@u|aHWgS&8@NnБ`yuVS'9+;c[6Qtn]:oYV-!57쫬b} !Ir ;O5;&.^g&$%sҞ.NuC =3}P8 f2}J!'ԙs%-yd2YL懜+׮3Y|c]]aAkE"N`k$%XSS3tUUEWxlB<OwZAcO9yuF]WGzzzVY%*}8"Nq!Grn'$$ n`ei_ZVF-qDdBR͞5}lO==0L joޚhoCn;j$>|H2h`h7]d:9:@YyyІM"hԈᷮ\ ١};x*ܻūf&'CPG>ldhx`ܢVWW߽͐$;cڔ Pp`ȠvoKNɾZ);SS? F 335ճn( 5Su3=#33mr[!vv4FڳK &$&߽PGPޞn|&)&O PSSÍjV!C._^YY.+,lݺtMMK/)):gG,-32=hjN4AŭPSh(g_DpsZ[Z@YY|?ztݞuCa`gkWQs3@(g_{|>_WGĄ!>35WG /\"IdAffm}|j`.w' bqRr =JW"H1F5R;9y$'Nǣ/Cj\"!S&SY7fǙFF[$?^Qֿ{kod2.N$I& 5cn~L4a_Z7oҖ!!bޥt/ tZo߽ 񠮔9"6.C1#G)j mh(^ dqCC+KKHwPgl uS'ܼ|X|\ijjN~}v;Nl6;+;)M< /--%K#M6kvUb@bR4 \qZOwŸD$a#|g-Zvԋ]K$i'r87BjWXT$'>.[7b89Q-z徃Y3gY7`{C y6:rFuM Xt 7oc^P@w7W(,,f_ۺ5<G YC٬Ù,ۧG"b̤)ԡ*/ק|e+855йn4MvMMCivm+'>m-oQ)F}trt+Kˤ¢"~~Z=f+`{.{vǷ&GsGwvڅ]ʊ㺹ٿ:wq BbeaZftut~iKo/5+X^Q{yz;;p-\}-ꜪE3~lc}R,.!uN2sVϺ(AED"8p6Q;y?JeB<ڿu !%DtnG Xr{v;XLܿ'ܻ߿{π~P7nVU_ z6oY31L.Ak%G{;̜3qDdIIǸсt)%%0Թ"0js@~e7o͵07̡^ࠔʪ*[^=&" gUeEqA>R"!TVW[Vmg˶&}r4]MƁobTB*\--C#VX) B)k RpZ9h3 !!$;#MWشnL1Ԣ\SJ_YQRTݖl|j ^BKoDc!.rMN-*ȷsFHEL&֡0V;BP)EɯoB1:zU1RzsM)*NIԁ`Dk0RzsM)!P!RNBH _p$k֮~!&LhҖL)?hǏWv4P`QRSS'OrGAr,]޾)"yb PfΜIšb_/P8#>/?uO>PrrrT]6pjiL1HOO 2eѣGg̘ݶm/^|6/_=xizBQ]pԜ>{F!7%m igj(lذ ŋ.\ŋvvv .,mF&]Č3.\J9\jӜ9s*** 3foٲE%z}yڵ{;dffVp9TP(|5n"$x@ttN9LMMcbbn޼)۸xb)Z8qFQhSNٓf 6,++Kȑ#~~~:::m۶ݶm]~&~Ĉfffڝ:u m4 ڵm۶ZZZ^^^ǎz >|Ŋ4?5*9kZwr>jTvN{k׮ZjԨQ~mnH "#= 1 RƼOM3qҦr6m8n#G{nx%I`2W\D$wo޼Ot:}Μ9Oi4IгgOkk9##j9|0I'NߺuB|"LgϞikkג%KBBBjjjd;HӄB]'Imڴ9p֭[MMMJKKI\f ɜ;w3g͛d2-Z$ X+böm>| ?ŋǎ:t(9se5';;{Μ9zzzeee59BK,^$ܜF(+T+{@hHHQM^87?p&?e̲r͛7w^$G٩S'$KJJ ݻI7nA$I07Jg_bŒI{{JTܹs cÆ JlrƧNUR$UVk׎:!p&MOM_8-,,9d2׬Y}v\۷ord}(E]{cՏ8qׯ`oǧW^.K֭[gddT&jhM.Bp~ԏ?Ǐ+blC$I^qID5Æe`///}}O$ֳgO>}sT?} ɓ'Kg8qH$^8|p'ڵkcƌÇW#Yb`cc󂂂رc]vcԨQҜrqq xqDDDMMMǎ}?N+++}} 6ٳݻwǎkݺBpT~iLe5:0e״"jt$|_>zթS={\HYMX8oݾ}+׮-Ylۦ~~6ou"h4Z.]U;,,0%%Ez3;;dHg"_n:mmٳgB-)V^^~ҥ\ꭁï\m۶[n՝[dؤ@NZ}nGGG'<<}˗/oժU鵲^KKXvH׍Lz״"jt$bxɓ>Aλix}{n+.qWઅt-99ŋ:u{]VVo>$ZZZvO.m˗/^xӦMwܑ Ac2W^޿());K^^>Ⱦζ055hM6M܆q̙/_=zݺu7oB,K#/F&GkZw~ 5:FH[zj׮]v튋۰a"3"e5aᬮ}lW^[~ ҭ[7$wݱcGMMMSN?p8TN;L&} Svaܹ* B)r}||v!1 .\;v! ZU̙3wޅvϏF?^εn]W^~9hӦ͛]]]SRRСNtȑ ,7'5w| kd%%%}w!C 2dÆ 111΋Մ?%"H\]J^m۶<:Iڵݻwl64mڴKoɓ'v;wnCDžh4ھ}ڷof͚Z#Ԝb֭[``syyyxxxppŋ]]]]vG533<~xsueeeݻw9sfEEŖ-[~WiӦ͚5ݻw[~ݻnjcjj*0ڵ+--:u*u{֭[P@SSӧ/X 77zɓ'/'hjjܸq]v7YӺPSרA$9e&){OΝ;߿?eʔH8z5U / 7^+wIea\R ͛7{{{x<]"P`/_LfttCH]V-);e[[[6׵k׫WJ&''Ӈ֖CLzUΝ;ϟogggddwߥSsu֭[s\'' BjRLѣݻkkkIo, M6yzzxMZ-=Њ%zq"Pwޝ;w @4'B_zZtРA7oVːЗ!))|SYK5&x!RNBH *N:A2BHEAԽKS !7הRjiU@K*J8p@ ݳǜf:;9YZXmZ[8HBH]Tz2ukV9۳lP~?v4pws>=z\Ac&M(.u)s/]zMͦZ}!T=T۫{.< $VgVV<^kV,q6 "I<=`njrc0蚚mZ{Yt*#B!6q~m޵K]o:Fvj޽E>v8ÙY?NSqH!P|s~=}CݸYU?2ƀBH (jj3zYRR1ntgB!W8WZV~̬\ s9:x !PYUYQ\ϯH=ۺj>[%59N B WK[P΢ҢB+;m]}b4B)QQVo`hlJ( 'ͻ-"Bb0zFZ:z /9**]U[TomU!Pd2l U RWU7!jt*URH:D!r0 hRV>B,!p"BJ‰B) 'B!!PK5jٷgN =NBH X8B!%`D!!RNBH xU-B$!1q㖭"$"[x|/O&q"jI\]g8F;F8eJUM‰B8|xF֭K&]:NB-ASg@AzX8BHnjkN֧ubD!"hfLwqr{9?b0aX8BTl6{9͟y j\"q"BJ‰B) 'B!,!T*t: u !jjAx׊JUQVJBs(+TR442H#{D=B!bqvF*AT7~QRTlB5[!.-.L}oiJ r8܂v"j efiU8-A\-mJ!j)vBH X8B!%CBI_zFS?rIDATn=Yn`D5G'>~B$/֫[Qj(eŅ5*DzfNkryF&Z:_z,k$IdeEYIaAM5klQNpLuOzRp)BYSZRdneK,?eI<7;odjп_[YVjnmg`1B,.+-^S721>q5D 6heyYiq?`Sb59\DHʲRg֤D" @Pb!u烌$% I $>^:K9ST}[O)_QVP3R4J&­(7>9!Rq"%gRn 'QZ,L$U@6lA޾{/}pLL=ܬYGuꪮ#>O}3a~>Iit7k56nh/^p);>onn֭s1#\*#4{Y8owRK4fTTX,Ӂdj=Sѱ.ΓǏSy8KN Q.Jװtwep4WܹζtB6H,+/̼un==5¢b''uD})%7nZZXYi88$A+9Tsmsqr ==ݸD>{~`,9=CF,foj˛4c7fyyWߘ4}];]UM\8 uMuwa +[R]M$eqi[ od8K߶m{?AԳgvZ)%#+3:6 'B͔%bq71m|@QD*FrMLmmݸ5}/_mغ퇡C͟G=8>ѻWK=q&Y)HbU9D"$`0RNyF"8tPWWZuߏ8iρ;mQqRtU׮{;8 qBuwGD=&=qj뎝m||V,YηG<" Z7^Ț{ܫoԚeq<.w苗EBH(ߞ/(LHH.a}zk5m1UTӄ{i:z5eLCmѫ6 vM;ft ##YMi)KG<=ðK#9@@D@< ޚU|~Cx\.GSF)!EEYs%$!D-b+W`2@RT 20l(IX,&$Я/)##33)%EK__o!ܱCiYٙ$$YXXxҕg5b8) gܔi7PXTt9? !!zt735{uut>RuHVYZY ҷϟ>uO"Op9 =Ϝ6UOWWkp=pws^߷n&,B~ 胠Fue? 7 l ˪9RKMM#Ԥddd$ doYQR=Bk@ AB ž_a:x|(&dA5ǭˣ@aq0{vE99oߥƹ8Kgѽ@D"!IIL|H$׻PX C{jH cBTj.'GdvJuTCX]#$IdCD5y'Ozwݼ}7&.,&`лw <|I𑭍K胇n/ 'AD$"$t:tq4X[W(5cE@HHHL(\^C[)!(OW H?Wx2Ƣ3w!HhP#&܌Fedd]ʹO_px.ccko\jRRM:5)!10 m-i$WC$ɼ|6kv%GG?H 2 34H$K~@_bлuأ[3/ص;*YΝl>={߹]OƍƷ҄U نm[f5s\%KO"#4QU|~vNX.S&ݔjV4MLjY@# 4< JZ b[2Wռz 4&_ͱkు#llG :MLM[0t維 x*/>Ȉ rmmCNNNn^[4-<#%ԈE"5nvm3:/JXaɭJ`2oOfbo[clO߶mt>~RYYٿOoh[ /lC,퐁FEOZWfЫ<;[9$IDdPWhwg.\kTOA]bq%eKD"t/Լx]&6qٳD"K$4ziyqN\R2rEE%G~ӿ$&'hi&jj*+߾{{$ՕN ^aC$n.4ƭsWo@jzr$B"0hW(WP^P^C;F]$۟f8;t\~h(N=i@ 㰇:oSOMi垔r%i![[aȀK7 %@J!a.; $IWgdt৭zzzn..O" b9D~7!32 |p3k>@/~@ &`@W/r, ȭ}{i-7w$}0)%PG) n.$InپoUUW]/-+ũi Z$&IDBRr@;;;}|R׾@ޚ͡Z %X,0?BBfvhADD.[ǟfcVU|~tLl'kma#7?^:pr ugh3kc8~sμ²ʣЂѤ !jJ1hbb654*X#&Ж(ר`4Rvk wefe{o3̹:=ٗj\f-P,vip(wlzIW!Xqu%N4:o5_uө8Zr]yZWgS|O?йc7KY#cm[-x:,@Pّ;W{>XKK˯u?'?M{]lW/^zot.O~s׏~_Gϵځ}[[ۮ =5Fʁ/nܹs?mO<=7ZI`ub,4U6 ]:~{_),|{]{߽hd=W޽qukV-Q#z[>[w߳=/6%fq@!"8nl\&woq{ npyީwu :HkYyRR$aunh[xɗKT(D$X=uَMu]2qgByIvuu 3WI VLcm8O=UJNKC78QY-3~wbZW-=9#ǚ:om9 %[`ե]xtcg=t,Ļ>u}*e3/RLD`ўW9 l<7 ^k1v]n`ZkLQT-NXmii՛A*1qњn^?vش#" z)V^qūW3f݀V Db%eDDcX"YԨ`$D^IEWRyμsgznmZ{Μn3a얒Ӎ͗/ݣZd|b!(W>d1ƊȋLv@`1v@@IDdT-c1V1+  %ZKd98cͱ5Bc$$"k3Nc&Q vcdO{sNܢ"1nv a_)1Fk~!c1Vsw?ǧ1֘Ɵ? Sퟆ]' VIyt/yb 6 ITH !BPkd1l=3\ڝel@ m؞R&ap)-2!Z4H Ck13-'lfUJI)BJ+RH)sRJUlܔ_ZkD4H),cNcpLD 3H{'b^;ZħXk'g&,RRRZR d@HYS 5Z1VkBp{_FB.k@IENDB`hamster-3.0.3/data/screenshots/overview2.png000066400000000000000000001673771452646177100211310ustar00rootroot00000000000000PNG  IHDR5PsBITO IDATxu\lt4HEvS,|gSg׳مݢOTB@)IiXؚ12.˲.8{sΝ9s`yl Bo)XNݐ@ D0_ o J !a2G@ )Da] qqTP@ _j qFm&=GQ9 2pk《¤8 @4/D;M*0 /gѨ /*nTmԤ@ /0'FQFq*ԠA[lTjddm 8h>Tm̨aH=AOѨP!dd? 6P@ D3D4΀jZ2*-pr /F@UjB X!A 8d+㔕U1@@4skA544i4Aj@EerdTP($ ,59UWK–f0`,D C qV6JJt:t:Ѿoоwd6bB2BNjӒp捻R)啗 |P@ '4F+*+++ZN0*ΠhXFIhKPAP(,-~Iݵ7@ a2t]3+3ee%:NdAH 2a\̧y<@ ɡt/}K^5`e0Cok@ )A<:PDǡȩҐZ@D1jz !fc & LL 540b, ja.r հţjwIy% 5QV~gȻf,5۸iGZӇ[110PUS0L(VLQ1 (N9㤸X"sy`!TTPT$W!&Y#B40blηGOԴT&@n s3.Gnrsrl ȍܼ|{;۬lr׌V]c4jM  @F#h4j|ƏE q[VR(%4fTkgSZ-ahH9 5bo`0̴ڰ0hic zzEm ¤F믚vDSB!F8N J{3pqQCW>_Y-hhCJ5x !kX'G:^CQQ(/OIM3оxxԯ_FFF=v=쉣&&m˯ zj,\S^~FaQwTsQZ{fVϾ|_ޱ1 F{.&NuqrDA _3?`կdFFFwԨ_R8zԱ@IIIQQ/|qˆut:./_ |{z2;rZqhSGR_:@(8~\;Wr :Q\Rjan6~N.@Wo:O86;tsS'_Mۖ6`_w!JimS Ūp)Xj5:Z9߮{hU5fJ)3Q$?`-ZxuElm!˱Z̹dៃWPPx՟}w+x @>?zpS(r$%=y&)9Ғ^[kz!_ x%e[=-_f1:f kVwmtcu55M ^}?{ ϝ3=h5\Sv)!Bܕ1jJR-p-^!:Z4Ǐ/رylX{fVdtiff)~5' &9i'!vu+RZuz/Rm{^ȡâ`΢ş|07gzLr?Ϟyޤ]*Уsg_&wpm3a/It픴4#Cxs Μ1&FG[g9ںI)!]V5NholO\ *,,rknѼ9l6'!_7'%Xϛ9Z*s%.|_kEC#˫ظNѰӦGs)qǘXg޹ .]#+'' N՝`/Cܝ7^ =!#Oenxʙs2g?//E/,ch`p`9mƬOs-޾ySgϑAMDž-pOܢs!LJ ``_?{KRSSwvrKA8Њ0RFPiP7!' EX߽S,cA)++ߵ29%eւrskd!YUSGWd?\5#] Laj72ϱSܓ[Y97}zoLEAA1=#c oo/\*Ufef~>vr8?}F4 SS0 ԙ3se4u}?baά دS"2mߧLq8z:-否}6έee׌ oࠦ.++^~+݆Դ4hΕ㖕zt~ګϟ{Ue=Ч?-kvȞvhc#Ã{v?pc]vl762?ry+ao`xny@q![6y{]#V@D fx}:&ޖniniMEEE6573L*ccFAA?'Y߽K,BAPcŹyEE93hO wmރ-^2KP%wm߾y\v;7;:8s/[1E#Xh! Xq?$x16Nl'o]-+/?s{w/[@8 oAb6VǏ%+}{G ݻsy6KWG D[^y@AWx#*;iL)f#r勄Gvbbc={saj=ρ{PA~A@<(8%R> `@ӄFz4꭛60NJI[ie/Ɇ[7bzOsT-GR&pJz2$Aǜ g/Xk&mmYi}r'-((x˖zuKf}M8(++KMM E Q#\ ˰ 8L9ݻt)+-ͭ=9~c+*(gdNzt8m;wn x~Ν [@e];{ jODb~W/?R߿#,S&MlJSM΃)w!^ݻf[w-&r!oߪjE gFikiר YY2T Ps X9?ڰ;]PED uמ飯n߼%.UQ^VN$tpw|bO1*s  ~:fe}~"UՁ/\tvvUZu[$>ը=._vMֈ?}<䪽.4X." JJ L&&`dɈ=}Ĕ"HlTìvn٤-8ZQPP0wђ/IffRQVc9tDQIqkzGwĈ6 -._--/T<gedZB^__FBF9WJmA223-L 3+( B$u371kUWKcȑ"\k6^J6$hki@VNY<7ЩF tlJt w =¢"8ߑFrTUƍ#BExD1/*.fhmTݻ?oFfQ85/\7.}|}oȰY]Z}zܾ3a,PCCooo&Qmۺjik>ðr{[܁ 2+qK)hH*&{ۚ9˞KJD AΎ--^6y9YP4;TǺS3-<ywQ# r! Klj ð2.?Ҿ~}z7DJNR@ H .>}[=bmĸhN'|W`20 0DžB!]ߍd21q>(#V4DžrjFSTfh4@P^Ƒ"GEU88ht[LK(qJqKDj:egW'GHP/JY=_5d$yIl+U-_ x56 ~aZr=sM}Q;54 k ev_"J };wYH# I3vA"DȨZVJ h'~6;XmZcں:z JxzWA(2'.(RvD3!3;ۖkW-rGW SBcw^!o4PVz>*:ŷ=sH e9욜[9΅_ѐCܐޞ!9|ȉ:w ĩ>œ] <]mEBiG43hz#BD9++W H쯐DHG}?j6poۦ\@ե=Ҏh40 0:QZR* uA9!b2N #*Vjj"~N! ʮSkceXJAx uumMF믚vt5/d tfA^.j p<[{kU!?$BF546)++q⿨rg'Oym?FǖxںN(ĩ _rNmux$Nk)(%''UUcC믚vDAzz P( 0?O߰j3Bzֶ+B(dejh  "&#B40 p6@х\|F]0LKMNGAB!ޅ`MAQQB0tahH? H;К;TIӕX,%eSaN {<Xd&Y#B40rfc BkԨ=a4 8M\a0 TMD3G)h`m\ YS4 IDAT4g0 9$OVyRuahH9 L\1vt5_k>8ջAADW*WMDFSm\ˢєirhtBFEQP@ y!=kʗ@ į8c f@ KXGr.Ǟ_EEEz}@ iq-**n0S~%@q@ 3@ g (@ !/Pp5kZXZ98:-[q2?[XOɩZ699yo#[[L8);;[:;eT3s G |$y`airYl79>3%%V\}uA~N70KڻwoB0,,LCCClon߾maa!/[%c΃ۻd̘9 3?F>|d.\bp тA3VMU <>oSN~u1 CϜ)+,Xt}2V&:>w6D^l߱3++VTP066ptt䲲2 Ôj-a}!988>SygꪪR_%f 4ZSix;vkAƍ%gXEn 9yWϞ~AԨ###޽q\ $TmJmu&|*"""S9r봴~Z&!v8^MץpuqqwwظO;:rf߾}F|,eqk_?ITnòa*ɿGpp[D֍KJJj^^^^ȯ||KJ^:$ә TlԮ}|q++K2f2eŤx2P Q+[G* KaU?w}E1nx3s kSL-(( s>ڵ[wm]&#GROiiiGfhdܮ}K.T{ )PS35u^xI9ȸDž J)+ȁO10g\[%!! *w7wm]{={$4Ɏz޹{.23>yБr555fcƎəod O֔gTƍ;~8888ڒ^ lڴs/^-˗?ݽM63gnذlkk;iҤa!UCCbefd2̑׺޽k HGhnegg 6tbu2hQ^^^^^' n?ʤ$Q&Mܫ1c\n޽i4K;:j/paÆٶlr3C?~X |>O߾yΝ]ڿ۷ΛwOkjjL}8޷_W.XlVluFz{y=},K<9*((t955u^^wܞ:uʢŋjq$˗\f_'O...'O]rgΈ 9z>{sn(**:}ڿmܴ\.Oꂂ'O^vEQ6%3͟bŊM>]ln |ȑ7o88:usέj^U_W _ۏ9B}t=wܸݻYzŋUTTtǧNbccpB[[AݻwÇK.Ǐ@bvNvQQQ!à׵qqu55~3g2z̘/^jiiؾ]̺Կ? W\QT\t2:NN(I/\ryGgLcbctuWZ秢C߾} 7ngdd>zbS›z/ZԽ[7?oސi> RD۪%U^dIZZj\\aBN{y'OO5h۶ꎒf^n@ 8~Ӏ8΍;w>1$!1 ?~>|/o" :9~8>wFƏ+" >:nX>w3$bK"ݍ/_k.0k̡CU'F6jժUV,6|5kiͯ=#+++^ ]ӯ\tK.BrWffA^nܸqԩ:8Çnݺ$$$83EEEooﺘ^Z[RRYT\ܥkסC$}>>455srt"۫˓ .."-::x̘f666#G#~FG;n)Q_f  } fѭ컇077#U}]-h~7n2dhJYY1{leeeBSN-ZaÆY 58pk~!** B!۷ٳg>|X\\\PPлwoODvvs8}w~mV2\~݅oޜGO9OKKkꀽ=}\LQH'Jgju&%9hL8q,e~jjjnnܿ/!6.ۧСC خ]gON$q8 @ ZP e3>yѩgRRRLLLTTÇ@YYƍ؋.;~|ժUÇT¬3̌bdfffdf~٤E R{ܪ%;'Ȑxbll%Z$+;Ѐ:LMM ȌV MDOGwVugHAOBvSG`(((ۥ^lA'N)Һ>h xӧO`uQWWÇǏuuq\ x;AՖo^-ȯ%%%\.WYY:eLZdOMݻue)+I51*=5^$<}򅧇-'O֭[oogjʗ/B~̿i[ҽ󵴵sr͛7^=vr'Ǐ\^ll\6ҵ!0 p+Rut:Ff gАRqD ,,,==߿Ou=zzjXwԺt"Iv `0S&O^z͛7o"""-_>GKKk_~ĉ4_߾?/\^>>|>ƌ^`nn֩Sd$==Rgُ?|K-]J>R&UW&Iz̘aaa!!!SNIKѣǏ>|[n.ׯ(_>2e裏?1""Ν;lଦF@^K;u|% a6ڵ;&6ʕTKiUtR~Fsrt|=͚7nLJGD7b Q͛?BB̝7l𢢢#UtHd߸1k;::lٲO겕HPSSС}FF&6ХsÇ{{y{ve}^?j }ׯ}W맬f&$&ǿzJCS)((= ܩSup8wgϞكݰ׭ʩӧ}}BA 2f $5/X\z<_x|>EFPTT܈ƉA*q|F6m ..J]4..nԩ-Z|d2\]\N>faAAsfϪ/Ǐ׮ikk>mZAAAЍत$&igg׷OEE ǧ/_p֭wjkk[3DSfס]] L&dgԅ򸸸֭[aDQQ'Oj(3#yyyv9ɹyyӦngk[u_'OG̟'a|!b5.g())U 2dJ 2Ο??a>?bĈx9Bhii]x[;Cjjmm| ^oN1 %ȐgԎ{Ջ\* B]U,@_011p;P~3<@qd>& rǹU+&:: !'P No w&b(@ !/zQ^^~СiӦ}ƍ}vksvv޼y3;i$sk|!M}|ƒ%KnݺaeYYׯ_~nݺ#Fԋ|Ç7]TT4y䜜'''ߺu+!!!((M>>99AԂ .6 \V DIgfUQQx<ޮ]޽0{lr1 jcǎmܸ1!!y֭b﷤h7nw>x M>Cf\n^n5 8HhDtaaaa``٭[777;::ߟz-… o߾ݲeKϟO8NNN3fXYYEFFN<͛}Kmڴ!Ôk׮]z577wܹ Tm@ ~t'|||Lg϶m6i$77'O@||۷]w%KGT̙3/]t-ϟ?ȀÇzNTyS8Q~:uhbmmYUUQQ{◧IgݻBaBBBDDDPPPDDD```ǎ?}_~uppĈ'jjjvŋ;w]˗?|0{+VXZZm۶hBxxx>t(//O&& FSpФO}tXX3 6h`''666ڷ/((0119xZRR+W8СLOOxBaa!%P]]}ԩ!7o::9N?qxðfp~SQU8i҉sss DIcǎ5kPA222}666PPP0p!CX[[Ǔ7k׮@aa@C QQQ˗/߰aP(ro߾_/w,,,rs7o3ѣښ[^~Y--C^|yƍ-Zt?lܰ],k/^)-=|萲rVVVvܽkW֭/^PR\|d ,4 [[>}ܺuk666|>еkWGGG}=___33ǏݻWT¶mBBBRRRrss]\\dۻwݻwu҅ȥ(,,|9A;txeeeݻ{.W{i4ZVV֎9 Jʤ(~~yy*$0LAAAWW7)))p7@4{t7ovqqzjZZ̘1d?Ȗ-[mx;;ӧ ؽ{Mp2dʕ+eTsԩM6EEE1̞={.Xg4"A۹yy*yd=پJJJ8{y{sQ/LLL^|ٶm[==lJNǏ,րUUU߼ybA Dz'q˗/_^]Ν;2sΜ9sMiٲ#Gjj-BNcF߿*().{tcccKC]|>C__̜r38 Nk--aÇw [uh4;NoݺDѽ>~tuqg2>>=z%EENYP(TQQСb0'RB$wtt=ZAA@@fFMBFD4---QPPp)'73#֭[nja٩))W\QF-^$;;G}V \.ݻ}MHH S$ŋq/ 66vԩ@CA`q>_ x||>7rBQZV65͛X|Yc@ ϮCZ83L&SA 2@ @q@ y DYL$fYm@4iPhx{{51|xc[@ M4Djl+Q'P{@ y @ @ 3@ g (@ !/P@ B^8@ @q@ y @ @ 3@ g4`͚VN˖-qL͝2eӂ |~u|~ Ӽ<*p-LL  ] êN<ⷑ-L-&N ׮]gU>Ӧ^S8zg'=}} KCբjMz;heϫWa*jM2tX+ggS{+D5n<%%V!jM;Dp\[u(h8vyС۷esVX 824>!3gvqٳH,9obw3f<}ׯ]0oՅ!Qt F[R\|…'SNר+uV#`/3z۷O8addԻOwTNgY7nwCrss/{:Θ1}ժU_~%S.\x޽XZhm۶S_|=F.YL2??e%%%0h\ƫ+M+W.(Nϝ3GGGz/|v5 KfϚW⌌ȑ=ׯ_%Z|}`⏧ׯ9}O>p)3sw*bS|z|u{@@q7 IDAT\رc...Fhѣ͝;ctkΝ||ĉ۶T'&L_BBB .5s{mBzp0KR@ L&e=VhT;yzֺh_/_:zca0ESp0 ð@ DJJj^^^^ȯ||KJ^N! pqq /^v;=bXl$J2SS۴iA~eX,+''Gv$N㸿[MD).)ٴy];e0>!^4e箝&@7oް*Tի׬mZ3<<̓1nx3s kSL-(('&~ڭE  qsѵwpܳg93nxS3+kK%4xիv!T;zsKJJI &]=/^?+@_,- HJN~RSlnU n<.~_x){$ SRXlsϛ;6''gq [;׃@߄yFnU g4i_544X,VfFQ^^J' ɛ??:?{J5pCQP&ݳðÆUTTͼe~Bєɓ/\خ};wFEEg͞fAAzrzh/]<~XjjQ?{&Mܫ1cD3SNYxqXXXurp@II饋kٳ6m,&ׯ]2d9s^|!K]}\8~Ϟ>8QLH̖nϞ;w%%ա=ΈOHppp073=LIIآgάkM]򠢣$77o7E^yhC  n|+Vxpe,xrr0i۶ݫW? 3Ƒ#o qptܩ{w̝[ռ>}ǚ~V:~"';fh?;Lr劢KtғΜ9CFA9rdESNi׮\* ѤcƼxRKKk[;E.]we˖kkkrJ+W3z4tȑ6\.#t:yLl,ń$$&|KKmwr>'&&'%ݿOMUcǎ|>?""C ?IJvv5˸qcE^z-+3ӧpaNll)!0[ ߦM4t,-- amm% "# }BazzK ?nϻq#~ǑB_`kޞunݺvfg ɫce]tYf:LƲ4 |>Æ_$y Zjժ͞4i)\.WLEwRAqF^Zq 5JJJ455Y,֍9`@CCKϛ7Dvɟ?4yrLt?qϟKu(߻c=>RJOTP-cǎ9r$66Kuҙܠh]viiiZT%:vѽ{{1wc%IMUL?oxGPccb%gTw(q[AXX8:͖b 1?81Oz~XZXܺxBB>n....((S\Tx#Uٽ{"ӯ_omm]|c&;/锫d2* [o^-ȯ%%%\.:#oݺ =zpCCàM䖗X,VUWPXHnDFFf{9'OS#`;u":6*}Qq1ݻw%%lQW,]… c:ARۭXE~Izzl6;99%11 0 kic)>%5҂Uc) W wyq111qqqR C 񚖽|k\kQQQJjjU`8`0S&O^z͛7o"""-_>+pfΚ˗,^dҥpȦfddut{1XP&3f̌|*lssN:<|ءC>.SM7a†?xѣ-bt}}}%%OnںL׿֭pbxxi'%'O2z̘aaa!!!SN׬ð v{ՈHWW 8@[[k/^ڰqc@!*q|պe0~o߾}IFՙ-ǧ>jܹ?< ;f2ae_CH$R=%$(KmQ{{K^iso"!ƾ Ss0Xy]sgY9r$SN ،x<^W&LI3B eg|TYIӗ lkK˸WyI0}YW:8 A='44f4_mQ>,JYaC gcN|Yo\ WW|5ѭ/$+󜜜}dd㥥?A|a]hΝ6n sNȐuB?s 8p!gg[7opq S}`СN nݻv?q6$4tϊC$o޸p\׮[=5,,Ub:㤩mh.*`CKHHLw&j|~~>H422rvr޹kwȺ!eXhLF=}+/F]W]]]oyT*U]]W"j;0KtjDWѭT۱/<Qóh[HWb 37&$4xIgZ4__2ܹnW{)3j\\G[ijhεoX{{q"Er2|t^^^lLLCCJs0AQQ1---6&FN^,6[__ӧO1W!4nxkkk"X\\|):v7YF&(8֭[7n m&&d29;;L&mxݽ|TTT\ܮ\o>9 D"!].EGڹN4 o`{.II)^^gcVVV?۷?!>lذǎؾnĈKӧNUVVb ۶C!ۡDž G"FnxA:SWL[BSSW>~bn߾mddwӲ<PVVVUU%򣺺:--᤿~7B3-mBjCAh%% qB} 7}LEy9d2B2¦&&)##U 9N[n'!.[TU?18`۶Ca׮)JyYVXYYYYY))))Lx@:Y$..at:]QQӣ؎)GDEEX66!N 445 8o 555 ***x<1++fweI Ʀf2lmmMyo>nfddXXX())IIIMtrׯ/ h׮MP(yyy!ZI}ctIIIӦM[vmYYD'gg#c㷙o߾3wnܗZ}v;,).y ))$mx]Kqಊ߰Y,6d,bX,&+5%-gV]<ɸ3dee(_Al!t޲WXГJv݀$MjR+j, }RoG%T*uWѭT۱/M@Qtr@@Q<yD 3 *g@T @Q<yDb54,|aNPPpYYV^SSO ut54˻% khWU͛aٛ6mhbp:P ; Hd1GOedyqab0$iׯ;"kQ4m불r >CVFRt4\|Ŝbc ,\&MTI"j]i…'Oׯ_./J S''O=rH$,\!C!}CG(--Ŗ%lmmLLLsSSt"{N8p`׃N׏tz9sZQ'1]x<~ҥ ]  9""m]vvJJJZj*/g3 11k׮oǍCEl1NVV+!544Ɲ?w !tY-mn~ה)lڱd BpbĈ!:6ݹ،b\wvv}l١NV^oaVYN׏pޤ焆46Г?j4_ ʥD"[⟗bb;tAammm$D"agdx!SPPXUU5a|c=ŋEOd4Wq,Ez'Obug7Xv-ʳ98:*)+ƫ9ƞ<ƏwO>uOB1S#յkn߹k{|. I/\2}ƌYjFƱqyՎkV@!dldt!PYYYvvNDDĔɓo-[7yx ?Gy/+**lmlZn¢B׿\NND"Jh] I˖/?wvݺyNKp8.njjj]}~u2d3BWػwU^>l z]a޿uzP+7nh49CFFϒ)=.`2fL޲ӿyB(;'guuuqW'..ndd4IBB555qW(رN5~Lm--$đ|ŧNEQyGÇ3g޾}gիV-] Siq}עE [MsM]ŋm۶j=,33s=ˍ0w++vCjU\ZrZL&tcTYz1+/}qƇ~;3l0?_-[6W|N64$nh33ŋ0$%$UUl6̙3JsfxO--ݺu!djj.b$(pQ.Y|I'L)=羿pbqOFE555p8  j_=R-Xk8{v;o{ Gؾf̘1\xQYYhCj'@-{NQaAP`UUUu&O{_X!8(hݘMbbbId+%g?n|X YGNr$:."KKKlwSzF 2`_*[` $nDZZd:::kjjb46S~PVV!##CyY_W?}wfffyyE;3fyM~ @3Ν?ev{w <Lsn{\8o Ω.6R79zGl6r޽X.mK]kL+)ƖLMNNvuukoŸJJJQVVreee***Feή M T[3,6.%%%(Οǖ/Z& ZZZ$"33Fh߿PWdžx*5u@0JYyYJKK[6)-+_#ֽCaME1Sŋw)(J54g8~cx+:zugj'"EhhXN;쓀N3 )):6d2!6v֋H$.0+`Νcbbx/!aB~b _N8p`Llܽ{tutO B`*(jF***nyaz@h)Lѿ=nFFT*֭[E_yFui===oo+CœH#mc7_[5ջyĈ7oPTTjςr3[߷o޼ aX3'Oɇt4& IDAT;w^!4hРgO [RRRr]3m!7oX|԰PcK}}Ǐgd={EJJ,-]SS39yy&)..N&'%9߼%ill8-?0~=Ɍjll):F229:8qqXyZw3y&veaXl6dY,&bXLVjJZϬ^ ['++C&ӹiWUU555A577ƥDgϝ``5!ظKi%###&6_?yjjjD###g'1 sAUUcv% -ʼnD"Q\Hg@˗u{\. ;{ҋa~4 CD?&u3Qi__a3;݃<5LC]CAyz }$ w >Q4ҥ꺱O*檮.QD:b/ GEG_˗zضC }T}Hת["{ f.g@T ߀#G^_NއJ&7n1lz!(|lllN@  FoG"yz{edfv挺X{{ii鼼ؘyB Dd!4hxyD 3 *g@T @Q<yD 3zRlkkk,X_Uc7oڶ\m] gdvTo5u -mಲ2foڴYGWoiHH(h<3,,,y/=x%?~$IO:%d$irqqq۷tt7` $M~u'VWWu7>v4o3g@ӕVX,!qEі >zxؘ+8ŵ纀:Ő0tz9sM\KѿvիWsފz?Ο?~SQ^ d-V 9!! ǏZ<{I"H$Ryy9Bj4_u!a]vΝ]v,p>HD"Bj„ XGz:AHFJJJϞ}[9!1fĈ{wa%/^=dFqqeej17ݘVnyQQTjVCvWGX.^VVV>cFyy@U5uC#8b*q,Ez'Ob?~d7fl?E5u i!IWD80|MLyGa DAA27'WOWHKK+)*v`wJC5VPPPUU^ZXX477?yVyF/362z!o*>>!4+ ]p)//_hǨ-[t!WVV$""bE8 ɑH$Z 5LKK;n!X,֫WF–':9/9|GAANgϞ0q\]]uŸ[l޲uKEEE<ѣ\zTԵk9K-kv˖/?w͟b0SL10SQ'327"bcxzNZt鳧OZF( w"Ls3p@m-wXIAA/ˬ;w-[w`0ї%UGrn)..߸@aaaaUUU]`AUUU f%]Ox>~#"i+&&$MƾZ% ;>';{T{NQaAP`UUUrrƖtƨѣLQQ1!1ŋ~!f5d}",,,H$RV[[u6s 3ޟÆYKHHYGXZZ؂L▖說RB~O~ នGp$m;]¢"K&hbz&~t?mm-ϳDC77[^^uKKg a[&ImE"WrŊd2YSS{Nޗ6?:]]..δsJKGErֻw;?cx%9#F GQԍÏ=#m.[VVollTVQ>`g׭[pݽbFB\.[57rx3`ȑ# œٳ7nܔːYGie ձqeee!77WE3vvv``OgiIIO%$̙3W:C>&$&9s&**TLL=i BHWWeJJUU62`.;PWEJ%%-..f0fZYiiiza_IIq%5kֆ[!=^6+wqq}_C:}+0^H 1W.999ȐcDhhi...۶un,1cJTTTLLLMLL"x I̙kkk{_W벲)^^nn^N˯NGꐙ3g3>5-ڵW N}8iwEIK: rrrX>NJ4&Kœ >g tzÃE3߇.ϟ;KR}||oa"V0\V6fLb2Y,d̪]2Yގr_$L[iiÇC#ݰ>w&j|~~>H422rvr޹kwȺ!eXhLF=}+/5ɃD"(.N$` 3D ?~y7@Q<yD &h.UWWہtJuss=Jzg>*:7d ǧJzj-ze- FAQ<|cBBCQjj,hid2sm; xluIgEUeո k 7 Dd^X{{ii鼼ؘ[[[1<^UUF%ܻ8abZZZlL YlOb\y=BhD"RttmmTooLPp[x&@ptt\EE;8:fee쮌")!L& x<-tVJIIH$,QF>7W@|h4kצz{S( ص1WhiӦY~b̷oΙ;7M5.[fb77?zHGGջ펒;޾ٳL&ݰr@7eaXl6dY,&bXLVjJZϬ:xbqgPLٶ-C!eJܽs :tsz&'[ "D8}o9! 1 e˗캺@y9ގD}JIeT'A(%%ގKTT/%=RmcM@Qtr@@Qtބ"+ @|D 3 *g@T @Q<yD 3 *g@T t>ψ<|d}_hMMM455 UmmN&O6}ߡl6!Dܶ*$i["ZֿuόKW..)ng+d} _r 2l3߾JB7nngqKDrT_O߶s)=÷lABoO6c Y !7+9L yA!png[jfOp]tzĮ=&wq_jJGWdBmVm;l!#sɻlСC:sGEޝ:=nk3!iӤ)O=wrtj]!W>=v܌ymGB[Xw/]UomU~-6}1)Sf_kVBÚ=+ك3'}s;?` 3\RRRRR{= Yϩ IDATE+-33XZV~DԎ=BӼ0@=fݣ'rƆm!YaEE:޼;Ӽ'G)*(FݪֺU+p8\UuQg~7vxI MLL,'7?x8'%+V}kוC,ٳX 6**. ,-((B!~9yrN`;%$-_Iol*/]𓁞葶̬,-&Lf2z1p iEE𷂝x݇¦\nfֻw9aVV7,+k+kW+wFجZLD-i^iY_d1ﭯnψ{Ə;̪;]n“EUTVr\~{͈22E>|p8O_=UWUa6>VZ'=~te V:y\ظM[Lhl=I.;Zڿ?BH ss.ӪvF<4a˗VsRRRZꪭJJJس[F"TTw |n.)) ޺:gں:p֬=v+c 2d*r?1F+ ch`@P2faJ  46D|@ 67GmعAQ-74Nj!ۓ<1c}+k5_=ݼUXXpvNtۭ:B~8E$ُE=zY[W7vDں}wYo0]6b񹦫D<uѐΏ},pc'4=C|ODWa=0g{8\t謹Gvh u;݈pH:_?Ei?6Οr_#ttH$)%Ųk[^&)с!Ĭ,<"z::JJWi? $Z Z,ްm>Ztu]H ٳ5?/]LP(~r~=d9: 5w>Bhۤw}Rdۭ7!{vm㣤O@9‰_v7~t/U ؎9Bo2PK:. "{"<@!U*VRBKIMEag1GcR¢f&׬X6fvSϱ^t9OR54ԅ0͛yMMM,KBBp4JtzIiFG־K4<{},={f~9!̆mN / ۓ677less3z>345|=Bf }^^ߗBNkjFf;wda5`_Z\'6~WRЃGyOhH~X]ogkׇ:ܺ*/ߍ#~dU- ݼ5s\So>}IRRKcTzz >_.-5Uk(ʭ+-˩Minp]M݁CG3[B*mYG:}^ɓ,֯Sba>HB\5bמKʞ͈ᕕUݲe.}EF<ѡ[Y!8oy'OЗ3 +YR229A$$$U*lw{ ʆo5}I '6Ɔ`|u>`0BښYY3(‹ySٸc'OTB!tBQg~+.)qwuw/n}fp{uK&ƺ::jgy+&&]ѐ]oϿf&L$Λ^9ovP~^JUPPX0wڕ+x؎6}twq G"(7Sdeׄ9qr`O7!ߵcIe+֭'#%%Z4}6L>Hhߕwo-] ccL622UaPQVD=p3dʐ2#ul E{whK**u<=9]"x%ۛ*z㋉m^XOWd8R?|r7-^Eಊ߰Y,6d,bX,&+5%mɜ%=JKb1uӿ YưX5ؓבN;MB]I!݅`7hwB9x 8H$ wA$M:H$ IBB<]8:v!+j|x"Ot IF=-H0{;qqqXQ~>SN!@A~DC*`Hu0= Q<yD Jnv^FQ|Mw `>yD 3 *g@T @Q<yD 3 *g@T @Q<yD 3 *g@T @Q!t׀ & 3 *g@T @Q<yD 3 *g@T @Q<yDv!|ڕ+z;`_ߊob_E]a>yDKyˍ0gDgO׽Ⱦuu m3lƎJlkyMӧvfOu鎮wc2X[ٷ iÖ&sv[>V[i4Y cÄ+WJˇ]Ct}UuuG#ᷯ2GN?}庰 d䌛>/QNpz8+=0vٹh;v; ѥ3yoglnft݅VD=puūܲO-\}˦]uz˅i !CMH"^f2YRL8B(=#!4x#ᷯ6!fMMMރ#5|m1%%VmrD[>J']DNo_mR{ڌi>>^S?~weK#<{έ:4m 3ӯ6|޿ BeJt{qmm~m/}b0"6!MI)B´ߐ#22،J_+KWiY A~!//)0_$gf;ZZZ!m֓/l[SSlii*^ ~x|?8p]鄟uޕqU?.9N/(*lY.\kƛvݦx2g̷o:7;M6{sĎz:~aQqO :*Oϵstpo kB7n:e#Gle&xbܶHHH^q҃>*'K7;H ~+_ A=LzUSSx ߈jp}ie"-M|Z3/}9ŋd$=ryy='y؄e]߾d JJiz2o_!Դ|MKcCNm!uee+ׅwq|7!W.`yDq]B7VWlز}PSXԴ3fccM؆ʪ*Pci&"is:}*Kydwfr44 p}?͝}`Ϯ*?-]QQYd2Z\L whkJa3| -;۰icO<|uF~8W655پuἹ7ns:oC=Ga?ftﳧN`sS<}`ڂXԉʪ~{B.^=&;8]*4s8yz#}99:0¢ⓧddq8A@[l])U[[cm5? lwٖͱ˖766޶e))·nu"/?ϫfN6uZy>\~c|8Wmnn lnf2cO,c#Z56pڝ[7/7_kjv迮ڷ'<,Qɾ-͏>k_d!v?mscGeed܁b2+׬<ur" !Tp$m;0UW[yyM߇P(HR t2h/?uw6PS;9]ueP̊ҡdW"GJI%TJ"e-Z׮]kKUӡ;)ѭfLJ>(yx̼{ߟ3 ^ikitun5?M;/\8sE -M "ibpUeeeKLV@e2@uXQQт.twzQo3 [Y.hnn9s}_(n=mt %3+G\\HPP{YX0FEH2`҄B 3|!)%1t⾴dP}K Ҧ{"10#9}2:N\mWEbbvy hQ.Nhd0:Tnr P)q I;D* !.ѹHߺs?DAONn@O;y륌̬'}ΡGt?'5rr܇ݺ-##ԡZm]&ғGfP**?j|+~knnQyEEMVV&yVB3v+[Kc2q~\@Lwx_,qƄOO=cvDe6W~I]UVT\ѭafDlÐ@tWԇTj()*|hPҮNS:Mc g|7kx5$z2Ys#9o]U+8W3 |'O.#Z""wgJfILJVRPPQR'> 3+q}]}=Ɍ;sv"+ {j񧮖\wzD>Se%E E#M7X=='=KKRwhZn&aNnnYQQ-L'O`fly~9)9eذoG`[8yLq7v̢hw5AݤHS^"#3z8azR!Vj ^ÑfuWpvyؠ-d'={wQV,RdEO+,*zϵo{䩛dfe ~2226K@NVx䔴ܨ'._} 466Ɯ% ^Jx$;'Sg~9͕G[LȤ7DvUuuii+g̜.++wOFf$ހӦ^r^X]S{Þqc^|{/^;1<薍s˶T*&/Ͻ).Vנ ዆3O/{My6pg#9)Oܹ}Q2yEGKJ#^:t&2;e"}n;ܽKKNFE*hhn;I{3/??6qsG-2x"Q"((",,?PC}߮ӵYYuk\RR =[&;΃9}:J֖Aero^ă`dhM[2^M >jt^>׬ߐ\__]ҏIO*W֝JE.`Xl6dY,&bXLV =uڍ?@KK eSZZp/ :X,.@H>4p@mmmu9rù'xOꚓS8JN|ȨGЇ\Q(/#yFÇ |W` b *\\G|7A!lB!/g B_0@!`B!~<!ByB! B˧NBKS @丞B!~<!Bl 7fN?OzN7Ngd;vٶ{^ MS[[KwgzWM m [w_뗜dSR[Laax ! `ZVZ#0u鄷=oiinoQK[Lۤ$m 8{6Dwھ~S6k+ ^?*7XvuѼ@UuգOwxnvٰ{^v˝x}1>|&<#3ׯ;7lnny#6:`GcNyPO}t\Qs fr+O1m>,QGK3Դ):.++0ztitBP(tBG?~{Ϝ>|$SlXvQ A>X=mn0^M-yO1CNFܟ9}7CG8ibV  kjbC#L|\3evrduxƭ[- yVWx;b{v[DezJ| s-_&%99=%a۪*pݶνg_X~߄H윇M71EK^˖{e2775 }p$OX/f}L^A߱˧C''̷8=*өLQS۾ wr8Deǫyn'O1o-ankc'ckj:c]ϣ-RW>|HQA@HXgzhɨ#R{0z`ߝ/9g.ı#1Νb))qKV .V.[J~K|b 124 k[]SfYl6QX_ϣGD1l؛7d;J,s\走,0oinΔϣʪ222 !)duxk1c5&M$bXi˶ZZ|fw`0kV/05LH:wCfV6T_sr,sup=]@JutԴ]:d왳de*++OVWר/#~|K6fMt05-]C}ҿ2M hQqjee*p*W@7;s!Ʌ KKKM0fgfg(&wЛJVH g8Z))-wLPX)S 3>{41TQV/1^ZZZF1}hqcEEE Ǫ;t`2`҄>%$Bܗ٩8M&Ebt<#o(xJ[ݞTzFfPء WBRTݾAaakoPRT43`P_h׹Vt7g|giZCѴ MMÜ&FY4ܼ|gdftNO#wߗ PSUmf4܇#WLfܙYQ(s\9vN6(O~!]fG }^=s&Ie0cFYySqR@PPP={ ͷM8=d[!3;Gu.n߹Y'O%$$3l&+hy/w^rmӆzWpp}oС=x_34432i~ Q]U]]ZZ3ݓ,7`ƴi~2226Ks [˗s*.+;-s/>LHH'n2fyC۬윬위OGǜtt1dee4&O:w1x!;98=Fj 99; \URP륄OsrKܚWptPLKO$k Nk~7n%'ou_ 6Htر}3 <'|g`blD'܉wpDw\Zmsum|wKWS>p|G )((x$,4(DDEYcJv9oدvqѣxo8CZJJcҤQN 6fLb2Y,dS7hkk}dw|.X,.@HZ?3_Ny=zt>Wq*~=>>$?9YHXHHHHXXHWP3B|0v̌{h@`555^t>?l8Wj?}ԇV!ֽ{{'W~Uڏ>}Zl6L~HBhMj O2  B !3B!/g B_0@!`B!~<!BE=u{"B !3B!/gȱ~\ZZo0 lll-BL&.7xj 6&ܶ}3B bEE% 쐋,~v'6}Um%K#Dvs_Befl7NnfL_kUrbp( B?}zgN> tt)K;PSS]\\lԨT*vQ A|!4АFOikowsjj?~oc32 p)-ϙ|Dꚝ~V/>yfm4g2/Fpx˖{ aƍ# _.Zjx#˂BqqqBϽrgf;sr_h_r.c K551?]bhbiCjڻIOIuXl`dbdn! 1̭ G "?hϫ?b#7a٬O7 MZZ|fwx%%Q%&Mf3kVikjR&/!}y0H r~"v>WA\ͽ޻zzDAjYyqdƝ9xB!+6lkk;}wx%?|?bذs\9vx!J .spyzF i?rXmb4+**?''Nk8R!Dܻ}~C?6Km܅k?/o߾^Ɋ 8WXT(?݃2R2}韴yƍW;O4?2<}dddlm(oll9CRiۛmu <͎9k<װ/)q/ޅB0k49Y} :s?'̜.++wOFf$ހӦqD̬,?Er22eO˯~k5uڣ`Fn\%k ,6.[ƪYha_\7~/1**?832 ;aax}РC7o1;g*Kݼy+ZZNk" Px{ (OKOlIIIiCCexF|V\؃!zBPP0`p n[\68nr"BBm>m˺ mwlIqɘ*QᲲ2&9^>EEE fN v  _c{q,:u+++glTW+=%8bl&fLb1Y)ԍk73gbwm}!?^`fJa$%ly+BW{_brpuBBBBBBĿDDzpg?zF~',"|(hUu5uuGn6_ گ0pV! HKI>~!tut\78Wgp!K:ZG{ȗWSB!Wg B_0@!`B!~<!ByB! B ^?L~B13B!/g B_<1L}9/^p>v"ve@P]^]} .ر˧mBxas">>X7q+7/pY˗÷UUY.141ඥO3U! `ZVZؾy߾ѣG.QFmt55BCƜܱŭ;mB蓉t6z.WKJ\hmkhdl&-%mThOo߳'>3P8:IOƻ-B}bv?pp|-Z/= w[o*0 7wO sÆGz]z1d˂Bqqq6+ ?l1\ɍJ UZV LVwѣxX lgumq55 =d)I=lp 9~U(unK6H}=$:h& @OI!!A- Ҳ2StC ;eaXF%Uoʒ@+cdhhei+ژkii)z]| <"Чh0sJe?8f\ݚغNOٻxw#^VO?I,VSU%*ovٰrR~7/Z/@7Y`:ubz$V6\PNFqbb yTYYyXFF$$%]:ob,_j?./+9!..f=[w v]&gL8SPPXV^>k1G"fjl0߼/ƫ‚1* I u_T"WL$0yunK6Y37d))EY3gzr!q]m-[StIxYsG~{+m-䔴.˻s. 9}*Y<BFAae"qcEEE ʻ^ojt %3+G}S IDAT\\\~HO32W87@3$q I;ѡW\6QV2mݬT@R;KQ(]l w(immmEnunK6HKJJ,>IS}rqI˂< ""~0ea߷\#}vz̚15rrmi%鲼}Dz JRG0o|od}!>6{ T p8n~q+ 39uaH1qΜ]n-5gp()3߽_ZJ2"$BMULTP)s/ ҝ))(72ޝI<=}=gTIeeei~y4wwge稩o܈|&OX\RrYY>~2226Kx766Ɯ% ^Jx$;'Sg~9͕G[w3ݓ,7`ƴi4yyr}WT*M^{{S\Ag1'c62%%7ŻNq߄B 3N&9^>EEE fN v  r y߉MPP0`p n[\68n^[A jUC m W?psq11rrrs W,7oW`e@ZZNk" Px{ (OKO;-..1^M56!#BBm>m˺?PNURRР2F=8|%n+W8:((lf3,6dX,Jn\빧j~PEEǏkI)vx튐!'$;ZB\珀+ꚓzGP(O2@XDPѪ--j~I2̌!q}yFOIKI>~!tut\78`VC# j?<-#=gB/;7A!g B !3B!/g B_0@!`B!~<!BB=:_eB2߄ g B_0@!e{ ;ÖY7m-)7so<:ollAL/z>z̹Ɔ&6neof]dckdnd2yj 6&ܶu-B}v̬~x&r7xHoB}ghkzU[WG<Ӻ%BP(`L6dq1>^z魻.9=|0I.&+oVT7m`}-B}zW 555F!@y4>/3ideS&&͜>M}⤧O#Jghih) L-ݽVUw=8{ GgpтL`NbΡ&D9=%u9^8۪*w/yf+o޺yiOcb WTTclazа&ltp 4L`N7P_0ua'91`ĈaG9l/z]z11eA(!iE.0^s,9ܺs;M\ian6|0qBx۫jj@mmmn^Γgfji0z`ߝ/9g.1&~J9۫k@O1oaA:"%)g p8 n[[Z!گ8yG魱_N`NnMMMAxlL'zIt:Q'%5M@@ɩ)BBZyiYzQ[Y$^:2,2hm`YYrhp ,-`ˆ˖^%>~B6M!> (My;mݿoÏk}^VO?I,VSU%*wo{ghi:,.'+f#*++ka2<`8YTLlSR33;tu?,k' g増DD`|KsspbZZ|fwHx,H80}sy0mUlQ iUk)z"w)fI)'uvwF_RͶ075r6tf2jrKrr,`߾n>v]zF&Y[4Ȣ4Y{eynދʪ222 !)н%$69;s3mR345 FދI罊u 4HKK?L7/??ŋ$j*((,+/5+X1<qcEEE g͘7$ғef͜q8*)Ɔ tlVO66'!&c<ٹy#GzW_PꕶFrJZ{H ;T^^L,͗!z,JacT$&M/,,н1'+BP(̬qqqQ#?oZ}g(h2KL\m(m'O[Zֹld8Y3ƫ&ѓ;t%.!>ic#:DP~BU@e.*9}=dr4',( zYX;WHqfL'Ouuv4u[FFZEI,<&6ԙ˖X-%x͗!z,Jar*akBW.^0ݯSgOeju4'b=t,-=CK]2x}i)Ɉ`+K 5UfFs~Ts%e︾QRPod;KyzF7*hhj"61@_OY2=%-UsdYYE踟~2x"?K?yJFst?}MWLfܙYQ(m]rCNkOE!"dA\_[[Kgdf>GնQqc,ZhqL6Yj}Io=2Wΐ)+xTV^~뗯^knn ZZ^^[W7EWW~(Ooߴ ~$%{:Y3Nxԙ@9鲲2|ddf>K 1mM^t***ӞgO7ܙ:e Ѱ#P('N;easT7n_y<'M,.)v̬,O?[%<cNee421'c62%%7b2dmB!dA|˺NNI{,?{>T*&/Ͻ).Vנ3lxQTm-nɐ+**sS/ݢ3G{{yl72s $lc#ƒoSnrv F <mg܍= #BBm>m˺OVYY5dP|.S ҝkkj8_ј999㹆+͛kkP_WKqMdq*uoOwaai1qښ`t>+W8:(EO,Ja^!BmlllgPq}'%% *cG+8Q3,f2YldX,BOݸvcTTT>zx)m߮ }bw@׊[} U\3 5'  ~ /,"|(hUu5uuGnM2̌{!yP( گU+{!|(q}&!7}{B!!3B!/g B_0@!`B!~<!B_ -8B/dp=!ByB!yFEEA6/]u JK TUWsNL/z9ƞf]dckdnd2yj 6&ܶu-B/m;bNUܼu3z::I%dvQE~ganƏn{W 555F!@y4Oa˾Iee_E$1**;ݷ #ZqӜ)Ϲ w,\{k?fEakhB}b:jyWmU<37oraB G#%ˈ]sV88@EE]>V  kjbt]MI#F p8<e=}|뢥֋I/ DEyE Y&7q aƍ# m__\3i LM&O@ _ko1tPAd2orR)y{{e+7=}˂[]j# =d)I=6mmiaXk*hTVee޻F~oev82-==,(pYK:qf;555u3w_OQx,2hm`YYrhp ,-`ˆ˖^%>~B6M!&L!C/jkk mdfe_ƲG˾۪*aa!II uح?lvaؾ^;u=M,,,|uIqIp 1I&lW^mf2.bb,_jC%򲲘#hnٳC7ol٨#TUhaB۪qݫׅ ?̬l&6n,$'7r9Y9P;ikk탡z:kWۥgdE,gfgw!Hu˸ XBBlSqII]}=w=!KYK!##d:oXLq7RRAAaYy/U$o,05Y`jRZZwzQoF]ZJ"_e2d :Dx1'+BP(̬qqqQ#?oZ|3(+SԴӦ/3ruk@DTC+q I;ѡ<'7OPq.qƄOO\ATDCIkkk+ ,A/ u>c֌ mVp8G頺FN;ݺ-##t?]whweKۊ 'BߑE`>:]|afflÐ@iS_-1|0)zQ'b 0'77=3S__bn^~m]03+q}]}"ե+8m [N88$DxtqDT3qm1Z?MoZNu%7\=%kn'5+?joZzÄ?rrrRfHH RWoycuM_wg`fLۗɩ3gP('N;easTB--/39]VVfgIt3MhdGƍW;|%%׮'##ckGyccc̩F#d\F㿤$F\L-B XdCWT*M^{{S\Agdůg(F>P_?b0vmT̆B 3NGBBmܼMDTh5wyMYYukGE̛7x F <mg}>_/3kb 9sa!!ݶ{L6eݏ=*Qn޼]][eji99>.@Nӟ.",̣<-==&6N[Sѣ_z GE!4` v>Dq}'%% *cG+2Q3,f2YldX,BOݸvcUTT>zx)m߮ aX|B{ ]kEM['MnGjQ ?9YHXHHHHXXHWP5aCGΜ-,*:z,fwN>gfdߣ@71#~ XRRA{#>{n`9] N=aB ,FFΙ=c\G_ݾ BN g poBsI B !3B!/g B_0@!`B!~<!B]!P~Mx B !3BuWiiOE6{g]}}cccwjc'b[0Lg񂅆 v򩭭~ۯBht6z.=m|p\}y۷477z(%<ʹtHس@hј;u By,魻.9=|0I.&+ok--}T*$%LHXh`dbd{Ξ@4|eSc#"!#q8ò>8:IOƻW B=wТAvKu؞cIDAT-eDniS3޽EQq?̲M.y7 jeZ^PRQT5/ii^1*,3SK^K_L.iEB@MD`gwcvg]v]͍GÜY;gf`; \-+`!!DѼ6gڭz'+GxҴYD4!dŲA1yW.zAȈVX8clL^g<6bqKS?w8_VvQczzi~gɕNANΝp?^֭#~GFT({ٽ+?6?ge'vh>.v҆k7©XY5\Ѥm>>=<|ʯyw?Y3՝:v,+vWӧ?`IIi@^wFGuqqqqi⚔:t{G<=,l޶=/??d1c*۹g?jڜQ#MN-j䴍ySDŽE\]g,yaC[xg?ڞwG9v.}mNdh΀IGhѕ3Zj yy٧0 W9hЬ鯨j+J\iRɟOUVVuy}mط@kOvΝ}G~;.̝=fa;ڵ;JV:u_ܳhϒmt gySGo^)Rj˰?YٹcXjWb*nT|Yfc'MmvUuu^^m6؟t3^nؼeBlիe ^Q!(LAA !R{v{vwKҪU ABń˥ƌB!b777fͬm3nŲA1y+}; )iֻ/y>;774xry{[j'!xȐȈpB̩Č']Pzm#j-m34٠.ui4.喳wR;!c,.vRP@#Q323'r7&Oҷi h GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK 10 Statistics center 800 550 org.gnome.Hamster.GUI True vertical 24 True 0 True 2 12 6 True 0 Year: GTK_FILL GTK_FILL True 0 0 True 1 2 False 0 True True 5 5 True vertical True vertical 24 70 True False 0 True True vertical True True True 0 8 Starts and ends 0 True 0 Totals 1 False 0 160 True True True 0 True 1 False 1 100 True True True 0 True 1 2 0 200 True 0 0 32 30 False 1 1 0 Text we say when there is not enough data True 1 1 hamster-3.0.3/data/wscript000066400000000000000000000047341452646177100155340ustar00rootroot00000000000000# This file is meant to be included in the root wscript, # through the recurse("data") command. # An advantage of keeping it there # instead of blending it in the root wscript build() # is that the files are looked for in the same folder # (no need to prepend data/ everywhere) import os from waflib import Logs def build(ctx): if not ctx.env.skip_gsettings: ctx(features='glib2', settings_schema_files=['org.gnome.hamster.gschema.xml']) filename = "org.gnome.Hamster.metainfo.xml" ctx(features = "subst", source= "%s.in" % filename, target= "%s" % filename, dict = ctx.env, install_path = "${DATADIR}/metainfo" ) filename = "org.gnome.Hamster.GUI.desktop" ctx(features = "subst", source= "%s.in" % filename, target= "%s" % filename, dict = ctx.env, install_path = "${DATADIR}/applications" ) start_dir = ctx.path.find_dir('.') # glade builder files ctx.install_files('${DATADIR}/hamster', start_dir.ant_glob('*.ui')) # default files ctx.install_files('${DATADIR}/hamster', 'hamster.db') ctx.install_files('${DATADIR}/hamster', 'report_template.html') # icons ctx.install_files('${DATADIR}/hamster/art', start_dir.ant_glob('art/*.png')) ctx.install_files('${DATADIR}/icons/hicolor/16x16/apps', 'art/16x16/org.gnome.Hamster.GUI.png') ctx.install_files('${DATADIR}/icons/hicolor/22x22/apps', 'art/22x22/org.gnome.Hamster.GUI.png') ctx.install_files('${DATADIR}/icons/hicolor/24x24/apps', 'art/24x24/org.gnome.Hamster.GUI.png') ctx.install_files('${DATADIR}/icons/hicolor/32x32/apps', 'art/32x32/org.gnome.Hamster.GUI.png') ctx.install_files('${DATADIR}/icons/hicolor/48x48/apps', 'art/scalable/org.gnome.Hamster.GUI.png') ctx.install_files('${DATADIR}/icons/hicolor/scalable/apps','art/scalable/org.gnome.Hamster.GUI.svg') if not ctx.env.skip_icon_cache_update: ctx.add_post_fun(update_icon_cache) # icon cache update def update_icon_cache(ctx): """Update the gtk icon cache.""" if ctx.cmd == "install": # adapted from the previous waf gnome.py icon_dir = os.path.join(ctx.env.DATADIR, 'icons/hicolor') cmd = 'gtk-update-icon-cache -q -f -t {}'.format(icon_dir) err = ctx.exec_command(cmd) if err: Logs.warn('The following command failed:\n{}'.format(cmd)) else: Logs.pprint('YELLOW', 'Successfully updated GTK icon cache') hamster-3.0.3/help/000077500000000000000000000000001452646177100141255ustar00rootroot00000000000000hamster-3.0.3/help/.gitignore000066400000000000000000000003461452646177100161200ustar00rootroot00000000000000cs/*.page cs/*.mo cs/*.xml de/*.page de/*.mo de/*.xml es/*.page es/*.mo es/*.xml el/*.page el/*.mo el/*.xml fr/*.page fr/*.mo fr/*.xml gl/*.page zh_HK/*.page zh_HK/*.mo zh_HK/*.xml zh_TW/*.page zh_TW/*.mo zh_TW/*.xml zh_CN/*.page hamster-3.0.3/help/C/000077500000000000000000000000001452646177100143075ustar00rootroot00000000000000hamster-3.0.3/help/C/backup.page000066400000000000000000000021011452646177100164040ustar00rootroot00000000000000 How to back up the activity database. Backup

Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while.

For viewing contents of the database we can suggest using the DB Browser for SQLite (DB4S).

Previously the database was stored in ~/.local/share/hamster-applet/hamster.db. Recent versions of Hamster create a hard link between the old and new files. Any one of these files can be removed safely (they are references to the same item). The database is lost only if both references are deleted.

hamster-3.0.3/help/C/figures/000077500000000000000000000000001452646177100157535ustar00rootroot00000000000000hamster-3.0.3/help/C/figures/hamster-logo.png000066400000000000000000000052541452646177100210700ustar00rootroot00000000000000PNG  IHDR szzsBIT|d pHYs B(xtEXtSoftwarewww.inkscape.org< )IDATXŖk]U{syܹsg03ZB`Ap )1*J!o $bxƄTRZ MK_әG>=キ!vH ~$;de~{!I&_~ggJE!EvƄ%IĖ(- !xV^zs|ƍt{:J Y#es-:ҖCx*vcpQ`__,6lu/d羜9+9UcE i&=r-ͦ5(2= XvoO @wyn}c-9eî]^3]궏"$e/ІM=NmZE~wl6]oţ8zbWX1w遲F> 6OOfWؓVo= Id~E۴]k?ֽܧ+oء Ik>G|@^~Ck6DtE' πU9s\Ž-gG]|v@6n+ϼ mu< !X"b.1p!!yԘnBĶv]60ق{&>8FZDχxhi흝RJX nTjTZ\u9$3VI1JfLi_X#ndDܯmȿǺwvhL46F$XN&ߕbjH&$^ +ܪ?}Iбw8 򙼲/g!Pi+-յ*C6Z&Dܸ;_:K/x8D&OgJL -_XnA׏D;g  Ŋpx^t\Ap󾳒_rۯRGf*O {Qү?IG欸,[מy,ʥ5opQIAި5";K.[U~YqK&d*h*zˬ=>R'cLܪ(JxbЉ 8W]Bjk՚d\C&#=K2 {?<;B>U3kpa"0$InWGlKH*LMA Pi(UlK^:t\{dI066|رcGB!B߮S)RufAp]|>wx'; A |FNӇN,pV˓ء4 -u(,u Dx\XqppLg 0HLb攧*NGS#PМ3!Ħ:eʹ_bʲl 8@|XSOaFr +fؙcnZi?>(4PxIENDB`hamster-3.0.3/help/C/index.page000066400000000000000000000006711452646177100162600ustar00rootroot00000000000000 Hamster Manual Hamster Manual Your personal time keeping tool. Milo Casagrande milo@ubuntu.com

Creative Commons Share Alike 3.0

hamster-3.0.3/help/C/input.page000066400000000000000000000071461452646177100163140ustar00rootroot00000000000000 Tricks to speed up activity entry. Input

To start tracking, press the + button, type in the activity name in the entry, and hit the Enter key. To specify more detail on the fly, use this syntax: `time_info activity name@category, some description, #tag #other tag with spaces`.

Specify specific times as `13:10-13:45`, and "started 5 minutes ago" as `-5`.

Next comes the activity name

Place the category after the activity name, and start it with an at sign `@`, e.g. `@garden`

If you want to add a description and/or tags, add a comma `,`.

The description is just freeform text immediately after the comma, and runs until the end of the string or until the beginning of tags.

Place tags at the end right after a comma, and start each tag with a hash mark `#`.

Note that you can embed single-word tags in the description just by prepending a hash to any word. Note that sequences of alphanumeric characters that start with a digit are not considered as words so if you use Fix bug #123 as your description, the hash will be kept and there will be no supplementary tag named 123.

A few examples:

12:30-12:45 watering flowers

Forgot to note the important act of watering flowers over lunch.

tomatoes@garden, digging holes

Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description.

-7 existentialism, thinking about the vastness of the universe

Corrected information by informing application that I've been doing something else for the last seven minutes.

Hamster@Software, doing some #reviews of pull requests Hamster@Software, doing some reviews of pull requests, #reviews

Those two syntaxes are equivalent. Single word tags can be embedded in the description (except on the first word).

Time input

Relative times work both for start and end, provided they are preceded by an explicit sign, and separated by a space.

-30 -10 means started 30 minutes ago and stopped 10 minutes ago.

-5 +30 means started 5 minutes ago and will stop in 30 minutes (duration of 35 minutes).

Duration can be given instead of end, as 1, 2 or 3 digits without any sign.

-50 30 means started 50 minutes ago and lasted 30 minutes (so it ended 20 minutes ago).

Times can be entered with a colon (hh:mm), with a dot (hh.mm) or just the 4 digits (hhmm).

Date can be specified in ISO format (YYYY-MM-DD), e.g. `2019-12-24 19:00`. Otherwise, the time belongs to the current hamster day or, in the gui, to the day selected in the timeline.

hamster-3.0.3/help/C/keys.page000066400000000000000000000042021452646177100161160ustar00rootroot00000000000000 Controlling Hamster from the keyboard. Keyboard shortcuts

Hamster can be used very efficiently from the keyboard if desired. You may also find it useful to bind either the command hamster or hamster add to a keyboard application shortcut using your desktop UI settings.

The following key combinations can be used in the overview window.

Left/Right: Same as </> buttons. Navigate backwards or forwards in time.

Down/Up: Navigate the activity list, starting from the top/bottom respectively, and select a previous activity.

Home/End: Navigate to the first or last activity in the list, respectively, and select the activity.

PageDown/PageUp: Navigate the activity list if longer than one page.

Ctrl+N: Create a New activity from scratch.

Ctrl+R: Resume an existing activity. (if an activity is selected, of course, otherwise do nothing). All details of the selected activity, except start/end, are copied to the new activity.

Ctrl++: Same as the + button. Create a new activity. If an existing activity is selected, it will be resumed (same as Ctrl+R), otherwise, new from stratch (same as Ctrl+N).

Ctrl+Space: Stop tracking the ongoing activity, if any. Otherwise restart tracking the last activity. Useful for toggling tracking on and off.

Return: Edit/update the selected activity if any. Same as double click.

Delete: Delete the selected activity if any.

More Ctrl combinations

The keys above without Ctrl can also be used in combination with Ctrl, for example Ctrl+Left.

hamster-3.0.3/help/C/legal.xml000066400000000000000000000007561452646177100161250ustar00rootroot00000000000000

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License.

As a special exception, the copyright holders give you permission to copy, modify, and distribute the example code contained in this document under the terms of your choosing, without restriction.

hamster-3.0.3/help/C/merge.page000066400000000000000000000024161452646177100162470ustar00rootroot00000000000000 Automatic conflict solving. Splitting activities

Time Tracker does its best to avoid overlaps in activities. If you create an activity whose start and end time both lie within an existing activity, the existing activity will be split into two. In other cases of overlapping, the previous entries will be shrunk.

Former ongoing activity not split

The former ongoing activity is not "split into two" actually, but merely shortened to end when the new activity starts. Reported as issue 396.

Merging can become handy when entering information for the whole day. Start by entering the first activity with only a start time (i.e. activity "in progress"). For the next activity again set just the start time. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!

hamster-3.0.3/help/C/reports.page000066400000000000000000000016471452646177100166530ustar00rootroot00000000000000 Get data out of Time Tracker. Report and export

Apart from the HTML format that is offered by default in the Header barTools iconExport... dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats.

For programmatic access, there is a D-Bus API, that can be introspected using tools like D-Feet and dbus-monitor. And there is also a command-line interface (try hamster help in a terminal), that is very useful for scripting too.

hamster-3.0.3/help/C/statistics.page000066400000000000000000000006011452646177100173340ustar00rootroot00000000000000 How to find the detailed totals. Statistics

The totals sorted by activities, categories or tags are accessible by clicking the main Totals area at the bottom of the overview.

hamster-3.0.3/help/C/tracking.page000066400000000000000000000062101452646177100167460ustar00rootroot00000000000000 Tips on how to track your activities effectively. How to track time

Your time tracking habits will be dictated by your reason for collecting the data. What is that you want to do with the data? Is it plain curiosity, or a work requirement? And at what level of detail are you interested in the results?

Granularity

A suggested pace is to have 5 to 30 activities per day.

The intention of Time Tracker is to avoid micro-tracking so that one does not turn out spending more time on tracking than doing the activities! However, tracking in insufficient detail could result in there being no data which is useful to you a month later.

What should I write in each box?

For simple activities that don't have a project, use the action as the activity name and the category for the wider context. For example: lunch@work.

For more sophisticated tracking try to caption your activity in one or two words ("tree house", "project x", or similar) and use that caption in the activity field. Use the category to describe the activity in it's wider context - is it private or work, or something else? Finally, use tags to describe your actual action - is it reading or constructing, writing or painting.

This approach will alow you to see how much reading you have done through all your projects (by tag), how much time you have spent in your hobbies (by category), and how much time of all your work in project x you have spent analysing (by activity and tag)

Tips for improving your tracking data

Name activities so that they can be easily distinguished from each other. Activity name is also the only information that appears in the panel. Will you be able to determine what you are working on just by looking at the activity name?

Keep your list of categories small (say, 3 to 7) and pick ones that are unlikely to change over time. Also, keep them generic. For example: "work", "private", "misc".

Use the description field for short-term information like reference numbers. The search in the Overview window also looks in the description field, so finding activities where you mention the specific reference number will be as simple as typing it in the search box and pressing Enter.

Activities and tags can come and go as necessary. Once you think that you are done with an activity for good, remove it so that it doesn't pop up in the auto-complete any more. Don't worry: the facts (activities in the log) will not be deleted. This is just the "operational list".

hamster-3.0.3/help/Makefile.am000066400000000000000000000005121452646177100161570ustar00rootroot00000000000000@YELP_HELP_RULES@ HELP_ID = hamster HELP_LINGUAS = cs da de el es fa fr gl hu pl pt_BR ro ru sl te zh_CN zh_HK zh_TW HELP_FILES = \ backup.page \ index.page \ input.page \ keys.page \ merge.page \ reports.page \ statistics.page \ tracking.page \ legal.xml hamster-3.0.3/help/cs/000077500000000000000000000000001452646177100145325ustar00rootroot00000000000000hamster-3.0.3/help/cs/cs.po000066400000000000000000000417511452646177100155070ustar00rootroot00000000000000# Czech translation for hamster-time-tracker help. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker help. # Adrian Guniš , 2010. # Lucas Lommer , 2011. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2011-03-21 00:16+0000\n" "PO-Revision-Date: 2011-03-29 16:06+0200\n" "Last-Translator: Adrian Guniš \n" "Language-Team: Czech \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: cs\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Poedit-Language: Czech\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Tipy na efektivní sledování vašich činností" #: C/tracking.page:10(title) msgid "How to track time" msgstr "Jak sledovat čas" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Vaše zvyky ohledně sledování času se budou odvíjet od toho, kvůli čemu data " "sbíráte. Co plánujete dělat s daty? Jde o pouhou zvědavost nebo o pracovní " "povinnost? A do jaké úrovně podrobností vás zajímají výsledky?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Četnost" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Navržené tempo je 5 až 30 činností za den." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Záměrem aplikace Měřič času je vyhnout se podrobnému sledování, " "tak aby člověk nestrávil více času nad sledováním než nad prací! Na druhou " "stranu, sledování bez dostatku podrobností by mohlo vést k tomu, že nebude " "dostatek dat, která by mohla být užitečná o měsíc později." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Co bych měl psát do každého pole?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "U jednoduchých činností, u kterých neexistuje plán, použijte úkon jako název " "činnosti a kategorii pro širší kontext. Například: " "oběd@práce." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Pro důmyslnější sledování zkuste popsat vaši činnost jedním nebo dvěma slovy " "(\"dům na stromě\", \"projekt x\" nebo podobně) a tento titulek použijte v " "poli činnost. Kategorii použijte k popisu činnosti v " "širším kontextu - jde o soukromí nebo práci, nebo něco jiného? Nakonec " "použijte pole štítky k popisu vašeho aktuálního úkonu - jedná se " "o čtení nebo konstruování, psaní nebo malování?" #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Tento přístup vám umožní sledovat, kolik jste toho přečetli během všech " "svých projektů (podle štítku), kolik času jste strávili nad svými koníčky " "(podle kategorie) a kolik času ze všech svých prací v rámci projektu x jste " "strávili analyzováním (podle činnosti a štítku)." #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Tipy na vylepšení vašich sledovaných dat" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Činnosti popisujte tak, aby byly pro každého srozumitelné. Název činnosti je " "také jedinou informací, která se objeví na panelu. Budete schopni určit, na " "čem právě pracujete, při pouhém pohledu na název činnosti?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Udržujte svůj seznam kategorií malý (tak 3 až 7) a vybírejte takové, u " "kterých je pravděpodobné, že se časem nezmění. Také by se mělo jednat o " "všeobecné názvy, jako např.: \"práce\", \"soukromí\", \"různé\"." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Pole s popisem můžete použít pro krátkodobé informace jako např. referenční " "čísla. Vyhledávání v okně Přehled nahlíží také do pole s popisem, " "takže hledání činností, ve kterých uvedete určité referenční číslo, bude tak " "snadné jako jeho napsání do vyhledávacího pole a stisknutí klávesy " "Enter." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Činnosti a štítky můžete přidávat a odebírat podle potřeby. Pokud si " "myslíte, že činnost je již úplně ukončena, odstraňte ji tak, aby se již " "nezobrazovala v automatickém doplňování. Nedělejte si starosti: data " "(činnosti v protokolu) nebudou smazána. Jedná se pouze o \"provozní seznam\"." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Pár slov ke statistikám" #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statistiky" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Výsledky, které jsou dostupné přes odkaz Zobrazit " "statistiky, jsou experimentální a jsou brány jako vyhodnocení faktů, " "které můžete porovnat s vašim vlastním pozorováním. Opravy jsou vítány." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Nicméně, ukazatel \"Začátky a konce\" by vám měl dát jistou představu o " "využití vašeho času." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Získání dat z Měřiče času" #: C/reports.page:8(title) msgid "Report and export" msgstr "Zprávy a jejich export" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Kromě formátu HTML, který je standardně nabízen v dialogu Uložit zprávu, " "nabízí rozbalovací seznam na výběr také formáty TSV (hodnoty oddělené " "tabulátory, vhodné pro tabulkové procesory), XML a iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Pro přístup z jiných programů existuje rozhraní D-Bus API, které může být " "prohlíženo pomocí nástrojů jako D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Nejrychlejším způsobem získání dat z Měřiče času je vygenerování zprávy ve " "formátu HTML. Při stisknuté klávese Ctrl vyberte všechny potřebné " "buňky a pak je zkopírujte a vložte do cílové aplikace." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Automatické řešení konfliktů" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Rozdělování činností" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Měřič času se vždy snaží předcházet překrývání činností. Pokud " "vytvoříte činnost uprostřed existující činnosti, starší se rozdělí na dvě. V " "jiných případech překrytí dojde ke zkrácení předchozích záznamů." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Slučování může přijít vhod při zadávání informací za celý den. Začněte " "zadáním první činnosti a jako čas ukončení zaškrtněte pole \"probíhá\". U " "další činnosti opět nastavte pouze čas zahájení a označte ji jako " "probíhající. Dbejte na to, aby čas ukončení předchozí činnosti souhlasil s " "časem zahájení nové činnosti. Takto můžete pokračovat dále." #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Triky pro zrychlení zadávání činností" #: C/input.page:8(title) msgid "Input" msgstr "Zadávání dat" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Pro spuštění sledování napište název činnosti do vstupního pole a stiskněte " "klávesu Enter. Nicméně existuje několik triků, které vám ihned " "umožní stanovit více podrobností:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Použití znaku @ přidá kategorii" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Všechno za znakem čárky (,) bude uloženo v poli popis" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Pro okamžité stanovení času je nutné, aby byl zadán do vstupního pole jako " "první." #: C/input.page:23(p) msgid "A few examples:" msgstr "Několik příkladů:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 zalévání květin" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "Nezapomeňte si zaznamenat důležitou činnost - zalévání květin přes oběd." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "rajčata@zahrada, vyhloubení jamek" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "V zahradě potřebujete více rajčat. Vyhloubení jamek je čistě informativní, " "takže slouží jako popis." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existencialismus, přemýšlení o rozlehlosti vesmíru" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Opravná informace sdělující aplikaci, že před sedmi minutami jste dělali " "něco jiného. Relativní časy fungují pouze u probíhajících činností bez časů " "ukončení." # Poslední věta nedává moc smysl. Přeložil jsem to tedy tak, jak to funguje. #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "K tomu všemu je možné do vstupního pole pro štítky přidávat štítky. Štítky " "jsou oddělené čárkou. Když se zobrazí pole s návrhy, napište první písmeno " "štítku a stiskněte klávesu Tab pro dokončení záznamu prvního " "odpovídajícího štítku." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Měřič času" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Jak zálohovat databázi činností" #: C/backup.page:8(title) msgid "Backup" msgstr "Zálohování" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Činnosti jsou ukládány do databáze SQLite umístěné v ~/.local/share/" "hamster/hamster.db. Soubor je možné zálohovat a obnovit za " "chodu. Aplikace načte data automaticky za chvilku." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "K prohlížení obsahu databáze můžeme doporučit použití doplňku SQLite Manager určeného pro Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Adrian Guniš , 2010" #~ msgid "" #~ "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgstr "" #~ "Toto dílo podléhá licenci Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgid "" #~ "As a special exception, the copyright holders give you permission to " #~ "copy, modify, and distribute the example code contained in this document " #~ "under the terms of your choosing, without restriction." #~ msgstr "" #~ "Držitelé autorských práv vám poskytují svolení ke kopírování, upravování " #~ "a šíření ukázkového kódu obsaženého v tomto dokumentu za podmínek dle " #~ "vašeho výběru bez omezení." #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "Time Tracking logoMěřič času" #~ msgid "What's new in this release" #~ msgstr "Novinky v tomto vydání" #~ msgid "News go here." #~ msgstr "Novinky budou zde." hamster-3.0.3/help/da/000077500000000000000000000000001452646177100145115ustar00rootroot00000000000000hamster-3.0.3/help/da/da.po000066400000000000000000000410211452646177100154330ustar00rootroot00000000000000# Danish translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER. # This file is distributed under the same license as the hamster-time-tracker package. # Joe Jansen , 2011. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2011-04-03 19:22+0200\n" "PO-Revision-Date: 2011-04-01 16:33+0000\n" "Last-Translator: Joe Hansen \n" "Language-Team: Danish \n" "Language: da\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" #: ../C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Fif til hvordan du effektivt kan styre dine aktiviteter." #: ../C/tracking.page:10(title) msgid "How to track time" msgstr "Sådan styrer du tiden" #: ../C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Dine vaner i forbindelse med tidsstyring vil være dikteret af årsagen til, " "at du ønsker at indsamle dataene. Hvad ønsker du at bruge dataene til? Er " "det bare nysgerrighed eller et arbejdskrav? Og hvilket detaljeringsniveau er " "du interesseret i?" #: ../C/tracking.page:20(title) msgid "Granularity" msgstr "Granulering" #: ../C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Et forslag til antal aktiviteter per dag kunne ligge på 5-30." #: ../C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Formålet med Tidsstyring er at undgå mikrostyring, så man ikke " "bruger mere tid på at styre end rent faktisk på at udføre aktiviteterne!For " "lav detaljeringsgrad kan dog også resultere i, at der ikke er nogen data, " "som er brugbare for dig en måned senere." #: ../C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Hvad skal jeg skrive i hver boks?" #: ../C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "For simple aktiviteter som ikke har et projekt, brug handlingen som navn på " "aktiviteten og kategorien for en bredere benævnelse. " "For eksempel: frokost@arbejde." #: ../C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "For mere sofistikeret styring kan du forsøge at indfange din aktivitet i et " "eller to ord (\"træhus\", \"projekt x\" eller lignende) og bruge dette i " "feltet for aktiviteten. Brug kategorien til at " "beskrive aktiviteten bredt - er det privat eller arbejde eller noget andet? " "Endelig kan du bruge mærker til at beskrive din faktiske handling " "- er det læsning eller fysisk arbejde, skrivning eller maling." #: ../C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Denne fremgangsmåde vil tillade dig, at se hvor meget du har fået læst " "igennem alle projekter (efter mærket), hvor meget tid du har brugt på dine " "hobbyer efter kategorien), og hvor meget tid du har arbejdet på projekt x " "med analyser (efter aktiviteten og mærket)." #: ../C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Fif til forbedring af dine styringsdata" #: ../C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Navngiv aktiviteter så de nemt kan adskilles fra hinanden. Aktivitetsnavnet " "er også den eneste information, som fremgår af panelet. Vil du kunne " "bestemme, hvad du arbejder på bare ved at kigge på aktivitetsnavnet?" #: ../C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Hold din liste af kategorier lille (cirka 3-7) og vælg nogle som forventes " "ikke at blive ændret over tid. Hold dem også generiske. For eksempel " "\"arbejde\", \"privat\", \"diverse\"." #: ../C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Brug beskrivelsesfeltet for korttidsinformation såsom referencenummer. " "Søgningen i overbliksvinduet søger også i beskrivelsen, så det at " "finde aktiviteter hvor du har nævnt det specifikke referencenummer er så " "enkelt som at indtaste det i søgeboksen og trykke Retur." #: ../C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Aktiviteter og mærker kan bruges efter behov. Når du mener, at du er færdig " "med en aktivitet, så fjern den så den ikke længere viser sig i autofærdig. " "Vær ikke bekymret: Dataene (aktiviteter i loggen) vil ikke blive slettet. " "Dette er bare \"den igangværende liste\"." #: ../C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Bemærkning om fortolkning af statistik." #: ../C/statistics.page:8(title) msgid "Statistics" msgstr "Statistik" #: ../C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Resultaterne som er tilgængelige via henvisningen Vis " "statistik er eksperimentelle og de er en fortolkning af fakta. Denne " "fortolkning skal sammenlignes med dine egne observationer. Bidrag (patches) " "er velkomne." #: ../C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "\"Starter og slutter\" bør dog give dig en ide om din aktive tid." #: ../C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Hent data ud af tidsstyringen." #: ../C/reports.page:8(title) msgid "Report and export" msgstr "Rapport og eksport" #: ../C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Udover HTML-formatet der tilbydes som standard i dialogen Gem rapport, giver " "rullegardinet for format dig mulighed for at vælge TSV- (Tab/indryk adskilte " "værdier, velegnet til regneark), XML- og iCal-formater." #: ../C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "For programadgang er der D-Bus API, som kan introspiceres med brug af " "værktøjer som D-Feet." #: ../C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Den hurtigste måde at få data \"ud\" af tidsstyringen er ved at danne en " "HTML-rapport. Mens tasten Ctrl holdes nede, vælges alle de " "krævede celler, og så kopieres og indsættes de i målprogrammet." #: ../C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Automatisk konfliktløsning." #: ../C/merge.page:8(title) msgid "Splitting activities" msgstr "Opdeling af aktiviteter" #: ../C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Tidsstyring gør sit bedste for at undgå overlapning i " "aktiviteter. Hvis du opretter en aktivitet i midten af en eksisterende " "aktivet, vil den tidligere aktivitet blive delt op i to. I andre tilfælde af " "overlapning vil de forrige poster blive formindsket." #: ../C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Sammenføjning kan være en god ting når der indtastes information for hele " "dagen. Start med at indtaste den første aktivitet og vælg afkrydsningsboksen " "\"i gang\" for sluttiden. For den næste aktivitet igen sættes bare " "starttidspunktet og den markeres som igangværende. Observer hvordan " "sluttidspunktet for den forrige aktivitet bliver justeret til " "starttidspunktet for den nye. Gentag denne proces!" #: ../C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Fif der kan øge hastighed for aktivitetsindtastning" #: ../C/input.page:8(title) msgid "Input" msgstr "Inddata" #: ../C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Start styring ved at indtaste aktivitetsnavnet i inddataboksen og tryk på " "tasten Retur. Der er nogle få fif, som vil give dig mulighed for " "at angive flere detaljer løbende:" #: ../C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Brug @-symbolet til at tilføje en kategori" #: ../C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Alt efter et komma (,), vil blive gemt i beskrivelsesfeltet" #: ../C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "For at angive tidspunkt løbende, indtast først tidspunkt i inddataboksen" #: ../C/input.page:23(p) msgid "A few examples:" msgstr "Nogle få eksempler:" #: ../C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 vander blomster" #: ../C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Glemte at notere den vigtige vanding af blomster efter frokost." #: ../C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "tomater@haven, graver huller" #: ../C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Har brug for flere tomater i haven. Graver huller er rent informativt, så " "tilføjede det som en beskrivelse." #: ../C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 eksistentialisme, tanker om universets store vidder" #: ../C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Rettede information ved at informere program om, at jeg har lavet noget " "andet i de sidste syv minutter. Relativ tid virker kun for igangværende " "aktiviteter uden et sluttidspunkt." #: ../C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Derudover kan du tilføje mærker i inddatafeltet for mærker. Mærker adskilles " "med et komma. Tryk på Tab når forslagsboksen kommer frem for at " "færdiggøre inddata til det første matchende mærke." #: ../C/index.page:6(title) ../C/index.page:7(title) ../C/index.page:17(title) msgid "Time Tracking" msgstr "Tidssporing" #: ../C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: ../C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: ../C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: ../C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Sådan laver du sikkerhedskopi af aktivitetsdatabasen." #: ../C/backup.page:8(title) msgid "Backup" msgstr "Sikkerhedskopi" #: ../C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Aktiviteter gemmes i en SQLite-database, placeret i ~/.local/share/" "hamster/hamster.db. Filen kan løbende sikkerhedskopieres og " "gendannes. Programmet vil genindlæse data automatisk efter en kort " "tidsperiode." #: ../C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "For at se indholdet af databasen kan vi anbefale SQLite Manager til " "Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: ../C/backup.page:0(None) msgid "translator-credits" msgstr "" "Joe Hansen, 2011.\n" "\n" "Dansk-gruppen \n" "Mere info: http://www.dansk-gruppen.dk" #~ msgid "" #~ "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgstr "" #~ "Dette værk distribueres under licensen Creative Commons Navngivelse/" #~ "Del på samme vilkår 3.0 Unported." #~ msgid "" #~ "As a special exception, the copyright holders give you permission to " #~ "copy, modify, and distribute the example code contained in this document " #~ "under the terms of your choosing, without restriction." #~ msgstr "" #~ "Som en speciel undtagelse giver ophavsretholderen dig tilladelse til at " #~ "kopiere, ændre og distribuere eksempelkoden indeholdt i dette dokument " #~ "under betingelser du selv fastlægger, uden begrænsning." #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" # fejl her? #~ msgid "" #~ "Time Tracking-logoTime Tracking" #~ msgstr "" #~ "Time Tracking-logoTime Tracking" hamster-3.0.3/help/de/000077500000000000000000000000001452646177100145155ustar00rootroot00000000000000hamster-3.0.3/help/de/de.po000066400000000000000000000430561452646177100154550ustar00rootroot00000000000000# German translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Mario Blättermann , 2010. # Christian Kirbach , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-08-26 20:14+0000\n" "PO-Revision-Date: 2010-08-28 23:56+0200\n" "Last-Translator: Christian Kirbach \n" "Language-Team: Deutsch \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" "X-Poedit-Language: German\n" "X-Poedit-Country: GERMANY\n" #: C/legal.xml:3(p) msgid "" "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported " "License." msgstr "" "Dieses Werk ist lizenziert unter einer Creative Commons Attribution-Share Alike 3.0 " "Unported License." #: C/legal.xml:6(p) msgid "" "As a special exception, the copyright holders give you permission to copy, " "modify, and distribute the example code contained in this document under the " "terms of your choosing, without restriction." msgstr "" "Als besondere Ausnahme erteilen Ihnen die Urheberrechtsinhaber die " "Genehmigung, den in diesem Dokument enthaltenen Beispielcode ohne " "Einschränkung unter den Bedingungen Ihrer Wahl zu verbreiten." #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Tipps zum effektiven Erfassen Ihrer Tätigkeiten." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Zeiterfassung" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Ihre Gewohnheiten zur Zeiterfassung werden davon bestimmt, aus welchen " "Gründen Sie diese Daten überhaupt sammeln wollen. Was wollen Sie damit " "machen? Ist es einfach nur Spielerei, oder tatsächlich für Ihre tägliche " "Arbeit? Wie detailliert sollen die Ergebnisse sein?" # #: C/tracking.page:20(title) msgid "Granularity" msgstr "Detailgrad" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Empfehlenswert sind ungefähr zwischen 5 und 30 Tätigkeiten pro Tag." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Die Zeiterfassung will auch das allzu detaillierte Erfassen " "vermeiden. Schließlich sollen Sie ja nicht mehr Zeit für die Erfassung Ihrer " "Tätigkeiten aufwenden als für die Tätigkeiten selbst! Anders herum " "betrachtet, können mangelnde Details dazu führen, dass die erfassten Daten " "vielleicht schon einen Monat später nicht mehr sinnvoll verwertbar sind." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Was soll ich in jedes der Felder eintragen?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Für einfache Tätigkeiten ohne übergeordnetes Projekt verwenden Sie die " "Aktion an sich als Tätigkeit und die Kategorie für " "eine Verallgemeinerung. Beispiel: Mittagessen@Arbeit." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Für die etwas anspruchsvollere Erfassung sollten Sie Ihre Tätigkeit in ein " "oder zwei Worte fassen (»Baumhaus«, »Projekt X« o.ä.). Geben Sie dies im Feld " "Tätigkeit ein. Im Kategorie-Feld geben Sie einen " "verallgemeinernden Begriff ein, der beschreibt, ob es sich beispielsweise um " "eine private oder berufliche Angelegenheit oder auch etwas ganz Anderes " "handelt. Letztendlich beschreiben Sie im Feld Schlagworte Ihre " "aktuelle Aktion, ob Lesen oder Basteln, Schreiben oder Malen ..." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Dieser Ansatz vermittelt Ihnen einen Überblick, wie viel Zeit Sie in Ihren " "gesamten Projekten mit Lesen verbracht haben (anhand des Schlagwortes), wie " "viel Zeit Sie Ihren Hobbys gewidmet haben (anhand der Kategorie) oder wie " "viel Zeit die Arbeit am Projekt X in Anspruch nahm (anhand von Tätigkeit und " "Schlagwort)." #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Tipps zum Verbessern der erfassten Daten" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Benennen Sie Tätigkeiten so, dass Sie einfach voneinander zu unterscheiden " "sind. Der Name der Tätigkeit ist die einzige Information, die im Panel " "erscheint. Sind Sie in der Lage, allein anhand des Namens der Tätigkeit zu " "bestimmen, woran Sie gerade arbeiten?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Halten Sie Ihre Kategorienliste klein (etwa 3 bis 7 Kategorien) und suchen " "Sie sich Begriffe aus, die sich höchstwahrscheinlich auch über längere Zeit " "nicht ändern werden. Beispiele: »Arbeit«, »Privat«, »Sonstiges«." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Tragen Sie im Beschreibungsfeld kurz gefasste Informationen wie " "Referenzierungsnummern ein. Die Suche im Übersicht-Fenster " "berücksichtigt auch das Beschreibungsfeld, so dass das Finden von " "Tätigkeiten anhand der Referenzierungsnummer ebenso einfach wird wie die " "Eingabe in das Suchfeld und das Drücken der Eingabetaste." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Tätigkeiten und Schlagworte kommen und gehen… Sobald Sie der Meinung sind, " "dass Sie eine Tätigkeit erledigt haben, sollten Sie sie entfernen, so dass " "sie nicht mehr in der Liste zur automatischen Vervollständigung auftaucht. " "Keine Angst, die Daten an sich, also die Protokolle der Tätigkeit, werden " "dadurch nicht gelöscht. Dies ist nur die »Verlaufsliste«." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Ein Wort zur Interpretation der Statistiken." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statistiken" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Die über den Knopf Statistiken zeigen " "aufrufbaren Ergebnisse sind experimentell und nur Interpretationen der " "Fakten. Die Interpretation sollte mit Ihren eigenen Beobachtungen verglichen " "werden. Fehlerkorrekturen sind willkommen." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "In jedem Fall sollten Ihnen »Beginn« und »Ende« einen Eindruck über die " "aufgewendete Zeit vermitteln." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Daten zur Zeiterfassung auslesen." #: C/reports.page:8(title) msgid "Report and export" msgstr "Berichte erstellen und exportieren" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Neben dem als Vorgabe im Dialog Bericht speichern angebotenen " "HTML-Format ermöglicht die Format-Auswahlliste die Wahl zwischen TSV (durch " "Tabulatoren getrennte Werte, günstig für Tabellenkalkulationen), XML und " "iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Für Zugriffe auf Softwareebene gibt es eine D-Bus-Schnittstelle, die mit " "Werkzeugen wie D-Feet " "überwacht werden kann." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Der wirklich schnellste Weg, Daten aus der Zeiterfassung »heraus zu " "bekommen«, ist die Erstellung eines HTML-Berichts. Halten Sie die Strg-Taste gedrückt, während Sie alle benötigten Zellen auswählen und fügen " "Sie sie anschließend in die Zielanwendung ein." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Automatisches Lösen von Konflikten." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Teilen von Tätigkeiten" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Die Zeiterfassung tut ihr Bestes, Überschneidungen in den " "Tätigkeiten zu vermeiden. Falls Sie eine Tätigkeit innerhalb einer " "vorhandenen Tätigkeit erstellen, wird die erste vorhandene Tätigkeit in zwei " "unterteilt. In anderen Überschneidungsfällen werden vorherige Einträge " "geschrumpft." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Diese Zusammenführung kann ins Blickfeld rücken, wenn Sie die Information " "auf einen ganzen Tag ausdehnen. Beginnen Sie mit der Eingabe der ersten " "Tätigkeit und aktivieren Sie das Ankreuzfeld im Gange für die " "Endzeit. Beobachten Sie, wie die Endzeit der vorhergehenden Tätigkeit an die " "Startzeit der neuen Tätigkeit angepasst wird. Wiederholen Sie diesen " "Prozess, bis Sie zufrieden sind!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Tricks zum Beschleunigen der Eingabe von Tätigkeiten." #: C/input.page:8(title) msgid "Input" msgstr "Eingabe" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Um mit der Zeiterfassung zu beginnen, geben Sie den Namen der Tätigkeit in " "das Eingabefeld ein und drücken Sie die Eingabetaste. Es gibt " "einige Tricks, mit deren Hilfe Sie unmittelbar einige Details hinzufügen " "können:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Verwenden Sie das Symbol @, um eine Kategorie hinzuzufügen" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Alles nach dem Komma (,) wird zum Beschreibungsfeld hinzugefügt" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Um die Zeit unmittelbar anzugeben, tippen Sie sie zuerst in das Eingabefeld " "ein." #: C/input.page:23(p) msgid "A few examples:" msgstr "Einige Beispiele:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 Blumen gießen" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "Vergessen Sie nicht, den bedeutsamen Vorgang des Blumengießens während des " "Mittagessens zu erwähnen." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "Tomaten@Garten, Löcher graben" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Es werden mehr Tomaten im Garten gebraucht. Das Graben von Löchern ist rein " "informativ, deshalb wird es als Beschreibung hinzugefügt" #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 Existentialismus, Nachdenken über die Grundfesten des Universums" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Informationen werden korrigiert, indem die Anwendung darüber informiert " "wird, was Sie in den letzten 7 Minuten getan haben. Relative Zeiten haben " "keine Endzeit, sie werden für die letzten Tätigkeiten genutzt." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Darüber hinaus können Sie Eingabefeld Kategorien und Schlagworte " "Schlagworte hinzufügen. Drücken Sie die Tabulatortaste, wenn das " "Vorschlagfeld angezeigt wird. Dadurch wird das erste zutreffende Schlagwort " "vervollständigt." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Zeiterfassung" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Sichern der Datenbank der Tätigkeiten." #: C/backup.page:8(title) msgid "Backup" msgstr "Datensicherung" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Die Tätigkeiten werden in einer SQLite-Datenbank gespeichert, die sich in " "~/.local/share/hamster/hamster.db befindet. Die Datei " "kann gesichert und unmittelbar wiederhergestellt werden. Die Anwendung lädt " "die Daten automatisch nach einer kurzen Wartezeit neu." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Für die Betrachtung des Inhalts der Datenbank empfehlen wir den SQLite Manager für Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "Mario Blättermann , 2010\n" "Christian Kirbach , 2010" #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "a" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "Zeiterfassungs-LogoZeiterfassung" #~ msgid "What's new in this release" #~ msgstr "Neues in dieser Version" #~ msgid "News go here." #~ msgstr "Hier Neuigkeiten einfügen." hamster-3.0.3/help/el/000077500000000000000000000000001452646177100145255ustar00rootroot00000000000000hamster-3.0.3/help/el/el.po000066400000000000000000000531711452646177100154740ustar00rootroot00000000000000# Greek translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # Marios Zindilis , 2010. msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-09-24 09:24+0000\n" "PO-Revision-Date: 2010-10-01 14:12+0200\n" "Last-Translator: Michael Kotsarinis \n" "Language-Team: Greek \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" "X-Generator: Lokalize 1.0\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Υποδείξεις για την αποτελεσματική παρακολούθηση των δραστηριοτήτων σας." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Πως να παρακολουθείτε το χρόνο" #: C/tracking.page:12(p) msgid "Your time tracking habits will be dictated by your reason for collecting the data. What is that you want to do with the data? Is it plain curiosity, or a work requirement? And at what level of detail are you interested in the results?" msgstr "Οι συνήθειες παρακολούθησης του χρόνου σας θα υπαγορευτούν από τους λόγους που έχετε να συλλέξετε τα δεδομένα. Τι θέλετε να κάνετε με αυτά; Τα συλλέγετε απλά από περιέργεια ή είναι απαίτηση της εργασίας σας; Και ποιο επίπεδο λεπτομέρειας θέλετε να έχουν τα αποτελέσματα;" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Συχνότητα" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Ένα προτεινόμενος ρυθμός είναι να έχετε 5 με 30 δραστηριότητες την ημέρα." #: C/tracking.page:22(p) msgid "The intention of Time Tracker is to avoid micro-tracking so that one does not turn out spending more time on tracking than doing the activities! However, tracking in insufficient detail could result in there being no data which is useful to you a month later." msgstr "Ο σκοπό της Καταγραφής χρόνου είναι να αποφύγετε τη μικρο-καταγραφή έτσι ώστε να μην ξοδεύει κάποιος περισσότερο χρόνο καταγράφοντας παρά κάνοντας δραστηριότητες! Πάντως, η καταγραφή με ανεπαρκή λεπτομέρεια θα μπορούσε να καταλήξει στο να μην έχετε χρήσιμα δεδομένα ένα μήνα μετά." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Τι θα πρέπει να γράφω σε κάθε πεδίο;" #: C/tracking.page:33(p) msgid "For simple activities that don't have a project, use the action as the activity name and the category for the wider context. For example: lunch@work." msgstr "Για απλές δραστηριότητες που δεν ανήκουν σε έργο, χρησιμοποιήστε την ενέργεια ως όνομα για τη δραστηριότητα και την κατηγορία για το ευρύτερο πλαίσιο. Παραδείγματος χάριν: γεύμα@δουλειά." #: C/tracking.page:38(p) msgid "For more sophisticated tracking try to caption your activity in one or two words (\"tree house\", \"project x\", or similar) and use that caption in the activity field. Use the category to describe the activity in it's wider context - is it private or work, or something else? Finally, use tags to describe your actual action - is it reading or constructing, writing or painting." msgstr "Για πιο εξειδικευμένη καταγραφή προσπαθήστε να περιγράψετε τη δραστηριότητά σας με μια ή δύο λέξεις (\"κιόσκι κήπου\", \"έργο x\", ή παρόμοια) και χρησιμοποιήστε αυτή την περιγραφή στο πεδίο δραστηριότητα. Χρησιμοποιήστε το πεδίο κατηγορία για να περιγράψετε το ευρύτερο πλαίσιο της δραστηριότητας - είναι ιδιωτικό ή εργασιακό ή κάτι άλλο; Τέλος, σρησιμοποιήστε ετικέτες για περιγράψετε την πραγματική ενέργεια - μελέτη ή κατασκευή, συγγραφή ή βάψιμο." #: C/tracking.page:47(p) msgid "This approach will alow you to see how much reading you have done through all your projects (by tag), how much time you have spent in your hobbies (by category), and how much time of all your work in project x you have spent analysing (by activity and tag)" msgstr "Αυτή η προσέγγιση θα σας επιτρέψει να δείτε πόση μελέτη έχετε κάνει για όλα τα έργα σας (κατά ετικέτα), πόσο χρόνο αφιερώσατε στα χόμπυ σας (κατά κατηγορία) και πόσο χρόνο όλης της δουλειάς σας στο έργο x έχετε περάσει αναλύοντας (κατά δραστηριότητα και ετικέτα)" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Υποδείξεις για βελτίωση της καταγραφής σας δεδομένων" #: C/tracking.page:58(p) msgid "Name activities so that they can be easily distinguished from each other. Activity name is also the only information that appears in the panel. Will you be able to determine what you are working on just by looking at the activity name?" msgstr "Ονομάστε τις δραστηριότητες έτσι ώστε να διακρίνονται εύκολα μεταξύ τους. Το όνομα της δραστηριότητας είναι επίσης η μόνη πληροφορία που εμφανίζεται στην πλευρική στήλη. Θα μπορείτε να καταλάβετε σε τι δουλεύετε απλώς βλέποντας το όνομα της δραστηριότητας;" #: C/tracking.page:64(p) msgid "Keep your list of categories small (say, 3 to 7) and pick ones that are unlikely to change over time. Also, keep them generic. For example: \"work\", \"private\", \"misc\"." msgstr "Κρατήστε τη λίστα των κατηγοριών μικρή (ας πούμε, 3 ως 7) και διαλέξτε αυτές που είναι πιθανότερο να μην αλλάξουν με τον καιρό. Επίσης, κρατήστε τις γενικές. Παραδείγματος χάριν: \"εργασία\", \"ιδιωτικό\", \"διάφορα\"." #: C/tracking.page:69(p) msgid "Use the description field for short-term information like reference numbers. The search in the Overview window also looks in the description field, so finding activities where you mention the specific reference number will be as simple as typing it in the search box and pressing Enter." msgstr "Χρησιμοποιήστε το πεδίο περιγραφής για βραχύβιες πληροφορίες, όπως αριθμούς αναφοράς. Η αναζήτηση στο παράθυρο Επισκόπηση κοιτάζει επίσης στο πεδίο περιγραφής έτσι το να βρείτε δραστηριότητες όπου αναφέρετε τον συγκεκριμένο αριθμό αναφοράς θα είναι απλά να τον πληκτρολογήσετε στο πεδίο αναζήτησης και να πατήσετε Enter." #: C/tracking.page:76(p) msgid "Activities and tags can come and go as necessary. Once you think that you are done with an activity for good, remove it so that it doesn't pop up in the auto-complete any more. Don't worry: the facts (activities in the log) will not be deleted. This is just the \"operational list\"." msgstr "Οι δραστηριότητες και οι πληροφορίες μπορούν να προστίθενται και να αφαιρούνται κατά το δοκούν. Μόλις θεωρήσετε ότι έχετε τελειώσει οριστικά με μια δραστηριότητα, αφαιρέστε την έτσι ώστε να μην αναδύεται στην αυτόματη συμπλήρωση. Μην ανησυχείτε: τα δεδομένα (καταγεγραμμένες δραστηριότητες) δεν θα διαγραφούν. Αυτή είναι απλώς η \"λειτουργική λίστα\"." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Σημείωση για την ερμηνεία των στατιστικών." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Στατιστικά" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "Τα στατιστικά που διατίθενται μέσω του συνδέσμου Προβολή στατιστικών είναι πειραματικά και αποτελούν μόνο μια ερμηνεία των γεγονότων. Αυτή η ερμηνεία θα πρέπει να συγκρίνεται με τις δικές σας παρατηρήσεις. Οι διορθώσεις σας είναι καλοδεχούμενες." #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "Ωστόσο, το «Αρχίζει και τελειώνει» θα πρέπει να σας δίνει μια ιδέα για τον ενεργό σας χρόνο." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Λήψη δεδομένων από τον Καταγραφέα χρόνου." #: C/reports.page:8(title) msgid "Report and export" msgstr "Αναφορά και εξαγωγή" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "Εκτός από τη μορφή HTML η οποία προσφέρεται από προεπιλογή στο διάλογο Αποθήκευση αναφοράς, η αναδιπλούμενη λίστα μορφής σας επιτρέπει να επιλέξετε ανάμεσα στις μορφές TSV (Tab Separated Values, τιμές χωρισμένες με στηλοθέτη, κατάλληλο για εισαγωγή σε λογιστικά φύλλα), XML και iCal." #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "Για πρόσβαση για προγραμματισμό, υπάρχει το D-Bus API, το οποίο μπορείτε να εξετάσετε με εργαλεία όπως το D-Feet." #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "Ο γρηγορότερος τρόπος για να εξάγετε δεδομένα από τον Καταγραφέα χρόνου είναι να δημιουργήσετε μια αναφορά σε HTML. Κρατώντας πατημένο το πλήκτρο Ctrl, επιλέξτε όλα τα απαραίτητα κελιά, και μετά αντιγράψτε τα και επικολλήστε τα στην εφαρμογή που θέλετε." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Αυτόμαρη επίλυση διενέξεων." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Διαχωρισμός δραστηριοτήτων" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr "Ο Καταγραφέας χρόνου κάνει ότι καλύτερο μπορεί για να αποφεύγει αλληλοεπικαλύψεις στις δραστηριότητες. Αν δημιουργήσετε μια δραστηριότητα στη μέση μιας άλλης, η πρώτη θα κοπεί στα δύο. Σε άλλες περιπτώσεις αλληλοεπικάλυψης, οι προηγούμενες καταχωρήσεις θα μικρύνουν." #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "Η συγχώνευση μπορεί να είναι χρήσιμη όταν εισάγετε πληροφορίες για ολόκληρη τη μέρα. Αρχίστε " #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Κόλπα για να επιταχύνετε την εισαγωγή δραστηριοτήτων." #: C/input.page:8(title) msgid "Input" msgstr "Είσοδος" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "Για να αρχίσετε την καταγραφή, πληκτρολογήστε το όνομα της δραστηριότητας στο πεδίο εισόδου και πιέστε το πλήκτρο Enter. Υπάρχουν μερικά κόλπα που θα σας επιτρέψουν να καθορίσετε περισσότερες λεπτομέρειες ενώ γράφετε:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Χρησιμοποιήστε το σύμβολο @ για να προσθέσετε μια κατηγορία" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Ο,τιδήποτε μετά από ένα κόμμα (,) θα αποθηκευτεί στο πεδίο περιγραφής" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "Για να καθορίσετε χρόνο ενώ γράφετε, εισάγετέ τον πρώτο στο πεδίο εισόδου" #: C/input.page:23(p) msgid "A few examples:" msgstr "Μερικά παραδείγματα:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 πότισμα λουλουδιών" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Ξέχασα να σημειώσω τη σημασία του ποτίσματος λουλουδιών κατά τη διάρκεια του γεύματος." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "ντομάτες@κηπουρική, σκάβω τρύπες" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "Χρειάζομαι περισσότερες ντομάτες στον κήπο. Το σκάψιμο τρύπων είναι καθαρά πληροφοριακό, οπότε το προσέθεσα ως περιγραφή." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 υπαρξιακά, συλλογίζομαι το απέραντο του σύμπαντος" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "Διόρθωσα την πληροφορία ενημερώνοντας την εφαρμογή ότι έκανα κάτι άλλο κατά τα τελευταία επτά λεπτά. Οι σχετικοί χρόνοι δουλεύουν μόνο για τρέχουσες δραστηριότητες χωρίς χρόνο τέλους." #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "Πέρα από αυτό μπορείτε να προσθέσετε ετικέτες στο πεδίο εισόδου ετικέτων. Οι ετικέτες διαχωρίζονται με ένα κόμμα. Πιέστε το πλήκτρο Tab όταν εμφανιστεί το κουτί εισηγήσεων για να συμπληρώσετε την είσοδο στην πρώτη ετικέτα που ταιριάζει." #: C/index.page:6(title) #: C/index.page:7(title) #: C/index.page:17(title) msgid "Time Tracking" msgstr "Καταγραφή χρόνου" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Πώς να πάρετε ένα αντίγραφο ασφαλείας της βάσης δεδομένων δραστηριοτήτων." #: C/backup.page:8(title) msgid "Backup" msgstr "Αντίγραφο ασφαλείας" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "Οι δραστηριότητες αποθηκεύονται σε μια βάση δεδομένων SQLite, που βρίσκεται στο ~/.local/share/hamster/hamster.db. Μπορείτε να αντιγράψετε το αρχείο για λόγους ασφαλείας και να το επαναφέρετε ενώ δουλεύετε. Η εφαρμογή θα επαναφέρει τα δεδομένα αυτόματα μετά από ένα σύντομο χρονικό διάστημα." #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "Για να δείτε τα δεδομένα μέσα στη βάση δεδομένων σας εισηγούμαστε να χρησιμοποιήσετε το Διαχειριστή SQLite για το Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Μάριος Ζηντίλης , 2010" #~ msgid "" #~ "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgstr "" #~ "Αυτό το έργο διατίθεται υπό την Άδεια Creative Commons Attribution-Share Alike 3.0 " #~ "Unported." #~ msgid "" #~ "As a special exception, the copyright holders give you permission to " #~ "copy, modify, and distribute the example code contained in this document " #~ "under the terms of your choosing, without restriction." #~ msgstr "" #~ "Ως ειδική εξαίρεση, οι πνευματικοί ιδιοκτήτες σας επιτρέπουν να " #~ "αντιγράψετε, να τροποποιήσετε και να αναδιανείμετε τα παραδείγματα " #~ "πηγαίου κώδικα που περιλαμβάνονται σ' αυτό το έγγραφο υπό τους όρους της " #~ "επιλογής σας, χωρίς περιορισμό." #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "Λογότυπο της Καταγραφής χρόνουΚαταγραφή χρόνου" hamster-3.0.3/help/es/000077500000000000000000000000001452646177100145345ustar00rootroot00000000000000hamster-3.0.3/help/es/es.po000066400000000000000000000521401452646177100155050ustar00rootroot00000000000000# translation of hamster-time-tracker.help.master.po to Español # Spanish translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Jorge González , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker.help.master\n" "POT-Creation-Date: 2010-08-23 15:40+0000\n" "PO-Revision-Date: 2010-08-24 00:02+0200\n" "Last-Translator: Jorge González \n" "Language-Team: Español \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" "X-Generator: KBabel 1.11.4\n" #: C/legal.xml:3(p) msgid "" "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported " "License." msgstr "" "Este trabajo está licenciado bajo una Licencia Creative Commons atribución - " "compartir igual 3.0 para los Estados Unidos." #: C/legal.xml:6(p) msgid "" "As a special exception, the copyright holders give you permission to copy, " "modify, and distribute the example code contained in this document under the " "terms of your choosing, without restriction." msgstr "" "Como excepción especial, los poseedores de los derechos de autor le dan " "permiso para copiar, modificar y distribuir el ejemplo de código contenido " "en este documento bajo los términos que usted elija, sin restricción." #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "" "Consejos acerca de cómo seguir el tiempo de sus actividades de forma " "efectiva." #: C/tracking.page:10(title) msgid "How to track time" msgstr "¿Cómo seguir el tiempo?" #: C/tracking.page:12(p) #| msgid "" #| "Your time tracking habbits should heavily depend on the reason why you " #| "are collecting the data. What is that you want to do with it? Is it plain " #| "curiosity, or a work requirement? And in what detail are you interested " #| "in the results?" msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Sus hábitos de seguimiento de tiempo deberían depender de la razón por la " "que recolecta los datos. ¿Qué quiere hacer con ellos? ¿Es simple curiosidad " "o una necesidad del trabajo? ¿Y en qué detalle le interesan los resultados?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Granularidad" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Una pauta sugerida es tener entre 5 y 30 actividades por día." #: C/tracking.page:22(p) #| msgid "" #| "A suggested pace is to have 5 to 30 activities per day. The intention of " #| "Time Tracker is to avoid micro-tracking so that one does not " #| "turn out spending more time on tracking than doing the things. But not " #| "tracking in enough detail could result that there is nothing to dwell on " #| "a month later." msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "La intención del Gestor de tiempo es evitar los microseguimientos " "de tal forma que el usuario no gaste más tiempo en el seguimiento que en las " "actividades en si. Pero no seguir con suficiente detalle podría acabar con " "información insuficiente un mes después." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "¿Qué debería escribir en cada caja?" #: C/tracking.page:33(p) #| msgid "" #| "Exception to this rule are simple activities that don't have project. For " #| "those cases use the action as activity name, and category for wider " #| "context. Example: lunch@work." msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Para actividades simples que no tienen un proyecto, use la acción como el " "nombre de la actividad y la categoría para un contexto " "más amplio. Ejemplo: comer@trabajo." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Para un seguimiento más sofisticado intente resumir su actividad en una o " "dos palabras («árbol de casa», «proyecto x», o similar) y use ese resumen en " "el campo actividad. Use la categoría para describir la " "actividad en su contexto más amplio; ¿es un trabajo privado u otra cosa? " "Finalmente use las etiquetas para describir su acción actual; ya " "sea leyendo, construyendo, escribiendo o pintando." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Ésta aproximación le permitirá ver cuánta lectura ha realizado para todos " "sus proyectos (por etiqueta), cuánto tiempo ha empleado en sus hobbies (por " "categoría) y cuánto tiempo ha dedicado al proyecto x que ha estado " "analizando (por actividad y etiqueta)." #: C/tracking.page:55(title) #| msgid "Here are few tips that might improve your tracking data:" msgid "Tips for improving your tracking data" msgstr "Sugerencias para mejorar el seguimiento de sus datos" #: C/tracking.page:58(p) #| msgid "" #| "Name activities so that they can be easily distinguished from each other. " #| "Activity name is also the only bit that appears in the panel. Will you be " #| "able to determine what you are working on just by looking on the activity " #| "name?" msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Nombre las actividades para que se puedan distinguir fácilmente entre ellas. " "El nombre de la actividad es también lo único que aparece en el panel. ¿Será " "capaz de determinar en qué está trabajando simplemente mirando el nombre de " "la actividad?" #: C/tracking.page:64(p) #| msgid "" #| "Keep your category number low (say, 3 to 7) and pick ones that are " #| "unlikely to change over time. Also, keep them generic. For example: \"work" #| "\", \"private\", \"misc\"." msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Mantenga su número de categorías bajo (entre 3 y 7) y elija unas que " "probablemente no cambien a lo largo del tiempo. También, manténgalas " "genéricas. Por ejemplo: «trabajo», «privado», «varios»." #: C/tracking.page:69(p) #| msgid "" #| "Use the description field for short-term information like bug numbers. " #| "The search in overview window also looks in the description field, so " #| "finding activities where you mention the specific bug or key will be as " #| "simple as typing it in the search box and hitting Enter." msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Use el campo de descripción para información a corto plazo, como números de " "errores. La búsqueda en la ventana de vista general también busca en el " "campo de descripción, de tal forma que buscar actividades donde menciona el " "error o clave específica, es tan simple como escribirlo en la caja de " "búsqueda y pulsar Intro.." #: C/tracking.page:76(p) #| msgid "" #| "Activities and tags can come and go as necessary. Once you think that you " #| "are done with an activity for good - remove it so it does not pop up in " #| "the auto-complete. Don't worry - the facts (activities in the log) will " #| "stay in tact. This is just the \"operational list\"" msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Las actividades y etiquetas pueden aparecer y desaparecer según las " "necesidades. Una vez que crea que ha terminado con una actividad; quítela " "para que no aparezca en el autocompletado. No se preocupe, los hechos " "(actividades en el registro) se quedarán intactas. Es simplemente la «lista " "operacional»." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Nota sobre la interpretación de estadísticas." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Estadísticas" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Los resultados accesibles a través del enlace Mostrar " "estadísticas son experimentales y son interpretaciones de los hechos. " "Esta interpretación se debe comparar con sus propias observaciones. Se " "agradecen parches." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "No obstante, «Comienza y acaba»le debería dar alguna idea acerca de los " "tiempos de sus actividades." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Sacar los datos del Gestor de tiempo." #: C/reports.page:8(title) msgid "Report and export" msgstr "Informar y exportar" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Además del formato HTML que se ofrece de forma predeterminada en el diálogo " "Guardar informe, la lista desplegable de formatos permite elegir formatos " "TSV (valores separados por tabulaciones, bueno para hojas de cálculo), XML e " "iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Para un acceso programado existe una API de D-Bus de la que se puede hacer " "introspección usando herramientas como D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "La forma más rápida de «sacar» datos del Gestor de tiempo es generando un " "informe HTML, mientras mantiene pulsada la tecla Ctrl, seleccione " "todas las celdas necesarias y después cópielas y pégelas en la aplicación de " "destino." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Resolución automática de conflictos" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Partir actividades" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "El Gestor de tiempo hace lo mejor que puede para evitar " "solapamientos entre actividades. Si crea una actividad en el medio de una " "actividad existente, la anterior se partirá en dos. En otros casos de " "solapamiento se encogerán las entradas anteriores." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Mezclar el aspecto puede ser útil al introducir información para todo el " "día. Comience introduciendo la primera actividad del día y establezca el " "tiempo en «en progreso». Para la siguiente actividad, de nuevo, establezca la " "hora de inicio y márquela como en progreso. Observe cómo la hora de " "finalización de la actividad anterior se ajusta a la hora de inicio de la " "actividad nueva." #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Trucos para acelerar la entrada de actividades" #: C/input.page:8(title) msgid "Input" msgstr "Entrada" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Para iniciar un seguimiento, escriba el nombre de la actividad en la caja de " "entrada y pulse Intro. No obstante, existen unos pocos trucos que " "le permitirán especificar más detalles al vuelo:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Use el símbolo @ para añadir una categoría" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "" "Todo lo que vaya detrás de una coma (,) se almacenará en el campo de " "descripción" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Para especificar una hora al vuelo, introdúzcala como el primer campo en la " "caja de entrada" #: C/input.page:23(p) msgid "A few examples:" msgstr "Algunos ejemplos:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "14:30-14:45 regar plantas" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "Se olvidó del importante acto de regar las plantas después de la comida." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "tomates@jardín, hacer agujeros" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Se necesitan más tomates en el jardín. Cavar agujeros es puramente " "informativo, así que se añade como una descripción." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existencialismo, pensar acerca de la inmensidad del universo" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Información corregida informando a la aplicación que se ha estado ocupado en " "otro asunto durante los últimos siete minutos. Los tiempos relativos sólo " "funcionan con los tiempos de finalización, esto es, para la actividad más " "reciente." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Sobre ello puede añadir etiquetas en el campo de entrada de etiquetas. Las " "etiquetas están delimitadas por comas. Pulsar Tab cuando aparezca " "la caja de sugerencias completará la entrada con la primera etiqueta " "coincidente." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Gestión de tiempo" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Compartir Igual 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Cómo respaldar la base de datos de actividades." #: C/backup.page:8(title) msgid "Backup" msgstr "Respaldo" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Las actividades se almacenan en una base de datos SQLite ubicada en ~/." "local/share/hamster/hamster.db. El archivo se puede respaldar " "y restaurar al vuelo. La aplicación recargará automáticamente los datos tras " "un corto tiempo." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Para ver el contenido de la base de datos le sugerimos usar SQLite Manager de Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Jorge González , 20010" #, fuzzy #~| msgid "" #~| "We suggest to write project name into the activity field, use category " #~| "to define the project in wider context - is it private or work, or " #~| "something else. Use tags to distinguish between different activities in " #~| "the project. Example: hamster@hacking, #prog #bugs" #~ msgid "" #~ "We suggest that you write the project name in the activity " #~ "field and use category to define the project in its wider " #~ "context - is it private or work, or something else?" #~ msgstr "" #~ "Se sugiere que escriba el nombre del proyecto en el campo de actividad, " #~ "use la categoría para definir el proyecto en un contexto más amplio; es " #~ "trabajo privado o algo más. Use las etiquetas para distinguir entre las " #~ "diferentes actividades en el proyecto. Ejemplo: hamster@programación, " #~ "#software #bugs" #~ msgid "" #~ "You can use tags to distinguish between different activities in the " #~ "project. For example: presentation@work, #writing." #~ msgstr "" #~ "Puede usar etiquetas para distinguir entre diferentes actividades en el " #~ "proyecto. Por ejemplo: presentación@trabajo, #escribir." #, fuzzy #~| msgid "" #~| "Tags are best when you need to handle large numbers - say if you have " #~| "hundred of projects - having a large activity list will just slow down " #~| "the input as it will be hard to remember the right name. Instead " #~| "consider using tags." #~ msgid "" #~ "Use tags instead of activities when you need to handle a large number of " #~ "activities (if you have hundreds of projects, for example). Having a long " #~ "list of activities will just slow down input, as it will be hard to " #~ "remember the right name." #~ msgstr "" #~ "Las etiquetas son lo más indicado cuando necesita gestionar grandes " #~ "números (si tiene cientos de proyectos) tener una gran lista de " #~ "actividades sólo ralentizará la entrada ya que será difícil recoerdar el " #~ "nombre correcto. En su lugar, considere usar las etiquetas." #~ msgid "What goes where" #~ msgstr "¿Qué va dónde?" #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "Logotipo del Gestor de tiempo Gestión de tiempo" #~ msgid "What's new in this release" #~ msgstr "Qué hay nuevo en esta publicación" #~ msgid "News go here." #~ msgstr "Las noticias van aquí." hamster-3.0.3/help/fa/000077500000000000000000000000001452646177100145135ustar00rootroot00000000000000hamster-3.0.3/help/fa/fa.po000066400000000000000000000321041452646177100154410ustar00rootroot00000000000000# Persian translation for hamster-time-tracker. # Copyright (C) 2012 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # سید‌علی‌اکبر نجفیان , 2012. msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2012-04-07 15:05+0000\n" "PO-Revision-Date: 2012-04-29 19:35+0330\n" "Last-Translator: Arash Mousavi \n" "Language-Team: Farsi (Persian) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fa\n" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "نکاتی راجع به پیگیری فعالیت‌ها به صورت موثر و مفید." #: C/tracking.page:10(title) msgid "How to track time" msgstr "چگونگی دنبال کردن زمان" #: C/tracking.page:12(p) msgid "Your time tracking habits will be dictated by your reason for collecting the data. What is that you want to do with the data? Is it plain curiosity, or a work requirement? And at what level of detail are you interested in the results?" msgstr "عادت‌های شما در پیگیری زمان، به دلیل شما برای جمع‌آوری اطلاعات بر می‌گردد. دلیل جمع‌آوری این اطلاعات چیست؟ یک کنجکاوی ساده یا یک احتیاج کاری است؟ و در چه سطحی، شما به جزئیات نتایج نیاز دارید؟" #: C/tracking.page:20(title) msgid "Granularity" msgstr "دانه دانه بودن" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "یک شیوه پیشنهادی داشتن ۵ تا ۳۰ فعالیت در هر روز است." #: C/tracking.page:22(p) msgid "The intention of Time Tracker is to avoid micro-tracking so that one does not turn out spending more time on tracking than doing the activities! However, tracking in insufficient detail could result in there being no data which is useful to you a month later." msgstr "" #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "چه چیزی باید در هر جعبه بنویسم؟" #: C/tracking.page:33(p) msgid "For simple activities that don't have a project, use the action as the activity name and the category for the wider context. For example: lunch@work." msgstr "برای یک فعالیت ساده که یک پروژه ندارد، از عمل با عنوان فعالیت و شاخه برای محتوای بزرگتر استفاده کنید. به عنوان مثال: lunch@work." #: C/tracking.page:38(p) msgid "For more sophisticated tracking try to caption your activity in one or two words (\"tree house\", \"project x\", or similar) and use that caption in the activity field. Use the category to describe the activity in it's wider context - is it private or work, or something else? Finally, use tags to describe your actual action - is it reading or constructing, writing or painting." msgstr "" #: C/tracking.page:47(p) msgid "This approach will alow you to see how much reading you have done through all your projects (by tag), how much time you have spent in your hobbies (by category), and how much time of all your work in project x you have spent analysing (by activity and tag)" msgstr "" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "نکته‌هایی برای بهینه‌سازی پیگیری اطلاعات شما" #: C/tracking.page:58(p) msgid "Name activities so that they can be easily distinguished from each other. Activity name is also the only information that appears in the panel. Will you be able to determine what you are working on just by looking at the activity name?" msgstr "" #: C/tracking.page:64(p) msgid "Keep your list of categories small (say, 3 to 7) and pick ones that are unlikely to change over time. Also, keep them generic. For example: \"work\", \"private\", \"misc\"." msgstr "" #: C/tracking.page:69(p) msgid "Use the description field for short-term information like reference numbers. The search in the Overview window also looks in the description field, so finding activities where you mention the specific reference number will be as simple as typing it in the search box and pressing Enter." msgstr "" #: C/tracking.page:76(p) msgid "Activities and tags can come and go as necessary. Once you think that you are done with an activity for good, remove it so that it doesn't pop up in the auto-complete any more. Don't worry: the facts (activities in the log) will not be deleted. This is just the \"operational list\"." msgstr "" #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "نکته‌هایی بر تفسیر آمارها." #: C/statistics.page:8(title) msgid "Statistics" msgstr "آمارها" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "" #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "در هر حال، «آغازها و پایان‌ها» باید ایده‌هایی راجع به زمان فعال شما بدهند." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "دریافت اطلاعات از طریق ابزار پیگیری زمان." #: C/reports.page:8(title) msgid "Report and export" msgstr "گزارش و صدور" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "" #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "" #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "" #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "حل تناقضات به صورت خودکار." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "منشعب کردن فعالیت‌ها" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr "" #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "ادغام‌کردن می‌تواند هنگام وارد کردن اطلاعات برای کل روز مفید باشد. با وارد کردن اولین فعالیت و انتخاب «در جریان» برای زمان پایان شروع کنید. برای فعالیت بعدی دوباره، فقط زمان آغاز را تنظیم کنید و به عنوان در جریان نشانه‌گذاری کنید. دقت کنید که چگونه زمان پایان فعالیت قبلی تنظیم شده به‌عنوان زمان آغاز فعالیت بعدی تنظیم می‌شود. این کار را تا زمانی که راضی شوید انجام دهید!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "ترفندهایی برای سرعت بخشیدن به ورودی‌های فعالیت." #: C/input.page:8(title) msgid "Input" msgstr "ورود" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "برای آغاز پیگیری، نام فعالیت را داخل جعبه وارد کرده و کلید Enter را بفشارید. فنونی وجود دارند که به شما اجازه می‌دهند تا جزییات بیشتری را روی هوا مشخص کنید:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "از نماد @ برای اضافه کردن یک گروه استفاده کنید" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "همه چیز بعد از یک کاما «،» در یک فیلد توضیح ذخیره خواهد شد" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "برای تعیین زمان روی هوا، ابتدا آن را در جعبه ورودی وارد کن" #: C/input.page:23(p) msgid "A few examples:" msgstr "چند مثال:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "۱۲:۳۰-۱۲:۴۵ آبیاری گل‌ها" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "یادداشت کردن وظیفه‌ی مهم آبیاری گل‌ها نسبت به ناهار را فراموش کرد." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "گوجه‌فرنگی‌ها@باغ, کندن چاله" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "گوجه فرنگی‌های بیشتری در باغچه مورد نیاز است." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-۷ اگزیستانسیالیسم، تفکر در مورد پهناوری جهان هستی" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "تصحیح اطلاعات به وسیله‌ی آگاه‌کردن برنامه‌ها از اینکه در هفت دقیقه‌ی گذشته مشغول انجام کاری بوده‌ام. زمان‌های وابسته فقط برای فعالیت‌های در جریان بدون زمان انتهایی کار می‌کنند." #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "" #: C/index.page:6(title) #: C/index.page:7(title) #: C/index.page:17(title) msgid "Time Tracking" msgstr "پیگیری زمان" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "چگونگی تهیه پشتیبان از پایگاه داده‌ی فعالیت‌ها." #: C/backup.page:8(title) msgid "Backup" msgstr "پشتیبان" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "فعالیت‌ها بر روی یک پایگاه داده‌ی SQLite ذخیره شده‌اند، در مسیر ~/.local/share/hamster/hamster.db قابل دستیابی می‌باشد. از این طریق پرونده می‌تواند پشتیبان‌گیری و بازیابی شود. برنامه اطلاعات پس از مدت کوتاهی مجددا بار می‌کند." #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "برای مشاهده‌ی محتویات پایگاه داده ما پیشنهاد می‌کنیم از SQLite Manager برای موزیلا فایرفاکس استفاده کنید." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "علی‌اکبر نجفیان /nآرش موسوی " hamster-3.0.3/help/fr/000077500000000000000000000000001452646177100145345ustar00rootroot00000000000000hamster-3.0.3/help/fr/fr.po000066400000000000000000000424221452646177100155070ustar00rootroot00000000000000# French translation for hamster-time-tracker. # Copyright (C) 2010 Listed translators # This file is distributed under the same license as the hamster-time-tracker package. # # Florent Thévenet , 2010. # Claude Paroz , 2010. # Bruno Brouard , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-09-21 11:51+0000\n" "PO-Revision-Date: 2010-09-23 22:23+0200\n" "Last-Translator: Bruno Brouard \n" "Language-Team: GNOME french team \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" #: C/legal.xml:3(p) msgid "" "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported " "License." msgstr "" "Ce document est sous licence Creative Commons Paternité-Partage des " "Conditions Initiales à l'Identique 3.0 Unported." #: C/legal.xml:6(p) msgid "" "As a special exception, the copyright holders give you permission to copy, " "modify, and distribute the example code contained in this document under the " "terms of your choosing, without restriction." msgstr "" "À titre d'exception, les titulaires des droits d'auteur vous autorisent à " "copier, modifier et redistribuer le code d'exemple contenu dans ce document, " "selon la licence de votre choix, sans restrictions." #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Astuces pour bien gérer vos activités." #: C/tracking.page:10(title) msgid "How to track time" msgstr "La gestion du temps" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Les raisons pour lesquelles vous accumulez des données sur votre emploi du " "temps vont déterminer la manière d'effectuer le suivi de vos activités. Que " "voulez-vous faire avec les données ? Est-ce juste de la curiosité ou une " "nécessité professionnelle ? Quel niveau de détails vous intéresse dans les " "résultats ?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Granularité" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Un bon rythme est d'avoir 5 à 30 activités par jour." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Le but du gestionnaire de temps est d'éviter la micro-gestion " "afin que vous ne passiez pas plus de temps à gérer vos activités qu'à les " "pratiquer ! Cependant, des détails insuffisants peuvent provoquer un manque " "de données qui vous seraient utiles un mois plus tard." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Que dois-je écrire dans chaque champ ?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Pour des activités simples qui ne font pas partie d'un projet, utilisez " "l'action comme nom d'activité et la catégorie comme " "contexte plus large. Par exemple : déjeuner@travail." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Pour une gestion plus sophistiquée, essayez de décrire vos activités en un " "ou deux mots (« arbre maison », « projet x » ou quelque chose de similaire) et " "utilisez cette légende dans le champ activité. Utilisez la " "catégorie pour décrire l'activité dans un contexte plus " "large - est-ce privé, professionnel ou autre chose ? Enfin, utilisez les " "étiquettes pour décrire l'action précise - est-ce de la lecture " "ou de la création, de l'écriture ou du dessin." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Cette approche vous permet de voir combien de temps de lecture vous avez " "consacré dans tous vos projets (par étiquette), combien de temps consacré à " "vos passe-temps (par catégorie) et combien de temps à faire de l'analyse " "pour votre travail dans le projet x (par activité et étiquette)" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Astuces pour améliorer vos données de suivi" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Nommez les activités de façon à pouvoir les différencier facilement l'une de " "l'autre. Le nom de l'activité est également la seule information qui " "apparaît dans le tableau de bord. Êtes-vous capable de déterminer sur quoi " "vous travaillez rien qu'en voyant le nom de l'activité ?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Réduisez au minimum la liste des catégories (disons 3 à 7) et choisissez-les " "pour qu'elles varient le moins possible dans le temps. Elles devraient être " "génériques, comme par exemple : « travail », « privé », « divers »." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Utilisez le champ de description pour des informations brèves comme des " "numéros de référence. La recherche dans la fenêtre Résumé se fait " "également dans ce champ ; ainsi, pour rechercher des activités pour " "lesquelles vous avez inscrit un numéro de référence particulier, il suffit " "de le saisir dans le champ de recherche et d'appuyer sur Entrée." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Les activités et les étiquettes peuvent apparaître et disparaître selon les " "besoins. Une fois que vous pensez en avoir fini pour de bon avec une " "activité, supprimez-la afin qu'elle n'apparaissent plus dans les " "propositions d'auto-complétion. Ne vous inquiétez pas : les faits (activités " "journalisées) ne sont pas détruits. Il s'agit juste de la « liste " "opérationnelle »." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Note sur l'interprétation des statistiques." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statistiques" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Les résultats accessibles depuis le bouton Afficher " "les statistiques sont expérimentaux et sont une interprétation de la " "réalité. Cette interprétation doit être comparée avec vos propres " "observations. Toutes corrections sont les bienvenues." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Cependant, les « Débuts et fins » devraient vous donner une idée de votre " "temps d'activité." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Exploitation des données du gestionnaire de temps." #: C/reports.page:8(title) msgid "Report and export" msgstr "Rapports et exportations" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "À part le format HTML utilisé par défaut dans la boîte de dialogue " "d'enregistrement des rapports, la liste déroulante de formats vous permet de " "choisir parmi les formats TSV (Tab Separated Values, soit « Valeurs séparées " "par des tabulations », format bien adapté aux tableurs), XML et iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Pour les programmeurs, il existe une API D-Bus, qui peut être examinée en " "profondeur avec des outils comme D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "La façon la plus rapide pour extraire des données du gestionnaire de temps " "est de générer un rapport HTML. Tout en appuyant sur la touche Ctrl, sélectionnez toutes les cellules voulues, puis copiez et collez-les " "dans l'application cible." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Résolution automatique de conflits." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Découpage des activités" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Le gestionnaire de temps fait tout ce qu'il peut pour éviter des " "chevauchements dans les activités. Si vous créez une activité en plein " "milieu d'une activité existante, celle-ci sera coupée en deux. Dans les " "autres cas, les activités précédentes seront écourtées." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "La fusion peut devenir commode lors de la saisie d'informations pour toute " "la journée. Commencez par saisir la première activité et cochez la case « en " "cours » pour l'heure de fin. Faites de même pour l'activité suivante et vous " "constaterez que l'heure de fin de l'activité précédente s'ajuste à l'heure " "de début de l'activité suivante. Vous pouvez continuer ainsi pour toutes les " "activités de votre journée !" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Astuces pour accélérer la saisie d'une activité." #: C/input.page:8(title) msgid "Input" msgstr "Saisie" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Pour commencer le suivi, saisissez le nom de l'activité dans la zone de " "saisie puis appuyez sur la touche Entrée. Voici quelques astuces " "qui vous permettent de fournir davantage de détails au passage :" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Utilisez le symbole @ pour ajouter une catégorie" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "" "Tout ce qui vient après une virgule « , » est placé dans le champ description" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Pour indiquer l'heure tout en écrivant, saisissez-la en premier dans la zone " "de saisie" #: C/input.page:23(p) msgid "A few examples:" msgstr "Quelques exemples :" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 arrosage des fleurs" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "On a oublié de noter l'indispensable arrosage des fleurs avant le déjeuner." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "tomates@jardin, creusé des trous" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "On a besoin de plus de tomates dans le jardin. Que l'on creuse des trous est " "juste une information, donc on l'ajoute comme description." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existentialisme, réflexion sur l'infinie grandeur de l'univers" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Correction d'information en indiquant à l'application que j'ai fait quelque " "chose d'autre pendant les 7 dernières minutes. La saisie de temps relatif ne " "fonctionne que pour les activités en cours, sans heure de fin." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "De plus, vous pouvez ajoutez des étiquettes dans le champ de saisie des " "étiquettes. Les étiquettes sont séparées par des virgules. Le gestionnaire " "de temps vous propose une liste d'étiquettes correspondant à votre saisie, " "appuyez sur la touche Tab pour finir la saisie de l'étiquette " "selon la première étiquette correspondante affichée." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Gestion du temps" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Partage des Conditions Initiales à l'Identique 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Sauvegarde de la base de données des activités." #: C/backup.page:8(title) msgid "Backup" msgstr "Sauvegarde" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Les activités sont stockées dans une base de données SQLite, dans le fichier " "~/.local/share/hamster/hamster.db. Ce fichier peut être " "sauvegardé et restauré à n'importe quel moment. L'application recharge " "automatiquement les données après un court instant." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Pour explorer le contenu de la base de données, vous pouvez utiliser le " "Gestionnaire SQLite pour Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "Florent Thévenet , 2010\n" "Claude Paroz , 2010\n" "Bruno Brouard , 2010" hamster-3.0.3/help/gl/000077500000000000000000000000001452646177100145275ustar00rootroot00000000000000hamster-3.0.3/help/gl/gl.po000066400000000000000000000411371452646177100154770ustar00rootroot00000000000000# Galician translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Fran Diéguez , 2010. # Fran Dieguez , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-08-17 09:22+0000\n" "PO-Revision-Date: 2010-08-24 21:56+0200\n" "Last-Translator: Fran Dieguez \n" "Language-Team: Galician \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" #: C/legal.xml:3(p) msgid "" "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported " "License." msgstr "" "Este traballo ten a licenza Creative Commons Atribución Compartir igual 3.0 de Estado " "Unidos." #: C/legal.xml:6(p) msgid "" "As a special exception, the copyright holders give you permission to copy, " "modify, and distribute the example code contained in this document under the " "terms of your choosing, without restriction." msgstr "" "Unha excepción especial, os mantedores do copyright danlle permiso para " "copiar, modificar e distribuír o código de exemplo contido neste documento " "baixo os termos da súa elección sen restricións." #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Suxestións sobre como xestionar as súas actividades con efectividade." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Como xestionar o tempo" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Os seus hábitos de xestión de tempo deberán depender da razón pola que " "recolecta os datos. Que quere facer con eles? É simple curiosidade ou unha " "necesidade de traballo? E en que detalle lle interesa os resultados?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Granularidade" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Unha pauta suxerida é ter entre 5 e 30 actividades ao día." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "A intención do Xestor de tempo é evitar os microseguimentos de " "tal forma que o usuario non gaste máis tempo no seguimento que nas " "actividades en si. Pero non seguir con suficiente detalle podería acabar con " "información insuficiente un mes despois." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Que debería escribir en cada caixa?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Para actividades sinxelas que non teñen un proxecto use a acción como o nome " "da actividade e a categoría para un contexto máis " "amplo. Exemplo: comer@traballo." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Para un seguimento máis sofisticado tente resumir a súa actividade en unha " "ou dúas palabras («árbore da casa», «proxecto x», ou similar) e use ese resumo " "no campo actividade. Use a categoría para describir a " "actividade no seu contexto máis amplo. ¿é un traballo privado ou outra " "cousa? Finalmente use as etiquetas para describir a acción " "actual; xa sexa lendo, construíndo ou pintando." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Esta aproximación permitiralle ver canta lectura realizou para todos os seus " "proxectos (por etiqueta), canto tempo empregou nos seus hobbies (por " "categoría) e canto tempo adicou ao proxecto x que estivo analizando (por " "actividade e etiqueta)." #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Suxestións para mellorar o seguimento dos seus datos" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Nome das actividades para que se poidan distinguir facilmente entre elas. O " "nome da actividade é tamén o único que aparece no panel. ¿Será capaz de " "determinar en que está traballando simplemente mirando o nome da súa " "actividade?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Manteña o seu número de categorías baixo (entre 3 e 7) e elixa unhas que " "probabelmente non cambien ao longo do tempo. Tamén, mantéñaas xenéricas. Por " "exemplo: «traballo», «privado», «varios»." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Use o campo de descrición para información a curto prazo, como números de " "erros. A busca na xanela de vista xeral tamén busca no campo de descrición, " "de tal forma que buscar actividades onde menciona o erro ou chave " "específica, é tan sinxelo como escribilo na caixa de busca e premer " "Intro." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "As actividades e etiquetas poden aparecer e desaparecer segundo as " "necesidades. Unha vez que crea que rematou unha actividade; quítea para que " "non apareza no autocompletado. Non se preocupe, os feitos (actividades no " "rexistro) quedarán intactos. É simplemente a «lista operacional»." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Nota da interpretación das estatísticas." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Estatísticas" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Os resultados están accesíbeis mediante a ligazón Mostrar as estatísticas son experimentais e son interpretacións dos " "feitos. Esta interpretación debería ser comparada coas súas observacións. Os " "parches son benvidos." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Sen embargo, os \"Inicios e finais\" deberían darlle unha idea sobre o tempo " "activo." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Sacar os datos do Seguidor de tempo." #: C/reports.page:8(title) msgid "Report and export" msgstr "Informar e exportar" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Ademáis do formato HTML que é ofrecido de forma predefinida no diálogo de " "Gardar informe, o despregábel de formato permítelle seleccionar o formato " "TSV (Valores separados por tabulacións, bo para follas de cálculo), XML e " "iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Para un acceso programático existe unha API de D-Bus da que se pode facer " "introspección usando ferramentas como D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "A forma máis rápida de «sacar» datos do Xestor de tempo é xerando un informe " "HTML, mentres mantén premida a tecla Ctrl, seleccione todas as " "celas necesarias e despois cópieas e pégueas no aplicativo de destino." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Resolución automática de conflitos" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Partir actividades" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "O Xestor de tempo fai o mellor que pode para evitar solapamentos " "entre actividades. Se crea unha actividade no medio dunha actividade " "existente, a anterior partirase en dous. Noutros casos de solapamento " "encolleranse as entradas anteriores." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Mesturar o aspecto pode ser útil ao introducir información para todo o día. " "Comence introducindo a primeira actividade do día e estabeleza o tempo en «en " "progreso». Para a seguinte actividade, de novo, estabeleza a hora de inicio " "e márquea como en progreso. Observe como a hora de finalización da " "actividade anterior axústase á hora de inicio da nova actividade." #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Trucos para acelerar a entrada de actividades" #: C/input.page:8(title) msgid "Input" msgstr "Entrada" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Para iniciar un seguimento, escriba o nome da actividade na caixa de entrada " "e prema Intro. Porén, existen uns poucos trucos que lle " "permitirán especificar máis detalles ao voo:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Use o símbolo @ para engadir unha categoría" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Todo despois dunha coma (,) almacenaranse no campo de descrición" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Para especificar unha hora ao voo, insírea primeiro na caixa de entrada" #: C/input.page:23(p) msgid "A few examples:" msgstr "Uns poucos exemplos:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 regar plantas" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Esqueceuse do importante acto de regar as plantas despois da comida." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "tomates@xardin, cavar buratos" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Necesitas máis tomates no xardín. Cavar buratos é puramente informativo, " "polo que engádeo como unha descrición." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existencialimo, pensando sobre a grandeza do universo" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Información corrixida informando ao aplicativo que se estivo ocupando noutro " "asunto durante os últimos sete minutos. Os tempos relativos só funcionan cos " "tempos de finalización, isto é, para a actividade máis recente." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Sobre ilo pode engadir etiquetas no campo de entrada de etiquetas. As " "etiquetas están delimitadas por comas. Premer Tabulación cando " "apareza a caixa de suxestións completará a entrada coa primeira etiqueta " "coincidente." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Time Tracking" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Compartir igual 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Como facer unha copia de seguridade da base de datos da actividade." #: C/backup.page:8(title) msgid "Backup" msgstr "Copia de seguridade" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "As actividades almacénanse nunha base de datos SQLite, almacenada en " "~/.local/share/hamster/hamster.db. Pode facer unha copia " "de seguridade do ficheiro e restáureo cando queira. O aplicativo recargará " "os datos automáticamente despois dun pequeno tempo." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Para ver os contidos da base de datos podemos suxerirlle o uso de SQLite Manager para Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Fran Diéguez , 2010;" #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "Logo de seguemento de tempoSeguemento de texto" hamster-3.0.3/help/hu/000077500000000000000000000000001452646177100145415ustar00rootroot00000000000000hamster-3.0.3/help/hu/hu.po000066400000000000000000000407271452646177100155270ustar00rootroot00000000000000# Hungarian translation of hamster-time-tracker help # Gabor Kelemen , 2010. # Copyright (C) 2010. Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker-help master\n" "POT-Creation-Date: 2010-10-05 20:52+0000\n" "PO-Revision-Date: 2010-10-06 04:04+0200\n" "Last-Translator: Gabor Kelemen \n" "Language-Team: Hungarian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Tippek tevékenységeinek hatékony nyilvántartásához." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Hogyan tartsa nyilván idejét" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Időnyilvántartási szokásait az adatgyűjtés oka diktálja. Mit szeretne tenni " "az adatokkal? Egyszerűen csak kíváncsi, vagy munkája megköveteli? Milyen " "részletességben kíváncsi az eredményekre?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Részletesség" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "A javasolt sebesség napi 5 és 30 közötti tevékenység naponta." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Az Időnyilvántartó célja a mikronyilvántartás elkerülése, nehogy " "több időt töltsön a nyilvántartással, mint a tényleges tevékenységekkel. " "Azonban a nem elég részletes nyilvántartás azt is eredményezheti, hogy egy " "hónap múlva már nem lesznek értelmezhetők az adatok." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Mit írjak az egyes mezőkbe?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Egyszerű tevékenységekhez, amelyek nem egy projekt részei, használja a " "tevékenység nevét, és bővebb kontextushoz a kategóriát. Például: ebéd@munka." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "A részletesebb nyilvántartás érdekében próbálja meg tevékenységeit egy vagy " "két szóban összefoglalni („kutyaház-barkácsolás”, „X projekt”, vagy " "ilyesmi), és használja ezt az összefoglalót a tevékenység mezőben " "a tevékenység szélesebb kontextusban való leírásához – magánjellegű vagy " "munkahelyi, vagy valami más? Végül címkék használatával írja le a " "tényleges tevékenységet – olvasás vagy építés, írás vagy festés." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Ez a megközelítés lehetővé teszi, hogy mennyit töltött olvasással az összes " "projektjében (címke szerint), mennyi időt töltött hobbijaival (kategória " "szerint), és az X projekten a munkával töltött időből mennyit töltött " "elemzéssel (tevékenység és címke szerint)." #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Tippek a nyilvántartási adatok javításához" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Tevékenységeit nevezze el, hogy egyszerűen megkülönböztethesse azokat " "egymástól. A tevékenység neve az egyetlen információ, ami a panelen " "megjelenik. Meg fogja tudni határozni, hogy min dolgozik, ha csak a " "tevékenység nevét látja?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "A kategóriák listáját fogja rövidre (3-7 elem), és válasszon várhatóan " "később sem változó és általános neveket. Például: „munka”, „személyes”, " "„egyéb”." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "A leírás mezőt rövid távú információkhoz, például referenciaszámokhoz " "használhatja. Az Áttekintés ablakban történő keresés a leírás " "mezőben is keres, így az adott referenciaszámot tartalmazó tevékenységek " "megkeresése a keresés mezőbe gépeléssel, és az Enter " "megnyomásával egyszerűen elvégezhető." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "A tevékenységek és címkék igény szerint változhatnak. Ha úgy gondolja, hogy " "egy tevékenységgel kész van, távolítsa el azt, így nem jelenik meg többé az " "automatikus kiegészítésben. Ne aggódjon: a tények (a naplóban lévő " "tevékenységek) nem kerülnek törlésre. Ez csak a „műveleti lista”." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "A statisztika értelmezése." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statisztika" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "A Statisztika megjelenítése hivatkozáson " "keresztül elérhető eredmények kísérletiek, és a tények értelmezését " "képviselik. Ezt az értelmezést vesse össze megfigyeléseivel. A programhoz " "küldött javításokat nagyra értékeljük!" #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Azonban a „Kezdet és vég” nagyjából pontosan összefoglalja az aktívan " "töltött idejét." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Adatok kinyerése az Időnyilvántartóból." #: C/reports.page:8(title) msgid "Report and export" msgstr "Jelentés és exportálás" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "A Jelentés mentése ablakban alapértelmezésben felajánlott HTML formátumon " "kívül a formátum legördülő lista lehetővé teszi a TSV (Tab-határolt értékek, " "táblázatkezelőhöz), XML és iCal formátumok kiválasztását is." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Programokból való eléréshez használható a D-Bus API, amely a D-Feethez hasonló eszközökkel " "figyelhető." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Az Időnyilvántartóból a leggyorsabban HTML jelentés készítésével nyerheti ki " "az adatokat. A Ctrl billentyű lenyomása közben jelölje ki a " "szükséges cellákat, majd másolja és illessze be azokat a célalkalmazásba." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Automatikus ütközésfeloldás." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Tevékenységek elválasztása" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Az Időnyilvántartó mindent megtesz a tevékenységek közti " "átfedések elkerüléséhez. Ha egy meglévő tevékenység közepén hoz létre új " "tevékenységet, akkor az előbbi ketté lesz vágva. Más esetekben a korábbi " "bejegyzések le lesznek rövidítve." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Az egyesítés az egész napra vonatkozó információk bevitelekor jön jól. " "Kezdje el bevinni az első tevékenységet, és válassza ki a „folyamatban” " "jelölőnégyzetet befejezési időként. A következő tevékenységhez ismét csak a " "kezdési időt adja meg, és jelölje folyamatban lévőként. Figyelje meg, hogy " "az előző tevékenység befejezési ideje hogyan változik az új kezdési idejére." #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Trükkök a tevékenységek bevitelének felgyorsítására." #: C/input.page:8(title) msgid "Input" msgstr "Adatbevitel" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "A követés megkezdéséhez írja be a tevékenység nevét a beviteli mezőbe, és " "nyomja meg az Enter billentyűt. Néhány egyszerű trükk " "segítségével több részletet adhat meg menet közben:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Kategória hozzáadásához használja a @ szimbólumot" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "A vesszőt (,) követően minden a leírás mezőbe kerül" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "Az idő megadásához elsőként adja meg azt a beviteli mezőben" #: C/input.page:23(p) msgid "A few examples:" msgstr "Néhány példa:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 virágok meglocsolása" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "Elfelejtettem felírni a virágok halaszthatatlan meglocsolását ebéd után." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "paradicsomok@kert, lyukak ásása" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Több paradicsom kell a kertbe. A lyukak ásása csak információs célt szolgál, " "így leírásként van megadva." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 lételmélet, gondolkodás az univerzum végtelenségéről" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Az információk javítása az alkalmazás értesítésével arról, hogy valami mást " "csinált az utolsó hét percben. A relatív idők csak folyamatban lévő, " "befejezési idő nélküli tevékenységekkel működnek." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Ezen kívül megadhat címkéket is a címke bemeneti mezőben. A címkéket vessző " "választja el. Nyomja meg a Tab billentyűt a javaslatdoboz " "megjelenésekor az adatbevitel kiegészítéséhez az első illeszkedő címkére." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Időnyilvántartás" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Hogyan mentse a tevékenység-adatbázist." #: C/backup.page:8(title) msgid "Backup" msgstr "Biztonsági mentés" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "A tevékenységek egy SQLite adatbázisban találhatók a ~/.local/share/" "hamster/hamster.db helyen. A fájl menet közben menthető és " "helyreállítható. Az alkalmazás egy rövid idő elteltével automatikusan " "újratölti az adatokat." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Az adatbázis tartalmának megjelenítéséhez a Mozilla Firefoxhoz készült SQLite " "Managert javasoljuk." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Kelemen Gábor " #~ msgid "" #~ "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgstr "" #~ "Ez a mű a Creative Commons Attribution-Share Alike 3.0 Unported License " #~ "alá esik." #~ msgid "" #~ "As a special exception, the copyright holders give you permission to " #~ "copy, modify, and distribute the example code contained in this document " #~ "under the terms of your choosing, without restriction." #~ msgstr "" #~ "Speciális kivételként a szerzői jog tulajdonosai engedélyezik a " #~ "dokumentum által tartalmazott példakód másolását, módosítását és " #~ "terjesztését az Ön által választott feltételek szerint, korlátozások " #~ "nélkül." hamster-3.0.3/help/pl/000077500000000000000000000000001452646177100145405ustar00rootroot00000000000000hamster-3.0.3/help/pl/pl.po000066400000000000000000000320421452646177100155140ustar00rootroot00000000000000# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # Aviary.pl # Jeśli masz jakiekolwiek uwagi odnoszące się do tłumaczenia lub chcesz # pomóc w jego rozwijaniu i pielęgnowaniu, napisz do nas: # gnomepl@aviary.pl # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "POT-Creation-Date: 2011-10-28 11:49+0000\n" "PO-Revision-Date: 2010-06-01 23:33+0100\n" "Last-Translator: Łukasz Jernaś \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" "X-Poedit-Language: Polish\n" "X-Poedit-Country: Poland\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "" #: C/tracking.page:10(title) msgid "How to track time" msgstr "" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" #: C/tracking.page:20(title) msgid "Granularity" msgstr "" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "" #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Informacje dotyczące interpretacji statystyk." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statystyki" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Wyniki dostępne po naciśnięciu przycisku Wyświetl " "statystyki są eksperymentalne i stanowią interpretację faktów. " "Interpretacja ta powinna zostać porównana z własnymi obserwacjami. Poprawki " "do tego algorytmu są mile widziane." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Jednakże sekcja „Rozpoczęcia i zakończenia” daje dobry pogląd na sposób " "wykorzystywanego czasu." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Pozyskiwanie danych z programu Zarządzanie czasem." #: C/reports.page:8(title) msgid "Report and export" msgstr "Raportowanie i eksportowanie" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Oprócz formatu HTML, który jest dostępny domyślnie w oknie dialogowym " "„Zapisz sprawozdanie”, dostępne są również formaty TSV (wartości oddzielone " "znakiem tabulatora, dobry dla arkuszy kalkulacyjnych), XML oraz iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Dostęp programowy możliwy jest za pomocą interfejsu D-Bus, które można " "podejrzeć za pomocą narzędzi takich jak D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Najszybszych sposobem na pozyskanie danych z programu Zarządzanie czasem " "jest utworzenie raportu w formacie HTML. Następnie, przytrzymując klawisz " "Ctrl, należy zaznaczyć wszystkie potrzebne komórki i skopiować je " "do docelowego programu." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Automatyczne rozwiązywanie konfliktów." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Rozdzielanie czynności" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "W programie Zarządzanie czasem zaimplementowanoa algorytm " "unikania nakładających się czynności. W momencie tworzenia nowej czynności w " "trakcie trwania innej, poprzednia czynność zostanie podzielona na dwie. W " "innych przypadkach czas trwania czynności zostanie skrócony." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Scalanie może okazać się przydatne podczas wprowadzania informacji za cały " "dzień. Należy rozpocząć od wprowadzenia pierwszej czynności i zaznaczenia " "pola wyboru „w trakcie”. Dla następnej czynności należy ustawić czas " "rozpoczęcia i znów zaznaczyć pole wyboru „w trakcie”. W tym przypadku czas " "zakończenia poprzedniej czynności zostanie dostosowany do czasu rozpoczęcia " "bieżącej czynności. Proces ten można powtarzać, aż do uzyskania zamierzonego " "efektu." #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Sztuczki przyspieszające wprowadzanie czynności." #: C/input.page:8(title) msgid "Input" msgstr "Śledzenie" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "W celu rozpoczęcia śledzenia, należy wprowadzić nazwę czynności w pole " "tekstowe i nacisnąć klawisz Enter. Istnieje jednak kilka " "sztuczek, pozwalających na podanie większej ilości szczegółów:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Wykorzystanie znaku @ do dodawania kategorii." #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Treść znajdująca się po przecinku (,) zostanie zapisana jako opis." #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Aby podać czas, należy wprowadzić go na pierwszym miejscu w polu tekstowym." #: C/input.page:23(p) msgid "A few examples:" msgstr "Kilka przykładów:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "14:30-14:45 podlewanie kwiatów" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Zapomniano o podlaniu kwiatów podczas przerwy obiadowej." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "pomidory@ogród, kopanie dołków" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Potrzeba więcej pomidorów w ogrodzie. Kopanie dołków jest tylko czynnością " "poboczną, więc podano jako opis." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 egzystencjalizm, rozmyślanie nad ogromem wszechświata" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Poprawiono informacje poprzez wprowadzenie danych o czynnościach dokonanych " "przez ostatnie siedem minut. Czasy względne działają poprawnie tylko dla " "czynności bez określonego czasu zakończenia." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Ponadto można wprowadzić etykiety w polu tekstowym o nazwie „Etykiety”. Do " "ich rozdzielania należy skorzystać z przecinka. Naciśnięcie klawisza " "Tab w momencie pojawienia się okienka podpowiedzi spowoduje " "uzupełnienia etykiety o pierwszą zaznaczoną pozycję." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Zarządzanie czasem" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Uznanie autorstwa 3.0 Polska" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Jak utworzyć kopię zapasową bazy czynności." #: C/backup.page:8(title) msgid "Backup" msgstr "Kopia zapasowa" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Czynności są zapisywanie w bazie danych SQLite, znajdującej się w pliku " "~/.local/share/hamster/hamster.db. Plik ten może zostać " "skopiowany i przywrócony w trakcie pracy programu, zostanie on automatycznie " "wczytany." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Do przeglądania zawartości bazy czynności polecamy rozszerzenie SQLite Manager dla przeglądarki Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "Aviary.pl , 2010\n" "Łukasz Jernaś , 2010" hamster-3.0.3/help/pt_BR/000077500000000000000000000000001452646177100151335ustar00rootroot00000000000000hamster-3.0.3/help/pt_BR/pt_BR.po000066400000000000000000000400231452646177100165000ustar00rootroot00000000000000# Brazilian Portuguese translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Isis Binder , 2010. # Enrico Nicoletto , 2011. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2011-04-01 23:37+0000\n" "PO-Revision-Date: 2011-04-02 17:44-0300\n" "Last-Translator: Enrico Nicoletto \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pt_BR\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Virtaal 0.6.1\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Dicas de como registrar suas atividades efetivamente." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Como registrar o tempo" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Seus hábitos de gerencimento de tempo serão ditados pelo motivo de você " "estar colhendo os dados. Isto é, o que você quer fazer com os dados? É uma " "simples curiosidade, ou um requerimento de trabalho? E você está interessado " "nos resultados em qual nível de detalhamento?" # Granularidade tem a ver com o nível de detalhamento do comportamento de um objeto que é exposto. Quão mais bem detalhado é o comportamento do seu objeto é exposto, mais fina é sua granularidade. # Fonte: http://www.guj.com.br/java/41464-granularidade #: C/tracking.page:20(title) msgid "Granularity" msgstr "Granularidade" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Um ritmo sugerido é ter de 5 a 30 atividades por dia." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "A intenção do Gerenciador de tempo é evitar micro-registros de " "modo que não acabe gastando mais tempo ao registrar do que ao realizar as " "atividades em si! Entretanto, registrar com detalhamento insuficiente pode " "resultar em não existir nenhum dado útil para você um mês depois." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "O que eu deveria escrever em cada caixa?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Para atividades simples que não possuam um projeto, use a ação como nome da " "atividade e a categoria para um contexto mais amplo. " "Por exemplo: almoço@trabalho." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Para um registro mais sofisticado tente resumir sua atividade em uma ou duas " "palavras (\"casa na árvore\", \"projeto x\", ou similar) e use este resumo " "no campo atividade. Use o campo categoria para " "descrever a atividade em seu contexto mais amplo - isto é pessoal, de " "trabalho ou algo mais? Finalmente use etiquetas para descrever " "sua ação atual - está lendo ou construindo, escrevendo ou pintando." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Esta abordagem lhe permitirá ver quantas leituras você fez em todos os seus " "projetos (por etiqueta), quanto tempo você gastou em seu hobbies (por " "categoria) e quanto tempo de todo o seu trabalho no projeto x você gastou " "analisando (por atividade e etiqueta) " #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Dicas para melhorar seus dados de registro" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Dê nome a atividades de modo que possam ser facilmente distinguidas uma das " "outras. O nome da atividade é também a única informação que aparece no " "painel. Você será capaz de determinar no que você está trabalhando apenas " "olhando o nome da atividade?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Mantenha a sua lista de categorias pequena (digamos, de 3 a 7) e escolha " "aquelas que não costumam mudar com o tempo. Ainda mais, torne-as genéricas. " "Por exemplo: \"trabalho\", \"pessoal\", \"diversos\"." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Use o campo de descrição para informações de curto prazo como referência a " "um número. A pesquisa na janela Visão geral também examina o " "campo de descrição, então encontrar atividades aonde você mencionou o número " "de referência específico será tão fácil quanto digitar na caixa de busca e " "pressionar Enter." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Atividades e etiquetas podem ir e vir conforme necessário. Uma vez que você " "ache que terminou uma atividade, será melhor removê-la para que ela não " "apareça no completado automaticamente nunca mais. Não se preocupe: os " "acontecimentos (atividades no registro) não serão excluídos. Isto é apenas a " "\"lista operacional\"." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Observação sobre a interpretação das estatísticas." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Estatísticas" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Os resultados acessíveis através do link Exibir " "estatísticas são experimentais e são uma interpretação dos fatos. Essa " "interpretação deve ser comparada com as suas próprias observações. Correções " "são bem-vindas." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Porém, os \"Inícios e finais\" devem lhe fornecer alguma idéia sobre o seu " "tempo ativo." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Extrair dados do Gerenciador de tempo." #: C/reports.page:8(title) msgid "Report and export" msgstr "Relatar e exportar" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "Além do formato HTML, oferecido por padrão na janela de diálogo Salvar " "relatório, a lista suspensa de formatos permite que você escolha entre os " "formatos TSV (Valores separados por tabulações, bom para planilhas), XML e " "iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Para acesso programado, existe a API D-BUS, cujas informações podem ser " "extraídas usando ferramentas como D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "O modo mais rápido de se extrair dados do Gerenciador de Tempo é gerar um " "relatório HTML. Enquanto pressiona a tecla Ctrl, selecione todas " "as células necessárias, e então copie-as e cole-as no aplicativo de destino." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Resolução automática de conflito." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Dividindo atividades" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "O Gerenciador de tempo faz o seu melhor para evitar sobreposições " "de atividades. Se você criar uma atividade em meio a uma outra atividade " "existente, esta será dividida em duas. Em outros casos de sobreposição, as " "entradas anteriores serão encolhidas." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "O recurso de combinação é útil ao fornecer informações para o dia inteiro. " "Inicie digitando a primeira atividade e selecione a caixa de seleção \"em " "progresso\" para o horário de finalização. Para a próxima atividade, " "configure novamente somente o horário de início e marque-a como em execução. " "Observe como o tempo de finalização da tarefa anterior é ajustado ao horário " "de início da nova tarefa. Repita o processo até ficar feliz!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Truques para agilizar a digitação de uma atividade." #: C/input.page:8(title) msgid "Input" msgstr "Entrada" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Para iniciar o registro, digite o nome da atividade na caixa de entrada e " "pressione a tecla Enter. Existem alguns truques que podem lhe " "permitir especificar mais detalhes rapidamente:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Use o símbolo @ para adicionar uma categoria" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Tudo depois de uma vírgula (,) será armazenado no campo de descrição" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Para especificar horários rapidamente, digite-o primeiro na caixa de entrada" #: C/input.page:23(p) msgid "A few examples:" msgstr "Alguns exemplos:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 regar as flores" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Esqueci que é mais importante regar as flores que almoçar." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "tomates@jardim, cavando buracos" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "É necessário ter mais tomates no jardim. Cavar buracos é apenas uma " "informação, então adicionei-o como uma descrição." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existencialismo, pensando sobre a imensidão do universo" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Informações foram corrigidas informando o aplicativo que eu estive fazendo " "outra coisa nos último sete minutos. Horários relativos funcionam somente " "com atividades em execução sem um horário final." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Ainda, você pode adicionar etiquetas no campo de entrada de etiquetas. " "Etiquetas são delimitadas por uma vírgula. Pressione a tecla Tab " "quando a caixa de sugestão aparecer para completar a entrada com a primeira " "etiqueta correspondente." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Gerenciador de tempo" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Como realizar o backup do banco de dados de atividades." #: C/backup.page:8(title) msgid "Backup" msgstr "Backup" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "As atividades são armazenadas em um banco de dados SQLite, localizado em " "~/.local/share/hamster/hamster.db. O arquivo pode ser " "salvo em um backup e restaurado quando necessário. A aplicação irá " "recarregar os dados automaticamente após um curto intervalo de tempo." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Para visualizar o conteúdo do banco de dados, nós podemos sugerir o uso do " "SQLite Manager para o Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "Ísis Binder , 2010\n" "Enrico Nicoletto , 2011." hamster-3.0.3/help/ro/000077500000000000000000000000001452646177100145455ustar00rootroot00000000000000hamster-3.0.3/help/ro/ro.po000066400000000000000000000405131452646177100155300ustar00rootroot00000000000000# Romanian translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Tabita Dolean , 2010. # Lucian Adrian Grijincu , 2010. msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: " "http://bugzilla.gnome.org/enter_bug.cgi?product=tasque&component=general\n" "POT-Creation-Date: 2010-12-05 11:27+0000\n" "PO-Revision-Date: 2010-12-08 01:06+0300\n" "Last-Translator: Lucian Adrian Grijincu \n" "Language-Team: Romanian Gnome Team \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2);;\n" "X-Generator: Virtaal 0.6.1\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "" "Sfaturi despre cum să pontați activitățile dumneavoastră într-un mod " "eficient." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Cum să țineți evidența timpului" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "Obiceiurile dumneavoastră de pontaj vor fi dictate de motivul pentru care " "adunați informațiile. Ce doriți să faceți cu informațiile? Este o simplă " "curiozitate sau o cerință de serviciu? Și la ce nivel de detaliu sunteți " "interesat de rezultate?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Granularitate" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Un ritm sugerat este de avea 5-30 activități pe zi." #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "Scopul programului Pontaj activități este de a evita micro-" "pontajul astfel încât nu se va întâmpla să consumați mai mult timp pentru " "pontaj în loc să vă faceți treaba! Cu toate acestea, o granularitate prea " "mare ar putea face ca datele să nu vă mai fie utile o lună mai târziu." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Ce ar trebui să scriu în fiecare căsuță?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "Pentru activități simple care nu au un proiect, utilizați acțiunea ca numele " "activității și categoria pentru contextul mai larg. " "De exemplu: prânz@muncă." #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "Pentru un pontaj mai sofisticat încercați să dați un titlu activității " "dumneavoastră prin unul sau mai multe cuvinte („casă în copac”, „proiectul " "x”, sau asemănător) și folosiți titlul în câmpul activitate. " "Utilizați categorie pentru a descrie activitatea în contextul ei " "mai larg - este personal sau pentru muncă, sau altceva? În cele din urmă, " "folosiți etichete pentru a descrie acțiunea dumneavoastră curentă " "- citiți, construiți, scrieți sau pictați." #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "Această metodă vă va permite să vedeți cât de mult ați citit prin toate " "proiectele dumneavoastră (prin etichetă), cât de mult timp v-ați petrecut " "pentru hobbyurile dumneavoastră (prin categorie), cât de mult timp din " "toată munca în cadrul proiectului x ați petrecut-o analizând (prin " "activitate și etichetă)" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Sfaturi pentru îmbunătățirea informațiilor de pontaj" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "Numiți activitățile astfel încât acestea să poată fi ușor diferențiate unele " "de altele. Numele activității este de asemenea singura informație ce apare " "în panou. Veți fi capabil să determinați la ce lucrați doar uitându-vă la " "numele activității?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "Păstrați lista de categorii mici (să zicem, 3-7) și alegeți-le pe acelea " "care sunt puțin probabil să se schimbe în timp. De asemenea, păstrați-le " "generice. De exemplu: „muncă”, „personal”, „diverse”." #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "Utilizați câmpul descriere pentru informații pe termen scurt cum ar fi " "numere de referință. Căutarea în fereastra Privire de ansamblu " "caută de asemenea și în câmpul de descriere, astfel încât căutarea " "activităților unde menționați numărul de referință specific, vor fi atât de " "simple ca tastarea lui în caseta de căutare și apăsând tasta " "Enter." #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "Activitățile și etichetele pot veni și pleca cum este necesar. După ce " "credeți că ați terminat cu o activitate de-a binele, eliminați-o ca să nu " "apară în auto-completare deloc. Nu vă faceți griji: acțiunile (activitățile " "din istoric) nu vor fi șterse. Aceasta este doar „lista cu operații”." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Notă privind interpretarea statisticilor." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statistici" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "Rezultatele care sunt accesibile prin intermediul legăturii Arată statisticile sunt experimentale și sunt o " "interpretare a acțiunilor. Această interpretare ar trebui să fie comparată " "cu observațiile dumneavoastră." #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" "Cu toate acestea, „Începutul și sfârșitul” ar trebui să vă facă o idee cu " "privire la timpul dumneavoastră activ." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Obține date din Pontaj activități." #: C/reports.page:8(title) msgid "Report and export" msgstr "Raportare și exportare" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "În afară de formatul HTML care este în mod implicit oferit în fereastra " "Salvează raport, lista de selecție vă permite sa alegeți TSV (Valori " "separate prin tab, bun pentru foi de calcul tabelar), XML și formate iCal." #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "Pentru accesul programatic, există API-ul D-Bus, care poate fi analizat " "utilizând instrumente cum ar fi D-Feet." #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "Cea mai rapidă modalitate de a obține date în afara Pontajului de activități " "este prin generarea unui raport HTML. În timp ce țineți apăsat tasta " "Ctrl, selectați toate celulele necesare, și apoi copiați-le și " "lipiți-le în aplicația destinație." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Rezolvarea automată a conflictelor." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Divizarea activităților." #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "Pontaj activități face tot posibilul pentru a evita suprapunerile " "de activități. Dacă veți crea o activitate în mijlocul unei activități " "existente, fosta activitate va fi împărțită în două. În aceste cazuri de " "suprapunere, intrările anterioare vor fi micșorate." #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "Fuzionarea poate fi la îndemână atunci când introduceți informații pentru o " "zi întreagă. Începeți prin introducerea primei activități și selectați " "caseta „în curs” pentru timpul de finalizare. Pentru următoarea activitate " "din nou selectați doar ora de începere și marcați-o ca fiind în desfășurare. " "Observați modul în care timpul de încheiere a activității anterioare s-a " "ajustat la ora de începere a uneia noi. Repetați procesul până când sunteți " "fericit!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Trucuri pentru a accelera introducerea activităților." #: C/input.page:8(title) msgid "Input" msgstr "Intrare" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "Pentru a începe pontajul, tastați numele activității în caseta de intrare și " "apăsați tasta Enter. Există câteva trucuri care vă permit să " "specificați mai multe detalii în timpul rulării:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Utilizați simbolul @ pentru a adăuga o categorie" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Totul după o virgulă (,) va fi stocat în câmpul de descriere" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" "Pentru a specifica timpul în timpul rulării, introduceți-l mai întâi în " "căsuța de intrare" #: C/input.page:23(p) msgid "A few examples:" msgstr "Câteva exemple:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 udat flori" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" "Am uitat să notez actul important de udare al florilor după masa de prânz." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "roșii@grădină, săpat gropi" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" "Am nevoie de roșii mai multe în grădină. Săparea de gropi este pur " "informațional, așa că adăugați-o ca descriere." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 existențialism, cu gândul la imensitatea universului" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "Am corectat informațiile prin informarea aplicației că am făcut altceva în " "ultimele șapte minute. Timpul relativ funcționează doar pentru activitățile " "fără timp de terminare." #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "Pe partea de sus puteți să adăugați etichete în câmpul de introducere de " "etichete. Etichetele sunt delimitate printr-o virgulă. Apăsați Tab când apare caseta de sugestii pentru a finaliza introducerea primei " "etichete care se potrivește." #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "Pontaj activități" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Distribuire în condiții identice 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Cum să faceți copie de siguranță bazei de date cu activități" #: C/backup.page:8(title) msgid "Backup" msgstr "Copie de siguranță" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "Activitățile sunt stocate într-o bază de date SQLite, situată la ~/." "local/share/hamster/hamster.db. Puteți crea copie de siguranță " "și să îl restaurați în timpul rulării. Aplicația va reîncărca informațiile " "automat după un timp scurt." #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "Pentru a vedea conținutul bazei de date vă putem sugera să utilizați SQLite " "Manager pentru Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Tabita Dolean , 2010" hamster-3.0.3/help/ru/000077500000000000000000000000001452646177100145535ustar00rootroot00000000000000hamster-3.0.3/help/ru/ru.po000066400000000000000000000356361452646177100155560ustar00rootroot00000000000000# Russian translation for hamster-time-tracker. # Copyright (C) 2011 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Yuri Myasoedov , 2011. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2011-11-12 07:51+0000\n" "PO-Revision-Date: 2011-11-15 12:24+0300\n" "Last-Translator: Yuri Myasoedov \n" "Language-Team: Russian \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Советы по увеличению эффективности работы." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Как следить за временем" #: C/tracking.page:12(p) msgid "Your time tracking habits will be dictated by your reason for collecting the data. What is that you want to do with the data? Is it plain curiosity, or a work requirement? And at what level of detail are you interested in the results?" msgstr "" #: C/tracking.page:20(title) msgid "Granularity" msgstr "" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "" #: C/tracking.page:22(p) msgid "The intention of Time Tracker is to avoid micro-tracking so that one does not turn out spending more time on tracking than doing the activities! However, tracking in insufficient detail could result in there being no data which is useful to you a month later." msgstr "" #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "" #: C/tracking.page:33(p) msgid "For simple activities that don't have a project, use the action as the activity name and the category for the wider context. For example: lunch@work." msgstr "" #: C/tracking.page:38(p) msgid "For more sophisticated tracking try to caption your activity in one or two words (\"tree house\", \"project x\", or similar) and use that caption in the activity field. Use the category to describe the activity in it's wider context - is it private or work, or something else? Finally, use tags to describe your actual action - is it reading or constructing, writing or painting." msgstr "" #: C/tracking.page:47(p) msgid "This approach will alow you to see how much reading you have done through all your projects (by tag), how much time you have spent in your hobbies (by category), and how much time of all your work in project x you have spent analysing (by activity and tag)" msgstr "" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "" #: C/tracking.page:58(p) msgid "Name activities so that they can be easily distinguished from each other. Activity name is also the only information that appears in the panel. Will you be able to determine what you are working on just by looking at the activity name?" msgstr "" #: C/tracking.page:64(p) msgid "Keep your list of categories small (say, 3 to 7) and pick ones that are unlikely to change over time. Also, keep them generic. For example: \"work\", \"private\", \"misc\"." msgstr "" #: C/tracking.page:69(p) msgid "Use the description field for short-term information like reference numbers. The search in the Overview window also looks in the description field, so finding activities where you mention the specific reference number will be as simple as typing it in the search box and pressing Enter." msgstr "" #: C/tracking.page:76(p) msgid "Activities and tags can come and go as necessary. Once you think that you are done with an activity for good, remove it so that it doesn't pop up in the auto-complete any more. Don't worry: the facts (activities in the log) will not be deleted. This is just the \"operational list\"." msgstr "" #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Заметки об интерпретации статистики." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Статистика" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "Результаты, доступные по ссылке Показать статистику носят экспериментальный характер и являются лишь интерпретацией фактов. Эту интерпретацию следует сравнивать с собственными наблюдениями. Исправления приветствуются." #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "Тем не менее, раздел «Начинается и заканчивается» должен дать некоторое представление о занятиях." #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Извлечение данных из программы." #: C/reports.page:8(title) msgid "Report and export" msgstr "Отчёты и экспортирование" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "Несмотря на то, что формат HTML предлагается по умолчанию в диалоге сохранения, можно выбрать форматы TSV (значения, разделённые табуляцией; подходит для электронных таблиц), XML или iCal из выпадающего списка." #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "Для программного доступа предусмотрен API для D-Bus, который может быть проанализирован с использованием таких инструментов, как D-Feet." #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "Наиболее быстрый способ получить данные из программы — создание отчёта в HTML. Удерживая нажатой клавишу Ctrl, выберите все необходимые ячейки, а затем скопируйте их и вставьте в нужное приложение." #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Автоматическое разрешение конфликтов" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Разделение активностей" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr " Учёт времени делает всё возможное, чтобы избежать пересечений времени занятий. При создании нового занятия в середине существующего, существующее будет разбито на две части. В других случаях перекрытия, время предыдущих записей будет сокращено." #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "Объединение может быть удобным при вводе информации о занятиях за весь день. Начните ввод первого занятия и отметьте флажок «В процессе» вместо ввода времени окончания. При вводе следующего занятия сделайте это снова: укажите время начала занятия и отметьте, что оно находится в процессе выполнения. Заметьте, время окончания предыдущего занятия ограничилось временем начала нового. Повторяйте эту процедуру, пока не останетесь довольны результатом!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Приёмы ускоренного ввода занятий." #: C/input.page:8(title) msgid "Input" msgstr "Ввод" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "Для того, чтобы начать учёт времени, введите название занятия в поле ввода и нажмите клавишу Enter. Существует несколько приёмов, позволяющих сразу уточнить некоторые детали:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Используйте символ @ для добавления категорий" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "После символа запятой всё будет сохранено в поле описания" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "Для того, чтобы сразу уточнить время, введите его первым в поле ввода" #: C/input.page:23(p) msgid "A few examples:" msgstr "Несколько примеров:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 поливка цветов" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Забыл отметить важное занятие — поливку цветов во время обеда." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "помидоры@сад, выкапывание ям" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "Нужно больше помидоров в саду. «Выкапывание ям» носит чисто информативный характер, поэтому добавляется в качестве описания." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 экзистенциализм, размышления о просторах Вселенной" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "Исправление данных. Информирование приложения о том, что в последние семь минут я занимался чем-то другим. Относительное время срабатывает только для занятий, находящихся в процессе выполнения, без времени окончания." #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "Кроме того, можно добавлять метки в специальном поле. Метки разделяются запятой. Когда появляется окно выбора, нажмите Tab для дополнения ввода первой подходящей меткой." #: C/index.page:6(title) #: C/index.page:7(title) #: C/index.page:17(title) msgid "Time Tracking" msgstr "Учёт времени" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Как архивировать базу данных занятий." #: C/backup.page:8(title) msgid "Backup" msgstr "Архивирование данных" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "Информация о занятиях сохраняется в базе данных SQLite, расположенной в ~/.local/share/hamster/hamster.db. Этот файл может быть заархивирован или восстановлен в ходе работы. Приложение перезагрузит данные автоматически через какое-то время." #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "Для просмотра содержимого базы данных мы можем предложить использовать SQLite Manager для браузера Mozilla Firefox." #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Юрий Мясоедов , 2011" hamster-3.0.3/help/sl/000077500000000000000000000000001452646177100145435ustar00rootroot00000000000000hamster-3.0.3/help/sl/sl.po000066400000000000000000000347361452646177100155360ustar00rootroot00000000000000# Slovenian translations for hamster-time-tracker help. # Copyright (C) 2009 hamster-time-tracker COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # Andrej Žnidaršič , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker help master\n" "POT-Creation-Date: 2010-10-08 22:34+0000\n" "PO-Revision-Date: 2010-10-26 21:20+0100\n" "Last-Translator: Andrej Žnidaršič \n" "Language-Team: Slovenian GNOME Translation Team \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);\n" "X-Poedit-Country: SLOVENIA\n" "X-Poedit-Language: Slovenian\n" "X-Poedit-SourceCharset: utf-8\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "Namigi kako učinkovito slediti svoje dejavnosti." #: C/tracking.page:10(title) msgid "How to track time" msgstr "Kako slediti čas" #: C/tracking.page:12(p) msgid "Your time tracking habits will be dictated by your reason for collecting the data. What is that you want to do with the data? Is it plain curiosity, or a work requirement? And at what level of detail are you interested in the results?" msgstr "Vaše navade sledenja časa bo diktiral vaš vzrok za zbiranje podatkov. Kaj želite storiti s podatki? Je to običajna radovednost ali delovna zahteva? Kako podrobno vas zanimajo rezultati?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "Zrnatost" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "Predlagana hitrost je 5 do 30 dejavnosti na dan." #: C/tracking.page:22(p) msgid "The intention of Time Tracker is to avoid micro-tracking so that one does not turn out spending more time on tracking than doing the activities! However, tracking in insufficient detail could result in there being no data which is useful to you a month later." msgstr "Namen Sledilnika časa je izogibanje mikro-sledenju zato, da ne porabite več časa za sledenje kot za izvajanje dejavnosti! Vendar lahko sledenje v premajhnih podrobnostih povzroči, da en mesec kasneje nimate na voljo uporabnih podatkov." #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "Kaj naj napišem v vsako polje?" #: C/tracking.page:33(p) msgid "For simple activities that don't have a project, use the action as the activity name and the category for the wider context. For example: lunch@work." msgstr "Za enostavne dejavnosti, ki nimajo projekta uporabite dejanje kot ime dejavnosti in kategorija za širšo vsebino. Na primer: kosilo@služba." #: C/tracking.page:38(p) msgid "For more sophisticated tracking try to caption your activity in one or two words (\"tree house\", \"project x\", or similar) and use that caption in the activity field. Use the category to describe the activity in it's wider context - is it private or work, or something else? Finally, use tags to describe your actual action - is it reading or constructing, writing or painting." msgstr "Za bolj izpopolnjeno sledenje opišite svojo dejavnost v eni ali dveh besedah (\"hiša na drevesu\", \"projekt x\" ali podobno) in ta opis uporabite v polju dejavnost. Za opis dejavnosti v njeni širši vsebini uporabite kategorija - je zasebna ali delo ali nekaj drugega? Na koncu uporabite oznake za opis vašega dejanskega dejanja - je to branje, pisanje, risanje ali gradnja." #: C/tracking.page:47(p) msgid "This approach will alow you to see how much reading you have done through all your projects (by tag), how much time you have spent in your hobbies (by category), and how much time of all your work in project x you have spent analysing (by activity and tag)" msgstr "Ta pristop vam bo omogočal ogled koliko časa ste brali v vseh svojih projektih (po oznaki), koliko časa ste porabili za svoje konjičke (po kategoriji) in koliko časa ste porabili za preučevanje v projektu x (po dejavnosti in oznaki)." #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "Namigi za izboljšanje vaših podatkov sledenja" #: C/tracking.page:58(p) msgid "Name activities so that they can be easily distinguished from each other. Activity name is also the only information that appears in the panel. Will you be able to determine what you are working on just by looking at the activity name?" msgstr "Imenujte dejavnosti tako, da jih je mogoče enostavno ločiti eno od druge. Ime dejavnosti je edini podatek, ki se pojavi v pultu. Ali boste lahko ugotovili na čem delate samo s pogledom na ime dejavnosti?" #: C/tracking.page:64(p) msgid "Keep your list of categories small (say, 3 to 7) and pick ones that are unlikely to change over time. Also, keep them generic. For example: \"work\", \"private\", \"misc\"." msgstr "Obdržite seznam kategorij majhen (na primer med 3 in 7) in izberite takšne, ki se zelo verjetno čez čas ne bodo spremenile. Kategorije naj bodo splošne. Na primer \"delo\", \"zasebno\", \"različno\"." #: C/tracking.page:69(p) msgid "Use the description field for short-term information like reference numbers. The search in the Overview window also looks in the description field, so finding activities where you mention the specific reference number will be as simple as typing it in the search box and pressing Enter." msgstr "Polje opisa uporabite za kratkoročne podatke kot na primer številke sklicev. Iskanje v oknu Pregled išče tudi v polju opis, zato bo iskanje dejavnosti, kjer omenite določeno številko sklica, zelo enostavno. Morali boste le vpisati številko sklica in pritisniti Vnosno tipko." #: C/tracking.page:76(p) msgid "Activities and tags can come and go as necessary. Once you think that you are done with an activity for good, remove it so that it doesn't pop up in the auto-complete any more. Don't worry: the facts (activities in the log) will not be deleted. This is just the \"operational list\"." msgstr "Dejavnosti in oznake naj se pojavljajo in izginjajo po potrebi. Ko boste mislili, da ste z dejavnostjo končali za vedno, jo odstranite zato, da se ne pojavi več v polju samodejnega dopolnjevanja. Ne skrbite: dejstva (dejavnosti v dnevniku) ne bodo izbrisana. To je samo \"delovni seznam\"." #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "Opomba o interpretaciji statistike." #: C/statistics.page:8(title) msgid "Statistics" msgstr "Statistika" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "Do rezultatov je mogoče dostopati preko povezave Pokaži statistiko. Statistika je preizkusna in je interpretacija dejstev. Primerjajte jo s svojimi opazovanji. Popravki so dobrodošli." #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "Statistika \"Začetki in konci\" bi vam morala dati približek vašega dejavnega časa. " #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "Dobite podatke iz sledilnika časa." #: C/reports.page:8(title) msgid "Report and export" msgstr "Poročanje in izvoz" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "Poleg zapisa HTML, ki je v pogovornem oknu shranjevanja poročila privzeto ponujen, vam spustno polje zapisa ponuja zapise TSV (s tabulatorji ločene vrednosti, dobro za preglednice), XML in iCal." #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "Za programski dostop je na voljo API D-Bus, ki ga je mogoče opazovati z orodji kot je D-Feet." #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "Najhitrejši način za pridobivanje podatkov \"ven\" iz Sledilnika časa je ustvarjanje poročila HTML. Med pritiskom tipke Ctrl izberite vse zahtevane celice in jih skopirajte in prilepite v ciljni program. " #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "Samodejno razreševanja sporov." #: C/merge.page:8(title) msgid "Splitting activities" msgstr "Razdeljevanje dejavnosti" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr "Sledilnik časa se poskuša izogniti prekrivanju dejavnosti. V primeru, da ustvarite dejavnost v obstoječi dejavnosti, bo bila prva razdeljena na dva dela. V drugih primerih prekrivanja bodo predhodni vnosti skrčeni." #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "Združevanje lahko postane priročno pri vnašanju dejavnosti za cel dan. Začnite z vnašanjem prve dejavnosti in za končni čas izberite izbirno polje \" v teku\". Za naslednjo dejavnost nastavite samo začetni čas in jo označite kot v teku. Opazujte kako se končni čas predhodnega vnosa prilagodi na začetni čas nove dejavnosti. Ponavljajte postopek dokler ne boste zadovoljni!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "Triki za hitrejše vnašanje dejavnosti." #: C/input.page:8(title) msgid "Input" msgstr "Vnos" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "Za začetek sledenje vtipkajte ime dejavnosti v vnosno polje in pritisnite Vnosno tipko. Obstaja nekaj trikov, ki vam omogočajo sprotno navedbo več podrobnosti." #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "Uporabite simbol @ za dodajanje kategorija" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "Vse za vejico (,) bo bilo shranjeno v polje opisa" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "Za sprotno navedbo časa, ga najprej vnesite v vnosno polje" #: C/input.page:23(p) msgid "A few examples:" msgstr "Nekaj primerov:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 zalivanje rož" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "Pozabil zaliti rože po kosilu." #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "paradižniki@vrt, kopanje lukenj" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "Potrebujem več paradižnikov na vrtu. Kopanje lukenj je podrobnost, zato je dodana kot opis." #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 eksistencializem, razmišljanje o ogromnih razsežnostih vesolja" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "Popravljanje podatkov z obveščanjem programa, da sem zadnjih 7 minut počenjal nekaj drugega. Relativni časi delujejo le za trajajoče dejavnosti brez končnega časa." #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "Poleg tega lahko v polje vnosa oznak dodate oznake. Oznake so ločene z vejicami. Pritisnite Tabulator, ko polje predlogov samodejno dopolni vnos do prve ujemajoče se oznake." #: C/index.page:6(title) #: C/index.page:7(title) #: C/index.page:17(title) msgid "Time Tracking" msgstr "Sledenje časa" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "Kako ustvariti varnostno kopijo podatkovne zbirke dejavnosti." #: C/backup.page:8(title) msgid "Backup" msgstr "Varnostna kopija" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "Dejavnosti so shranjene v podatkovni zbirki SQLite, shranjeni v ~/.local/share/hamster/hamster.db. Ustvariti je mogoče varnostno kopijo datoteke in jo po potrebi obnoviti. Program bo po kratkem času samodejno znova naložil podatke." #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "Za ogled vsebune podatkovne zbirke predlagamo link href=\"https://addons.mozilla.org/en-US/firefox/addon/5817\">Upravljalnik SQLite za Mozillo Firefox" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Andrej Žnidaršič " hamster-3.0.3/help/te/000077500000000000000000000000001452646177100145355ustar00rootroot00000000000000hamster-3.0.3/help/te/te.po000066400000000000000000000243201452646177100155060ustar00rootroot00000000000000# Telugu translation for hamster-time-tracker. # Copyright (C) 2011 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Praveen Illa , 2011. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2011-11-26 17:03+0000\n" "PO-Revision-Date: 2011-11-26 22:45+0530\n" "Last-Translator: Praveen Illa \n" "Language-Team: Telugu \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" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "మీ కార్యకలాపాలను ప్రభావవంతంగా ఎలా ట్రాక్ చెయ్యాలో తెలిపే చిట్కాలు." #: C/tracking.page:10(title) msgid "How to track time" msgstr "సమయాన్ని కనుక్కోవడం ఎలా" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" #: C/tracking.page:20(title) msgid "Granularity" msgstr "" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "" #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "ప్రతీ పెట్టెలో ఏమి వ్రాయాలి?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "మీ డేటాను తెలుసుకొనుటను మెరుగుపరుచుటకు చిట్కాలు" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "" #: C/statistics.page:8(title) msgid "Statistics" msgstr "గణాంకాలు" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "" #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "" #: C/reports.page:8(title) msgid "Report and export" msgstr "నివేదించు మరియు ఎగుమతిచేయి" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "కార్యకలాపాలను విభజించుట" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "కార్యకలాప ప్రవేశాన్ని వేగవంతం చేయుటకు జిమ్మిక్కులు" #: C/input.page:8(title) msgid "Input" msgstr "ఇన్‌పుట్" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "కొత్త విభాగాన్ని జతచేయుటకు @ చిహ్నాన్ని వాడండి" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "ప్రతీ కామా తరువాత (,) వివరణ క్షేత్రంలో భద్రపరుచబడుతుంది" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" #: C/input.page:23(p) msgid "A few examples:" msgstr "కొన్ని ఉదాహరణలు:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 పువ్వులపై నీళ్ళు చల్లాలి" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "" #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "క్రియేటివ్ కామన్స్ షేర్ ఎలైక్ 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "" #: C/backup.page:8(title) msgid "Backup" msgstr "బ్యాకప్" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "Praveen Illa , 2011" hamster-3.0.3/help/wscript000066400000000000000000000056151452646177100155520ustar00rootroot00000000000000# waf script called from the root wscript, by # conf.recurse("help") # Mallard waf adaptor written by Ulrik Sverdrup # may be distributed, changed, used, etc freely for any purpose ## Mallard functionality definitions ## import os from waflib import Logs, TaskGen def _read_makefile_am(filename): "read a Makefile.am file for HELP_* variable definitions, return a dict" varstring = open(filename).read() varstring = varstring.replace("\\\n", " ") varlines = [L for L in varstring.splitlines() if L.startswith("HELP")] return dict(tuple(map(str.strip, var.split("=", 1))) for var in varlines) def init_mallard(self): mf_am = self.path.find_resource(self.variable_definitions) HELP_VAR = _read_makefile_am(mf_am.abspath()) require_vars = "HELP_ID HELP_LINGUAS HELP_FILES".split() have_vars = set(var for var in HELP_VAR if HELP_VAR[var]) missing_vars = set(require_vars).difference(have_vars) if missing_vars: print("Missing HELP variable declarations in {}:".format(mf_am.abspath())) print("\n".join(missing_vars)) self.bld.env.update(HELP_VAR) self.default_install_path='${PREFIX}/share/help' def apply_mallard(self): bld = self.bld lst = self.to_list(bld.env["HELP_LINGUAS"]) cnode = self.path.find_dir("C") pages = [p.name for p in cnode.ant_glob(["*.page", "*.xml"])] # Check if the declared page list is consistent declared_pages = self.to_list(bld.env["HELP_FILES"]) missing_pages = set(pages).difference(declared_pages) if missing_pages: print("Warning: Some pages not declared:") print("\n".join(missing_pages)) install_path = lambda lang: os.path.join(bld.env.DATADIR, "help", lang, "${HELP_ID}") for lang in lst: node = self.path.find_resource("%s/%s.po" % (lang, lang)) mo = self.path.find_or_declare("%s/%s.mo" % (lang, lang)) bld(name='msgfmt', color='BLUE', rule='${MSGFMT} ${SRC} -o ${TGT}', source=node, target=mo, ) for page in pages: out = self.path.find_or_declare('%s/%s' % (lang, page)) src = self.path.find_resource('C/%s' % page) bld(name='itstool', color='BLUE', rule='${ITSTOOL} -m ${SRC} -o ${TGT}', source=[mo, src], target=out, install_path=install_path(lang) ) if bld.is_install: page_nodes = [cnode.find_resource(page) for page in pages] instdir = install_path("C") bld.install_files(instdir, page_nodes) TaskGen.feature("mallard")(init_mallard) TaskGen.feature("mallard")(apply_mallard) TaskGen.after('init_mallard')(apply_mallard) ## End Mallard functionality ## # Build Configuration def configure(ctx): lookfor = "itstool" try: ctx.find_program('msgfmt', var='MSGFMT') ctx.find_program(lookfor, var='ITSTOOL') ctx.env.docs = True except ctx.errors.ConfigurationError: Logs.warn("'{}' not found; documentation build disabled".format(lookfor)) ctx.env.docs = False def build(ctx): if ctx.env.docs: task = ctx( features="mallard", variable_definitions="Makefile.am", ) hamster-3.0.3/help/zh_CN/000077500000000000000000000000001452646177100151265ustar00rootroot00000000000000hamster-3.0.3/help/zh_CN/zh_CN.po000066400000000000000000000362671452646177100165050ustar00rootroot00000000000000# Chinese (China) translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # TeliuTe , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-12-07 23:55+0000\n" "PO-Revision-Date: 2010-12-18 00:19+0800\n" "Last-Translator: TeliuTe \n" "Language-Team: Chinese (China) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Chinese\n" "X-Poedit-Country: CHINA\n" #: C/tracking.page:7(desc) msgid "Tips on how to track your activities effectively." msgstr "如何更有效追踪您活动的小提示。" #: C/tracking.page:10(title) msgid "How to track time" msgstr "如何追踪时间" #: C/tracking.page:12(p) msgid "" "Your time tracking habits will be dictated by your reason for collecting the " "data. What is that you want to do with the data? Is it plain curiosity, or a " "work requirement? And at what level of detail are you interested in the " "results?" msgstr "" "您的时间追踪习惯将会由您收集这些数据的原因来描述。您希望用这些数据来做什么?" "只是简单的好奇,或者是工作需要?您对多详细的结果感兴趣?" #: C/tracking.page:20(title) msgid "Granularity" msgstr "间隔" #: C/tracking.page:21(p) msgid "A suggested pace is to have 5 to 30 activities per day." msgstr "建议每天有5到30个活动。" #: C/tracking.page:22(p) msgid "" "The intention of Time Tracker is to avoid micro-tracking so that " "one does not turn out spending more time on tracking than doing the " "activities! However, tracking in insufficient detail could result in there " "being no data which is useful to you a month later." msgstr "" "时间追踪器的意图是防止琐碎记录,因而花费较多时间的项目比正在活动的" "项目更不容易被移除!然而,不够详细的追踪会导致一个月后,您不能得到有用的数" "据。" #: C/tracking.page:31(title) msgid "What should I write in each box?" msgstr "我应该在每个盒子里写什么?" #: C/tracking.page:33(p) msgid "" "For simple activities that don't have a project, use the action as the " "activity name and the category for the wider context. " "For example: lunch@work." msgstr "" "对于简单的、不是一项工程的活动,使用动作来作为活动 名,项目作上下文。例如:午饭@工作。" #: C/tracking.page:38(p) msgid "" "For more sophisticated tracking try to caption your activity in one or two " "words (\"tree house\", \"project x\", or similar) and use that caption in " "the activity field. Use the category to describe the " "activity in it's wider context - is it private or work, or something else? " "Finally, use tags to describe your actual action - is it reading " "or constructing, writing or painting." msgstr "" "对于更复杂的追踪,尝试用一到两个词来标记您的活动(“树屋”、“项目 x”,或类似" "的),在活动区域中输入标题。在项目中描述活动的相关情况 " "- 它是私人的还是工作上的,或是其他别的?最后,在标签里输入活动的实" "际操作 - 是阅读还是制作,是写作还是绘画。" #: C/tracking.page:47(p) msgid "" "This approach will alow you to see how much reading you have done through " "all your projects (by tag), how much time you have spent in your hobbies (by " "category), and how much time of all your work in project x you have spent " "analysing (by activity and tag)" msgstr "" "这个近似值能让您看到在所有的项目(通过标签)中,阅读花费了多少时间,多少时间您" "花费在爱好上(通过分类),以及在某个项目上您花费时间的细节(通过活动和标签)" #: C/tracking.page:55(title) msgid "Tips for improving your tracking data" msgstr "用于您改进数据跟踪的小提示" #: C/tracking.page:58(p) msgid "" "Name activities so that they can be easily distinguished from each other. " "Activity name is also the only information that appears in the panel. Will " "you be able to determine what you are working on just by looking at the " "activity name?" msgstr "" "给活动起个好名称,以便使它们很容易区分。活动名也是面板上显示的唯一信息。您能" "仅仅通过查看活动名,就知道当前进行的工作吗?" #: C/tracking.page:64(p) msgid "" "Keep your list of categories small (say, 3 to 7) and pick ones that are " "unlikely to change over time. Also, keep them generic. For example: \"work" "\", \"private\", \"misc\"." msgstr "" "保持简短列表项(一般说是3到7个),选择那种不大可能随着时间而改变的。当然也要保" "证它们的通用性,比如:“工作”、“私人”、“音乐”。" #: C/tracking.page:69(p) msgid "" "Use the description field for short-term information like reference numbers. " "The search in the Overview window also looks in the description " "field, so finding activities where you mention the specific reference number " "will be as simple as typing it in the search box and pressing Enter." msgstr "" "在描述框里输入简短的信息,比如是编号。在概述窗口中搜索也可以查找描" "述框内容,因此在这里,您可以通过简单地输入它,然后按回车键,就可以" "找到指定编号的活动。" #: C/tracking.page:76(p) msgid "" "Activities and tags can come and go as necessary. Once you think that you " "are done with an activity for good, remove it so that it doesn't pop up in " "the auto-complete any more. Don't worry: the facts (activities in the log) " "will not be deleted. This is just the \"operational list\"." msgstr "" "活动和标签可以根据需要来取舍,一旦您认为已经很好地完成了活动,就可以删除它," "这样它就不会在自动完成中弹出。不必担心:实际的工作(记录在日志中的活动)不会被" "删除,这仅仅只是“列表操作”。" #: C/statistics.page:6(desc) msgid "Note on interpretation of statistics." msgstr "解释各项统计条目" #: C/statistics.page:8(title) msgid "Statistics" msgstr "统计" #: C/statistics.page:10(p) msgid "" "The results that are accessible via the Show " "Statistics link are experimental and they are an interpretation of the " "facts. This interpretation should be compared with your own observations. " "Patches are welcome." msgstr "" "通过访问 显示统计 链接得到的结果,是实验用的,它" "们应该可以和你自己的经验相对照。欢迎指出不足之处。" #: C/statistics.page:16(p) msgid "" "However, the \"Starts and Ends\" should give you some idea about your active " "time." msgstr "不过,“开始和结束”可以给出一些你活动时间长短的参考。" #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "从时间追踪器里获得数据。" #: C/reports.page:8(title) msgid "Report and export" msgstr "报告和导出" #: C/reports.page:10(p) msgid "" "Apart from the HTML format that is offered by default in the Save report " "dialog, the format drop-down allows you to choose TSV (Tab Separated Values, " "good for spreadsheets), XML, and iCal formats." msgstr "" "在保存报告对话框中,默认提供的是 HTML 网页格式,在格式下拉列表中,您还可以选" "择 TSV 格式(标签分离数值,用于电子表格较好),XML 和 iCal 格式。" #: C/reports.page:15(p) msgid "" "For programmatic access, there is D-Bus API, that can be introspected using " "tools like D-Feet." msgstr "" "对于可编程访问,可以使用内置类似 D-Feet 的工具。" #: C/reports.page:21(p) msgid "" "The fastest way to get the data \"out\" of the Time Tracker is by generating " "a HTML report. While holding the Ctrl key down, select all the " "needed cells, and then copy and paste them into the target application." msgstr "" "要快速从时间追踪器的 HTML 报告中“取出”数据,按住 Ctrl 键,选择所需" "的单元格,然后把它们复制粘贴到其他应用程序中。" #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "自动解决矛盾。" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "分离活动" #: C/merge.page:10(p) msgid "" "Time Tracker does its best to avoid overlaps in activities. If " "you create an activity in the middle of an existing activity, the former " "will be split into two. In other cases of overlapping, the previous entries " "will be shrunk." msgstr "" "时间追踪器 可以非常好地解决各个活动的重叠部分。如果你在一个活动时" "间段内,创建了另一个活动,表格将会分成两个。在其他重叠情况下,原来的项目会避" "让。" #: C/merge.page:17(p) msgid "" "Merging can become handy when entering information for the whole day. Start " "by entering the first activity and select the \"in progress\" check box for " "the end time. For the next activity again set just the start time and mark " "it as ongoing. Observe how the end time of the previous activity gets " "adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" "一整天的输入信息也很容易合并,选中第一个开始的活动,然后在最后的时间打勾“正在" "进行中”复选框。第二个活动也点开始时间然后标记正在进行。检查上一个活动的结束时" "间,已调整为一个新活动的开始时间,重复这些过程到完工!" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "快捷操作活动项的诀窍。" #: C/input.page:8(title) msgid "Input" msgstr "输入" #: C/input.page:10(p) msgid "" "To start tracking, type in the activity name in the input box and hit the " "Enter key. There are a few tricks that will allow you to specify " "more detail on the fly:" msgstr "" "要开始跟踪,在输入框里输入活动名称,然后按 回车键。还有一些方法可" "以让你设定更多细节:" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "添加项目时使用 @ 符号" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "在英文逗点(,)后的内容,将会保存到活动描述里" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "要设定时间,请在输入框开头输入它" #: C/input.page:23(p) msgid "A few examples:" msgstr "一些例子:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 浇花" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "标记备忘午饭后浇花的重要事情。" #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "西红柿@花园, 翻地" #: C/input.page:32(p) msgid "" "Need more tomatoes in the garden. Digging holes is purely informational, so " "added it as a description." msgstr "在花园里种更多西红柿,翻地是一个具体的任务信息,因此把它添加到描述里。" #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "-7 的存在,是考虑到更广阔的应用环境中" #: C/input.page:39(p) msgid "" "Corrected information by informing application that I've been doing " "something else for the last seven minutes. Relative times only work for " "ongoing activities without an end time." msgstr "" "让应用程序提供正确信息,我已经做了一些,除了最后的7分钟。重新激活的时间仅仅用" "于正在进行的没有结束时间的活动。" #: C/input.page:46(p) msgid "" "On top of that you can add tags in the tag input field. Tags are delimited " "by a comma. Press the Tab when the suggestion box appears to " "complete the input to the first matching tag." msgstr "" "在顶部,你可以在标签输入框添加标签,标签由逗号分割,按 Tab 键可以" "完成输入第一个匹配的标签。" #: C/index.page:6(title) C/index.page:7(title) C/index.page:17(title) msgid "Time Tracking" msgstr "时间追踪器" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "知识共享-相同方式共享协议 3.0" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "如何备份活动的数据库。" #: C/backup.page:8(title) msgid "Backup" msgstr "备份" #: C/backup.page:10(p) msgid "" "Activities are stored in an SQLite database, located at ~/.local/share/" "hamster/hamster.db. The file can be backed up and restored on " "the go. The application will reload the data automatically after a short " "while." msgstr "" "活动存储在一个 SQLite 数据库里,位于 ~/.local/share/hamster-time-tracker/" "hamster.db。应用程序会在一个短时间后自动重载数据。" #: C/backup.page:17(p) msgid "" "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "" "要查看数据库的内容,我们建议您使用 Mozilla Firefox 的 SQLite 管理器 扩展。" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "TeliuTe , 2010" #~ msgid "" #~ "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 " #~ "Unported License." #~ msgstr "" #~ "本文的许可协议: 知识共享署名-相同方式共享 3.0 Unported License." #~ msgid "" #~ "As a special exception, the copyright holders give you permission to " #~ "copy, modify, and distribute the example code contained in this document " #~ "under the terms of your choosing, without restriction." #~ msgstr "" #~ "相应地,您可以根据自己的选择,复制、修改和分发文档里的代码范例,这没有什么" #~ "限制。" #~ msgid "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgstr "" #~ "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #~ msgid "" #~ "Time Tracking logoTime Tracking" #~ msgstr "" #~ "" #~ "时间追踪器图标 时间追踪器" hamster-3.0.3/help/zh_HK/000077500000000000000000000000001452646177100151305ustar00rootroot00000000000000hamster-3.0.3/help/zh_HK/zh_HK.po000066400000000000000000000201431452646177100164730ustar00rootroot00000000000000# Chinese (Hong Kong) translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Kevin_Wei_2 , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-03-04 22:08+0000\n" "PO-Revision-Date: 2010-03-27 20:32+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (Hong Kong) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: C/legal.xml:3(p) msgid "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License." msgstr "這份作品根據據Creative Commons Attribution-Share Alike 3.0 Unported License來授權" #: C/legal.xml:6(p) msgid "As a special exception, the copyright holders give you permission to copy, modify, and distribute the example code contained in this document under the terms of your choosing, without restriction." msgstr "有一個特殊的例外,著作權人允許你複製、修改和散佈這份文件中的範例程式碼,可以自行選擇條款,沒有限制。" #: C/statistics.page:6(desc) #, fuzzy msgid "Note on interpretation of statistics." msgstr "在此頁筆記上使用工具" #: C/statistics.page:8(title) msgid "Statistics" msgstr "統計" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "" #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "" #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "從時間追蹤程式將資料匯出。" #: C/reports.page:8(title) msgid "Report and export" msgstr "報告與匯出" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "" #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "" #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "要將資料「送出」時間追蹤程式最快的方式就是產生 HTML 報告。當按住 Ctrl 鍵時,選擇所有需要的儲存格,然後複製並將它們貼到目標應用程式中。" #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "自動解決衝突。" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "分割活動" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr "" #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "加速活動項目的小技巧。" #: C/input.page:8(title) msgid "Input" msgstr "輸入" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "要開始追蹤,在入視窗中輸入活動名稱然後按下鍵盤上的Enter按鍵。有一些些技巧能允許你一次記載許多細節。" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "使用 @ 符號來加入分類" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "任何在逗號 (,) 之後的東西都會儲存在描述欄位" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" #: C/input.page:23(p) msgid "A few examples:" msgstr "一些例子:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 澆花" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "" #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "" #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "" #. When image changes, this message will be marked fuzzy or untranslated for you. #. It doesn't matter what you translate it to: it's not used at all. #: C/index.page:18(None) msgid "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" msgstr "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #: C/index.page:6(title) #: C/index.page:7(title) msgid "Time Tracking" msgstr "時間追蹤" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/index.page:17(title) msgid "Time Tracking logoTime Tracking" msgstr "Time Tracking logoTime Tracking" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "如何備份活動資料庫。" #: C/backup.page:8(title) msgid "Backup" msgstr "備份" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "活動都儲存在 SQLite 資料庫中,就在 ~/.local/share/hamster/hamster.db。這個檔案可以隨時備份或還原。程式會在一段時間後自動重新載入資料。" #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "想要看看資料庫的內容,我們建議使用 Mozilla Firefox 的 SQLite Manager。" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "如對翻譯有任何意見,請送一封電子郵件給\n" "以下地址,GNOME 翻譯隊伍會盡快回覆你:\n" "community@linuxhall.org\n" "\n" "Kevin_Wei_2 , 2010." hamster-3.0.3/help/zh_TW/000077500000000000000000000000001452646177100151605ustar00rootroot00000000000000hamster-3.0.3/help/zh_TW/zh_TW.po000066400000000000000000000201401452646177100165500ustar00rootroot00000000000000# Chinese (Taiwan) translation for hamster-time-tracker. # Copyright (C) 2010 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Kevin_Wei_2 , 2010. # msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "POT-Creation-Date: 2010-03-04 22:08+0000\n" "PO-Revision-Date: 2010-03-26 21:23+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (Taiwan) \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: C/legal.xml:3(p) msgid "This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License." msgstr "這份作品依據Creative Commons Attribution-Share Alike 3.0 Unported License來授權" #: C/legal.xml:6(p) msgid "As a special exception, the copyright holders give you permission to copy, modify, and distribute the example code contained in this document under the terms of your choosing, without restriction." msgstr "有一個特殊的例外,著作權人允許你複製、修改和散佈這份文件中的範例程式碼,可以自行選擇條款,沒有限制。" #: C/statistics.page:6(desc) #, fuzzy msgid "Note on interpretation of statistics." msgstr "在此頁筆記上使用工具" #: C/statistics.page:8(title) msgid "Statistics" msgstr "統計" #: C/statistics.page:10(p) msgid "The results that are accessible via the Show Statistics link are experimental and they are an interpretation of the facts. This interpretation should be compared with your own observations. Patches are welcome." msgstr "" #: C/statistics.page:16(p) msgid "However, the \"Starts and Ends\" should give you some idea about your active time." msgstr "" #: C/reports.page:6(desc) msgid "Get data out of Time Tracker." msgstr "從時間追蹤程式將資料匯出。" #: C/reports.page:8(title) msgid "Report and export" msgstr "報告與匯出" #: C/reports.page:10(p) msgid "Apart from the HTML format that is offered by default in the Save report dialog, the format drop-down allows you to choose TSV (Tab Separated Values, good for spreadsheets), XML, and iCal formats." msgstr "" #: C/reports.page:15(p) msgid "For programmatic access, there is D-Bus API, that can be introspected using tools like D-Feet." msgstr "" #: C/reports.page:21(p) msgid "The fastest way to get the data \"out\" of the Time Tracker is by generating a HTML report. While holding the Ctrl key down, select all the needed cells, and then copy and paste them into the target application." msgstr "要將資料「送出」時間追蹤程式最快的方式就是產生 HTML 報告。當按住 Ctrl 鍵時,選擇所有需要的儲存格,然後複製並將它們貼到目標應用程式中。" #: C/merge.page:6(desc) msgid "Automatic conflict solving." msgstr "自動解決衝突。" #: C/merge.page:8(title) msgid "Splitting activities" msgstr "分割活動" #: C/merge.page:10(p) msgid "Time Tracker does its best to avoid overlaps in activities. If you create an activity in the middle of an existing activity, the former will be split into two. In other cases of overlapping, the previous entries will be shrunk." msgstr "" #: C/merge.page:17(p) msgid "Merging can become handy when entering information for the whole day. Start by entering the first activity and select the \"in progress\" check box for the end time. For the next activity again set just the start time and mark it as ongoing. Observe how the end time of the previous activity gets adjusted to the start time of the new one. Repeat the process until happy!" msgstr "" #: C/input.page:6(desc) msgid "Tricks to speed up activity entry." msgstr "加速活動項目的小技巧。" #: C/input.page:8(title) msgid "Input" msgstr "輸入" #: C/input.page:10(p) msgid "To start tracking, type in the activity name in the input box and hit the Enter key. There are a few tricks that will allow you to specify more detail on the fly:" msgstr "要開始追蹤,在入視窗中輸入活動名稱然後按下鍵盤上的Enter按鍵。有一些些技巧能允許您一次記載許多細節。" #: C/input.page:18(p) msgid "Use the @ symbol to add a category" msgstr "使用 @ 符號來加入分類" #: C/input.page:19(p) msgid "Everything after a comma (,) will be stored in the description field" msgstr "任何在逗號 (,) 之後的東西都會儲存在描述欄位" #: C/input.page:20(p) msgid "To specify time on the fly, enter it first in the input box" msgstr "" #: C/input.page:23(p) msgid "A few examples:" msgstr "一些例子:" #: C/input.page:27(code) #, no-wrap msgid "12:30-12:45 watering flowers" msgstr "12:30-12:45 澆花" #: C/input.page:28(p) msgid "Forgot to note the important act of watering flowers over lunch." msgstr "" #: C/input.page:31(code) #, no-wrap msgid "tomatoes@garden, digging holes" msgstr "" #: C/input.page:32(p) msgid "Need more tomatoes in the garden. Digging holes is purely informational, so added it as a description." msgstr "" #: C/input.page:38(code) #, no-wrap msgid "-7 existentialism, thinking about the vastness of the universe" msgstr "" #: C/input.page:39(p) msgid "Corrected information by informing application that I've been doing something else for the last seven minutes. Relative times only work for ongoing activities without an end time." msgstr "" #: C/input.page:46(p) msgid "On top of that you can add tags in the tag input field. Tags are delimited by a comma. Press the Tab when the suggestion box appears to complete the input to the first matching tag." msgstr "" #. When image changes, this message will be marked fuzzy or untranslated for you. #. It doesn't matter what you translate it to: it's not used at all. #: C/index.page:18(None) msgid "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" msgstr "@@image: 'figures/hamster-logo.png'; md5=4a7b2f9ef6d9510fe1a648429bc4e3ba" #: C/index.page:6(title) #: C/index.page:7(title) msgid "Time Tracking" msgstr "時間追蹤" #: C/index.page:9(name) msgid "Milo Casagrande" msgstr "Milo Casagrande" #: C/index.page:10(email) msgid "milo@ubuntu.com" msgstr "milo@ubuntu.com" #: C/index.page:13(p) msgid "Creative Commons Share Alike 3.0" msgstr "Creative Commons Share Alike 3.0" #: C/index.page:17(title) msgid "Time Tracking logoTime Tracking" msgstr "Time Tracking logoTime Tracking" #: C/backup.page:6(desc) msgid "How to back up the activity database." msgstr "如何備份活動資料庫。" #: C/backup.page:8(title) msgid "Backup" msgstr "備份" #: C/backup.page:10(p) msgid "Activities are stored in an SQLite database, located at ~/.local/share/hamster/hamster.db. The file can be backed up and restored on the go. The application will reload the data automatically after a short while." msgstr "活動都儲存在 SQLite 資料庫中,就在 ~/.local/share/hamster/hamster.db。這個檔案可以隨時備份或還原。程式會在一段時間後自動重新載入資料。" #: C/backup.page:17(p) msgid "For viewing contents of the database we can suggest using the SQLite Manager for Mozilla Firefox." msgstr "想要看看資料庫的內容,我們建議使用 Mozilla Firefox 的 SQLite Manager。" #. Put one translator per line, in the form of NAME , YEAR1, YEAR2 #: C/index.page:0(None) msgid "translator-credits" msgstr "" "如對翻譯有任何意見,請送一封電子郵件給\n" "以下地址,GNOME 翻譯團隊會盡快回覆您:\n" "community@linuxhall.org\n" "\n" "Kevin_Wei_2 , 2010." hamster-3.0.3/org.gnome.Hamster.GUI.service.in000066400000000000000000000001301452646177100210760ustar00rootroot00000000000000[D-BUS Service] Name=org.gnome.Hamster.GUI Exec=@BINDIR@/hamster --gapplication-service hamster-3.0.3/org.gnome.Hamster.WindowServer.service.in000066400000000000000000000001461452646177100231170ustar00rootroot00000000000000[D-BUS Service] Name=org.gnome.Hamster.WindowServer Exec=@LIBEXECDIR@/hamster/hamster-windows-service hamster-3.0.3/org.gnome.Hamster.service.in000066400000000000000000000001211452646177100204530ustar00rootroot00000000000000[D-BUS Service] Name=org.gnome.Hamster Exec=@LIBEXECDIR@/hamster/hamster-service hamster-3.0.3/org.gnome.Hamster.yml000066400000000000000000000022111452646177100172110ustar00rootroot00000000000000--- app-id: org.gnome.Hamster runtime: org.gnome.Platform runtime-version: '45' sdk: org.gnome.Sdk command: hamster modules: - name: intltool sources: - type: archive url: https://launchpad.net/intltool/trunk/0.51.0/+download/intltool-0.51.0.tar.gz md5: 12e517cac2b57a0121cda351570f1e63 cleanup: - "*" - name: python3-hamster-dependencies buildsystem: simple ensure-writable: - easy-install.pth - setuptools.pth build-commands: - pip3 install --no-index --find-links="file://${PWD}" --prefix=${FLATPAK_DEST} dbus-python sources: - type: file url: https://dbus.freedesktop.org/releases/dbus-python/dbus-python-1.2.18.tar.gz sha256: 92bdd1e68b45596c833307a5ff4b217ee6929a1502f5341bae28fd120acf7260 - name: hamster buildsystem: simple builddir: true prefix: "/app" build-commands: - "./waf configure --prefix=${FLATPAK_DEST}" - "./waf build" - "./waf install" sources: - type: dir path: "." finish-args: - "--socket=wayland" - "--socket=fallback-x11" - "--filesystem=xdg-documents" - "--own-name=org.gnome.Hamster" - "--own-name=org.gnome.Hamster.GUI" - "--own-name=org.gnome.Hamster.WindowServer" hamster-3.0.3/po/000077500000000000000000000000001452646177100136135ustar00rootroot00000000000000hamster-3.0.3/po/.gitignore000066400000000000000000000001161452646177100156010ustar00rootroot00000000000000.intltool-merge-cache POTFILES stamp-it Makefile.in.in hamster.pot *.gmo *.mo hamster-3.0.3/po/LINGUAS000066400000000000000000000004341452646177100146410ustar00rootroot00000000000000# Please keep this list sorted alphabetically af ar as be bg bn bn_IN ca ca@valencia cs da de el en_CA en_GB en@shaw eo es et eu fi fr gl gu he hi hr hu id it ja kn ko ku lt lv mai mk ml mr nb nl or pa pl pt pt_BR ro ru si sl sq sr sr@latin sv ta te th tr ug uk vi zh_CN zh_HK zh_TW hamster-3.0.3/po/POTFILES.in000066400000000000000000000007451452646177100153760ustar00rootroot00000000000000# List of source files containing translatable strings. # Please keep this file sorted alphabetically. data/date_range.ui data/edit_activity.ui data/preferences.ui data/org.gnome.Hamster.GUI.desktop.in data/org.gnome.hamster.gschema.xml src/hamster-cli.py src/hamster/about.py src/hamster/edit_activity.py src/hamster/lib/stuff.py src/hamster/overview.py src/hamster/preferences.py src/hamster/reports.py src/hamster/widgets/activityentry.py src/hamster/widgets/reportchooserdialog.py hamster-3.0.3/po/POTFILES.skip000066400000000000000000000000071452646177100157250ustar00rootroot00000000000000build/ hamster-3.0.3/po/af.po000066400000000000000000000573311452646177100145520ustar00rootroot00000000000000# Afrikaans translation for hamster. # Copyright (C) 2011 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # jcbrand , 2011. # F Wolff , 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-12-07 09:56+0200\n" "Last-Translator: JC Brand \n" "Language-Team: translate-discuss-af@lists.sourceforge.net\n" "Language: af\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" "X-Generator: Virtaal 0.7.0-beta4\n" "X-Project-Style: gnome\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Voeg vorige taak by" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "tot" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "aan die gang" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Beskrywing:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Tyd:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Taak:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etikette:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Staak registrasie wanneer ledig" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Staak registrasie van huidige taak wanneer die rekenaar ledig word" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Staak registrasie tydens afskakel" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" "Staak registrasie van huidige taak wanneer die rekenaar afgeskakel word" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Herinner aan die huidige taak elke x minute" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "Herinner my aan die taak elke gespesifiseerde hoeveelheid minute." "Stel na 0 of groter as 120 om herinnerings af te skakel" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Herinner ook wanneer geen taak gestel is nie" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Herinner ook elke notify_interval minute indien daar met geen taak begin is " "nie." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Hoe laat begin die dag? (Verstekwaarde is 05:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Take sal onder gister val indien die huidige tyd minder as die gegewe dag se " "aanvangstyd is, maar onder vandag indien dit meer as daardie aanvangstyd is. " "Take wat oor twee dae strek, sal onder die dag verskyn waarin die meeste tyd " "gespandeer is." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Moet 'n wisseling van werkruimte ook 'n taakverandering teweegbring?" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "Lys van aktiewe tydregistrasie metodes. \"name\" bemoontlik die wisseling van " "take volgens naam, soos in die workspace_mapping gedefinieer. \"memory\" " "bemoontlik die wisseling na die vorige taak sodra daar na 'n werkruimte " "teruggekeer word." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Verander taak met wisseling van werkruimte" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Indien oorskakeling volgens naam aan is, sal hierdie lys die taakname stel " "waarheen oorgeskakel moet word, met die werkruimtes wat deur die item se " "indeks verteenwoordig word." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Wys / verskuil die Tydregister-venster" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Sleutelbordkortpad om die Tydregister venster te wys / verskuil." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Wissel hamster toepassing-venster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" "Bevel om die sigbaarheid van Hamster se toepassing-venster aan of af te " "skakel." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Wissel hamster toepassing-venster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Wissel sigbaarheid van hamster se toepassing-venster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tydregister" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projek Hamster - Tydregister" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Tydregistrasie Oorsig" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Oorsigblad van die hamster tydregister" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Wys statistiek" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorieë" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Take" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etikette" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Geen data vir hierdie tydgleuf" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Stoor verslag..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dag" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Week" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Maand" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Oorsig — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Oorsig" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Taak" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Aansig" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totale" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Verwyder" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Voeg nuwe by" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Redigeer" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Voorkeure vir Tydregister" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Staak tydregistrasie wanneer die rekenaar ledig word" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Herinner aan die huidige taak elke:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Nuwe dag begin teen" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Gebruik die volgende doenlys indien beskikbaar:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrasie" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Tydregistrasie" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorieë" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategorielys" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Voeg kategorie by" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Verwyder kategorie" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Redigeer kategorie" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Take" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Taaklys" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Voeg taak by" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Verwyder taak" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Redigeer taak" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etikette wat in outovoltooi moet verskyn" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorieë en etikette" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Hervat die laaste taak wanneer na 'n werkruimte teruggekeer word" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Begin 'n nuwe taak wanneer werkruimtes gewissel word:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Werkruimtes" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dag:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Week:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Maand:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Omvang:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Pas toe" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Tydregistrasie" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Voeg vorige taak by" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Oorsig" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistiek" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "R_edigeer" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Hulp" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Inhoud" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_p taak" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Wissel" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Begin _taak" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Begin met 'n nuwe taak" #: ../data/today.ui.h:13 msgid "Today" msgstr "Vandag" #: ../data/today.ui.h:14 msgid "totals" msgstr "Totale" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Wys Oorsig" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Geen take" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorie" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Beskrywing" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Begin" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Einde" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durasie" #: ../src/hamster-cli:308 msgid "Uncategorized" msgstr "Ongekategoriseerd" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projek Hamster — hou u tyd dop" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Kopiereg © 2007–2010 Toms Bauģis en andere" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Projek Hamster Webwerf" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Aangaande" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "J-C Brand\n" "F Wolff" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Ongesorteer" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Werk" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Lees die nuus" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Beloer aandele" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Uiters geheime projek X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Wêrelddominasie" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dag-tot-dag" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Middagete" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Gee die blommetjies water" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Doen bollemakiesies" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Redigeer taak" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ure in totaal geregistreer" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Geen" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Naam" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nuwe kategorie" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nuwe taak" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuut" msgstr[1] "%(interval_minutes)d minute" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nooit" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "taak" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "begintyd" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "eindtyd" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duur in minute" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorie" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "beskrywing" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etikette" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Aktiwiteitsverslag vir %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Aktiwiteitsverslag vir %(start_d)s %(start_B)s – %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Aktiwiteitsve rslag vir %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Aktiwiteitsverslag vir %(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totale per dag" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Taaklog" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "take" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorieë" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Onderskeiding:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Wys sjabloon" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Dit kan oorskryf word met 'n eie weergawe in %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Alle" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Daar is nog geen data om mee statistiek te genereer nie.\n" "'n Week van gebruik sal werk!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Versamel tans data — kom kyk weer na 'n week verby is!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Eerste taak is op %s geregistreer." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s jaar" msgstr[1] "%(num)s jare" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tyd sover geregistreer is %(human_days)s mensdae (%(human_years)s) of " "%(working_days)s werkdae (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Die langste aaneenlopende werk is gedoen op %(date)s en was %(hours)s uur " "lank." msgstr[1] "" "Die langste aaneenlopende werk is gedoen op %(date)s en was %(hours)s ure " "lank." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Daar is %s rekord." msgstr[1] "Daar is %s rekords." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster wil u graag nog 'n bietjie langer dophou!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Met %s persent van alle take wat voor 09:00 begin, spring u vroeg aan die " "werk." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "Met %s persent van alle take wat na 23:00 begin, lyk u na 'n naguil." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Met %s persent van alle take korter as 15 minute, lyk u na 'n besige by." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Geen rekords vandag" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%su" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Sopas begin" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Stoor verslag — Tydregister" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-verslag" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-geskeide waardes (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Tydregister" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "Projek Hamster (GNOME-tydregistreerder)" #~ msgid "_About" #~ msgstr "_Aangaande" #~ msgid "_Preferences" #~ msgstr "_Voorkeure" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_p registrasie" #~ msgid "To_day" #~ msgstr "Van_dag" #~ msgid "_Add earlier activity" #~ msgstr "Voeg _vorige taak by" #~ msgid "Starts and ends" #~ msgstr "Begin en eindig" #~ msgid "Year:" #~ msgstr "Jaar:" #~ msgid "Preferences" #~ msgstr "Voorkeure" #~ msgid "Changed activity" #~ msgstr "Veranderde taak" #~ msgid "Switched to '%s'" #~ msgstr "Oorgeskakel na '%s'" #~ msgid "Working on %s" #~ msgstr "Werk tans aan %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster-tydregistreerder. Gebruik:" hamster-3.0.3/po/ar.po000066400000000000000000000733341452646177100145670ustar00rootroot00000000000000# Arabic translations for gnome package. # Copyright (C) 2008 THE gnome'S COPYRIGHT HOLDER # This file is distributed under the same license as the gnome package. # Anas Afif Emad, , 2008. # Khaled Hosny , 2009, 2010, 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: gnome 2-24\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2011-02-13 23:17+0300\n" "Last-Translator: Khaled Hosny \n" "Language-Team: Arabic \n" "Language: ar\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n" "X-Generator: Virtaal 0.6.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "أضف نشاطا سابقا" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "إلى" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "جارٍ" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "الوصف:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "الوقت:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "النّشاط:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "الوسوم:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "أوقف التتبع عند الخمول" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "أوقف تتبع النشاط الحالي عندما يصبح الحاسوب خاملًا" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "أوقف التتبع عند إيقاف التشغيل" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "أوقف تتبع النشاط الحالي عند إيقاف التشغيل" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ذكّر بالمهمة الحالية كل س من الدقائق" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "ذكّر بالمهمة الحالية كلما مرت المدة المحددة بالدقائق. اجعلها 0 أو أكبر من 120 " "لتعطيل التذكير." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "ذكر أيضا عند عدم ضبط أي نشاط" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "ذكّر أيضا كل notify_interval دقائق إذا لم يُبدأ أي نشاط" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "إظهار وإخفاء نافذة مقتفي الوقت" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "اختصار لوحة المفاتيح لإظهار وإخفاء نافذة مقتفي الوقت" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "متتبع الوقت" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "مشروع هامستر - تتبع وقتك" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "متتبع الوقت" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "اعرض الإحصائيّات" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "الفئات" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "الأنشطة" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "الوسوم" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "لا بيانات عن هذه الفترة" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "احفظ التقرير..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "يوم" #: ../data/overview.ui.h:3 msgid "Week" msgstr "أسبوع" #: ../data/overview.ui.h:4 msgid "Month" msgstr "شهر" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "نظرة عامة — هامستر" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_نظرة عامة" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "نشاط" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_عرض" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "المجموع" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "أزِل" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "أضِف جديدا" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "حرّر" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "تفضيلات متتبع الوقت" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "أوقف التتبع عندما يصبح الحاسوب خاملًا" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ذكّر بالنشاط الحلي كل:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "يبدأ اليوم عند" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "استخدم قائمة المهام التالية إن توفرت:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "التكامل" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "التتبع" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ال_فئات" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "قائمة الفئات" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "أضف فئة" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "أزل الفئة" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "حرّر الفئة" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "الأ_نشطة" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "قائمة الأنشطة" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "أضف نشاطا" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "أزل النشاط" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "حرّر النّشاط" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "الوسوم التي ستظهر في الإكمال التلقائي" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "الفئات والوسوم" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "استكمل آخر نشاط عند العودة إلى مساحة عمل" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "ابدأ نشاطا جديدا عند التبديل بين مساحات العمل:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "مساحات العمل" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "يوم:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "أسبوع:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "شهر:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "مدى:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "طبّق" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "ال_تتبع" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "أضف نشاطا سابقا" #: ../data/today.ui.h:4 msgid "Overview" msgstr "نظرة عامة" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "الإحصائيّات" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_حرّر" #: ../data/today.ui.h:7 msgid "_Help" msgstr "م_ساعدة" #: ../data/today.ui.h:8 msgid "Contents" msgstr "المحتويات" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "أو_قف التتبع" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "ب_دّل" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "ا_بدأ التتبع" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "ابدأ نشاطا جديدا" #: ../data/today.ui.h:13 msgid "Today" msgstr "اليوم" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "المجموع" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "أظهر _نظرة عامة" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "لا أنشطة" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "الفئة" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "الوصف" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "البداية" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "النهاية" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "المدّة" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "الفئات" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "مشروع هامستر — تتبع وقتك" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "حقوق النشر © 2007–2010 توم باوغيس وآخرون" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "موقع مشروع هامستر" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "عن متتبع الوقت" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "فريق عربآيز للترجمة http://www.arabeyes.org:\n" "أنس عفيف عماد\t\n" "خالد حسني\t\t" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "غير مرتّب" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "عمل" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "قراءة الأخبار" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "مراقبة الأسهم" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "المشروع س السرّي للغاية" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "السيطرة على العالم" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "الأعمال المعتادة" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "الغداء" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "سقي الأزهار" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "الوقوف على اليدين" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "حدّث النّشاط" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d ساعة" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d دقيقة" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d ساعة %d دقيقة" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B، %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s، %(start_Y)s – %(end_d)s %(end_B)s، %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s، %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s، %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A، %d %B" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ساعات متتبعة إجمالا" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "بدون" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "الاسم" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "فئة جديدة" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "نشاط جديد" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d دقائق" msgstr[1] "%(interval_minutes)d دقائق" msgstr[2] "%(interval_minutes)d دقائق" msgstr[3] "%(interval_minutes)d دقائق" msgstr[4] "%(interval_minutes)d دقائق" msgstr[5] "%(interval_minutes)d دقائق" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "أبدا" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "النشاط" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "وقت البدء" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "وقت الانتهاء" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "المدة بالدقائق" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "الفئة" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "الوصف" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "وسوم" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "تقرير نشاط %(start_d)s %(start_B)s، %(start_Y)s – %(end_d)s %(end_B)s، " "%(end_Y)s " #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "تقرير نشاط %(start_d)s %(start_B)s – %(end_d)s %(end_B)s، %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "تقرير نشاط %(start_d)s %(start_B)s، %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "تقرير نشاط %(start_d)s %(start_B)s – %(end_d)s، %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %B، %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "المجموع باليوم" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "سجل النشاط" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "الأنشطة" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "الفئات" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "التمييز:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "التاريخ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "أظهر القالب" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "يمكنك تخطيه بحفظ نسختك في ‪%(home_folder)s‬" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "الكل" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "لا توجد بيانات لتوليد الإحصائيات.\n" "أسبوع من الاستخدام سيكون مناسبا." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "يجمع البيانات — عد بعد أسبوع." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d، %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %B" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "سُجّل أول نشاط في %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "ولا سنة" msgstr[1] "سنة واحدة" msgstr[2] "سنتين" msgstr[3] "%(num)s سنوات" msgstr[4] "%(num)s سنة" msgstr[5] "%(num)s سنة" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "الوقت المتتبع حتى الآن %(human_days)s من الأيام العادية (%(human_years)s) أو " "%(working_days)s من أيام العمل (%(working_years)s)" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%B %d، %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "أطول عمل متصل حدث في %(date)s وكان %(hours)s ساعة." msgstr[1] "أطول عمل متصل حدث في %(date)s وكان ساعة واحدة." msgstr[2] "أطول عمل متصل حدث في %(date)s وكان ساعتين." msgstr[3] "أطول عمل متصل حدث في %(date)s وكان %(hours)s ساعات." msgstr[4] "أطول عمل متصل حدث في %(date)s وكان %(hours)s ساعة." msgstr[5] "أطول عمل متصل حدث في %(date)s وكان %(hours)s ساعة." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "لا تسجيلات." msgstr[1] "يوجد تسجيل واحد." msgstr[2] "يوجد تسجيلين." msgstr[3] "يوجد %s تسجيلات." msgstr[4] "يوجد %s تسجيلا." msgstr[5] "يوجد %s تسجيل." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "يريد هامستر مراقبتك لمدة أطول." #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "مع نسبة %s من كل الحقائق تبدأ قبل 9ص، يظهر أنك شخص مبكّر." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "مع نسبة %s من كل الحقائق تبدأ بعد 11م، يظهر أنك كائن ليلي." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "مع نسبة %s من كل الحقائق أقل من 15 دقيقة، يظهر أنك نحلة مشغولة." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "لا سجلّات اليوم" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sس" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "بدأ للتو" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "احفظ التقرير — متتبع الوقت" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "تقرير HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "قيم مفصولة بفاصلة (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "مسار الوقت" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "مشروع هامستر (متتبع الوقت لجنوم)" #~ msgid "_About" #~ msgstr "_عن" #~ msgid "_Preferences" #~ msgstr "ال_تفضيلات" #~ msgid "Sto_p Tracking" #~ msgstr "أو_قف التتبع" #~ msgid "To_day" #~ msgstr "ا_ليوم" #~ msgid "_Add earlier activity" #~ msgstr "أ_ضف نشاطا سابقا" #~ msgid "Starts and ends" #~ msgstr "البداية والنهاية" #~ msgid "Year:" #~ msgstr "سنة:" #~ msgid "Preferences" #~ msgstr "التفضيلات" #~ msgid "Changed activity" #~ msgstr "نشاط تغير" #~ msgid "Switched to '%s'" #~ msgstr "انتقل إلى '%s'" #~ msgid "Working on %s" #~ msgstr "يعمل على %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "متتبع الوقت هامستر. الاستخدام:" #~ msgid "totals by activity" #~ msgstr "المجموع بالنشاط" #~ msgid "totals by category" #~ msgstr "المجموع بالفئة" #~ msgid "Show:" #~ msgstr "أظهر:" #~ msgid "Activities" #~ msgstr "الأنشطة" #~ msgid "Global Hotkey" #~ msgstr "مفتاح الاختصار العام" #~ msgid "Tracking" #~ msgstr "التتبع" #~ msgid "Move activity down" #~ msgstr "انقل النشاط لأسفل" #~ msgid "Move activity up" #~ msgstr "انقل النشاط لأعلى" #~ msgid "Preview:" #~ msgstr "معاينة:" #~ msgid "Show window" #~ msgstr "أظهر النافذة" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "اكتب نشاطا ثم اضغط مفتاح الإدخال ليبدأ التتبع" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "أخبرني بالمزيد" #~ msgid "Ad_d Earlier Activity" #~ msgstr "أ_ضف نشاطًا سابقًا" #~ msgid "Hamster" #~ msgstr "هامستر" #~ msgid "_Activity:" #~ msgstr "ال_نّشاط:" #~ msgid "_Today" #~ msgstr "ال_يوم" #~ msgid " _Day" #~ msgstr " ي_وم" #~ msgid " _Month" #~ msgstr " _شهر" #~ msgid " _Week" #~ msgstr " _أسبوع" #~ msgid "Overview" #~ msgstr "نظرة عامة" #~ msgid "Totals" #~ msgstr "المجموع" #~ msgid "Categories:" #~ msgstr "الفئات:" #~ msgid "Date interval:" #~ msgstr "الفترة الزمنية:" #~ msgid "Save as HTML" #~ msgstr "احفظ بنسق HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "ماذا سيُكتب في صندوق النشاط؟" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "يوجد تنسيق بسيط جدا يتيح لك إضافة التفاصيل إلى أنشطتك:\n" #~ "\n" #~ "علامة \"@\" تعني فئة. مثلا \"ري الأزهار@البيت\" ستبدأ في تتبع النشاط \"ري " #~ "الأزهار\" في الفئة \"البيت\"\n" #~ "\n" #~ "الفاصلة (\",\") تحدد بداية الوصف. مثلا: \"ري الأزهار, الفل والياسمين\" " #~ "ستبدأ في تتبع النشاط \"ري الأزهار\" وتضيف إليه الوصف \"الفل والياسمين\".\n" #~ "\n" #~ "ويمكن جمعهما معا \"ري الأزهار@البيت, الفل والياسمين\".\n" #~ "\n" #~ "والآن، ابدأ التتبع." #~ msgid "Total Time" #~ msgstr "الوقت الكلي" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "الكل" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "المجموع" #~ msgid "Overview for %(date)s" #~ msgstr "نظرة على %(date)s" #~ msgid "Time tracking for masses" #~ msgstr "مقتفي الوقت للجماهير" #~ msgid "Move _Down" #~ msgstr "إنتقل للأ_سفل" #~ msgid "Move _Up" #~ msgstr "إنتقل للأ_على" #~ msgid "N_ew Category" #~ msgstr "_فئة جديدة" #~ msgid "_New Activity" #~ msgstr "نشاط _جديد" #~ msgid "Activity" #~ msgstr "النشاط" #~ msgid "hours" #~ msgstr "ساعات" #~ msgid "Category" #~ msgstr "الفئة" #~ msgid "Week" #~ msgstr "أسبوع" #~ msgid "Delete activity" #~ msgstr "إحذف نشاط" #~ msgid "Earlier activities" #~ msgstr "الأنشطة السابقة" #~ msgid "Generate Report" #~ msgstr "ولّد تقريراً" #~ msgid "Newer activities" #~ msgstr "الأنشطة الأحدث" #~ msgid "Show month" #~ msgstr "أظهر الشهر" #~ msgid "Time tracking for masses." #~ msgstr "مقتفي الوقت للجماهير." #~ msgid "name" #~ msgstr "الاسم" #~ msgid "Other" #~ msgstr "أخرى" #~ msgid "Overview for %s - %s" #~ msgstr "لمحة عن %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%d.%m.%y" #~ msgid "%d. %b" #~ msgstr "%d. %b" #~ msgid "%B %d." #~ msgstr "%B %d." hamster-3.0.3/po/as.po000066400000000000000000001060141452646177100145600ustar00rootroot00000000000000# Assamese translation for hamster. # Copyright (C) 2009 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # Nilamdyuti Goswami , 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-12 12:34+0530\n" "Last-Translator: Nilamdyuti Goswami \n" "Language-Team: as_IN \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" "X-Generator: Lokalize 1.0\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "পূৰ্ববৰ্তী কাম যোগ কৰক" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "গন্তব্য" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "চলমান" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "বিৱৰণ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "সময়:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "কাম:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "টেগসমূহ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "কামহীন অৱস্থাত বৰ্তমান কামৰ নিৰীক্ষণ বন্ধ কৰা হ'ব" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "কম্পিউটাৰ কামহীন অৱস্থাত হ'লে বৰ্তমান কামৰ নিৰীক্ষণ বন্ধ কৰা হ'ব" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "কম্পিউটাৰ বন্ধ হ'লে ট্ৰেক কৰা বন্ধ কৰক" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "বন্ধ কৰা হ'লে বৰ্তমান কামৰ নিৰীক্ষণ বন্ধ কৰা হ'ব" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "প্ৰতি x মিনিট অন্তৰ বৰ্তমান কামৰ বিষয়ে স্মৰণ কৰোৱা হ'ব" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "মিনিটে ধাৰ্য সুনিৰ্দিষ্ট সময়ৰ অন্তৰত বৰ্তমান কাম সম্বন্ধে স্মৰণ কৰোৱা হ'ব । স্মৰণ " "ব্যৱস্থা নিষ্ক্ৰিয় কৰাৰ বাবে ০ বা ১২০ ৰ পৰা অধিক কোনো সংখ্যা নিৰ্ধাৰণ কৰক ।" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "কোনো কাম নিৰ্ধাৰিত ন'হ'লে সূচিত কৰা হ'ব" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "কোনো কাম আৰম্ভ নকৰিলে প্ৰতি notify_interval মিনিটত সূচনা প্ৰদান কৰা হ'ব ।" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "কি সময়ত দিনটো আৰম্ভ হয় (অবিকল্পিত ৫:৩০ লে)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "যদি বৰ্তমান সময ধাৰ্য্য কৰা আৰম্ভনী তাৰিখত আৰু আজিৰ তাৰিখতকে কম হয়; তেনেহলে " "কাৰ্য্যসমূহক যোৱাকালিৰ বুলি ধৰি গণনা কৰা হ'ব, যদি ই সময় পাৰ কৰিছে, তেনেহলে " "যিসমূহ কাৰ্য্যত দুদিনৰ বেছি লাগে, সেইবোৰ সেইফালে যাব যিফালে কাৰ্য্যৰ বৃহতম ভাগ আছে।" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "কৰ্মস্থানে ট্ৰিগাৰ কাৰ্য্য অদল-বদল কৰিব লাগে নে" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "সামৰ্থবান অনুসৰণ পদ্ধতিসমূহৰ তালিকা। \"name\" -এ workspace_mapping -ত নামেৰে " "বুজুৱা অদল-বদল কাৰ্য্যসমূহকসামৰ্থবান কৰিব। \"memory\" -এ পূৰৱৰ্তী কৰ্মস্থানলৈ ঘূৰী " "যাওতে সৰ্বশেষ কাৰ্য্যলে যোৱাটো সামৰ্থবান কৰিব।" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "কৰ্মস্থান সলনি হওতে কাৰ্য্য অদল-বদল কৰা" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "যদি নামেৰে অদল-বদল কৰা সামৰ্থবান হয়, তেনেহলে এই তালিকায় অদল-বদল হ'ব লগিয়া " "কাৰ্য্যৰ নামসমূহ, বস্তুৰ ইনডেক্স দি প্ৰতিৰূপন হোৱা কাৰ্য্যস্থানসমূহলে সংস্থাপন কৰে।" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "সময় অনুসৰণৰ উইন্ডো দেখুৱা/লুকোৱা" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "সময় অনুসৰণৰ উইন্ডো দেখুৱাবলে/লুকাবলে কিবৰ্ড ছৰ্টকাট।" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "hamster অনুপ্ৰয়োগ উইন্ডো কাৰ্য্যক অদল-বদল কৰা" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "hamster অনুপ্ৰয়োগ উইন্ডোৰ দৃশ্যমানতা অদল-বদল কৰিবৰ বাবে কমান্ড।" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "hamster অনুপ্ৰয়োগ উইন্ডোক অদল-বদল কৰা" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "hamster অনুপ্ৰয়োগ উইন্ডোৰ দৃশ্যমানতাক অদল-বদল কৰা।" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "সময় অনুসৰণ" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster - আপোনাৰ সময় অনুসৰণ কৰক" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "সময় অনুকৰণ অভাৰভিউ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "hamster সময় অনুকৰকৰ অভাৰভিউ উইন্ডো" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "পৰিসংখ্যা দেখুৱাওক" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "বিভাগসমূহ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "কাৰ্য্যসমূহ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "টেগসমূহ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "এই ব্যৱধানত কোনো তথ্য উপস্থিত নাই" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "প্ৰতিবেদন সঞ্চয় কৰক..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "দিন" #: ../data/overview.ui.h:3 msgid "Week" msgstr "সপ্তাহ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "মাহ" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "সংক্ষিপ্ত তথ্য - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "সংক্ষিপ্ত তথ্য (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "কাম" #: ../data/overview.ui.h:8 msgid "_View" msgstr "দৰ্শন কৰক (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "মুঠ" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "আতৰাওক" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "নতুন যোগ কৰক" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "সম্পাদনা" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "সময় অনুসৰণ ব্যৱস্থা সম্পৰ্কিত পছন্দ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "কম্পিউটাৰ কামহীন অৱস্থাত থাকিলে সময় অনুসৰণ বন্ধ কৰা হ'ব" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "বৰ্তমান কাম সম্বন্ধে স্মৰণ কৰোৱা প্ৰতি:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "নতুন দিন আৰম্ভ হয়" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "যদি উপলব্ধ আছে তেনেহলে নিম্নলিখীত todo তালিকা ব্যৱহাৰ কৰক" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "অনুকলন" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "অনুসৰণ কৰা হৈ আছে" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "বিভাগ (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "বিভাগৰ তালিকা" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "বিভাগ যোগ কৰক" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "বিভাগ আঁতৰাওক" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "বিভাগ সম্পাদনা" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "কাম (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "কামৰ তালিকা" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "কাম যোগ কৰক" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "কাম আঁতৰাওক" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "কাম সম্পাদনা" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "টেগসমূহ স্বয়ংসম্পূৰ্ণত দেখা দিব লাগে" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "বিভাগসমূহ আৰু টেগসমূহ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "কৰ্মস্থানলৈ উভতি যাওতে সৰ্বশেষ কাৰ্য্য চলাই থাকা" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "কৰ্মস্থানসমূহ অদল-বদল কৰোতে নতুন কাৰ্য্য আৰম্ভ কৰক:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "কৰ্মস্থানসমূহ" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "দিন:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "সপ্তাহ:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "মাহ:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "বিস্তাৰ:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "প্ৰয়োগ কৰা" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "অনুসৰণ কৰা হৈ আছে (_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "পূৰ্ববৰ্তী কাৰ্য্য যোগ কৰক" #: ../data/today.ui.h:4 msgid "Overview" msgstr "সংক্ষিপ্ত তথ্য" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "পৰিসংখ্যা" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "সম্পাদন (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "সহায় (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "সমলসমূহ" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "অনুসৰণ বন্ধ কৰক (_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "কাম পৰিবৰ্তন (_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "অনুসৰণ আৰম্ভ কৰক (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "নতুন কাৰ্য্য আৰম্ভ কৰক" #: ../data/today.ui.h:13 msgid "Today" msgstr "আজি" #: ../data/today.ui.h:14 msgid "totals" msgstr "সৰ্বমুঠসমূহ" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "অভাৰভিউ দেখুৱাওক" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "কোনো কাম হোৱা নাই" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "শ্ৰেণী" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "বিৱৰণ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "আৰম্ভ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "সমাপ্তি" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "অৱকাল" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "বিভাগসমূহ" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster - সময় অনুসৰণ কৰক" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "স্বত্বাধিকাৰ © ২০০৭-২০০৯ Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "প্ৰকল্প Hamster ৱেব-ছাইট" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "সময় অনুসৰণ ব্যৱস্থাৰ বিষয়ে" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "অমিতাক্ষ ফুকন (aphukan@fedoraproject.org)" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "অনুক্ৰম বিহীন" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "কাম" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "সংবাদ পাঠ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "স্টকৰ বাতৰি" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "অত্যন্ত গোপনীয় প্ৰকল্প X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "বিশ্বৰ ওৰত ৰাজত্ব" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "দৈনন্দিন" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "মধ্যভোজ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ফুল গছত পানি দিয়া" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "যোগাসন" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "কাম উন্নহয়ন কৰক" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "সৰ্বমুঠ %s ঘন্টাসমূহ অনুসৰণ কৰা হৈছে" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "কোনো নহয়" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "নাম" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "নতুন বিভাগ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "নতুন কাম" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d মিনিট" msgstr[1] "%(interval_minutes)d মিনিট" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "কেতিয়াও নহয়" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "কাম" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "আৰম্ভৰ সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "সমাপ্তিৰ সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "মিনিটত অৱকাল" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "বিভাগ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "বিৱৰণ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "টেগসমূহ" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" " %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s -ৰ " "বাবে কাৰ্য্য প্ৰতিবেদন" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s -ৰ বাবে কাৰ্য্য " "প্ৰতিবেদন" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s -ৰ বাবে কাৰ্য্য প্ৰতিবেদন" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s -ৰ বাবে কাৰ্য্য প্ৰতিবেদন" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "দিনৰ হিচাপত সৰ্বমূঠ" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "কাৰ্য্য লগ" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "কাৰ্য্যসমূহ" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "বিভাগসমূহ" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "পৃথক কৰা:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "তাৰিখ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "টেমপ্লেইট দেখুৱা" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "আপুনি আপোনাৰ সংস্কৰণক %(home_folder)s -ত সঞ্চয় কৰি ইয়াক অভাৰৰাইড কৰিব পাৰে" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "সকলো" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "পৰিসংখ্যান নিৰ্মাণৰ বাবে কোনো তথ্য উপস্থিত নাই ।\n" "এক সপ্তাহ ব্যৱহাৰৰ পিছত পৰ্যাপ্ত তথ্য উপলব্ধ হ'ব!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "এতিয়াও তথ্য সংগ্ৰহ কৰা হৈছে — এসপ্তাহ পিছত পুনৰায় পৰীক্ষা কৰক!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "প্ৰথম কামৰ তথ্য %s ত ৰেকৰ্ড কৰা হৈছে ।" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s বছৰ" msgstr[1] "%(num)s বছৰ" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "সময় অনুসৰণৰ কাল: %(human_days)s দিন (%(human_years)s) বা %(working_days)s " "কামৰ দিন (%(working_years)s) ।" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "%(date)s তাৰিখত %(hours)s ঘন্টা কাম দীৰ্ঘসময়কাল কাম ৰূপে চিহ্নিত কৰা হৈছে" msgstr[1] "%(date)s তাৰিখত %(hours)s ঘন্টা কাম দীৰ্ঘসময়কাল কাম ৰূপে চিহ্নিত 
কৰা হৈছে" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s ৰেকৰ্ড উপস্থিত আছে ।" msgstr[1] "%s ৰেকৰ্ড উপস্থিত আছে ।" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster আৰু কিছু সময়ৰ বাবে আপোনাৰ কাম নিৰীক্ষণ কৰিবলৈ ইচ্ছুক!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s শতাংশ কাম ৰাতিপুৱা ৯টাৰ আগতে আৰম্ভ হোৱাৰ মানে, আপুনি সোণকালেই কাম আৰম্ভ কৰা " "যেন লাগিছে।" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s শতাংশ কাম ৰাতি ১১ টাৰ পিছত আৰম্ভ হোৱা মানে, আপুনি ৰাতি কাম কৰি ভাল পায় যেন " "লাগিছে।" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "%s শতাংশ কাম ১৫ মিনিটতকৈ কাম সময়ৰ মানে, আপুনি বৰ ব্যস্ত যেন লাগিছে।" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "আজিৰ কোনো তথ্য উপস্থিত নাই" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "এইমাত্ৰ আৰম্ভ হৈছে" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "প্ৰতিবেদন সঞ্চয় কৰক - সময় অনুসৰণ" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML ৰিপোৰ্ট" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "টেব দ্বাৰা বিভাজিত মান (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "সময় অনুসৰণ" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "কাৰ্য্যসমূহ উইন্ডো দেখুৱাওক" #~ msgid "Sto_p Tracking" #~ msgstr "অনুসৰণ বন্ধ কৰক (_p)" #~ msgid "To_day" #~ msgstr "আজি (_d)" #~ msgid "_Add earlier activity" #~ msgstr "পূৰ্ববৰ্তী কাৰ্য্য যোগ কৰক (_A)" #~ msgid "Show _Overview" #~ msgstr "সংক্ষিপ্ত তথ্য প্ৰদৰ্শন কৰা হ'ব (_O)" #~ msgid "_Preferences" #~ msgstr "পছন্দ (_P)" #~ msgid "_About" #~ msgstr "বিষয়ে (_A)" #~ msgid "Year:" #~ msgstr "বছৰ:" #~ msgid "Starts and ends" #~ msgstr "আৰম্ভ হয় আৰু সমাপ্ত হয়" #~ msgid "Preferences" #~ msgstr "পছন্দসমূহ" #~ msgid "Changed activity" #~ msgstr "সলনি হোৱা কাৰ্য্য" #~ msgid "Switched to '%s'" #~ msgstr "'%s' লে অহা হল" #~ msgid "Working on %s" #~ msgstr "%s ত কাম কৰা হৈছে" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster সময় নিৰিক্ষক। ব্যৱহাৰ:" #~| msgid "Project Hamster Website" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "প্ৰকল্প Hamster (Gnome সময় অনুসৰণ)" #~ msgid "Activities" #~ msgstr "কাম" #~ msgid "Global Hotkey" #~ msgstr "সাৰ্বজনীন হট-কি" #~ msgid "Tracking" #~ msgstr "অনুসৰণ" #~ msgid "Move activity down" #~ msgstr "কাম তললৈ স্থানান্তৰ কৰক" #~ msgid "Move activity up" #~ msgstr "কাম ওপৰলৈ স্থানান্তৰ কৰক" #~ msgid "Preview:" #~ msgstr "পূৰ্বদৃশ্য:" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "কোনো কামৰ অনুসৰণ আৰম্ভৰ বাবে কামৰ নাম লিখক আৰু Enter " #~ "টিপক!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "অধিক বিৱৰণ" #~ msgid "Ad_d Earlier Activity" #~ msgstr "পূৰ্ববৰ্তী কাম যোগ কৰক (_d)" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "কাম: (_A)" #~ msgid "_Today" #~ msgstr "আজি (_T)" #~ msgid " _Day" #~ msgstr "দিন (_D)" #~ msgid " _Month" #~ msgstr "মাহ (_M)" #~ msgid " _Week" #~ msgstr "সপ্তাহ (_W)" #~ msgid "Overview" #~ msgstr "সংক্ষিপ্ত তথ্য" #~ msgid "Totals" #~ msgstr "মুঠ" #~ msgid "Categories:" #~ msgstr "বিভাগ:" #~ msgid "Date interval:" #~ msgstr "তাৰিখৰ ব্যৱধান:" #~ msgid "Save as HTML" #~ msgstr "HTML ৰূপে সংৰক্ষণ কৰক" #~ msgid "What should be typed in the activity box?" #~ msgstr "কাম চিহ্নকাৰী বক্সত কি লিখা হ'ব?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "কামৰ সৈতে বিৱৰণ সংযোজনৰ বাবে এটা সহজ চিন্টেক্স উপস্থিত আছে:\n" #~ "
 \n" #~ "\"@\" চিহ্ন দ্বাৰা এটা শ্ৰেণী চিহ্নিত কৰা হয় । উদাহৰণ: \"watering flowers@home" #~ "\" লিখা হ'লে \"home\" শ্ৰেণীৰ অধিন উপস্থিত \"watering flowers\" কাম নিৰীক্ষণ " #~ "কৰা হ'ব ।\n" #~ "\n" #~ "(\",\") চিহ্ন দ্বাৰা বিৱৰণৰ প্ৰাৰম্ভ চিহ্নিত কৰা হয় । উদাহৰণ: \"watering " #~ "flowers, begonias and forgetmenots\" লিখা হ'লে \"watering flowers\" কাম " #~ "অনুসৰণ কৰা হ'ব আৰু \"begonias and forgetmenots\" বিৱৰণৰ সৈতে যোগ কৰা হ'ব ।\n" #~ "
\n" #~ "ওপৰলৈ উল্লিখিত দুটা বিন্যাস একেলগেও লিখা যাব: \"watering flowers@home, " #~ "begonias 
and forgetmenots\" \n" #~ "\n" #~ "কাম অনুসৰণ আৰম্ভ কৰক!\n" #~ " " #~ msgid "Total Time" #~ msgstr "মুঠ সময়" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "সকলো" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "মুঠ" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s ৰ সংক্ষিপ্ত তথ্য" hamster-3.0.3/po/be.po000066400000000000000000000675141452646177100145560ustar00rootroot00000000000000# Belarusian translation of hamster. # Copyright (C) 2009 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Alexander Nyakhaychyk , 2009. # Kasia Bondarava , 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-11 22:50+0300\n" "Last-Translator: Kasia Bondarava \n" "Language-Team: Belarusian \n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Virtaal 0.6.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Ранейшы занятак" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "да" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "у працэсе" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Апісанне:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Час:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Занятак:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Цэтлікі:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Спыніць адсочванне ў стане бяздзейнасці" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Спыніць адсочванне бягучага занятку, калі камп'ютар становіцца бяздзейным" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Спыніць адсочванне пры спыненні працы" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Спыніць адсочванне бягучага занятку пры спыненні працы" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Нагадваць пра бягучае заданне кожныя x хвілін" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Нагадваць пра бягучае заданне праз вызначаную колькасць хвілін. Значэнне 0 " "ці большае за 120 адключае нагадванне." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Таксама нагадваць, калі ніякі занятак не вызначаны" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Таксама нагадваць кожныя notify_interval хвілін, калі ніякі занятак не " "пачаты." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Калі пачынаецца дзень (прадвызначана а 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Занятак лічыцца ўчорашнім, калі бягучы час меншы за вызначаны час пачатку " "дня, і сённяшнім, калі гэты час большы. Занятак, расцягнуты на два дні, " "будзе аднесены да таго дня, у які дзейнасць была больш працяглай." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Ці павінна пераключэнне прасторы працы выклікаць пераключэнне занятку" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Спіс уключаных спосабаў адсочвання. \"name\" - уключыць пераключэнне " "заняткаў па назве, у адпаведнасці са значэннем ключа \"workspace_mapping\"; " "\"memory\" - уключыць пераключэнне на апошні занятак пры вяртанні на " "папярэднюю прастору працы." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Пераключаць занятак пры змяненні прасторы працы" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Калі ўключана пераключэнне па назве, гэты спіс прызначае назвы заняткаў для " "пераключэння, прасторы працы, прадстаўленыя індэксамі элементаў." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Ці трэба паказваць акно Трэкера часу" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Клавіятурны скарот для паказу ці хавання акна Трэкера часу." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Дзеянне пераключэння акна праграмы hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Загад для змянення бачнасці акна праграмы hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Пераключэнне акна праграмы hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Пераключыць бачнасць акна праграмы hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Трэкер часу" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Праект Hamster - адсочванне свайго часу" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Агляд Трэкера часу" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Акно агляду Трэкера часу hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Паказаць статыстыку" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Катэгорыі" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Заняткі" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Цэтлікі" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Няма даных для гэтага прамежку" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Захаваць справаздачу..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Дзень" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Тыдзень" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Месяц" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Агляд — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Агляд" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Занятак" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Паглядзець" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Агулам" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Выдаліць" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Дадаць" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Рэдагаваць" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Настройкі Трэкера часу" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Спыняць адсочванне, калі камп'ютар становіцца бяздзейным" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Нагадваць аб бягучым занятку кожныя:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Новы дзень пачынаецца а" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Ужыць наступны спіс спраў, калі ён даступны:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Інтэграцыя" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Адсочванне" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Катэгорыі" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Спіс катэгорыяў" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Дадаць катэгорыю" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Выдаліць катэгорыю" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Рэдагаваць катэгорыю" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Заняткі" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Спіс заняткаў" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Дадаць занятак" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Выдаліць занятак" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Рэдагаваць занятак" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Цэтлікі, даступныя пры аўтаматычным дапаўненні" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Катэгорыі і цэтлікі" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Узнаўляць апошні занятак па вяртанні на прастору працы" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Пачынаць новы занятак па пераключэнні прасторы працы:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Прасторы працы" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Дзень:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Тыдзень:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Месяц:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Дыяпазон:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Ужыць" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Адсочванне" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Дадаць ранейшы занятак" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Агляд" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статыстыка" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Рэдагаваць" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Дапамога" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Змест" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Спыніць адсочванне" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Пера_ключыць" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Пачаць адсочванне" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Пачаць новы занятак" #: ../data/today.ui.h:13 msgid "Today" msgstr "Сёння" #: ../data/today.ui.h:14 msgid "totals" msgstr "агулам" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Паказаць агляд" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Няма занятку" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Катэгорыя" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Апісанне" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Пачатак" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Канец" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Працягласць" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "катэгорыі" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Праект Hamster — адсочванне свайго часу" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Аўтарскія правы © 2007–2010 Toms Bauģis і іншыя" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Сеціўная пляцоўка праекта Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Аб Трэкеры часу" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Alexander Nyakhaychyk https://launchpad.net/~nab\n" "Кацярына Бондарава " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Неадсартавана" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Праца" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Чытанне навін" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Праверка біржавых каціровак" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Суперсакрэтны праект X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Сусветнае панаванне" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Будзённыя справы" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Абед" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Паліванне кветак" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Стаянне дагары нагамі" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Абнавіць занятак" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d г." #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d хв." #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d г. %d хв." #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %b, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Агулам адсочана %s гадзін" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ніякі" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Назва" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Новая катэгорыя" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Новы занятак" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d хвіліна" msgstr[1] "%(interval_minutes)d хвіліны" msgstr[2] "%(interval_minutes)d хвілін" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Ніколі" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "занятак" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "пачатак" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "канец" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "працягласць у хвілінах" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "катэгорыя" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "апісанне" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "цэтлікі" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Справаздача за %(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Справаздача за %(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Справаздача за %(start_d)s %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Справаздача за %(start_d)s – %(end_d)s %(start_B)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Усяго па днях" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Журнал заняткаў" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "заняткі" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "катэгорыі" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Адрозненне:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Дата" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Паказаць шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Можна яго засланіць, змясціўшы сваю версію ў %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Усе" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Пакуль не хапае даных для генеравання статыстыкі.\n" "Карыстайцеся праграмай прынамсі на працягу тыдня." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Усё яшчэ збіраем даныя — паспрабуйце праз тыдзень." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Першы занятак быў запісаны %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s год" msgstr[1] "%(num)s гады" msgstr[2] "%(num)s гадоў" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "На дадзены момант адсочана %(human_days)s звычайных дзён (%(human_years)s) " "ці %(working_days)s працоўных дзён (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Найбольш працяглы занятак быў %(date)s і цягнуўся %(hours)s гадзіну." msgstr[1] "" "Найбольш працяглы занятак быў %(date)s і цягнуўся %(hours)s гадзіны." msgstr[2] "Найбольш працяглы занятак быў %(date)s і цягнуўся %(hours)s гадзін." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Усяго %s запіс." msgstr[1] "Усяго %s запісы." msgstr[2] "Усяго %s запісаў." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Праграме hamster трэба сабраць крыху больш інфармацыі." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s працэнтаў усіх вашых заняткаў пачынаюцца раней за 9 гадзіну раніцы. Гэта " "значыць, што вы жаўрук." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s працэнтаў усіх вашых заняткаў пачынаюцца пасля 11 гадзіны вечара. Гэта " "значыць, што вы сава." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s працэнтаў усіх вашых заняткаў карацейшыя за 15 хвілін. Гэта значыць, што " "вы працавітая пчолка." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Сёння няма запісаў" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s г." #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Толькі пачатак" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Захаванне справаздачы – Трэкер часу" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Справаздача HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Значэнні, падзеленыя табуляцыяй (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Справаздача Трэкера часу" #~ msgid "Show activities window" #~ msgstr "Паказаць акно заняткаў" #~ msgid "Sto_p Tracking" #~ msgstr "_Спыніць адсочванне" #~ msgid "To_day" #~ msgstr "Сё_ння" #~ msgid "_Add earlier activity" #~ msgstr "_Дадаць ранейшы занятак" #~ msgid "Show _Overview" #~ msgstr "Паказаць _агляд" #~ msgid "_Preferences" #~ msgstr "_Настройкі" #~ msgid "_About" #~ msgstr "_Аб праграме" #~ msgid "Year:" #~ msgstr "Год:" #~ msgid "Starts and ends" #~ msgstr "Граніцы заняткаў" #~ msgid "Preferences" #~ msgstr "Настройкі" #~ msgid "Changed activity" #~ msgstr "Змена занятку" #~ msgid "Switched to '%s'" #~ msgstr "Пераключэнне на \"%s\"" #~ msgid "Working on %s" #~ msgstr "Праца над %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Трэкер часу Hamster. Правілы карыстання:" hamster-3.0.3/po/bg.po000066400000000000000000000644311452646177100145530ustar00rootroot00000000000000# Bulgarian translation of hamster-time-tracker po-file. # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. # Copyright (C) 2010 Damyan Ivanov. # This file is distributed under the same license as the hamster-time-tracker package. # Alexander Shopov , 2008, 2009, 2010, 2011, 2012, 2013. # Damyan Ivanov , 2010. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-01-13 22:13+0200\n" "PO-Revision-Date: 2013-01-13 22:15+0200\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" "Language: bg\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Добавяне на нова дейност" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "до" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "тече" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Описание:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Време:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Дейност:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Етикети:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Преустановяване на отчитането при бездействие" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Преустановяване на отчитането на текущата дейност, когато компютърът " "бездейства" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Преустановяване на отчитането при изключване на компютъра" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" "Преустановяване на отчитането на текущата дейност при изключване на компютъра" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Време в минути за повтарящо се напомняне" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Напомняне за текущата задача на всяко изтичане на указания брой минути. За " "да изключите напомнянето, задайте да е 0 или над 120." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Напомняне и когато не е зададена дейност" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Да се напомня на интервал равен на ключа „notify_interval“ в минути, ако не " "е зададена текуща дейност." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Кога започва денят (стандартно е в 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Дейностите се броят към предишния ден, ако текущото време е преди указаното " "за начало на деня, и се броят към днешния ден, ако текущото време е след " "това. Дейностите, които са в два дни, се броят към този, в който е по-" "голямата част от тях." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Дали смяната на плота означава и смяна на дейността" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Списък с включените методи за проследяване. При „name“ смяната е според " "името, указано в ключа „workspace_mapping“. При „memory“ ще се превключва " "към последната дейност при преминаване към предишен работен плот." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Смяна на дейността при смяна на плота" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ако смяната по име е включена, списъкът задава имената на дейностите, към " "които да се превключва. Работните плотове се представят с индекса на " "дейността." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Показване и скриване на прозореца за отчитане на времето." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Клавишна комбинация за показване и скриване на прозореца за отчитане на " "времето." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Показване и скриване на главния прозорец на програмата Хамстер" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Команда за показване и скриване на главния прозорец на програмата." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Показване и скриване на прозореца на програмата" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Показване и скриване на главния прозорец на програмата Хамстер" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:69 msgid "Time Tracker" msgstr "Отчитане на времето" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Проект Хамстер — отчитане на времето" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Преглед на отчитането на времето" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Прозорец за преглед на аплета за отчитане на времето" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Статистика" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Категории" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Дейности" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:156 msgid "Tags" msgstr "Етикети" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "За този период няма данни" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Запазване на отчет…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Ден" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Седмица" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Месец" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Преглед — Хамстер" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Преглед" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:150 msgid "Activity" msgstr "Дейност" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Изглед" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Общо" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Изтриване" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Добавяне" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Редактиране" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Настройки на отчитането на времето" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Преустановяване на отчитането при бездействие на компютъра" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Напомняне за текущата дейност на всеки:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Денят започва в" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Използване на следния списък със задачи, ако е наличен:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Интеграция" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Отчитане" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Категории" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Списък с категории" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Добавяне на категория" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Премахване на категорията" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Редактиране на категория" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Дейности" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Списък с дейности" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Добавяне на дейност" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Премахване на дейността" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Редактиране на дейност" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Етикети, които да се появяват при дописването" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Категории и етикети" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Връщане на дейността при връщане на плота" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Започване на нова дейност при смяна на плота:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Работни плотове" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Ден:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Седмица:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Месец:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Период:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Прилагане" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Отчитане" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Добавяне на предишна дейност" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Преглед" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статистика" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Редактиране" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Помо_щ" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Ръководство" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Преустановяване на отчитането" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Смяна" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Начало на отчитането" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Започване на нова дейност" #: ../data/today.ui.h:13 msgid "Today" msgstr "Днес" #: ../data/today.ui.h:14 msgid "totals" msgstr "общо" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Показване на прегледа" #: ../src/hamster-cli:254 ../src/hamster/today.py:295 msgid "No activity" msgstr "Без дейност" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Категория" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Описание" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Начало" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Край" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Продължителност" #: ../src/hamster-cli:308 msgid "Uncategorized" msgstr "Без категория" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Проект Хамстер — отчитане на времето" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Авторски права: © 2007-2010 Toms Bauģis и др." #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Уеб сайт на Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Относно отчитането на времето" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Александър Шопов \n" "\n" "Проектът за превод на GNOME има нужда от подкрепа.\n" "Научете повече за нас на http://gnome.cult.bg\n" "Докладвайте за грешки на http://gnome.cult.bg/bugs" #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:281 msgid "Unsorted" msgstr "Без подредба" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Обновяване на дейността" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d ч." #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d мин." #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d ч. %d мин." #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s — %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s — %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s — %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%d %b, %A" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s часа общо" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Няма" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Име" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Нова категория" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Нова дейност" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d минута" msgstr[1] "%(interval_minutes)d минути" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Никога" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "дейност" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "начало" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "край" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "продължителност" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "категория" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "описание" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "етикети" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Журнал на дейността за: %(start_d)s %(start_B)s %(start_Y)s — %(end_d)s " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Журнал на дейността за: %(start_d)s %(start_B)s — %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Журнал на дейността за: %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Журнал на дейността за: %(start_d)s — %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Общо по дни" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Журнал на дейността" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "дейности" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "категории" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Подреждане по:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Дата" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Може да се замени от потребителски шаблон, поставен в папката %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Всички" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Все още няма данни, за изчисляването на статистика.\n" "Добре е да има данни за една седмица (примерно)!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Все още се събират данни. Пробвайте след седмица!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Първата дейност е записана на %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s година" msgstr[1] "%(num)s години" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Времето, което е отчетено досега, е %(human_days)s човекодни " "(%(human_years)s) или %(working_days)s работни дни (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Най-дългата непрекъсната дейност е започнала на %(date)s и е продължила " "%(hours)s час." msgstr[1] "" "Най-дългата непрекъсната дейност е започнала на %(date)s и е продължила " "%(hours)s часа." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Има %s запис." msgstr[1] "Има %s записа." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster трябва да ви наблюдава още известно време!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "%s %% от всички записи са преди 9 часа̀. Много сте ранобудни!" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "%s %% от всички записи са след 23 часа̀. Вие сте нощна птица!" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "%s %% от всички записи са под 15 минути. Много сте заети!" #: ../src/hamster/today.py:249 msgid "No records today" msgstr "Няма записи за днес" #: ../src/hamster/today.py:256 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s, " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:259 #, python-format msgid "%sh" msgstr "%s ч." #: ../src/hamster/today.py:286 msgid "Just started" msgstr "Започнато току що" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Запазване на отчет на времето" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Отчет в HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Стойности разделени с табулации (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Отчитане на времето" hamster-3.0.3/po/bn.po000066400000000000000000001014531452646177100145560ustar00rootroot00000000000000# Bengali translation for hamster-time-tracker # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Runa Bhattacharjee , 2008, 2009. # Maruf Ovee , 2009. # Israt Jahan , 2010. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: bn\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2010-01-28 15:35+0600\n" "Last-Translator: Israt Jahan \n" "Language-Team: Bengali \n" "Language: bn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "পূর্ববর্তী কাজ যোগ করুন" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "প্রতি" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "চলমান" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "বিবরণ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "সময়:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "কাজ:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "ট্যাগ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "কর্মহীন অবস্থায় বর্তমান কাজে নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "কম্পিউটার কর্মহীন অবস্থায় হলে বর্তমান কর্মের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "কম্পিউটার বন্ধ হলে" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "বন্ধ করা হলে বর্তমান কাজের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "প্রতি x মিনিট অন্তর বর্তমান কর্মের বিষয়ে স্মরণ করানো হবে" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "মিনিটে ধার্য সুনির্দিষ্ট সময়ের অন্তরে বর্তমান কর্ম সম্বন্ধে স্মরণ করানো হবে। স্মরণ " "ব্যবস্থা নিষ্ক্রিয় করার জন্য ০ অথবা ১২০ থেকে অধিক কোনো সংখ্যা নির্ধারণ করুন।" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "উপরন্তু, কোনো কাজ নির্ধারিত না হলে সূচিত করা হবে" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "উপরন্তু, কোনো কাজ না আরম্ভ করা হলে প্রতি notify_interval মিনিটে সূচনা প্রদান করা " "হবে।" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "At what time does the day start (defaults to 5:30AM)" #: ../data/hamster.schemas.in.h:10 #, fuzzy msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "কম্পিউটার কর্মহীন অবস্থায় হলে বর্তমান কর্মের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Should workspace switch trigger activity switch" #: ../data/hamster.schemas.in.h:12 #, fuzzy msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "last activity when returning to a previous workspace." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Switch activity on workspace change" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "সময় নিরীক্ষণের উইন্ডো প্রদর্শনের জন্য কী-বোর্ড শর্টকাট।" #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "সময় নিরীক্ষণের উইন্ডো প্রদর্শনের জন্য কী-বোর্ড শর্টকাট।" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "সময় অনুসরণ" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "Project Hamster - সময় নিরীক্ষণ করুন" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "সময় অনুসরণ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "পরিসংখ্যান প্রদর্শন করুন" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "বিভাগ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "কাজ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "ট্যাগ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "এই ব্যবধানের মধ্যে কোনো তথ্য উপস্থিত নেই" #: ../data/overview.ui.h:1 #, fuzzy msgid "Save report..." msgstr "প্রতিবেদন সংরক্ষণ করুন" #: ../data/overview.ui.h:2 msgid "Day" msgstr "দিন" #: ../data/overview.ui.h:3 msgid "Week" msgstr "সপ্তাহ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "মাস" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "সংক্ষিপ্ত তথ্য - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "সংক্ষিপ্ত তথ্য (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "কাজ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "সর্বমোট" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "মুছে ফেলুন" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "সম্পাদনা" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "সময় নিরীক্ষণ ব্যবস্থা সম্পর্কিত পছন্দ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "কম্পিউটার কর্মহীন অবস্থায় থাকলে সময় নিরীক্ষণ বন্ধ করা হবে" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "বর্তমান কাজ সম্বন্ধে স্মরণ করানো হবে, প্রতি:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "নতুন দিন শুরু হশ" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "অবধি" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "অনুসরণ বন্ধ করা হবে" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "বিভাগ (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "বিভাগের তালিকা" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "বিভাগ যোগ করুন" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "বিভাগ মুছে ফেলুন" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "বিভাগ সম্পাদনা" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "কাজ (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "কাজের তালিকা" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "কাজ যোগ করুন" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "কাজ মুছে ফেলুন" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "কাজ সম্পাদনা" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Tags that should appear in autocomplete" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "বিভাগ এবং ট্যাগ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Resume the last activity when returning to a workspace" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Start new activity when switching workspaces:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "ওয়ার্কস্পেস" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "সপ্তাহ" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "মাস" #: ../data/range_pick.ui.h:4 #, fuzzy msgid "Range:" msgstr "ডাটা সীমা" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "অনুসরণ বন্ধ করা হবে (_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "পূর্ববর্তী কাজ যোগ করুন" #: ../data/today.ui.h:4 msgid "Overview" msgstr "সংক্ষিপ্ত তথ্য" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "পরিসংখ্যান" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "সম্পাদনা (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "সহায়তা (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "বিষয়বস্তু" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "অনুসরণ বন্ধ করা হবে (_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "পরিবর্তন (_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "অনুসরণ বন্ধ করা হবে (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "নতুন কাজ শুরু" #: ../data/today.ui.h:13 msgid "Today" msgstr "আজ" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "সর্বমোট" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "সংক্ষিপ্ত তথ্য প্রদর্শন করা হবে (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "কোনো কাজ হয়নি" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "বিভাগ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "বিবরণ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "আরম্ভ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "সমাপ্তি" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "অবধি" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "বিভাগ" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster - সময় নিরীক্ষণ করুন" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "স্বত্বাধিকার © ২০০৭-২০০৯ টমস বগিস ও অন্যান্যদের" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "প্রজেক্ট Hamster ওয়েব-সাইট" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "সময় অনুসরণ ব্যবস্থার পরিচিতি" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "রুণা ভট্টাচার্য (runab@redhat.com)" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "অনুক্রম বিহীন" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "কাজ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "সংবাদ পাঠ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "স্টকের খবরাখবর" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "অত্যন্ত গোপনীয় প্রজেক্ট X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "বিশ্বের উপর রাজত্ব" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "দৈনন্দিন" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "মধ্যভোজ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ফুলের গাছে জল দেওয়া" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "যোগাসন" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "কাজ হালনাগাদ করুন" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%1$A, %2$b %3$d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s hours tracked total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "নাম" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "নতুন বিভাগ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "নতুন কাজ" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d মিনিট" msgstr[1] "%(interval_minutes)d মিনিট" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "কখনো নয়" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "কর্ম" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "আরম্ভের সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "সমাপ্তির সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "অবকাল, মিনিটে ধার্য" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "বিভাগ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "বিবরণ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ট্যাগ" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s-এর " "সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s-এর সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s-এর সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s-এর সংক্ষিপ্ত তথ্য" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%1$b %2$d, %3$Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "সর্বমোট" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "কাজ" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "কাজ" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "বিভাগ" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "তারিখ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "সকল" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "পরিসংখ্যান নির্মাণের জন্য কোনো তথ্য উপস্থিত নেই।\n" "এক সপ্তাহ ব্যবহারের পরে পর্যাপ্ত তথ্য উপলব্ধ হবে!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "এখনো তথ্য সংগ্রহ করা হচ্ছে — এক সপ্তাহ পরে পুনরায় পরীক্ষা করুন!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%1$b %2$d, %3$Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "প্রথম কর্মের তথ্য %s-এ রেকর্ড করা হয়েছে।" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s বৎসর" msgstr[1] "%(num)s বৎসর" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "সময় অনুসরণের কাল: %(human_days)s দিন (%(human_years)s) অথবা %(working_days)s " "কাজের দিন (%(working_years)s)।" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "%(date)s তারিখে %(hours)s ঘন্টা ব্যাপী কাজ সবচেয়ে দীর্ঘমেয়াদি কাজ রূপে চিহ্নিত " "করা হয়েছে" msgstr[1] "" "%(date)s তারিখে %(hours)s ঘন্টা ব্যাপী কাজ সবচেয়ে দীর্ঘমেয়াদি কাজ রূপে চিহ্নিত " "করা হয়েছে" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s-টি রেকর্ড উপস্থিত রয়েছে।" msgstr[1] "%s-টি রেকর্ড উপস্থিত রয়েছে।" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster আরো কিছু সময়ের জন্য আপনার কাজ নিরীক্ষণ করতে ইচ্ছুক!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s শতাংশ কর্ম সকাল ৯-টা আগে আরম্ভ করা হয়েছে। সম্ভবত আপনার দিন বেশ তাড়াতাড়ি শুরু " "হয়ে থাকে।" #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s শতাংশ কর্ম রাত ১১-টার পরে আরম্ভ করা হয়েছে। সম্ভবত আপনি রাতের বেলা কাজ করতে " "বেশি পছন্দ করেন।" #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s শতাংশ কর্ম ১৫ মিনিটের মধ্যে সমাপ্ত হয়েছে। সম্ভবত আপনি অনেক ধরনের কাজ করে " "থাকেন।" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "আজকের কোনো তথ্য উপস্থিত নেই" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "কেবল শুরু হয়েছে" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "রিপোর্ট সংরক্ষণ করুন - সময় অনুসরণ" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML রিপোর্ট" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ট্যাব দ্বারা বিভাজিত মান (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "সময় অনুসরণ" #~ msgid "Show window" #~ msgstr "উইন্ডো প্রদর্শন করা হবে" #~ msgid "_About" #~ msgstr "পরিচিতি (_A)" #~ msgid "_Preferences" #~ msgstr "পছন্দ (_P)" #~| msgid "Project Hamster Website" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "প্রজেক্ট Hamster ওয়েব-সাইট অনুসরণ" #~ msgid "Ad_d Earlier Activity" #~ msgstr "পূর্ববর্তী কাজ যোগ করুন (_d)" #~ msgid "Tell me more" #~ msgstr "আরও বলুন" #~ msgid "_Today" #~ msgstr "আজ (_T)" #~ msgid "Preview:" #~ msgstr "প্রাকদর্শন:" #~ msgid "Add" #~ msgstr "যোগ" #~ msgid "General" #~ msgstr "সাধারণ" #~| msgid "Global Hotkey" #~ msgid "Global Hotkey" #~ msgstr "সার্বজনীন হট-কী" #~ msgid "Move activity down" #~ msgstr "কাজ নীচে স্থানান্তর করুন" #~ msgid "Move activity up" #~ msgstr "কাজ উপরে স্থানান্তর করুন" #~| msgid "Starts and ends" #~ msgid "Starts and ends" #~ msgstr "আরম্ভ ও সমাপ্তি" #~ msgid "Year:" #~ msgstr "বৎসর:" #~ msgid "Working on %s" #~ msgstr "%s-এ কাজ করা হচ্ছে" #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "কাজ যোগ করুন" #~ msgid "Switched to '%s'" #~ msgstr "'%s' এ পরিবর্তিত" #~ msgid "Total Time" #~ msgstr "সর্বমোট সময়" #~ msgid "Activities" #~ msgstr "কাজ" #~ msgid "Tracking" #~ msgstr "অনুসরণ" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "কোনো কাজের অনুসরণ আরম্ভের জন্য কাজের নাম লিখুন ও Enter " #~ "চাপুন!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "অধিক বিবরণ" #~ msgid "Hamster" #~ msgstr "Hamster (হ্যামস্টার)" #~ msgid "_Activity:" #~ msgstr "কাজ: (_A)" #~ msgid " _Day" #~ msgstr " দিন (_D)" #~ msgid " _Month" #~ msgstr " মাস (_M)" #~ msgid " _Week" #~ msgstr " সপ্তাহ (_W)" #~ msgid "Overview" #~ msgstr "সংক্ষিপ্ত তথ্য" #~ msgid "Totals" #~ msgstr "সর্বমোট" #~ msgid "Categories:" #~ msgstr "বিভাগ:" #~ msgid "Date interval:" #~ msgstr "তারিখের ব্যবধান:" #~ msgid "Save as HTML" #~ msgstr "HTML রূপে সংরক্ষণ করুন" #~ msgid "What should be typed in the activity box?" #~ msgstr "কাজ চিহ্নকারী বাক্সের মধ্যে কী লেখা হবে?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "কাজের সাথে বিবরণ সংযোজনের জন্য একটি সহজ সিন্টেক্স উপস্থিত রয়েছে:\n" #~ " \n" #~ "\"@\" চিহ্ন দ্বারা একটি শ্রেণী চিহ্নিত করা হয়। উদাহরণ: \"watering flowers@home" #~ "\" লেখা হলে \"home\" শ্রেণীর অধিন উপস্থিত \"watering flowers\" কাজটি " #~ "নিরীক্ষণ করা হবে।\n" #~ "\n" #~ "(\",\") চিহ্ন দ্বারা বিবরণের প্রারম্ভ চিহ্নিত করা হয়। উদাহরণ: \"watering " #~ "flowers, begonias and forgetmenots\" লেখা হলে \"watering flowers\" কাজ " #~ "অনুসরণ করা হবে ও \"begonias and forgetmenots\" বিবরণ এর সাথে যোগ করা হবে।\n" #~ "\n" #~ "উপরে উল্লিখিত দুটি বিন্যাস একসাথেও লেখা যাবে: \"watering flowers@home, " #~ "begonias and forgetmenots\" \n" #~ "\n" #~ "কাজ অনুসরণ আরম্ভ করুন!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "সর্বধরন" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "সর্বমোট" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s-র সংক্ষিপ্ত তথ্য" hamster-3.0.3/po/bn_IN.po000066400000000000000000000765371452646177100151620ustar00rootroot00000000000000# translation of bn_IN.po to Bengali INDIA # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Runa Bhattacharjee , 2008, 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: bn_IN\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2009-09-16 11:05+0530\n" "Last-Translator: Runa Bhattacharjee \n" "Language-Team: Bengali INDIA \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "পূর্ববর্তী কর্ম যোগ করুন" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "অবধি" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "চলমান" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "বিবরণ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "সময়:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "কর্ম:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "কর্মহীন অবস্থায় বর্তমান কর্মের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "কম্পিউটার কর্মহীন অবস্থায় হলে বর্তমান কর্মের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "কম্পিউটার বন্ধ হলে" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "বন্ধ করা হলে বর্তমান কর্মের নিরীক্ষণ বন্ধ করা হবে" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "প্রতি x মিনিট অন্তর বর্তমান কর্মের বিষয়ে স্মরণ করানো হবে" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "মিনিটে ধার্য সুনির্দিষ্ট সময়ের অন্তরে বর্তমান কর্ম সম্বন্ধে স্মরণ করানো হবে। স্মরণ " "ব্যবস্থা নিষ্ক্রিয় করার জন্য 0 (০) অথবা 120 (১২০) থেকে অধিক কোনো সংখ্যা নির্ধারণ " "করুন।" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "উপরন্তু, কোনো কর্ম নির্ধারিত না হলে সূচিত করা হবে" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "উপরন্তু, কোনো কর্ম না আরম্ভ করা হলে প্রতি notify_interval মিনিটে সূচনা প্রদান করা " "হবে।" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "সময় নিরীক্ষণের উইন্ডো প্রদর্শনের জন্য কি-বোর্ড শর্টকাট।" #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "সময় নিরীক্ষণের উইন্ডো প্রদর্শনের জন্য কি-বোর্ড শর্টকাট।" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "সময় অনুসরণ" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "Project Hamster - সময় নিরীক্ষণ করুন" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "সময় অনুসরণ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "পরিসংখ্যান" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "বিভাগ (_C)" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "কর্ম (_A)" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "এই ব্যবধানের মধ্যে কোনো তথ্য উপস্থিত নেই" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "দিন" #: ../data/overview.ui.h:3 msgid "Week" msgstr "সপ্তাহ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "মাস" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "সংক্ষিপ্ত তথ্য - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "সংক্ষিপ্ত তথ্য (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "কর্ম" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "সর্বমোট" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "সম্পাদনা" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "সময় নিরীক্ষণ ব্যবস্থা সম্পর্কিত পছন্দ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "কম্পিউটার কর্মহীন অবস্থায় থাকলে সময় নিরীক্ষণ বন্ধ করা হবে" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "বর্তমান কর্ম সম্বন্ধে স্মরণ করানো হবে, প্রতি:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "অবধি" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "অনুসরণ বন্ধ করা হবে (_S)" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "বিভাগ (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "বিভাগের তালিকা" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "বিভাগ যোগ করুন" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "বিভাগ মুছে ফেলুন" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "বিভাগ সম্পাদনা" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "কর্ম (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "কর্মের তালিকা" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "কর্ম যোগ করুন" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "কর্ম মুছে ফেলুন" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "কর্ম সম্পাদনা" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "বিভাগ (_C)" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "সপ্তাহ" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "মাস" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "অনুসরণ বন্ধ করা হবে (_S)" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "পূর্ববর্তী কর্ম যোগ করুন" #: ../data/today.ui.h:4 msgid "Overview" msgstr "সংক্ষিপ্ত তথ্য" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "পরিসংখ্যান" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "সম্পাদনা" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "অনুসরণ বন্ধ করা হবে (_S)" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "কর্ম পরিবর্তন" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "অনুসরণ বন্ধ করা হবে (_S)" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "নতুন কর্ম" #: ../data/today.ui.h:13 msgid "Today" msgstr "আজ" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "সর্বমোট" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "সংক্ষিপ্ত তথ্য প্রদর্শন করা হবে (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "কোনো কর্ম হয়নি" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "বিভাগ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "বিবরণ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "আরম্ভ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "সমাপ্তি" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "অবধি" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "বিভাগ (_C)" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster - সময় নিরীক্ষণ করুন" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "স্বত্বাধিকার © ২০০৭-২০০৯ টমস বগিস ও অন্যান্যদের" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "প্রজেক্ট Hamster ওয়েব-সাইট" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "সময় অনুসরণ ব্যবস্থার (Time Tracker) পরিচিতি" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "রুণা ভট্টাচার্য (runab@redhat.com)" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "অনুক্রম বিহীন" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "কাজ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "সংবাদ পাঠ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "স্টকের খবরাখবর" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "অত্যন্ত গোপনীয় প্রজেক্ট X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "বিশ্বের উপর রাজত্ব" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "দৈনন্দিন" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "মধ্যভোজ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ফুলের গাছে জল দেওয়া" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "যোগাসন" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "কর্ম আপডেট করুন" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 #, fuzzy msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s-র " "সংক্ষিপ্ত তথ্য" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s-র সংক্ষিপ্ত তথ্য" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s-র সংক্ষিপ্ত তথ্য" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "নাম" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "নতুন বিভাগ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "নতুন কর্ম" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d মিনিট" msgstr[1] "%(interval_minutes)d মিনিট" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "কখনো নয়" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "কর্ম" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "আরম্ভের সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "সমাপ্তির সময়" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "অবকাল, মিনিটে ধার্য" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "বিভাগ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "বিবরণ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s-র " "সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s-র সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s-র সংক্ষিপ্ত তথ্য" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s-র সংক্ষিপ্ত তথ্য" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "সর্বমোট" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "কর্ম" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "কর্ম (_A)" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "বিভাগ (_C)" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "তারিখ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "সকল" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "পরিসংখ্যান নির্মাণের জন্য কোনো তথ্য উপস্থিত নেই।\n" "এক সপ্তাহ ব্যবহারের পরে পর্যাপ্ত তথ্য উপলব্ধ হবে!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "এখনো তথ্য সংগ্রহ করা হচ্ছে — এক সপ্তাহ পরে পুনরায় পরীক্ষা করুন!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "প্রথম কর্মের তথ্য %s-এ রেকর্ড করা হয়েছে।" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s বৎসর" msgstr[1] "%(num)s বৎসর" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "সময় অনুসরণের কাল: %(human_days)s দিন (%(human_years)s) অথবা %(working_days)s " "কাজের দিন (%(working_years)s)।" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "%(date)s তারিখে %(hours)s ঘন্টা ব্যাপী কাজ সবচেয়ে দীর্ঘমেয়াদি কাজ রূপে চিহ্নিত " "করা হয়েছে" msgstr[1] "" "%(date)s তারিখে %(hours)s ঘন্টা ব্যাপী কাজ সবচেয়ে দীর্ঘমেয়াদি কাজ রূপে চিহ্নিত " "করা হয়েছে" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s-টি রেকর্ড উপস্থিত রয়েছে।" msgstr[1] "%s-টি রেকর্ড উপস্থিত রয়েছে।" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster আরো কিছু সময়ের জন্য আপনার কাজ নিরীক্ষণ করতে ইচ্ছুক!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s শতাংশ কর্ম সকাল ৯-টা আগে আরম্ভ করা হয়েছে। সম্ভবত আপনার দিন বেশ তাড়াতাড়ি শুরু " "হয়ে থাকে।" #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s শতাংশ কর্ম রাত ১১-টার পরে আরম্ভ করা হয়েছে। সম্ভবত আপনি রাতের বেলা কাজ করতে " "বেশি পছন্দ করেন।" #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s শতাংশ কর্ম ১৫ মিনিটের মধ্যে সমাপ্ত হয়েছে। সম্ভবত আপনি অনেক ধরনের কাজ করে " "থাকেন।" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "আজকের কোনো তথ্য উপস্থিত নেই" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "রিপোর্ট সংরক্ষণ করুন - সময় অনুসরণ" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML রিপোর্ট" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ট্যাব দ্বারা বিভাজিত মান (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "সময় অনুসরণ" #~ msgid "_About" #~ msgstr "পরিচিতি (_A)" #~ msgid "_Preferences" #~ msgstr "পছন্দ (_P)" #~ msgid "Activities" #~ msgstr "কর্ম" #~ msgid "Global Hotkey" #~ msgstr "সার্বজনীন হট-কি" #~ msgid "Tracking" #~ msgstr "অনুসরণ" #~ msgid "Move activity down" #~ msgstr "কর্ম নীচে স্থানান্তর করুন" #~ msgid "Move activity up" #~ msgstr "কর্ম উপরে স্থানান্তর করুন" #~ msgid "Preview:" #~ msgstr "পূর্বদৃশ্য:" #~ msgid "Show window" #~ msgstr "উইন্ডো প্রদর্শন করা হবে" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "কোনো কর্মের অনুসরণ আরম্ভের জন্য কর্মের নাম লিখুন ও Enter " #~ "টিপুন!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "অধিক বিবরণ" #~ msgid "Ad_d Earlier Activity" #~ msgstr "পূর্ববর্তী কর্ম যোগ করুন (_d)" #~ msgid "Hamster" #~ msgstr "Hamster (হ্যামস্টার)" #~ msgid "_Activity:" #~ msgstr "কর্ম: (_A)" #~ msgid "_Today" #~ msgstr "আজ (_T)" #~ msgid " _Day" #~ msgstr " দিন (_D)" #~ msgid " _Month" #~ msgstr " মাস (_M)" #~ msgid " _Week" #~ msgstr " সপ্তাহ (_W)" #~ msgid "Overview" #~ msgstr "সংক্ষিপ্ত তথ্য" #~ msgid "Starts and ends" #~ msgstr "আরম্ভ ও সমাপ্তি" #~ msgid "Totals" #~ msgstr "সর্বমোট" #~ msgid "Categories:" #~ msgstr "বিভাগ:" #~ msgid "Date interval:" #~ msgstr "তারিখের ব্যবধান:" #~ msgid "Save as HTML" #~ msgstr "HTML রূপে সংরক্ষণ করুন" #~ msgid "Year:" #~ msgstr "বৎসর:" #~ msgid "Working on %s" #~ msgstr "%s-এ কাজ করা হচ্ছে" #~ msgid "What should be typed in the activity box?" #~ msgstr "কর্ম চিহ্নকারী বক্সের মধ্যে কী লেখা হবে?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "কর্মের সাথে বিবরণ সংযোজনের জন্য একটি সহজ সিন্টেক্স উপস্থিত রয়েছে:\n" #~ " \n" #~ "\"@\" চিহ্ন দ্বারা একটি শ্রেণী চিহ্নিত করা হয়। উদাহরণ: \"watering flowers@home" #~ "\" লেখা হলে \"home\" শ্রেণীর অধিন উপস্থিত \"watering flowers\" কাজটি " #~ "নিরীক্ষণ করা হবে।\n" #~ "\n" #~ "(\",\") চিহ্ন দ্বারা বিবরণের প্রারম্ভ চিহ্নিত করা হয়। উদাহরণ: \"watering " #~ "flowers, begonias and forgetmenots\" লেখা হলে \"watering flowers\" কাজ " #~ "অনুসরণ করা হবে ও \"begonias and forgetmenots\" বিবরণ এর সাথে যোগ করা হবে।\n" #~ "\n" #~ "উপরে উল্লিখিত দুটি বিন্যাস একসাথেও লেখা যাবে: \"watering flowers@home, " #~ "begonias and forgetmenots\" \n" #~ "\n" #~ "কর্ম অনুসরণ আরম্ভ করুন!\n" #~ " " #~ msgid "Total Time" #~ msgstr "সর্বমোট সময়" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "সর্বধরন" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "সর্বমোট" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s-র সংক্ষিপ্ত তথ্য" hamster-3.0.3/po/ca.po000066400000000000000000000736131452646177100145500ustar00rootroot00000000000000# Catalan translation of hamster. # Copyright (C) 2009 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Sílvia Miranda , 2010, 2011. # Gil Forcada , 2008, 2009, 2010, 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker 2.24\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-18 14:10+0100\n" "Last-Translator: Gil Forcada \n" "Language-Team: català; valencià \n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bits\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Afegeix una activitat prèvia" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "fins" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "en curs" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descripció:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Temps:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activitat:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetes:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Para de comptar quan l'ordinador estigui inactiu" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Para de comptar l'activitat actual quan l'ordinador estigui inactiu" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Para el comptador en aturar l'ordinador" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Para de comptar l'activitat actual en aturar l'ordinador" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Recorda l'activitat actual cada x minuts" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Recorda l'activitat actual cada interval de minuts indicat. Si és 0 o més " "gran de 120 s'inhabiliten els recordatoris." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Recorda'm també si no hi ha cap activitat en actiu" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Recorda'm també si no s'ha iniciat cap activitat cada " "«notify_interval» (interval de notificació) minuts." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Hora d'inici del dia (hora per defecte: les 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Es considerarà que les activitats pertanyen a ahir si l'hora actual és " "anterior a la que s'ha indicat com a inici del dia, i que pertanyen a avui " "si l'hora és posterior. Les activitats que es duen a terme al llarg de dos " "dies es comptabilitzen al dia en què es realitzi la major part de " "l'activitat." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" "Indica si en canviar d'espai de treball s'ha d'activar el canvi d'activitat" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Llista dels mètodes de seguiment habilitats. «name» (nom) habilita el canvi " "d'activitats pel nom que s'hagi definit a workspace_mapping; " "«memory» (memòria) permet canviar a l'última activitat quan es torna a un " "espai de treball anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Canvia d'activitat en canviar d'espai de treball" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Si s'ha habilitat l'opció de canvi d'activitat per nom, en aquesta llista " "s'estableixen els noms d'activitat a què es podrà canviar. Els espais de " "treball es representen mitjançant l'índex de l'element." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostra/oculta la finestra del comptador de temps" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Drecera de teclat per mostrar o ocultar la finestra del comptador de temps." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Acció per ocultar o mostrar la finestra de l'aplicació Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Ordre per ocultar o mostrar la finestra de l'aplicació Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Oculta o mostra la finestra de l'aplicació Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Oculta o mostra la finestra de l'aplicació Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Comptador de temps" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projecte Hamster: controleu el temps" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Vista general del comptador de temps" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "La finestra de la vista general del comptador de temps Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostra les estadístiques" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categories" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Activitats" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetes" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "No hi ha dades en aquest interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Desa l'informe..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dia" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Setmana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mes" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Resum general: Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Resum general" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activitat" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Visualització" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totals" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Suprimeix" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Afegeix una nova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Edita" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferències del comptador de temps" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Atura el comptador quan l'ordinador estigui inactiu" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Recorda l'activitat actual cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "El dia comença a les" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Utilitza la llista de tasques següent si està disponible:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integració" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Comptador" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categories" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Llista de categories" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Afegeix una categoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Suprimeix la categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Edita la categoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activitats" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Llista d'activitats" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Afegeix una activitat" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Suprimeix l'activitat" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Edita l'activitat" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etiquetes que han d'aparèixer a la compleció automàtica" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categories i etiquetes" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Reprèn l'última activitat en tornar a un espai de treball" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Comença una activitat nova en canviar d'espai de treball:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Espais de treball" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dia:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Setmana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mes:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Període:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplica" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Comptador" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Afegeix una activitat prèvia" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Resum general" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estadístiques" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Edita" #: ../data/today.ui.h:7 msgid "_Help" msgstr "A_juda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Contingut" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Para de comptar" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Canvia" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "C_omença a comptar" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Comença una activitat nova" #: ../data/today.ui.h:13 msgid "Today" msgstr "Avui" #: ../data/today.ui.h:14 msgid "totals" msgstr "totals" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostra un resum general" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Cap activitat" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descripció" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Inici" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Final" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durada" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categories" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projecte Hamster: controleu el temps" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2010 Toms Bauģis i altres" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Lloc web del projecte Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Quant al comptador de temps" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Gil Forcada \n" "Sílvia Miranda " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sense ordre" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Feina" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Llegint notícies" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Comprovant estocs" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Projecte ultrasecret X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominació mundial" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dia a dia" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Dinar" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regant les flors" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Fent el pi" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualitza l'activitat" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d h" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d min" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d h %d min" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B de %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d de %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "S'han comptat %s hores en total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Cap" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nom" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Categoria nova" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Activitat nova" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minuts" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Mai" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "activitat" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hora d'inici" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "hora de finalització" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "minuts de durada" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descripció" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetes" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s de %(start_B)s de %(start_Y)s al " "%(end_d)s de %(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s de %(start_B)s al %(end_d)s de " "%(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Informe d'activitats del %(start_d)s de %(start_B)s de %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s al %(end_d)s de %(start_B)s de %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totals per dia" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Resum d'activitats" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "activitats" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categories" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distingeix:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostra la plantilla" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Ho podeu sobreescriure si deseu la vostra versió a %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Tots" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Encara no hi ha dades per generar les estadístiques.\n" "Hauríeu d'utilitzar l'aplicació almenys durant una setmana." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Encara s'estan recollint dades; espereu que hagi passat una setmana." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "La primera activitat es va enregistrar el %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s any" msgstr[1] "%(num)s anys" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "El temps enregistrat fins ara és de %(human_days)s dies naturals " "(%(human_years)s) o %(working_days)s dies feiners (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "L'activitat continuada de més durada va tenir lloc el %(date)s i va durar " "%(hours)s hora." msgstr[1] "" "L'activitat continuada de més durada va tenir lloc el %(date)s i va durar " "%(hours)s hores." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Hi ha %s registre." msgstr[1] "Hi ha %s registres." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "El Hamster necessita recollir més dades." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "El %s per cent de les activitats s'han iniciat abans de les 9 del matí: " "sembla que sou una persona molt matinera." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "El %s per cent de les activitats s'han iniciat després de les 11 del vespre: " "sembla que feu vida nocturna." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "El %s per cent de les activitats han durat menys de 15 minuts: sembla que " "sou una persona molt ocupada." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "No hi ha registres d'avui" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s h" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "S'acaba de començar" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Desa l'informe: Comptador de temps" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Informe en HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valors separats amb tabulador (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Comptador de temps" #~ msgid "Show activities window" #~ msgstr "Mostra la finestra d'activitats" #~ msgid "Sto_p Tracking" #~ msgstr "_Para de comptar" #~ msgid "To_day" #~ msgstr "A_vui" #~ msgid "_Add earlier activity" #~ msgstr "_Afegeix una activitat prèvia" #~ msgid "Show _Overview" #~ msgstr "Mostra un _resum general" #~ msgid "_Preferences" #~ msgstr "_Preferències" #~ msgid "_About" #~ msgstr "_Quant a" #~ msgid "Year:" #~ msgstr "Any:" #~ msgid "Starts and ends" #~ msgstr "Inicis i finals" #~ msgid "Preferences" #~ msgstr "Preferències" #~ msgid "Changed activity" #~ msgstr "S'ha canviat d'activitat" #~ msgid "Switched to '%s'" #~ msgstr "S'ha canviat a «%s»" #~ msgid "Working on %s" #~ msgstr "S'està fent %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Comptador de temps Hamster. Ús:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projecte Hamster (comptador de temps del GNOME)" #~ msgid "totals by activity" #~ msgstr "Totals per activitat" #~ msgid "totals by category" #~ msgstr "Totals per categoria" #~ msgid "Show:" #~ msgstr "Mostra:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Afegeix una activitat _prèvia" #~ msgid "Tell me more" #~ msgstr "Més informació" #~ msgid "_Today" #~ msgstr "_Avui" #~ msgid "Preview:" #~ msgstr "Previsualització:" #~ msgid "General" #~ msgstr "General" #~ msgid "Global Hotkey" #~ msgstr "Drecera global" #~ msgid "Move activity down" #~ msgstr "Mou l'activitat cap avall" #~ msgid "Move activity up" #~ msgstr "Mou l'activitat cap amunt" #~ msgid "Total Time" #~ msgstr "Temps total" #~ msgid "Activities" #~ msgstr "Activitats" #~ msgid "Tracking" #~ msgstr "Comptador" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Teclegeu una activitat i premeu la tecla de retorn " #~ "per a començar a comptar el temps" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Més informació" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Activitat:" #~ msgid " _Day" #~ msgstr "_Dia" #~ msgid " _Month" #~ msgstr "_Mes" #~ msgid " _Week" #~ msgstr "_Setmana" #~ msgid "Overview" #~ msgstr "Resum general" #~ msgid "Totals" #~ msgstr "Totals" #~ msgid "Categories:" #~ msgstr "Categories:" #~ msgid "Date interval:" #~ msgstr "Interval de dades:" #~ msgid "Save as HTML" #~ msgstr "Desa-ho com a HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "Què s'hauria d'escriure en la caixa d'activitat?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Amb una sintaxi molt senzilla podeu afegir detalls a les vostres " #~ "activitats:\n" #~ " \n" #~ "Amb el símbol «@» s'indica una categoria. Per exemple: «regant les " #~ "plantes@casa» començaria a comptar l'activitat «regant les plantes» de la " #~ "categoria «casa».\n" #~ "\n" #~ "La coma («,») indica l'inici d'una descripció. Per exemple: «regant les " #~ "plantes, les hortènsies i els rosers» iniciaria a comptar l'activitat " #~ "«regant les plantes» i hi afegiria la descripció «les hortènsies i els " #~ "rosers».\n" #~ "\n" #~ "També es poden combinar: «regant les plantes@casa, les hortènsies i els " #~ "rosers».\n" #~ "\n" #~ "Ja podeu començar a comptar el temps!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Totes" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Resum per a %(date)s" #~ msgid "Move _Down" #~ msgstr "Mou cap a_vall" #~ msgid "Move _Up" #~ msgstr "Mou cap _amunt" #~ msgid "N_ew Category" #~ msgstr "Categoria _nova" #~ msgid "_New Activity" #~ msgstr "Activitat _nova" #~ msgid "Delete activity" #~ msgstr "Suprimeix l'activitat" #~ msgid "Newer activities" #~ msgstr "Darreres activitats" #~ msgid "Show month" #~ msgstr "Mostra el mes" #~ msgid "name" #~ msgstr "nom" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " #~ msgid "Activity" #~ msgstr "Activitat" #~ msgid "hours" #~ msgstr "hores" #~ msgid "minutes" #~ msgstr "minuts" #~ msgid "Category" #~ msgstr "Categoria" #~ msgid "Week" #~ msgstr "Setmana" #~ msgid "Earlier activities" #~ msgstr "Activitats prèvies" #~ msgid "Other" #~ msgstr "Altres" #~ msgid "Time tracking for masses" #~ msgstr "Comptador de temps per a tothom" #~ msgid "Time tracking for masses." #~ msgstr "Comptador de temps per a tothom." #~ msgid "Idle minutes:" #~ msgstr "Minuts inactiu:" #~ msgid "Add an older fact" #~ msgstr "Afegeix un esdeveniment vell" #~ msgid "" #~ "After how many minutes hamster should stop tracking activity when " #~ "computer is idle. Set to 0 to disable." #~ msgstr "" #~ "Després de quants minuts el Hamster hauria de parar de comptar activitat " #~ "quan l'ordinador estigui inactiu. Establiu-ho a 0 per a inhabilitar-ho." #~ msgid "Ad_d Older Fact" #~ msgstr "_Afegeix un esdeveniment vell" #~ msgid "Overview for %s - %s" #~ msgstr "Resum per a %s - %s" hamster-3.0.3/po/ca@valencia.po000066400000000000000000000735551452646177100163600ustar00rootroot00000000000000# Catalan translation of hamster. # Copyright (C) 2009 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Sílvia Miranda , 2010, 2011. # Gil Forcada , 2008, 2009, 2010, 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker 2.24\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-18 14:09+0100\n" "Last-Translator: Gil Forcada \n" "Language-Team: català; valencià \n" "Language: ca-XV\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bits\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Afig una activitat prèvia" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "fins" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "en curs" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descripció:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Temps:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activitat:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetes:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Para de comptar quan l'ordinador estiga inactiu" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Para de comptar l'activitat actual quan l'ordinador estiga inactiu" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Para el comptador en parar l'ordinador" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Para de comptar l'activitat actual en parar l'ordinador" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Recorda l'activitat actual cada x minuts" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Recorda l'activitat actual cada interval de minuts indicat. Si és 0 o més " "gran de 120 s'inhabiliten els recordatoris." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Recorda'm també si no hi ha cap activitat en actiu" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Recorda'm també si no s'ha iniciat cap activitat cada " "«notify_interval» (interval de notificació) minuts." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Hora d'inici del dia (hora per defecte: les 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Es considerarà que les activitats pertanyen a ahir si l'hora actual és " "anterior a la que s'ha indicat com a inici del dia, i que pertanyen a hui si " "l'hora és posterior. Les activitats que es duen a terme al llarg de dos dies " "es comptabilitzen al dia en què es realitzi la major part de l'activitat." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" "Indica si en canviar d'espai de treball s'ha d'activar el canvi d'activitat" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Llista dels mètodes de seguiment habilitats. «name» (nom) habilita el canvi " "d'activitats pel nom que s'haja definit a workspace_mapping; " "«memory» (memòria) permet canviar a l'última activitat quan es torna a un " "espai de treball anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Canvia d'activitat en canviar d'espai de treball" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Si s'ha habilitat l'opció de canvi d'activitat per nom, en esta llista " "s'estableixen els noms d'activitat a què es podrà canviar. Els espais de " "treball es representen mitjançant l'índex de l'element." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostra/oculta la finestra del comptador de temps" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Drecera de teclat per mostrar o ocultar la finestra del comptador de temps." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Acció per ocultar o mostrar la finestra de l'aplicació Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Orde per ocultar o mostrar la finestra de l'aplicació Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Oculta o mostra la finestra de l'aplicació Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Oculta o mostra la finestra de l'aplicació Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Comptador de temps" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projecte Hamster: controleu el temps" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Vista general del comptador de temps" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "La finestra de la vista general del comptador de temps Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostra les estadístiques" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categories" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Activitats" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetes" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "No hi ha dades en este interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Alça l'informe..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dia" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Setmana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mes" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Resum general: Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Resum general" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activitat" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Visualització" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totals" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Suprimeix" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Afig una nova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Edita" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferències del comptador de temps" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Para el comptador quan l'ordinador estiga inactiu" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Recorda l'activitat actual cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "El dia comença a les" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Utilitza la llista de tasques següent si està disponible:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integració" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Comptador" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categories" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Llista de categories" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Afig una categoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Suprimeix la categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Edita la categoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activitats" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Llista d'activitats" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Afig una activitat" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Suprimeix l'activitat" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Edita l'activitat" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etiquetes que han d'aparèixer a la compleció automàtica" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categories i etiquetes" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Reprén l'última activitat en tornar a un espai de treball" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Comença una activitat nova en canviar d'espai de treball:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Espais de treball" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dia:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Setmana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mes:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Període:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplica" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Comptador" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Afig una activitat prèvia" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Resum general" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estadístiques" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Edita" #: ../data/today.ui.h:7 msgid "_Help" msgstr "A_juda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Contingut" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Para de comptar" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Canvia" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "C_omença a comptar" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Comença una activitat nova" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hui" #: ../data/today.ui.h:14 msgid "totals" msgstr "totals" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostra un resum general" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Cap activitat" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descripció" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Inici" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Final" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durada" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categories" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projecte Hamster: controleu el temps" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2010 Toms Bauģis i altres" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Lloc web del projecte Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Quant al comptador de temps" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Gil Forcada \n" "Sílvia Miranda " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sense orde" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Faena" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Llegint notícies" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Comprovant estocs" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Projecte ultrasecret X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominació mundial" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dia a dia" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Dinar" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regant les flors" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Fent el pi" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualitza l'activitat" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d h" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d min" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d h %d min" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B de %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d de %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "S'han comptat %s hores en total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Cap" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nom" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Categoria nova" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Activitat nova" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minuts" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Mai" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "activitat" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hora d'inici" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "hora de finalització" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "minuts de durada" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descripció" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetes" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s de %(start_B)s de %(start_Y)s al " "%(end_d)s de %(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s de %(start_B)s al %(end_d)s de " "%(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Informe d'activitats del %(start_d)s de %(start_B)s de %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Informe d'activitats del %(start_d)s al %(end_d)s de %(start_B)s de %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totals per dia" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Resum d'activitats" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "activitats" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categories" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distingeix:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostra la plantilla" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Ho podeu sobreescriure si alceu la vostra versió a %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Tots" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Encara no hi ha dades per generar les estadístiques.\n" "Hauríeu d'utilitzar l'aplicació almenys durant una setmana." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Encara s'estan recollint dades; espereu que haja passat una setmana." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "La primera activitat es va enregistrar el %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s any" msgstr[1] "%(num)s anys" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "El temps enregistrat fins ara és de %(human_days)s dies naturals " "(%(human_years)s) o %(working_days)s dies feiners (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "L'activitat continuada de més durada va tindre lloc el %(date)s i va durar " "%(hours)s hora." msgstr[1] "" "L'activitat continuada de més durada va tindre lloc el %(date)s i va durar " "%(hours)s hores." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Hi ha %s registre." msgstr[1] "Hi ha %s registres." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "El Hamster necessita recollir més dades." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "El %s per cent de les activitats s'han iniciat abans de les 9 del matí: " "pareix que sou una persona molt matinera." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "El %s per cent de les activitats s'han iniciat després de les 11 del vespre: " "pareix que feu vida nocturna." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "El %s per cent de les activitats han durat menys de 15 minuts: pareix que " "sou una persona molt ocupada." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "No hi ha registres d'hui" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s h" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "S'acaba de començar" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Alça l'informe: Comptador de temps" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Informe en HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valors separats amb tabulador (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Comptador de temps" #~ msgid "Show activities window" #~ msgstr "Mostra la finestra d'activitats" #~ msgid "Sto_p Tracking" #~ msgstr "_Para de comptar" #~ msgid "To_day" #~ msgstr "A_vui" #~ msgid "_Add earlier activity" #~ msgstr "_Afig una activitat prèvia" #~ msgid "Show _Overview" #~ msgstr "Mostra un _resum general" #~ msgid "_Preferences" #~ msgstr "_Preferències" #~ msgid "_About" #~ msgstr "_Quant a" #~ msgid "Year:" #~ msgstr "Any:" #~ msgid "Starts and ends" #~ msgstr "Inicis i finals" #~ msgid "Preferences" #~ msgstr "Preferències" #~ msgid "Changed activity" #~ msgstr "S'ha canviat d'activitat" #~ msgid "Switched to '%s'" #~ msgstr "S'ha canviat a «%s»" #~ msgid "Working on %s" #~ msgstr "S'està fent %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Comptador de temps Hamster. Ús:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projecte Hamster (comptador de temps del GNOME)" #~ msgid "totals by activity" #~ msgstr "Totals per activitat" #~ msgid "totals by category" #~ msgstr "Totals per categoria" #~ msgid "Show:" #~ msgstr "Mostra:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Afegeix una activitat _prèvia" #~ msgid "Tell me more" #~ msgstr "Més informació" #~ msgid "_Today" #~ msgstr "_Avui" #~ msgid "Preview:" #~ msgstr "Previsualització:" #~ msgid "General" #~ msgstr "General" #~ msgid "Global Hotkey" #~ msgstr "Drecera global" #~ msgid "Move activity down" #~ msgstr "Mou l'activitat cap avall" #~ msgid "Move activity up" #~ msgstr "Mou l'activitat cap amunt" #~ msgid "Total Time" #~ msgstr "Temps total" #~ msgid "Activities" #~ msgstr "Activitats" #~ msgid "Tracking" #~ msgstr "Comptador" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Teclegeu una activitat i premeu la tecla de retorn " #~ "per a començar a comptar el temps" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Més informació" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Activitat:" #~ msgid " _Day" #~ msgstr "_Dia" #~ msgid " _Month" #~ msgstr "_Mes" #~ msgid " _Week" #~ msgstr "_Setmana" #~ msgid "Overview" #~ msgstr "Resum general" #~ msgid "Totals" #~ msgstr "Totals" #~ msgid "Categories:" #~ msgstr "Categories:" #~ msgid "Date interval:" #~ msgstr "Interval de dades:" #~ msgid "Save as HTML" #~ msgstr "Desa-ho com a HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "Què s'hauria d'escriure en la caixa d'activitat?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Amb una sintaxi molt senzilla podeu afegir detalls a les vostres " #~ "activitats:\n" #~ " \n" #~ "Amb el símbol «@» s'indica una categoria. Per exemple: «regant les " #~ "plantes@casa» començaria a comptar l'activitat «regant les plantes» de la " #~ "categoria «casa».\n" #~ "\n" #~ "La coma («,») indica l'inici d'una descripció. Per exemple: «regant les " #~ "plantes, les hortènsies i els rosers» iniciaria a comptar l'activitat " #~ "«regant les plantes» i hi afegiria la descripció «les hortènsies i els " #~ "rosers».\n" #~ "\n" #~ "També es poden combinar: «regant les plantes@casa, les hortènsies i els " #~ "rosers».\n" #~ "\n" #~ "Ja podeu començar a comptar el temps!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Totes" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Resum per a %(date)s" #~ msgid "Move _Down" #~ msgstr "Mou cap a_vall" #~ msgid "Move _Up" #~ msgstr "Mou cap _amunt" #~ msgid "N_ew Category" #~ msgstr "Categoria _nova" #~ msgid "_New Activity" #~ msgstr "Activitat _nova" #~ msgid "Delete activity" #~ msgstr "Suprimeix l'activitat" #~ msgid "Newer activities" #~ msgstr "Darreres activitats" #~ msgid "Show month" #~ msgstr "Mostra el mes" #~ msgid "name" #~ msgstr "nom" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " #~ msgid "Activity" #~ msgstr "Activitat" #~ msgid "hours" #~ msgstr "hores" #~ msgid "minutes" #~ msgstr "minuts" #~ msgid "Category" #~ msgstr "Categoria" #~ msgid "Week" #~ msgstr "Setmana" #~ msgid "Earlier activities" #~ msgstr "Activitats prèvies" #~ msgid "Other" #~ msgstr "Altres" #~ msgid "Time tracking for masses" #~ msgstr "Comptador de temps per a tothom" #~ msgid "Time tracking for masses." #~ msgstr "Comptador de temps per a tothom." #~ msgid "Idle minutes:" #~ msgstr "Minuts inactiu:" #~ msgid "Add an older fact" #~ msgstr "Afegeix un esdeveniment vell" #~ msgid "" #~ "After how many minutes hamster should stop tracking activity when " #~ "computer is idle. Set to 0 to disable." #~ msgstr "" #~ "Després de quants minuts el Hamster hauria de parar de comptar activitat " #~ "quan l'ordinador estigui inactiu. Establiu-ho a 0 per a inhabilitar-ho." #~ msgid "Ad_d Older Fact" #~ msgstr "_Afegeix un esdeveniment vell" #~ msgid "Overview for %s - %s" #~ msgstr "Resum per a %s - %s" hamster-3.0.3/po/cs.po000066400000000000000000000611261452646177100145660ustar00rootroot00000000000000# Czech translation of hamster. # Copyright (C) 2008, 2009, 2010 the author(s) of hamster. # This file is distributed under the same license as the hamster-time-tracker package. # # Adrian Guniš , 2008, 2009, 2010. # Petr Kovar , 2009, 2010. # Marek Černocký , 2010, 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-17 12:59+0100\n" "Last-Translator: Marek Černocký \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Přidat starší činnost" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "až" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "probíhá" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Popis:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Čas:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Činnost:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Štítky:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Zastavit sledování při nečinnosti" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Zastavit sledování aktuální činnosti při nečinnosti počítače" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Zastavit sledování při vypnutí počítače" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Zastavit sledování aktuální činnosti při vypnutí počítače" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Připomenout aktuální úlohu každých x minut" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Připomenout aktuální úlohu vždy po nastaveném času (min). Nastavte na 0 nebo " "větší než 120 pro zakázání upozorňování." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Připomenout, i když není nastavena žádná činnost" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Připomenout vždy po nastavené době upozorňování (notify_interval v min.), " "pokud nebyla spuštěna žádná činnost." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "V kolik hodin začíná den (výchozí čas je 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Činnosti budou zahrnuty do včerejška, pokud je aktuální čas před stanoveným " "začátkem dne, a do dneška v případě, že překročí tento čas. Činnosti, které " "trvají dva dny, se překlopí do dne, ve kterém se odehrává delší část " "činnosti." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Může přepínač pracovních ploch spustit přepínač činnosti?" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Seznam povolených metod sledování. Hodnota „name“ povolí přepínání činností " "podle názvu stanoveného v klíči workspace_mapping. Hodnota „memory“ povolí " "přepnutí na poslední činnost při návratu na předchozí pracovní plochu." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Přepnout činnost při změně pracovní plochy" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Pokud je přepínání podle názvu povoleno, tento seznam stanoví názvy " "činností, které mohou být přepnuty na pracovní plochy reprezentované " "seznamem položek." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Zobrazit / skrýt okno Sledování času" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Klávesová zkratka pro zobrazení / skrytí okna Sledování času." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Přepnout akci okna aplikace hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Příkaz pro přepínání viditelnosti okna aplikace hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Přepnout okno aplikace hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Přepnout viditelnost okna aplikace hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Sledování času" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster - sledujte svůj čas" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Přehled sledování času" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Okno s přehledem o sledování času Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Zobrazit statistiky" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorie" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Činnosti" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Štítky" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Žádná data v tomto intervalu" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Uložit zprávu..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Den" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Týden" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Měsíc" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Přehled — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "Pře_hled" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Činnost" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Zobrazení" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Celkem" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Odstranit" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Přidat nový" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Upravit" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Předvolby Sledování času" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Zastavit sledování při nečinnosti počítače" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Připomenout aktuální činnost každých:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Nový den začíná v" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Použít následující seznam úkolů, pokud je dostupný:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Začlenění" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Sledování" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorie" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Seznam kategorií" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Přidat kategorii" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Odstranit kategorii" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Upravit kategorii" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "Č_innosti" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Seznam činností" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Přidat činnost" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Odstranit činnost" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Upravit činnost" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Štítky, které se objeví v automatickém doplňování" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorie a štítky" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Pokračovat v poslední činnosti při návratu na pracovní plochu" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Spustit novou činnost při přepínání pracovních ploch:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Pracovní plochy" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Den:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Týden:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Měsíc:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Časové období:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Použít" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Sledování" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Přidat starší činnost" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Přehled" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistiky" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Upravit" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Nápověda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Obsah" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Zastavit sledování" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Př_epnout" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Spustit sledování" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Spustit novou činnost" #: ../data/today.ui.h:13 msgid "Today" msgstr "Dnes" #: ../data/today.ui.h:14 msgid "totals" msgstr "celkem" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Zobrazit přehled" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Žádná činnost" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorie" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Popis" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Začátek" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Konec" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Trvání" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorie" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekt Hamster — sledujte svůj čas" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2010 Toms Bauģis a další" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Webová stránka projektu Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "O appletu Sledování času" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Adrian Guniš , 2009, 2010" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Bez kategorie" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Práce" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Čtení novinek" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Kontrolování zásob" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Supertajný projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Hra World domination" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Každý den" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Oběd" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Zalévání květin" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Cvičení" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Aktualizace činnosti" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s %(start_Y)s – %(end_d)s. %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s – %(end_d)s. %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. – %(end_d)s. %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s celkem sledovaných hodin" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Žádný" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Název" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nová kategorie" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nová činnost" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuta" msgstr[1] "%(interval_minutes)d minuty" msgstr[2] "%(interval_minutes)d minut" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nikdy" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "činnost" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "čas zahájení" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "čas ukončení" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "doba trvání v minutách" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorie" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "popis" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "štítky" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Výstupní sestava činností za %(start_d)s. %(start_B)s %(start_Y)s – " "%(end_d)s. %(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Výstupní sestava činností za %(start_d)s. %(start_B)s – %(end_d)s. " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Výstupní sestava činností za %(start_d)s. %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Výstupní sestava činností za %(start_d)s. – %(end_d)s. %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d. %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Souhrny za den" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Záznam činností" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "činnosti" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorie" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Rozlišit:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Zobrazit šablonu" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Můžete ji přepsat uložením vaší verze do %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Vše" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Ještě nejsou žádná data pro vytvoření statistik.\n" "To je vhodné po týdnu používání!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Ještě se sbírají data — prohlédněte znovu za týden!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d. %m. %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %m." #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "První činnost byla zaznamenána %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s rok" msgstr[1] "%(num)s roky" msgstr[2] "%(num)s let" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Dosud sledovaný čas čítá %(human_days)s kalendářních dnů (%(human_years)s) " "nebo %(working_days)s pracovních dnů (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d. %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Nejdelší souvislá práce proběhla %(date)s a trvala %(hours)s hodinu." msgstr[1] "" "Nejdelší souvislá práce proběhla %(date)s a trvala %(hours)s hodiny." msgstr[2] "Nejdelší souvislá práce proběhla %(date)s a trvala %(hours)s hodin." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "K dispozici je %s záznam." msgstr[1] "K dispozici jsou %s záznamy." msgstr[2] "K dispozici je %s záznamů." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster by vás rád sledoval o trochu víc!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "S %s procenty všech aktivit spuštěných před 9 hodinou se zdá, že jste ranní " "ptáče." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "S %s procenty všech aktivit spuštěných po 23 hodině se zdá, že jste noční " "sova." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "S %s procenty všech aktivit kratších než 15 minut se zdá, že jste pilná " "včela." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Dnes žádné záznamy" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Právě spuštěno" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Uložit zprávu — Sledování času" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Zpráva ve formátu HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Hodnoty oddělené tabulátory (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Sledované období" #~ msgid "Show activities window" #~ msgstr "Zobrazit okno s činnostmi" #~ msgid "Sto_p Tracking" #~ msgstr "_Zastavit sledování" #~ msgid "To_day" #~ msgstr "_Dnes" #~ msgid "_Add earlier activity" #~ msgstr "Přid_at starší činnost" #~ msgid "Show _Overview" #~ msgstr "Zobrazit _přehled" #~ msgid "_Preferences" #~ msgstr "Před_volby" #~ msgid "_About" #~ msgstr "O _appletu" #~ msgid "Year:" #~ msgstr "Rok:" #~ msgid "Starts and ends" #~ msgstr "Začátky a konce" #~ msgid "Preferences" #~ msgstr "Předvolby" #~ msgid "Changed activity" #~ msgstr "Činnost změněna" #~ msgid "Switched to '%s'" #~ msgstr "Přepnuto na „%s“" #~ msgid "Working on %s" #~ msgstr "Pracuje se na %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Sledování času Hamster. Použití:" hamster-3.0.3/po/da.po000066400000000000000000000722461452646177100145520ustar00rootroot00000000000000# Danish translation of Hamster Applet # Copyright (C) 2008-2009 Free Software Foundation, Inc. # This file is distributed under the same license as the Hamster Applet package. # Ask Hjorth Larsen , 2008, 09. # Kenneth Nielsen , 2010. # Kris Thomsen , 2011. # Aputsiaq Niels Janussen , 2011. # TODO: # - Check og "None" i preferences.py:103 refererer til gøremål eller gøremålsliste # Husk at tilføje dit navn til translator-credits #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: Hamster Applet\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-18 20:00+0100\n" "Last-Translator: Aputsiaq Niels Janussen \n" "Language-Team: Danish \n" "Language: da\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" "X-Generator: Virtaal 0.6.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Tilføj tidligere aktivitet" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "til" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "i gang" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Beskrivelse:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Tid:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivitet:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Mærker:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stop måling ved inaktivitet" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stop måling af den aktuelle aktivitet når computeren er inaktiv" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stop måling når der slukkes" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stop måling af den aktuelle aktivitet når der slukkes" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Påmind om nuværende opgave hvert x'te minut" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Påmind om den nuværende opgave med det angivne interval i minutter. Sæt " "værdien til 0 eller højere end 120 for at deaktivere påmindelsen." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Påmind også når ingen aktivitet er angivet" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Påmind også hvert notify_interval minut, hvis ingen aktivitet er påbegyndt." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "På hvilket tidspunkt starter dagen (forvalget er 5.30 om morgenen)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktiviteter vil blive regnet som tilhørende i går, hvis den aktuelle tid er " "mindre end den specificerede start på dagen og ellers vil den blive regnet " "som tilhørende i dag. Aktiviteter, som spænder over to dage, vil tippe over " "til den dag hvor størstedelen af aktiviteten ligger." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Skal arbejdsområdeskift udløse aktivitetsskift" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Liste af aktiverede sporingsmetoder. \"name\" vil aktivere skift efter navn, " "defineret i arbejdsområde_kortlægning. \"memory\" vil aktivere skift til " "sidste aktivitet, når der returneres til et tidligere arbejdsområde." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Skift aktivitet ved arbejdsområdeskift" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Hvis skift efter navn er aktiveret, vil denne liste indeholde de " "aktivitetsnavne som der skal skiftes til, arbejdsområder repræsenteret ved " "objektets indeks." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Vis/skjul tidsstyringsvinduet" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Tastaturgenvej for at vise/skjule tidsstyringsvinduet." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Handling som slår hamster-programvinduet til eller fra" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" "Kommando for at slå synligheden af hamster-programvinduet til eller fra." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Slå hamster-programvinduet til eller fra" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Slå synligheden af hamster-programvinduet til eller fra." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tidsstyring" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster - få styr på din tid" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Tidsstyringsoversigt" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Oversigtsvinduet for tidsstyringen" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Vis statistik" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorier" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktiviteter" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Mærker" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Ingen data for dette interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Gem rapport..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dag" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Uge" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Måned" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Oversigt — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Oversigt" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivitet" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Vis" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Opgørelse" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Fjern" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Tilføj ny" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Redigér" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Indstillinger for tidsstyring" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stop måling når computeren er inaktiv" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Påmind om nuværende aktivitet hver:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Ny dag starter klokken" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Brug følgende gøremålsliste hvis den er tilgængelig:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integration" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Måling" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorier" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategoriliste" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Tilføj kategori" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Fjern kategori" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Redigér kategori" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktiviteter" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Aktivitetsliste" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Tilføj aktivitet" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Fjern aktivitet" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Redigér aktivitet" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Mærker som skal være tilgængelige til autofuldførelse" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorier og mærker" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Genoptag den sidste aktivitet, ved returnering til et arbejdsområde" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Start ny aktivitet ved arbejdsområdeskift:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Arbejdsområder" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dag:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Uge:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Måned:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Interval:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Anvend" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Måling" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Tilføj tidligere aktivitet" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Oversigt" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistik" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Redigér" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Hjælp" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Indhold" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_p måling" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "S_kift" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Start _måling" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Start ny aktivitet" #: ../data/today.ui.h:13 msgid "Today" msgstr "I dag" #: ../data/today.ui.h:14 msgid "totals" msgstr "opgørelse" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Vis oversigt" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Ingen aktivitet" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategori" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Beskrivelse" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Start" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Slut" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Varighed" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorier" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekt Hamster — få styr på din tid" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Ophavsret © 2007-2010 Toms Bauģis og andre" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Webside for Projekt Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Om tidsstyring" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Kris Thomsen \n" "Kenneth Nielsen \n" "Ask Hjorth Larsen \n" "Aputsiaq Janussen \n" "\n" "Dansk-gruppen \n" "Mere info: http://www.dansk-gruppen.dk" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Usorteret" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Arbejde" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Læser nyheder" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Tjekker aktier" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Superhemmeligt projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Verdensherredømmet" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Hverdagsting" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Frokost" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Vander blomster" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Står på hænder" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Opdatér aktivitet" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dt" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dt %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s %(start_Y)s – %(end_d)s. %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. – %(end_d)s. %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s timer målt i alt" # Check om det er et gøremål eller en gøremålsliste. #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ingen" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Navn" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Ny kategori" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Ny aktivitet" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minutter" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Aldrig" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivitet" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "starttidspunkt" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "sluttidspunkt" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "varighed i minutter" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategori" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "beskrivelse" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "mærker" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Aktivitetsrapport for %(start_d)s. %(start_B)s, %(start_Y)s – %(end_d)s. " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Aktivitetsrapport for %(start_d)s. %(start_B)s – %(end_d)s. %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Aktivitetsrapport for %(start_d)s. %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Aktivitetsrapport for %(start_d)s. – %(end_d)s. %(start_B)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d. %b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Opgørelser dagsvis" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Aktivitetslog" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktiviteter" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorier" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Skeln mellem:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Dato" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Vis skabelon" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Du kan tilsidesætte den ved at gemme din version i %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Alle" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Der er ingen data til at generere statistik over endnu.\n" "En uges brug ville være en god ting!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Indsamler data — vend tilbage når der er gået en uge!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d. %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Første aktivitet optaget den %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s år" msgstr[1] "%(num)s år" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tiden målt indtil nu er %(human_days)s egentlige dage (%(human_years)s) " "eller %(working_days)s arbejdsdage (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d. %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Længste kontinuerlige arbejdsindsats skete den %(date)s og varede %(hours)s " "time." msgstr[1] "" "Længste kontinuerlige arbejdsindsats skete den %(date)s og varede %(hours)s " "timer." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Der er %s måling." msgstr[1] "Der er %s målinger." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster vil godt kigge lidt mere på dig!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Med %s procent af alle aktiviteter begyndende før klokken 9 om morgenen, " "synes du at være lidt af et morgenmenneske." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Med %s procent af alle aktiviteter begyndende efter kl. 11 om aftenen, synes " "du at være lidt af en natugle." # Det er godtnok ikke en særlig underholdende bemærkning, kan nogen finde på noget bedre? #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Idet %s procent af alle aktiviteter varer kortere end 15 minutter, synes du " "at være en travl person." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Ingen målinger i dag" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%st" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Er lige startet" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Gem rapport — Tidsstyring" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-rapport" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabulatoradskilte værdier (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Tidsstyring" #~ msgid "Show activities window" #~ msgstr "Vis aktivitetsvinduet" #~ msgid "Show _Overview" #~ msgstr "Vis _oversigt" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_p måling" #~ msgid "To_day" #~ msgstr "I _dag" #~ msgid "_Add earlier activity" #~ msgstr "_Tilføj tidligere aktivitet" #~ msgid "_About" #~ msgstr "_Om" #~ msgid "_Preferences" #~ msgstr "_Indstillinger" #~ msgid "Starts and ends" #~ msgstr "Starter og slutter" #~ msgid "Year:" #~ msgstr "År:" #~ msgid "Preferences" #~ msgstr "Indstillinger" #~ msgid "Changed activity" #~ msgstr "Skiftede aktivitet" #~ msgid "Switched to '%s'" #~ msgstr "Skiftede til \"%s\"" #~ msgid "Working on %s" #~ msgstr "Arbejder på %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster-tidsstyring. Brug:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projekt Hamster (tidsstyring til GNOME)" #~ msgid "totals by activity" #~ msgstr "opgørelser aktivitetsvis" #~ msgid "totals by category" #~ msgstr "opgørelser kategorivis" #~ msgid "Show:" #~ msgstr "Vis:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Tilfø_j tidligere aktivitet" #~ msgid "Tell me more" #~ msgstr "Fortæl mig mere" #~ msgid "_Today" #~ msgstr "_I dag" #~ msgid "Preview:" #~ msgstr "Forhåndsvisning:" #~ msgid "General" #~ msgstr "Generelt" #~ msgid "Global Hotkey" #~ msgstr "Global genvejstast" #~ msgid "Move activity down" #~ msgstr "Flyt aktivitet ned" #~ msgid "Move activity up" #~ msgstr "Flyt aktivitet op" #~ msgid "Total Time" #~ msgstr "Samlet tid" #~ msgid "Activities" #~ msgstr "Aktiviteter" #~ msgid "Tracking" #~ msgstr "Måler" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Skriv en aktivitet og tryk Enter for at starte " #~ "måling!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Fortæl mere" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Aktivitet:" #~ msgid " _Day" #~ msgstr " _Dag" #~ msgid " _Month" #~ msgstr " _Måned" #~ msgid " _Week" #~ msgstr " _Uge" #~ msgid "Overview" #~ msgstr "Oversigt" #~ msgid "Totals" #~ msgstr "Opgørelse" #~ msgid "Categories:" #~ msgstr "Kategorier:" #~ msgid "Date interval:" #~ msgstr "Datointerval:" #~ msgid "Save as HTML" #~ msgstr "Gem som HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "Hvad bør der skrives i aktivitetsboksen?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "En simpel syntaks lader dig tilføje detaljer om dine aktiviteter:\n" #~ "\n" #~ "Symbolet \"@\" markerer en kategori. Eksempel: \"vander blomster@hjemme\" " #~ "vil starte aktiviteten \"vander blomster\" i kategorien \"hjemme\".\n" #~ "\n" #~ "Kommaer (\",\") markerer begyndelsen af en beskrivelse. Eksempel: " #~ "\"vander blomster, begoniaer og forglemmigejer\" vil starte aktiviteten " #~ "\"vander blomster\", og føje beskrivelsen \"begoniaer og forglemmigejer\" " #~ "til den.\n" #~ "\n" #~ "Disse kan kombineres: \"vander blomster@hjemme, begoniaer og " #~ "forglemmigejer\" fungerer uden problemer.\n" #~ "\n" #~ "Lad os så komme i gang!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Alle" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s. %(b)s" #~ msgid "Total" #~ msgstr "Opgørelse" #~ msgid "Overview for %(date)s" #~ msgstr "Oversigt for %(date)s" #~ msgid "Move _Down" #~ msgstr "Flyt _ned" #~ msgid "Move _Up" #~ msgstr "Flyt _op" #~ msgid "N_ew Category" #~ msgstr "N_y kategori" #~ msgid "_New Activity" #~ msgstr "_Ny aktivitet" #~ msgid "Activity" #~ msgstr "Aktivitet" #~ msgid "hours" #~ msgstr "timer" #~ msgid "Delete activity" #~ msgstr "Slet aktivitet" #~ msgid "Newer activities" #~ msgstr "Nyere aktiviteter" #~ msgid "Show month" #~ msgstr "Vis måned" #~ msgid "name" #~ msgstr "navn" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s. %(report_b)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_d)s. %(o_b)s" #~ msgid "Category" #~ msgstr "Kategori" #~ msgid "Week" #~ msgstr "Uge" #~ msgid "Earlier activities" #~ msgstr "Tidligere aktiviteter" #~ msgid "Other" #~ msgstr "Anden" #~ msgid "Time tracking for masses" #~ msgstr "Tidsstyring til folket" #~ msgid "Time tracking for masses." #~ msgstr "Tidsstyring til folket." #~ msgid "Overview for %s - %s" #~ msgstr "Oversigt for %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%d.%m.%y" #~ msgid "%d. %b" #~ msgstr "%d. %b" #~ msgid "%B %d." #~ msgstr "%d. %B" hamster-3.0.3/po/de.po000066400000000000000000000645411452646177100145550ustar00rootroot00000000000000# German Translation for GNOME hamster-time-tracker # Copyright (C) 2008 Project Hamster Team # This file is distributed under the same license as the projecthamster package. # Matthias Mailänder https://launchpad.net/~mailaender, 2008. # Hendrik Richter , 2008, 2009. # Mario Blättermann , 2009-2012. # Christian Kirbach , 2010, 2011. # Wolfgang Stöggl , 2011. # Benjamin Steinwender , 2017. # msgid "" msgstr "" "Project-Id-Version: Hamster master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-04-15 08:21+0200\n" "PO-Revision-Date: 2017-04-15 08:27+0200\n" "Last-Translator: Benjamin Steinwender \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: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 1.8.12\n" #: ../data/date_range.ui.h:1 msgid "Today:" msgstr "Heute:" #: ../data/date_range.ui.h:2 msgid "Week:" msgstr "Woche:" #: ../data/date_range.ui.h:3 msgid "Month:" msgstr "Monat:" #: ../data/date_range.ui.h:4 msgid "Range:" msgstr "Datumsbereich:" #: ../data/date_range.ui.h:5 msgid "to" msgstr "bis" #: ../data/date_range.ui.h:6 msgid "Apply" msgstr "Anwenden" #: ../data/edit_activity.ui.h:1 msgid "Add Earlier Activity" msgstr "Neue Tätigkeit hinzufügen" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Erfassung bei Untätigkeit anhalten" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Wenn sich der Rechner im Leerlauf befindet, die momentane Tätigkeit nicht " "weiter erfassen" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Beim Herunterfahren die Erfassung anhalten" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Beim Herunterfahren momentane Tätigkeit nicht weiter erfassen" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Alle X Minuten an momentane Tätigkeit erinnern" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Alle X Minuten an momentane Tätigkeit erinnern. Wenn dieser Wert 0 oder " "größer als 120 ist, wird die Erinnerung deaktiviert." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Auch dann erinnern, wenn keine Tätigkeit gesetzt ist" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Auch alle »notify_interval« Minuten erinnern, falls keine Tätigkeit begonnen " "wurde. " #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Zeit des Tagesbeginns (Vorgabe ist 5:30 Uhr)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Tätigkeiten werden dem gestrigen Tag zugeordnet, falls die aktuelle " "Tageszeit vor der als Tagesbeginn festgelegten Zeit liegt, und dem heutigen " "Tag, falls danach. Tätigkeiten, die sich über zwei Tage erstrecken, werden " "dem Tag zugeordnet, zu dem der längste Teil der Tätigkeit gehört." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Arbeitsflächenwechsel bedingt Tätigkeitswechsel" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Liste der aktivierten Methoden zur Zeiterfassung. »name« aktiviert den " "Wechsel der Tätigkeit anhand des Namens, der in »workspace_mapping« " "festgelegt ist. »memory« aktiviert die letzte Tätigkeit bei der Rückkehr zur " "vorherigen Arbeitsfläche." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Tätigkeit bei Arbeitsflächenwechsel ebenfalls wechseln" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Falls der Wechsel anhand des Namens aktiviert ist, gibt diese Liste die " "Namen an, zu denen gewechselt werden soll. Arbeitsflächen werden durch den " "Index des Eintrags dargestellt." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Zeiterfassungsfenster anzeigen/verbergen" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Tastenkürzel um das Zeiterfassungsfenster anzuzeigen/zu verbergen." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" "Aktion zum Ein- und Ausschalten der Sichtbarkeit des Anwendungsfensters von " "Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" "Befehl zum Ein- und Ausschalten der Sichtbarkeit des Anwendungsfensters von " "Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Hamster-Anwendungsfenster sichtbar/unsichtbar" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Die Sichtbarkeit des Hamster-Anwendungsfensters ein-/ausschalten." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../src/hamster/about.py:31 #: ../src/hamster/about.py:32 msgid "Time Tracker" msgstr "Zeiterfassung" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster - Erfassen Sie Ihre Zeit" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Zeiterfassungsübersicht" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Das Übersichtsfenster der Hamster-Zeiterfassung" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "hamster-time-tracker Einstellungen" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Im Leerlauf die Erfassung anhalten" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "An momentane Tätigkeit erinnern:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Neuer Tag beginnt um" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Folgende Aufgabenliste verwenden, falls verfügbar:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integration" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Erfassung" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorien" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategorienliste" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Kategorie hinzufügen" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Kategorie entfernen" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Kategorie bearbeiten" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Tätigkeiten" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Tätigkeitsliste" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Tätigkeit hinzufügen" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Tätigkeit entfernen" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Tätigkeit bearbeiten" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" "Schlagworte, die in der automatischen Vervollständigung erscheinen sollen" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorien und Schlagworte" #: ../src/hamster/about.py:34 msgid "Project Hamster — track your time" msgstr "Projekt-Hamster - Erfassen Sie Ihre Zeit" #: ../src/hamster/about.py:35 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2010 Toms Baugis und andere" #: ../src/hamster/about.py:37 msgid "Project Hamster Website" msgstr "Hamster-Projektwebsite" #: ../src/hamster/about.py:38 msgid "About Time Tracker" msgstr "Info zur Zeiterfassung" #: ../src/hamster/about.py:48 msgid "translator-credits" msgstr "" "Matthias Mailänder https://launchpad.net/~mailaender\n" "Hendrik Richter \n" "Mario Blättermann \n" "Christian Kirbach \n" "Benjamin Steinwender " #: ../src/hamster/edit_activity.py:81 msgid "Update activity" msgstr "Tätigkeit aktualisieren" #: ../src/hamster/overview.py:86 msgid "Export..." msgstr "Exportieren …" #: ../src/hamster/overview.py:88 msgid "Tracking Settings" msgstr "Erfassungseinstellungen" #: ../src/hamster/overview.py:254 msgid "Click to see stats" msgstr "Klicken Sie für Statistiken" #: ../src/hamster/preferences.py:52 ../src/hamster/reports.py:89 #: ../src/hamster/reports.py:126 ../src/hamster/reports.py:255 msgid "Unsorted" msgstr "Unsortiert" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:93 msgid "None" msgstr "Nichts" #: ../src/hamster/preferences.py:111 msgid "Name" msgstr "Name" #: ../src/hamster/preferences.py:136 ../src/hamster/reports.py:316 msgid "Category" msgstr "Kategorie" #: ../src/hamster/preferences.py:542 msgid "New category" msgstr "Neue Kategorie" #: ../src/hamster/preferences.py:557 msgid "New activity" msgstr "Neue Tätigkeit" #. notify interval slider value label #: ../src/hamster/preferences.py:584 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d Minute" msgstr[1] "%(interval_minutes)d Minuten" #. notify interval slider value label #: ../src/hamster/preferences.py:589 msgid "Never" msgstr "Nie" #. column title in the TSV export format #: ../src/hamster/reports.py:147 msgid "activity" msgstr "Tätigkeit" #. column title in the TSV export format #: ../src/hamster/reports.py:149 msgid "start time" msgstr "Beginn" #. column title in the TSV export format #: ../src/hamster/reports.py:151 msgid "end time" msgstr "Ende" #. column title in the TSV export format #: ../src/hamster/reports.py:153 msgid "duration minutes" msgstr "Dauer in Minuten" #. column title in the TSV export format #: ../src/hamster/reports.py:155 msgid "category" msgstr "Kategorie" #. column title in the TSV export format #: ../src/hamster/reports.py:157 msgid "description" msgstr "Beschreibung" #. column title in the TSV export format #: ../src/hamster/reports.py:159 ../src/hamster/reports.py:310 msgid "tags" msgstr "Schlagworte" #: ../src/hamster/reports.py:206 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Tätigkeitsprotokoll für %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:208 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Tätigkeitsprotokoll für %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:210 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Tätigkeitsprotokoll für %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:212 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Tätigkeitsprotokoll für %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:264 ../src/hamster/reports.py:296 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #: ../src/hamster/reports.py:304 msgid "Totals by Day" msgstr "Gesamt nach Tag" #: ../src/hamster/reports.py:305 msgid "Activity Log" msgstr "Tätigkeitsprotokoll" #: ../src/hamster/reports.py:306 msgid "Totals" msgstr "Gesamt" #: ../src/hamster/reports.py:308 msgid "activities" msgstr "Tätigkeiten" #: ../src/hamster/reports.py:309 msgid "categories" msgstr "Kategorien" #: ../src/hamster/reports.py:312 msgid "Distinguish:" msgstr "Unterscheiden:" #: ../src/hamster/reports.py:314 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:315 msgid "Activity" msgstr "Tätigkeit" #: ../src/hamster/reports.py:317 msgid "Tags" msgstr "Schlagworte" #: ../src/hamster/reports.py:318 msgid "Start" msgstr "Beginn" #: ../src/hamster/reports.py:319 msgid "End" msgstr "Ende" #: ../src/hamster/reports.py:320 msgid "Duration" msgstr "Dauer" #: ../src/hamster/reports.py:321 msgid "Description" msgstr "Beschreibung" #: ../src/hamster/reports.py:324 msgid "Show template" msgstr "Vorlage anzeigen" #: ../src/hamster/reports.py:325 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Sie können dies überschreiben, indem Sie Ihre Version in %(home_folder)s " "speichern" #: ../src/hamster/widgets/reportchooserdialog.py:40 msgid "Save Report — Time Tracker" msgstr "Bericht speichern — Zeiterfassung" #: ../src/hamster/widgets/reportchooserdialog.py:58 msgid "HTML Report" msgstr "HTML-Bericht" #: ../src/hamster/widgets/reportchooserdialog.py:66 msgid "Tab-Separated Values (TSV)" msgstr "Durch Tabulatoren getrennte Werte (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:74 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:81 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:98 msgid "Time track" msgstr "Zeiterfassung" #~ msgid "in progress" #~ msgstr "im Gange" #~ msgid "Description:" #~ msgstr "Beschreibung:" #~ msgid "Time:" #~ msgstr "Zeit:" #~ msgid "Activity:" #~ msgstr "Tätigkeit:" #~ msgid "Tags:" #~ msgstr "Schlagworte:" #~ msgid "Show Statistics" #~ msgstr "Statistiken zeigen" #~ msgid "Categories" #~ msgstr "Kategorien" #~ msgid "Activities" #~ msgstr "Tätigkeiten" #~ msgid "No data for this interval" #~ msgstr "Keine Daten für diese Zeitspanne" #~ msgid "Day" #~ msgstr "Tag" #~ msgid "Week" #~ msgstr "Woche" #~ msgid "Month" #~ msgstr "Monat" #~ msgid "Overview — Hamster" #~ msgstr "Übersicht — Hamster" #~ msgid "_Overview" #~ msgstr "Ü_bersicht" #~ msgid "_View" #~ msgstr "_Ansicht" #~ msgid "Remove" #~ msgstr "Entfernen" #~ msgid "Add new" #~ msgstr "Neu hinzufügen" #~ msgid "Edit" #~ msgstr "Bearbeiten" #~ msgid "Resume the last activity when returning to a workspace" #~ msgstr "" #~ "Bei Rückkehr auf eine Arbeitsfläche letzte Tätigkeit wiederaufnehmen" #~ msgid "Start new activity when switching workspaces:" #~ msgstr "Beim Arbeitsflächenwechsel neue Tätigkeit starten" #~ msgid "Workspaces" #~ msgstr "Arbeitsflächen" #~ msgid "Day:" #~ msgstr "Tag:" #~ msgid "_Tracking" #~ msgstr "_Erfassung" #~ msgid "Add earlier activity" #~ msgstr "Frühere Tätigkeit hinzufügen" #~ msgid "Overview" #~ msgstr "Übersicht" #~ msgid "Statistics" #~ msgstr "Statistiken" #~ msgid "_Edit" #~ msgstr "_Bearbeiten" #~ msgid "_Help" #~ msgstr "_Hilfe" #~ msgid "Contents" #~ msgstr "Inhalt" #~ msgid "Sto_p tracking" #~ msgstr "Erfassung _anhalten" #~ msgid "S_witch" #~ msgstr "_Wechseln" #~ msgid "Start _Tracking" #~ msgstr "Erfassung s_tarten" #~ msgid "Start new activity" #~ msgstr "Neue Tätigkeit starten" #~ msgid "totals" #~ msgstr "Gesamt" #~ msgid "Show Overview" #~ msgstr "Übersicht anzeigen" #~ msgid "No activity" #~ msgstr "Keine Tätigkeit" #, fuzzy #~ msgid "Uncategorized" #~ msgstr "Kategorien" #~ msgid "Work" #~ msgstr "Arbeit" #~ msgid "Reading news" #~ msgstr "Nachrichten lesen" #~ msgid "Checking stocks" #~ msgstr "Aktienkurse überprüfen" #~ msgid "Super secret project X" #~ msgstr "Supergeheimprojekt X" #~ msgid "World domination" #~ msgstr "Weltherrschaft" #~ msgid "Day-to-day" #~ msgstr "Tag für Tag" #~ msgid "Lunch" #~ msgstr "Mittagessen" #~ msgid "Watering flowers" #~ msgstr "Blumen gießen" #~ msgid "Doing handstands" #~ msgstr "Handstand machen" #~ msgid "%dh" #~ msgstr "%dh" #~ msgid "%dmin" #~ msgstr "%dmin" #~ msgid "%dh %dmin" #~ msgstr "%dh %dmin" #~ msgid "%B %d, %Y" #~ msgstr "%d. %B %Y" #~ msgid "" #~ "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgstr "" #~ "%(start_d)s. %(start_B)s %(start_Y)s – %(end_d)s. %(end_B)s %(end_Y)s" #~ msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgstr "%(start_d)s. %(start_B)s – %(end_d)s. %(end_B)s %(end_Y)s" #~ msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #~ msgstr "%(start_d)s. – %(end_d)s. %(start_B)s %(end_Y)s" #~ msgctxt "overview list" #~ msgid "%A, %b %d" #~ msgstr "%A, %d.%b." #~ msgid "%s hours tracked total" #~ msgstr "%s Stunden insgesamt erfasst" #~ msgctxt "years" #~ msgid "All" #~ msgstr "Alle" #~ msgid "" #~ "There is no data to generate statistics yet.\n" #~ "A week of usage would be nice!" #~ msgstr "" #~ "Es gibt noch keine Daten zur Erstellung einer Statistik.\n" #~ "Eine Woche Benutzung wäre wünschenswert!" #~ msgid "Collecting data — check back after a week has passed!" #~ msgstr "" #~ "Daten werden noch gesammelt — Bitte warten Sie, bis eine Woche vergangen " #~ "ist!" #~ msgctxt "first record" #~ msgid "%b %d, %Y" #~ msgstr "%d.%b.%Y" #~ msgctxt "first record" #~ msgid "%b %d" #~ msgstr "%d.%b." #~ msgid "First activity was recorded on %s." #~ msgstr "Die erste Tätigkeit wurde am %s aufgezeichnet." #~ msgid "%(num)s year" #~ msgid_plural "%(num)s years" #~ msgstr[0] "%(num)s Jahr" #~ msgstr[1] "%(num)s Jahre" #~ msgid "" #~ "Time tracked so far is %(human_days)s human days (%(human_years)s) or " #~ "%(working_days)s working days (%(working_years)s)." #~ msgstr "" #~ "Die bisher erfasste Zeit ist %(human_days)s Kalendertage " #~ "(%(human_years)s) oder %(working_days)s Arbeitstage (%(working_years)s)." #~ msgctxt "date of the longest activity" #~ msgid "%b %d, %Y" #~ msgstr "%d.%b.%Y" #~ msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." #~ msgid_plural "" #~ "Longest continuous work happened on %(date)s and was %(hours)s hours." #~ msgstr[0] "" #~ "Die längste zusammenhängende Tätigkeit geschah am %(date)s und dauerte " #~ "%(hours)s Stunde." #~ msgstr[1] "" #~ "Die längste zusammenhängende Tätigkeit geschah am %(date)s und dauerte " #~ "%(hours)s Stunden." #~ msgid "There is %s record." #~ msgid_plural "There are %s records." #~ msgstr[0] "Es gibt %s Aufzeichnung." #~ msgstr[1] "Es gibt %s Aufzeichnungen." #~ msgid "Hamster would like to observe you some more!" #~ msgstr "Hamster möchte Sie gern ein wenig genauer beobachten!" #~ msgid "" #~ "With %s percent of all activities starting before 9am, you seem to be an " #~ "early bird." #~ msgstr "" #~ "Da %s Prozent aller Aufgaben vor 9 Uhr begonnen wurden, sind Sie " #~ "sicherlich ein Frühaufsteher." #~ msgid "" #~ "With %s percent of all activities starting after 11pm, you seem to be a " #~ "night owl." #~ msgstr "" #~ "Da %s Prozent aller Aufgaben nach 23 Uhr begonnen wurden, sind Sie " #~ "sicherlich eine Nachteule." #~ msgid "" #~ "With %s percent of all activities being shorter than 15 minutes, you seem " #~ "to be a busy bee." #~ msgstr "" #~ "Da %s Prozent aller Aufgaben weniger als 15 Minuten in Anspruch nahmen, " #~ "scheinen Sie eine fleißige Biene zu sein." #~ msgid "No records today" #~ msgstr "Heute keine Aufzeichnungen" #~ msgid "%(category)s: %(duration)s" #~ msgstr "%(category)s: %(duration)s, " #~ msgid "%sh" #~ msgstr "%sh" #~ msgid "Just started" #~ msgstr "Soeben gestartet" #~ msgid "Show activities window" #~ msgstr "Aktivitäten-Fenster anzeigen" #~ msgid "Sto_p Tracking" #~ msgstr "Erfassung _anhalten" #~ msgid "To_day" #~ msgstr "_Heute" #~ msgid "_Add earlier activity" #~ msgstr "Fr_ühere Tätigkeit hinzufügen" #~ msgid "Show _Overview" #~ msgstr "Ü_bersicht anzeigen" #~ msgid "_Preferences" #~ msgstr "_Einstellungen" #~ msgid "_About" #~ msgstr "_Info" #~ msgid "Year:" #~ msgstr "Jahr:" #~ msgid "Starts and ends" #~ msgstr "Beginn und Ende" #~ msgid "Preferences" #~ msgstr "Einstellungen" #~ msgid "Changed activity" #~ msgstr "Geänderte Tätigkeit" #~ msgid "Switched to '%s'" #~ msgstr "Gewechselt zu »%s«" #~ msgid "Working on %s" #~ msgstr "Arbeit an %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster Zeiterfassung. Aufruf:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projekt-Hamster (GNOME-Zeiterfassung)" #~ msgid "Tell me more" #~ msgstr "Weitere Infos nötig" #~ msgid "totals by activity" #~ msgstr "Gesamt nach Tätigkeit" #~ msgid "totals by category" #~ msgstr "Gesamt nach Kategorie" #~ msgid "Show:" #~ msgstr "Anzeigen:" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "Projekt-Hamster - Erfassen Sie Ihre Zeit" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Frühere Tätigkeit hinzufügen" #~ msgid "_Today" #~ msgstr "_Heute" #~ msgid "Preview:" #~ msgstr "Vorschau:" #~ msgid "General" #~ msgstr "Allgemein" #~ msgid "Global Hotkey" #~ msgstr "Globales Tastenkürzel" #~ msgid "Move activity down" #~ msgstr "Tätigkeit nach unten verschieben" #~ msgid "Move activity up" #~ msgstr "Tätigkeit nach oben verschieben" #~ msgid "Total Time" #~ msgstr "Gesamte Zeit" #~ msgid "Activities" #~ msgstr "Tätigkeiten" #~ msgid "Tracking" #~ msgstr "Erfassung" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Geben Sie eine Tätigkeit ein und drücken Sie die " #~ "Eingabetaste, um mit der Zeiterfassung zu beginnen!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Einzelheiten " #~ "bitte" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Tätigkeiten:" #~ msgid " _Day" #~ msgstr " _Tag" #~ msgid " _Month" #~ msgstr " _Monat" #~ msgid " _Week" #~ msgstr " _Woche" #~ msgid "Overview" #~ msgstr "Übersicht" #~ msgid "Totals" #~ msgstr "Gesamt" #~ msgid "Categories:" #~ msgstr "Kategorien:" #~ msgid "Date interval:" #~ msgstr "Zeitspanne:" #~ msgid "Save as HTML" #~ msgstr "Als HTML speichern" #~ msgid "What should be typed in the activity box?" #~ msgstr "Was sollte im Tätigkeitsfeld eingegeben werden?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Mit einer einfachen Syntax können Sie Details zu Ihren Tätigkeiten " #~ "hinzufügen:\n" #~ " \n" #~ "Das Symbol »@« markiert eine Kategorie. Beispiel: »Blumen gießen@zu " #~ "Hause« beginnt mit der Erfassung der Tätigkeit »Blumen gießen« in der " #~ "Kategorie »zu Hause.\n" #~ "\n" #~ "Kommata (»,«) leiten eine Beschreibung ein. Beispiel: »Blumen gießen, " #~ "Begonien und Orchideen« beginnt mit der Erfassung der Tätigkeit »Blumen " #~ "gießen« und fügt die Beschreibung »Begonien und Orchideen« hinzu.\n" #~ "\n" #~ "Beide können kombiniert werden: »Blumen gießen@zu Hause, Begonien und " #~ "Orchideen« funktioniert hervorragend!\n" #~ "\n" #~ "Beginnen Sie nun mit der Erfassung!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Alle" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s.%(b)s" #~ msgid "Total" #~ msgstr "Gesamt" #~ msgid "Overview for %(date)s" #~ msgstr "Übersicht für %(date)s" #~ msgid "Move _Down" #~ msgstr "He_runter bewegen" #~ msgid "Move _Up" #~ msgstr "_Hoch bewegen" #~ msgid "N_ew Category" #~ msgstr "_Neue Kategorie" #~ msgid "_New Activity" #~ msgstr "_Neue Tätigkeit" #~ msgid "Delete activity" #~ msgstr "Tätigkeit entfernen" #~ msgid "Newer activities" #~ msgstr "Neuere Tätigkeiten" #~ msgid "Show month" #~ msgstr "Monat anzeigen" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s. %(report_b)s %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_d)s. %(o_b)s" #, fuzzy #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration)s, " #~ msgid "Activity" #~ msgstr "Tätigkeit" #~ msgid "hours" #~ msgstr "Stunden" #~ msgid "minutes" #~ msgstr "Minuten" #~ msgid "Category" #~ msgstr "Kategorie" #~ msgid "Week" #~ msgstr "Woche" #~ msgid "Earlier activities" #~ msgstr "Vorherige Tätigkeiten" #~ msgid "name" #~ msgstr "Name" #~ msgid "Other" #~ msgstr "Sonstiges" #~ msgid "Time tracking for masses" #~ msgstr "Zeiterfassung leicht gemacht" #~ msgid "Time tracking for masses." #~ msgstr "Zeiterfassung leicht gemacht" #~ msgid "Overview for %s - %s" #~ msgstr "Übersicht für %s - %s" #~ msgid "Idle minutes:" #~ msgstr "Minuten bis untätig:" #~ msgid "Add an older fact" #~ msgstr "Alte Begebenheit hinzufügen" #~ msgid "" #~ "After how many minutes hamster should stop tracking activity when " #~ "computer is idle. Set to 0 to disable." #~ msgstr "" #~ "Nach wie vielen Minuten soll Hamster aufhören die Aktivitäten zu " #~ "verfolgen wenn der Computer im Leerlauf ist. Auf 0 setzen zum Abschalten " #~ "deaktivieren." #~ msgid "Ad_d Older Fact" #~ msgstr "_Alte Begebenheit hinzufügen" #~ msgid "Add older fact - Hamster" #~ msgstr "Alte Gegebenheit hinzufügen - Hamster" #~ msgid "_Cancel" #~ msgstr "_Abbrechen" #~ msgid "_Update" #~ msgstr "_Aktualisieren" hamster-3.0.3/po/el.po000066400000000000000000000750171452646177100145650ustar00rootroot00000000000000# Greek translation of Hamster Applet # Copyright (C) 2009, Free Software Foundation, Inc. # This file is distributed under the same license as the Hamster Applet package. # # Jennie Petoumenou , 2009. # George Stefanakis , 2011. # Giannis Katsampirhs , 2011. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-04-24 17:17+0200\n" "Last-Translator: Tom Tryfonidis \n" "Language-Team: Greek \n" "Language: el\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Προσθήκη προηγούμενης δραστηριότητας" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "μέχρι" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "σε εξέλιξη" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Περιγραφή:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Χρόνος:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Δραστηριότητα:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Ετικέτες:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Διακοπή καταγραφής κατά την αδρανοποίηση" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Διακοπή καταγραφής παρούσας δραστηριότητας, όταν ο υπολογιστής βρίσκεται σε " "αδράνεια" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Διακοπή καταγραφής κατά τον τερματισμό" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Διακοπή καταγραφής παρούσας δραστηριότητας κατά τον τερματισμό" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Υπενθύμιση τρέχουσας εργασίας κάθε x λεπτά" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Υπενθύμιση της τρέχουσας δραστηριότητας σε κάθε ορισμένο αριθμό λεπτών. " "Ορίστε το σε 0 ή σε μεγαλύτερο από 120 για να απενεργοποιήσετε την " "υπενθύμιση." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Υπενθύμιση ακόμα και όταν δεν έχει οριστεί δραστηριότητα" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Να γίνεται υπενθύμιση σε κάθε διάστημα_υπενθύμισης ακόμα και αν δεν έχει " "ξεκινήσει μια δραστηριότητα." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Ποια ώρα ξεκινάει η ημέρα (προεπιλογή στις 5:30π.μ)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Αν η ώρα πραγματοποίησης μιας εργασίας είναι νωρίτερα από την καθορισμένη " "ώρα έναρξης της ημέρας, τότε θα καταγραφεί ως εργασία της προηγούμενης " "ημέρας. Οι δραστηριότητες που επεκτείνονται σε δύο ημέρες θα προσμετρούνται " "στην ημέρα όπου πραγματοποιήθηκε το μεγαλύτερο μέρος της εργασίας." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Αν η αλλαγή σε χώρο εργασίας θα επιφέρει και αλλαγή δραστηριότητας" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Λίστα από ενεργές μεθόδους καταγραφής. Το \"name\" θα ενεργοποιεί την " "αλλαγή δραστηριοτήτων κατά το όνομα που καθορίζεται στο workspace_mapping. " "Το \"memory\" θα ενεργοποιεί την εναλλαγή στην προηγούμενη δραστηριότητα " "κατά την επιστροφή τον προηγούμενο χώρο εργασίας." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Αλλαγή δραστηριότητας κατά την αλλαγή χώρου εργασίας" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Αν η αλλαγή κατά όνομα είναι ενεργή, αυτή η λίστα θα παρουσιάζει τα ονόματα " "των δραστηριοτήτων που θα πρέπει να μεταβείτε." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Εμφάνιση / απόκρυψη παραθύρου καταγραφής χρόνου." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Συντόμευση πληκτρολογίου για εμφάνιση / απόκρυψη του παραθύρου της " "καταγραφής χρόνου." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Ενέργεια εναλλαγής παραθύρου εφαρμογής hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Εντολή για εναλλαγή ορατότητας του παραθύρου της εφαρμογής hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Εναλλαγή παραθύρου εφαρμογής hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Εναλλαγή ορατότητας παραθύρου της εφαρμογής hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Καταγραφή χρόνου" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster - καταγράψτε το χρόνο σας" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Επισκόπηση καταγραφής χρόνου" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Το παράθυρο επισκόπησης της καταγραφής χρόνου hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Εμφάνιση στατιστικών" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Κατηγορίες" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Δραστηριότητες" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Ετικέτες" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Δεν υπάρχουν δεδομένα για αυτή την περίοδο" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Αποθήκευση αναφοράς" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Ημέρα" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Εβδομάδα" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Μήνας" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Επισκόπηση - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Επισκόπηση" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Δραστηριότητα" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Προβολή" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Συνολικά" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Απομάκρυνση" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Προσθήκη νέας" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Επεξεργασία" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Προτιμήσεις καταγραφής χρόνου" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Διακοπή καταγραφής όταν ο υπολογιστής βρίσκεται σε αδράνεια" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Υπενθύμιση των τρεχουσών δραστηριοτήτων κάθε:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Η νέα ημέρα αρχίζει στις" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Χρήση της ακόλουθης λίστας εκκρεμοτήτων αν είναι διαθέσιμη:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Ενσωμάτωση" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Καταγραφή" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "Κατη_γορίες" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Λίστα κατηγοριών" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Προσθήκη κατηγορίας" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Αφαίρεση κατηγορίας" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Επεξεργασία κατηγορίας" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Δραστηριότητες" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Λίστα δραστηριοτήτων" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Προσθήκη δραστηριότητας" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Αφαίρεση δραστηριότητας" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Επεξεργασία δραστηριότητας" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Ετικέτες που θα εμφανίζονται στην αυτόματη συμπλήρωση" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Κατηγορίες και ετικέτες" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" "Συνέχιση της τελευταίας δραστηριότητας κατά την επιστροφή σε ένα χώρο " "εργασίας" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Έναρξη νέας δραστηριότητας κατά την αλλαγή χώρων εργασίας:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Χώροι εργασίας:" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Ημέρα:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Εβδομάδα:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Μήνας:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Εύρος ημερομηνίας:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Εφαρμογή" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Καταγρα_φή" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Προσθήκη προηγούμενης δραστηριότητας" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Επισκόπηση" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Στατιστικά" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "Επε_ξεργασία" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Βοήθεια" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Περιεχόμενα" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Διακο_πή καταγραφής" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Α_λλαγή" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Εκκίνηση _καταγραφής" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Έναρξη νέας δραστηριότητας" #: ../data/today.ui.h:13 msgid "Today" msgstr "Σήμερα" #: ../data/today.ui.h:14 msgid "totals" msgstr "συνολικά" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Εμφάνιση επισκόπησης" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Χωρίς δραστηριότητα" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Κατηγορία" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Περιγραφή" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Έναρξη" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Τέλος" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Διάρκεια" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "κατηγορίες" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster - καταγράψτε το χρόνο σας" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Πνευματικά δικαιώματα © 2007-2010 Toms Baugis και άλλοι" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Ιστότοπος του Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Περί της Καταγραφής χρόνου" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Ελληνική μεταφραστική ομάδα GNOME\n" " Κώστας Παπαδήμας \n" " Ηλίας Μακρής \n" " Νίκος Αγιαννιώτης \n" " Τζένη Πετούμενου \n" " Μάριος Ζηντίλης \n" "\n" "Για περισσότερα δείτε http://www.gnome.gr/" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Αταξινόμητα" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Εργασία" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Ανάγνωση νέων" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Έλεγχος μετοχών" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Σούπερ μυστική εργασία Χ" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Παγκόσμια κυριαρχία" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Από ημέρα σε ημέρα" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Γεύμα" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Πότισμα λουλουδιών" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Γυμναστική" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Ενημέρωση δραστηριότητας" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Καταγράφηκαν συνολικά %s ώρες" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Καμία" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Όνομα" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Νέα κατηγορία" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Νέα δραστηριότητα" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d λεπτό" msgstr[1] "%(interval_minutes)d λεπτά" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Ποτέ" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "δραστηριότητα" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "ώρα εκκίνησης" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "χρόνος ολοκλήρωσης" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "λεπτά διάρκειας" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "κατηγορία" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "περιγραφή" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ετικέτες" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Αναφορά επισκόπησης για %(start_B)s %(start_d)s , %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Αναφορά δραστηριότητας για %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Αναφορά δραστηριότητας για %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Αναφορά δραστηριότητας για %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Σύνολα κατά ημέρα" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Αρχείο καταγραφής δραστηριοτήτων" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "δραστηριότητες" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "κατηγορίες" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Διάκριση:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Ημερομηνία" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Προβολή προτύπου" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Μπορείτε να το παρακάμψετε αποθηκεύοντας την έκδοσή σας σε %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Όλα" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Δεν υπάρχουν αρκετά δεδομένα για την δημιουργία στατιστικών.\n" "Χρειάζεται τουλάχιστον μια εβδομάδα εργασίας!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Γίνεται συλλογή δεδομένων — ελέγξτε ξανά όταν ολοκληρωθεί η εβδομάδα!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Η πρώτη δραστηριότητα καταγράφηκε στις %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s έτος" msgstr[1] "%(num)s έτη" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Ο χρόνος που καταγράφηκε μέχρι τώρα είναι %(human_days)s ανθρώπινες ημέρες " "(%(human_years)s) ή %(working_days)s εργάσιμες ημέρες (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Η μεγαλύτερη σε διάρκεια συνεχόμενη εργασία πραγματοποιήθηκε στις %(date)s " "και διήρκεσε %(hours)s ώρα." msgstr[1] "" "Η μεγαλύτερη σε διάρκεια συνεχόμενη εργασία πραγματοποιήθηκε στις %(date)s " "και διήρκεσε %(hours)s ώρες." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Υπάρχει %s εγγραφή" msgstr[1] "Υπάρχουν %s εγγραφές" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Το Hamster θα ήθελε να σας παρακολουθήσει λίγο ακόμα!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Από όλες τις εργασίες, με ποσοστό %s να έχουν ξεκινήσει πριν από τις 9πμ, " "φαίνεται ότι είστε πρωινός τύπος." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Με ποσοστό %s από όλες τις εργασίες να έχουν ξεκινήσει μετά από τις 11μμ, " "φαίνεται ότι είστε βραδινός τύπος." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Με ποσοστό %s από όλες τις εργασίες να έχουν ολοκληρωθεί σε λιγότερο από 15 " "λεπτά, φαίνεται ότι είστε μια πολυάσχολη μέλισσα. " #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Όχι εγγραφές σήμερα" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Μόλις ξεκίνησε:" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Αποθήκευση αναφοράς - Εφαρμογή καταγραφής χρόνου" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Αναφορά HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Καταγραφή χρόνου" #~ msgid "Show activities window" #~ msgstr "Εμφάνιση παραθύρου δραστηριοτήτων" #~ msgid "Show _Overview" #~ msgstr "Εμφάνιση _επισκόπησης" #~ msgid "Sto_p Tracking" #~ msgstr "Διακο_πή καταγραφής" #~ msgid "To_day" #~ msgstr "Σή_μερα" #~ msgid "_Add earlier activity" #~ msgstr "Π_ροσθήκη προηγούμενης δραστηριότητας" #~ msgid "_About" #~ msgstr "Π_ερί" #~ msgid "_Preferences" #~ msgstr "_Προτιμήσεις" #~ msgid "Starts and ends" #~ msgstr "Ξεκινάει και τελειώνει" #~ msgid "Year:" #~ msgstr "Έτος:" #~ msgid "Preferences" #~ msgstr "_Προτιμήσεις" #~ msgid "Changed activity" #~ msgstr "Τροποποιημένη δραστηριότητα" #~ msgid "Switched to '%s'" #~ msgstr "Άλλαξε σε '%s'" #~ msgid "Working on %s" #~ msgstr "Ενασχόληση με: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Καταγραφή χρόνου Hamster. Χρήση:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Έργο Hamster (Καταγραφή χρόνου του GNOME)" #~ msgid "totals by activity" #~ msgstr "σύνολα κατά δραστηριότητα" #~ msgid "totals by category" #~ msgstr "σύνολα κατά κατηγορία" #~ msgid "Show:" #~ msgstr "Προβολή:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Πρόσθεση προηγούμενης _δραστηριότητας" #~ msgid "Tell me more" #~ msgstr "Περισσότερες πληροφορίες" #~ msgid "_Today" #~ msgstr "_Σήμερα" #~ msgid "Preview:" #~ msgstr "Προεπισκόπηση:" #~ msgid "General" #~ msgstr "Γενικά" #~ msgid "Global Hotkey" #~ msgstr "Καθολική συντόμευση πλήκτρου" #~ msgid "Move activity down" #~ msgstr "Μετακίνηση κάτω" #~ msgid "Move activity up" #~ msgstr "Μετακίνηση πάνω" #~ msgid "Total Time" #~ msgstr "Συνολικός χρόνος" #~ msgid "Activities" #~ msgstr "Δραστηριότητες" #~ msgid "Tracking" #~ msgstr "Καταγραφή" hamster-3.0.3/po/en@shaw.po000066400000000000000000000742471452646177100155560ustar00rootroot00000000000000# Shavian translation for hamster. # Copyright (C) 2009 The Gnome Foundation. # Thomas Thurman , 2009. # Transliterate Hamster as ·𐑣𐑨𐑥𐑕𐑑𐑼 #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2010-05-16 16:06 -0400\n" "Last-Translator: Thomas Thurman \n" "Language-Team: Shavian \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "𐑨𐑛 𐑻𐑤𐑰𐑼 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "𐑑" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "𐑦𐑯 𐑐𐑮𐑴𐑜𐑮𐑧𐑕" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "𐑑𐑲𐑥:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "𐑑𐑨𐑜𐑟:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙 𐑪𐑯 𐑲𐑛𐑩𐑤" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙 𐑒𐑳𐑮𐑩𐑯𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑢𐑧𐑯 𐑒𐑩𐑥𐑐𐑿𐑑𐑼 𐑚𐑦𐑒𐑳𐑥𐑟 𐑲𐑛𐑩𐑤" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙 𐑪𐑯 𐑖𐑩𐑑𐑛𐑶𐑯" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙 𐑒𐑳𐑮𐑩𐑯𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑪𐑯 𐑖𐑩𐑑𐑛𐑶𐑯" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "𐑮𐑦𐑥𐑲𐑯𐑛 𐑝 𐑒𐑳𐑮𐑩𐑯𐑑 𐑑𐑭𐑕𐑒 𐑧𐑝𐑮𐑦 x 𐑥𐑦𐑯𐑦𐑑𐑕" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "𐑮𐑦𐑥𐑲𐑯𐑛 𐑝 𐑒𐑳𐑮𐑩𐑯𐑑 𐑑𐑭𐑕𐑒 𐑧𐑝𐑮𐑦 𐑕𐑐𐑧𐑕𐑦𐑓𐑲𐑛 𐑩𐑥𐑬𐑯𐑑 𐑝 𐑥𐑦𐑯𐑦𐑑𐑕. 𐑕𐑧𐑑 𐑑 0 𐑹 𐑜𐑮𐑱𐑑𐑼 𐑞𐑨𐑯 120 𐑑 " "𐑛𐑦𐑕𐑱𐑚𐑩𐑤 𐑮𐑦𐑥𐑲𐑯𐑛𐑼." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "𐑷𐑤𐑕𐑴 𐑮𐑦𐑥𐑲𐑯𐑛 𐑢𐑧𐑯 𐑯𐑴 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑦𐑟 𐑕𐑧𐑑" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "𐑷𐑤𐑕𐑴 𐑮𐑦𐑥𐑲𐑯𐑛 𐑧𐑝𐑮𐑦 notify_interval 𐑥𐑦𐑯𐑦𐑑𐑕 𐑦𐑓 𐑯𐑴 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑣𐑨𐑟 𐑚𐑰𐑯 𐑕𐑑𐑸𐑑𐑩𐑛." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "𐑨𐑑 𐑢𐑪𐑑 𐑑𐑲𐑥 𐑛𐑳𐑟 𐑞 𐑛𐑱 𐑕𐑑𐑸𐑑 (𐑛𐑦𐑓𐑷𐑤𐑑𐑕 𐑑 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟 𐑢𐑦𐑤 𐑚𐑰 𐑒𐑬𐑯𐑑𐑩𐑛 𐑨𐑟 𐑑 𐑚𐑦𐑤𐑪𐑙 𐑑 𐑘𐑧𐑕𐑑𐑼𐑛𐑱 𐑦𐑓 𐑞 𐑒𐑳𐑮𐑩𐑯𐑑 𐑑𐑲𐑥 𐑦𐑟 𐑤𐑧𐑕 𐑞𐑨𐑯 𐑞 " "𐑕𐑐𐑧𐑕𐑦𐑓𐑲𐑛 𐑛𐑱 𐑕𐑑𐑸𐑑; 𐑯 𐑑𐑫𐑛𐑱, 𐑦𐑓 𐑦𐑑 𐑦𐑟 𐑴𐑝𐑼 𐑞 𐑑𐑲𐑥. 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟 𐑞𐑨𐑑 𐑕𐑐𐑨𐑯 𐑑𐑵 𐑛𐑱𐑟, 𐑢𐑦𐑤 " "𐑑𐑦𐑐 𐑴𐑝𐑼 𐑑 𐑞 𐑕𐑲𐑛 𐑢𐑺 𐑞 𐑤𐑸𐑡𐑩𐑕𐑑 𐑐𐑸𐑑 𐑝 𐑞 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑦𐑟." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "𐑖𐑫𐑛 𐑢𐑻𐑒𐑕𐑐𐑱𐑕 𐑕𐑢𐑦𐑗 𐑑𐑮𐑦𐑜𐑻 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑕𐑢𐑦𐑗" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "𐑤𐑦𐑕𐑑 𐑝 𐑦𐑯𐑱𐑚𐑩𐑤𐑛 𐑑𐑮𐑨𐑒𐑦𐑙 𐑥𐑧𐑔𐑩𐑛𐑟. \"name\" 𐑢𐑦𐑤 𐑦𐑯𐑱𐑚𐑩𐑤 𐑕𐑢𐑦𐑗𐑦𐑙 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟 𐑚𐑲 𐑯𐑱𐑥 " "𐑛𐑦𐑓𐑲𐑯𐑛 𐑦𐑯 workspace_mapping. \"memory\" 𐑢𐑦𐑤 𐑦𐑯𐑱𐑚𐑩𐑤 𐑕𐑢𐑦𐑗𐑦𐑙 𐑑 𐑞 𐑤𐑭𐑕𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 " "𐑢𐑧𐑯 𐑮𐑦𐑑𐑻𐑯𐑦𐑙 𐑑 𐑩 𐑐𐑮𐑰𐑝𐑦𐑩𐑕 𐑢𐑻𐑒𐑕𐑐𐑱𐑕." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "𐑕𐑢𐑦𐑗 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑪𐑯 𐑢𐑻𐑒𐑕𐑐𐑱𐑕 𐑗𐑱𐑯𐑡" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "𐑦𐑓 𐑕𐑢𐑦𐑗𐑦𐑙 𐑚𐑲 𐑯𐑱𐑥 𐑦𐑟 𐑦𐑯𐑱𐑚𐑩𐑤𐑛, 𐑞𐑦𐑕 𐑤𐑦𐑕𐑑 𐑕𐑧𐑑𐑕 𐑞 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑯𐑱𐑥𐑟 𐑞𐑨𐑑 𐑖𐑫𐑛 𐑚𐑰 𐑕𐑢𐑦𐑗𐑑 " "𐑑, 𐑢𐑻𐑒𐑕𐑐𐑱𐑕𐑩𐑟 𐑮𐑧𐑐𐑮𐑩𐑟𐑧𐑯𐑑𐑩𐑛 𐑚𐑲 𐑞 𐑦𐑯𐑛𐑧𐑒𐑕 𐑝 𐑲𐑑𐑩𐑥." #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "𐑒𐑰𐑚𐑪𐑮𐑛 𐑕𐑹𐑑𐑒𐑳𐑑 𐑓𐑹 𐑖𐑴𐑦𐑙 𐑞 𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼 𐑢𐑦𐑯𐑛𐑴." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "𐑒𐑰𐑚𐑪𐑮𐑛 𐑕𐑹𐑑𐑒𐑳𐑑 𐑓𐑹 𐑖𐑴𐑦𐑙 𐑞 𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼 𐑢𐑦𐑯𐑛𐑴." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "𐑐𐑮𐑩𐑡𐑧𐑒𐑑 ·𐑣𐑨𐑥𐑕𐑑𐑼 — 𐑑𐑮𐑨𐑒 𐑿𐑼 𐑑𐑲𐑥" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "𐑖𐑴 𐑕𐑑𐑩𐑑𐑦𐑕𐑑𐑦𐑒𐑕" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "𐑒𐑨𐑑𐑩𐑜𐑪𐑮𐑰𐑟" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "𐑑𐑨𐑜𐑟" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "𐑯𐑴 𐑛𐑱𐑑𐑩 𐑓𐑹 𐑞𐑦𐑕 𐑦𐑯𐑑𐑼𐑝𐑩𐑤" #: ../data/overview.ui.h:1 #, fuzzy msgid "Save report..." msgstr "𐑕𐑱𐑝 𐑮𐑩𐑐𐑹𐑑" #: ../data/overview.ui.h:2 msgid "Day" msgstr "" #: ../data/overview.ui.h:3 msgid "Week" msgstr "𐑢𐑰𐑒" #: ../data/overview.ui.h:4 msgid "Month" msgstr "𐑥𐑳𐑯𐑔" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "𐑴𐑝𐑻𐑝𐑘𐑵 — ·𐑣𐑨𐑥𐑕𐑑𐑼" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_𐑴𐑝𐑻𐑝𐑘𐑵" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "𐑑𐑴𐑑𐑩𐑤𐑟" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "𐑮𐑦𐑥𐑵𐑝" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "𐑧𐑛𐑦𐑑" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼 𐑐𐑮𐑧𐑓𐑼𐑩𐑯𐑕𐑩𐑟" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙 𐑢𐑧𐑯 𐑒𐑩𐑥𐑐𐑿𐑑𐑼 𐑚𐑦𐑒𐑳𐑥𐑟 𐑲𐑛𐑩𐑤" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "𐑮𐑦𐑥𐑲𐑯𐑛 𐑝 𐑒𐑳𐑮𐑩𐑯𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑧𐑝𐑮𐑦:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "𐑯𐑿 𐑛𐑱 𐑕𐑑𐑸𐑑𐑕 𐑨𐑑" #: ../data/preferences.ui.h:7 #, fuzzy msgid "Use following todo list if available:" msgstr "𐑿𐑟 𐑓𐑪𐑤𐑴𐑦𐑙 𐑑𐑵𐑛𐑵 𐑤𐑦𐑕𐑑:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "𐑦𐑯𐑑𐑩𐑜𐑮𐑱𐑖𐑩𐑯" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "𐑑𐑮𐑨𐑒𐑦𐑙" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_𐑒𐑨𐑑𐑩𐑜𐑪𐑮𐑰𐑟" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "𐑒𐑨𐑑𐑧𐑜𐑹𐑰 𐑤𐑦𐑕𐑑" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "𐑨𐑛 𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "𐑮𐑦𐑥𐑵𐑝 𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "𐑧𐑛𐑦𐑑 𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑤𐑦𐑕𐑑" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "𐑨𐑛 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "𐑮𐑦𐑥𐑵𐑝 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "𐑧𐑛𐑦𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "𐑑𐑨𐑜𐑟 𐑞𐑨𐑑 𐑖𐑫𐑛 𐑩𐑐𐑽 𐑦𐑯 𐑷𐑑𐑴𐑒𐑩𐑥𐑐𐑤𐑰𐑑" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "𐑒𐑨𐑑𐑩𐑜𐑪𐑮𐑰𐑟 𐑯 𐑑𐑨𐑜𐑟" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "𐑮𐑩𐑟𐑿𐑥 𐑞 𐑤𐑭𐑕𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑢𐑧𐑯 𐑮𐑦𐑑𐑻𐑯𐑦𐑙 𐑑 𐑩 𐑢𐑻𐑒𐑕𐑐𐑱𐑕" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "𐑕𐑑𐑸𐑑 𐑯𐑿 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑢𐑧𐑯 𐑕𐑢𐑦𐑗𐑦𐑙 𐑢𐑻𐑒𐑕𐑐𐑱𐑕𐑩𐑟:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "𐑢𐑻𐑒𐑕𐑐𐑱𐑕𐑩𐑟" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "𐑢𐑰𐑒" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "𐑥𐑳𐑯𐑔" #: ../data/range_pick.ui.h:4 #, fuzzy msgid "Range:" msgstr "𐑛𐑱𐑑 𐑮𐑱𐑯𐑡" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_𐑑𐑮𐑨𐑒𐑦𐑙" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "𐑨𐑛 𐑻𐑤𐑰𐑼 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/today.ui.h:4 msgid "Overview" msgstr "𐑴𐑝𐑻𐑝𐑘𐑵" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "𐑕𐑑𐑩𐑑𐑦𐑕𐑑𐑦𐑒𐑕" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_𐑧𐑛𐑦𐑑" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_𐑣𐑧𐑤𐑐" #: ../data/today.ui.h:8 msgid "Contents" msgstr "𐑒𐑪𐑯𐑑𐑩𐑯𐑑𐑕" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_𐑕𐑑𐑪𐑐 𐑑𐑮𐑨𐑒𐑦𐑙" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_𐑕𐑢𐑦𐑗" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "𐑕𐑑𐑸𐑑 _𐑑𐑮𐑨𐑒𐑦𐑙" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "𐑕𐑑𐑸𐑑 𐑯𐑿 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../data/today.ui.h:13 msgid "Today" msgstr "𐑑𐑫𐑛𐑱" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "𐑑𐑴𐑑𐑩𐑤𐑟" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "𐑖𐑴 _𐑴𐑝𐑻𐑝𐑘𐑵" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "𐑯𐑴 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "𐑕𐑑𐑸𐑑" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "𐑧𐑯𐑛" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "𐑛𐑫𐑮𐑱𐑖𐑩𐑯" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "𐑒𐑨𐑑𐑩𐑜𐑪𐑮𐑰𐑟" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "𐑐𐑮𐑩𐑡𐑧𐑒𐑑 ·𐑣𐑨𐑥𐑕𐑑𐑼 — 𐑑𐑮𐑨𐑒 𐑿𐑼 𐑑𐑲𐑥" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "𐑒𐑪𐑐𐑦𐑮𐑲𐑑 © 2007–2009 ·𐑑𐑪𐑥𐑟 ·𐑚𐑬𐑜𐑦𐑕 𐑯 𐑳𐑞𐑼𐑟" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "𐑐𐑮𐑩𐑡𐑧𐑒𐑑 ·𐑣𐑨𐑥𐑕𐑑𐑼 𐑢𐑧𐑚𐑕𐑲𐑑" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "𐑩𐑚𐑬𐑑 𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "·𐑑𐑪𐑥𐑩𐑕 ·𐑔𐑻𐑥𐑩𐑯" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "𐑳𐑯𐑕𐑹𐑑𐑧𐑛" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "𐑢𐑻𐑒" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "𐑮𐑰𐑛𐑦𐑙 𐑯𐑿𐑟" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "𐑗𐑧𐑒𐑦𐑙 𐑕𐑑𐑪𐑒𐑕" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "𐑕𐑵𐑐𐑼 𐑕𐑰𐑒𐑮𐑩𐑑 𐑐𐑮𐑪𐑡𐑧𐑒𐑑 X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "𐑢𐑻𐑤𐑛 𐑛𐑭𐑥𐑩𐑯𐑱𐑖𐑩𐑯" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "𐑛𐑱-𐑑-𐑛𐑱" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "𐑤𐑳𐑯𐑗" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "𐑢𐑪𐑑𐑻𐑦𐑙 𐑓𐑤𐑬𐑼𐑟" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "𐑛𐑵𐑦𐑙 𐑣𐑨𐑯𐑛𐑕𐑑𐑨𐑯𐑛𐑟" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "𐑳𐑐𐑛𐑱𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d𐑣" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d𐑥𐑦𐑯" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d𐑣 %d𐑥𐑦𐑯" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s 𐑬𐑼𐑟 𐑑𐑮𐑨𐑒𐑑 𐑑𐑴𐑑𐑩𐑤" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "𐑯𐑳𐑯" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "𐑯𐑱𐑥" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "𐑯𐑿 𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "𐑯𐑿 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d 𐑥𐑦𐑯𐑦𐑑𐑕" msgstr[1] "%(interval_minutes)d 𐑥𐑦𐑯𐑦𐑑𐑕" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "𐑯𐑧𐑝𐑼" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "𐑕𐑑𐑸𐑑 𐑑𐑲𐑥" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "𐑧𐑯𐑛 𐑑𐑲𐑥" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "𐑛𐑫𐑮𐑱𐑖𐑩𐑯 𐑥𐑦𐑯𐑦𐑑𐑕" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "𐑒𐑨𐑑𐑧𐑜𐑹𐑰" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "𐑑𐑨𐑜𐑟" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑤𐑪𐑜 𐑓𐑹 %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑤𐑪𐑜 𐑓𐑹 %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑤𐑪𐑜 𐑓𐑹 %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑤𐑪𐑜 𐑓𐑹 %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "𐑑𐑴𐑑𐑩𐑤𐑟" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "𐑒𐑨𐑑𐑩𐑜𐑪𐑮𐑰𐑟" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "𐑛𐑱𐑑" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "𐑷𐑤" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "𐑞𐑺 𐑦𐑟 𐑯𐑴 𐑛𐑱𐑑𐑩 𐑑 𐑡𐑧𐑯𐑼𐑱𐑑 𐑕𐑑𐑩𐑑𐑦𐑕𐑑𐑦𐑒𐑕 𐑘𐑧𐑑.\n" "𐑩 𐑢𐑰𐑒 𐑝 𐑿𐑕𐑦𐑡 𐑢𐑫𐑛 𐑚𐑰 𐑯𐑲𐑕!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "𐑒𐑩𐑤𐑧𐑒𐑑𐑦𐑙 𐑛𐑱𐑑𐑩 — 𐑗𐑧𐑒 𐑚𐑨𐑒 𐑭𐑓𐑑𐑼 𐑩 𐑢𐑰𐑒 𐑣𐑨𐑟 𐑐𐑭𐑕𐑑!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "𐑓𐑻𐑕𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑢𐑪𐑟 𐑮𐑩𐑒𐑪𐑮𐑛𐑩𐑛 𐑪𐑯 %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s 𐑘𐑽" msgstr[1] "%(num)s 𐑘𐑽𐑟" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑑 𐑕𐑴 𐑓𐑸 𐑦𐑟 %(human_days)s 𐑣𐑿𐑥𐑩𐑯 𐑛𐑱𐑟 (%(human_years)s) 𐑹 " "%(working_days)s 𐑢𐑻𐑒𐑦𐑙 𐑛𐑱𐑟 (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "𐑤𐑪𐑙𐑩𐑕𐑑 𐑒𐑩𐑯𐑑𐑦𐑯𐑿𐑩𐑕 𐑢𐑻𐑒 𐑣𐑨𐑐𐑩𐑯𐑛 𐑪𐑯 %(date)s 𐑯 𐑢𐑪𐑟 %(hours)s 𐑬𐑼." msgstr[1] "𐑤𐑪𐑙𐑩𐑕𐑑 𐑒𐑩𐑯𐑑𐑦𐑯𐑿𐑩𐑕 𐑢𐑻𐑒 𐑣𐑨𐑐𐑩𐑯𐑛 𐑪𐑯 %(date)s 𐑯 𐑢𐑪𐑟 %(hours)s 𐑬𐑼𐑟." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "𐑞𐑺 𐑦𐑟 %s 𐑮𐑩𐑒𐑹𐑛." msgstr[1] "𐑞𐑺 𐑸 %s 𐑮𐑩𐑒𐑹𐑛𐑟." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "·𐑣𐑨𐑥𐑕𐑑𐑼 𐑢𐑫𐑛 𐑤𐑲𐑒 𐑑 𐑩𐑚𐑟𐑻𐑝 𐑿 𐑕𐑳𐑥 𐑥𐑹!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "𐑢𐑦𐑞 %s 𐑐𐑻𐑕𐑧𐑯𐑑 𐑝 𐑷𐑤 𐑓𐑨𐑒𐑑𐑕 𐑕𐑑𐑸𐑑𐑦𐑙 𐑚𐑦𐑓𐑹 9am, 𐑿 𐑕𐑰𐑥 𐑑 𐑚𐑰 𐑩𐑯 𐑻𐑤𐑰 𐑚𐑻𐑛." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "𐑢𐑦𐑞 %s 𐑐𐑻𐑕𐑧𐑯𐑑 𐑝 𐑷𐑤 𐑓𐑨𐑒𐑑𐑕 𐑕𐑑𐑸𐑑𐑦𐑙 𐑭𐑓𐑑𐑼 11pm, 𐑿 𐑕𐑰𐑥 𐑑 𐑚𐑰 𐑩 𐑯𐑲𐑑 𐑬𐑤." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "𐑢𐑦𐑞 %s 𐑐𐑻𐑕𐑧𐑯𐑑 𐑝 𐑷𐑤 𐑑𐑭𐑕𐑒𐑕 𐑚𐑰𐑦𐑙 𐑖𐑹𐑑𐑼 𐑞𐑨𐑯 15 𐑥𐑦𐑯𐑦𐑑𐑕, 𐑿 𐑕𐑰𐑥 𐑑 𐑚𐑰 𐑩 𐑚𐑦𐑟𐑰 𐑚𐑰." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "𐑯𐑴 𐑮𐑧𐑒𐑹𐑛𐑟 𐑑𐑫𐑛𐑱" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s𐑣" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "𐑡𐑳𐑕𐑑 𐑕𐑑𐑸𐑑𐑩𐑛" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "𐑕𐑱𐑝 𐑮𐑩𐑐𐑹𐑑 — 𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑼" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML 𐑮𐑩𐑐𐑹𐑑" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "𐑑𐑨𐑚-𐑕𐑧𐑐𐑼𐑱𐑑𐑩𐑛 𐑝𐑨𐑤𐑿𐑟 (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "𐑑𐑲𐑥 𐑑𐑮𐑨𐑒" #~ msgid "Show window" #~ msgstr "𐑖𐑴 𐑢𐑦𐑯𐑛𐑴" #~ msgid "_About" #~ msgstr "_𐑩𐑚𐑬𐑑" #~ msgid "_Preferences" #~ msgstr "_𐑐𐑮𐑧𐑓𐑼𐑩𐑯𐑕𐑩𐑟" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "𐑐𐑮𐑩𐑡𐑧𐑒𐑑 ·𐑣𐑨𐑥𐑕𐑑𐑼 𐑛𐑧𐑕𐑒𐑑𐑪𐑐 𐑑𐑲𐑥 𐑑𐑮𐑨𐑒𐑦𐑙" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_𐑨𐑛 𐑻𐑤𐑰𐑼 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #~ msgid "Tell me more" #~ msgstr "𐑑𐑧𐑤 𐑥𐑰 𐑥𐑹" #~ msgid "_Today" #~ msgstr "_𐑑𐑫𐑛𐑱" #~ msgid "Add" #~ msgstr "𐑨𐑛" #~ msgid "General" #~ msgstr "𐑡𐑧𐑯𐑼𐑩𐑤" #~ msgid "Global Hotkey" #~ msgstr "𐑜𐑤𐑴𐑚𐑩𐑤 𐑣𐑪𐑑𐑒𐑰" #~ msgid "Move activity down" #~ msgstr "𐑥𐑵𐑝 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑛𐑬𐑯" #~ msgid "Move activity up" #~ msgstr "𐑥𐑵𐑝 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦 𐑳𐑐" #~ msgid "Starts and ends" #~ msgstr "𐑕𐑑𐑸𐑑𐑕 𐑯 𐑧𐑯𐑛𐑟" #~ msgid "Year:" #~ msgstr "𐑘𐑽:" #~ msgid "Changed activity" #~ msgstr "𐑗𐑱𐑯𐑡𐑛 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #~ msgid "Switched to '%s'" #~ msgstr "𐑕𐑢𐑦𐑗𐑑 𐑑 '%s'" #~ msgid "Totals by category, activity" #~ msgstr "𐑑𐑴𐑑𐑩𐑤𐑟 𐑚𐑲 𐑒𐑨𐑑𐑧𐑜𐑹𐑰, 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦" #~ msgid "Working on %s" #~ msgstr "𐑢𐑻𐑒𐑦𐑙 𐑪𐑯 %s" hamster-3.0.3/po/en_CA.po000066400000000000000000000566071452646177100151360ustar00rootroot00000000000000# Canadian English translation for hamster. # Copyright (C) 2011 hamster-time-tracker'S COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Tiffany Antopolski , 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2011-09-14 14:01-0400\n" "Last-Translator: Tiffany Antopolski \n" "Language-Team: Canadian English\n" "Language: en_CA\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" "X-Generator: Virtaal 0.7.0\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Add Earlier Activity" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "to" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "in progress" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Description:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Time:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activity:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Tags:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stop tracking on idle" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stop tracking current activity when computer becomes idle" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stop tracking on shutdown" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stop tracking current activity on shutdown" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Remind of current task every x minutes" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Also remind when no activity is set" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Also remind every notify_interval minutes if no activity has been started." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "At what time does the day start (defaults to 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Should workspace switch trigger activity switch" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Switch activity on workspace change" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Show / hide Time Tracker Window" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Keyboard shortcut for showing / hiding the Time Tracker window." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Toggle hamster application window action" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Command for toggling visibility of the hamster application window." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Toggle hamster application window" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Toggle visibility of the hamster application window." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Time Tracker" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster - track your time" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Time Tracker" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Show Statistics" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categories" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Activities" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Tags" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "No data for this interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Save report..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Day" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Week" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Month" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Overview — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Overview" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activity" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_View" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totals" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Remove" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Add new" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Edit" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Time Tracker Preferences" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stop tracking when computer becomes idle" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Remind of current activity every:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "New day starts at" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Use following todo list if available:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integration" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Tracking" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categories" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Category list" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Add category" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Remove category" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Edit category" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activities" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Activity list" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Add activity" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Remove activity" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Edit activity" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Tags that should appear in autocomplete" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categories and Tags" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Resume the last activity when returning to a workspace" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Start new activity when switching workspaces:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Workspaces" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Day:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Week:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Month:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Range:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Apply" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Tracking" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Add earlier activity" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Overview" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistics" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Edit" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Help" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Contents" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_p tracking" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "S_witch" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Start _Tracking" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Start new activity" #: ../data/today.ui.h:13 msgid "Today" msgstr "Today" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Totals" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Show _Overview" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "No activity" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Category" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Description" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Start" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "End" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duration" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categories" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster — track your time" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Project Hamster Website" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "About Time Tracker" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "translator-credits" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Unsorted" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Work" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Reading news" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Checking stocks" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Super secret project X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "World domination" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Day-to-day" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunch" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Watering flowers" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Doing handstands" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Update activity" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %e, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s hours tracked total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "None" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Name" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "New category" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "New activity" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minute" msgstr[1] "%(interval_minutes)d minutes" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Never" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "activity" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "start time" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "end time" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duration minutes" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "category" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "description" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "tags" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %e, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totals by Day" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Activity Log" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "activities" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categories" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinguish:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Date" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Show template" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "You can override it by storing your version in %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "All" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Collecting data — check back after a week has passed!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %e, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %e" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "First activity was recorded on %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s year" msgstr[1] "%(num)s years" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %e, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Longest continuous work happened on %(date)s and was %(hours)s hour." msgstr[1] "" "Longest continuous work happened on %(date)s and was %(hours)s hours." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "There is %s record." msgstr[1] "There are %s records." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster would like to observe you some more!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "No records today" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Just started" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Save Report — Time Tracker" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML Report" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Time track" #~ msgid "Switched to '%s'" #~ msgstr "Switched to '%s'" #~ msgid "Working on %s" #~ msgstr "Working on %s" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (GNOME Time Tracker)" #~ msgid "_About" #~ msgstr "_About" #~ msgid "_Preferences" #~ msgstr "_Preferences" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_p Tracking" #~ msgid "To_day" #~ msgstr "To_day" #~ msgid "_Add earlier activity" #~ msgstr "_Add earlier activity" #~ msgid "Starts and ends" #~ msgstr "Starts and ends" #~ msgid "Year:" #~ msgstr "Year:" #~ msgid "Preferences" #~ msgstr "Preferences" #~ msgid "Changed activity" #~ msgstr "Changed activity" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster time tracker. Usage:" hamster-3.0.3/po/en_GB.po000066400000000000000000000714731452646177100151410ustar00rootroot00000000000000# English (British) translation. # Copyright (C) 2008 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Philip Withnall , 2008, 2010. # Bruce Cowan , 2009, 2010, 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-16 14:05+0100\n" "Last-Translator: Bruce Cowan \n" "Language-Team: British English \n" "Language: en_GB\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" "X-Generator: Virtaal 0.7.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Add Earlier Activity" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "to" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "in progress" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Description:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Time:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activity:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Tags:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stop tracking on idle" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stop tracking current activity when computer becomes idle" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stop tracking on shutdown" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stop tracking current activity on shutdown" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Remind of current task every x minutes" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Also remind when no activity is set" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Also remind every notify_interval minutes if no activity has been started." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "At what time does the day start (defaults to 05:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Should workspace switch trigger activity switch" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Switch activity on workspace change" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Show / hide Time Tracker Window" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Keyboard shortcut for showing / hiding the Time Tracker window." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Toggle hamster application window action" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Command for toggling visibility of the hamster application window." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Toggle hamster application window" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Toggle visibility of the hamster application window." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Time Tracker" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster — track your time" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Time Tracking Overview" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "The overview window of hamster time tracker" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Show Statistics" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categories" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Activities" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Tags" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "No data for this interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Save report…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Day" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Week" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Month" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Overview — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Overview" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activity" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_View" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totals" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Remove" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Add new" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Edit" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Time Tracker Preferences" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stop tracking when computer becomes idle" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Remind of current activity every:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "New day starts at" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Use following todo list if available:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integration" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Tracking" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categories" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Category list" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Add category" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Remove category" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Edit category" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activities" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Activity list" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Add activity" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Remove activity" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Edit activity" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Tags that should appear in autocomplete" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categories and Tags" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Resume the last activity when returning to a workspace" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Start new activity when switching workspaces:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Workspaces" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Day:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Week:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Month:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Range:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Apply" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Tracking" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Add earlier activity" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Overview" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistics" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Edit" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Help" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Contents" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_p tracking" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "S_witch" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Start _Tracking" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Start new activity" #: ../data/today.ui.h:13 msgid "Today" msgstr "Today" #: ../data/today.ui.h:14 msgid "totals" msgstr "totals" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Show Overview" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "No activity" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Category" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Description" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Start" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "End" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duration" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categories" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster — track your time" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Project Hamster Website" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "About Time Tracker" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Philip Withnall \n" "Bruce Cowan " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Unsorted" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Work" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Reading news" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Checking stocks" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Super secret project X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "World domination" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Day-to-day" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunch" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Watering flowers" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Doing handstands" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Update activity" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b." #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s hours tracked total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "None" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Name" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "New category" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "New activity" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minute" msgstr[1] "%(interval_minutes)d minutes" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Never" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "activity" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "start time" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "end time" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duration minutes" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "category" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "description" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "tags" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Activity report for %(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Activity report for %(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Activity report for %(start_d)s %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Activity report for %(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totals by Day" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Activity Log" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "activities" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categories" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinguish:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Date" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Show template" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "You can override it by storing your version in %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "All" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Collecting data — check back after a week has passed!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "First activity was recorded on %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s year" msgstr[1] "%(num)s years" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Longest continuous work happened on %(date)s and was %(hours)s hour." msgstr[1] "" "Longest continuous work happened on %(date)s and was %(hours)s hours." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "There is %s record." msgstr[1] "There are %s records." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster would like to observe you some more!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "With %s percent of all activities starting before 09:00, you seem to be an " "early bird." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "With %s percent of all activities starting after 23:00, you seem to be a " "night owl." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "No records today" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Just started" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Save Report – Time Tracker" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML Report" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Time track" #~ msgid "Show activities window" #~ msgstr "Show activities window" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_p Tracking" #~ msgid "To_day" #~ msgstr "To_day" #~ msgid "_Add earlier activity" #~ msgstr "_Add earlier activity" #~ msgid "Show _Overview" #~ msgstr "Show _Overview" #~ msgid "_Preferences" #~ msgstr "_Preferences" #~ msgid "_About" #~ msgstr "_About" #~ msgid "Year:" #~ msgstr "Year:" #~ msgid "Starts and ends" #~ msgstr "Starts and ends" #~ msgid "Preferences" #~ msgstr "Preferences" #~ msgid "Changed activity" #~ msgstr "Changed activity" #~ msgid "Switched to '%s'" #~ msgstr "Switched to '%s'" #~ msgid "Working on %s" #~ msgstr "Working on %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster time tracker. Usage:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (GNOME Time Tracker)" #~ msgid "totals by activity" #~ msgstr "totals by activity" #~ msgid "totals by category" #~ msgstr "totals by category" #~ msgid "Show:" #~ msgstr "Show:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Ad_d Earlier Activity" #~ msgid "Tell me more" #~ msgstr "Tell me more" #~ msgid "_Today" #~ msgstr "_Today" #~ msgid "Add" #~ msgstr "Add" #~ msgid "General" #~ msgstr "General" #~ msgid "Global Hotkey" #~ msgstr "Global Hotkey" #~ msgid "Move activity down" #~ msgstr "Move activity down" #~ msgid "Move activity up" #~ msgstr "Move activity up" #~ msgid "Total Time" #~ msgstr "Total Time" #~ msgid "Preview:" #~ msgstr "Preview:" #~ msgid "Activities" #~ msgstr "Activities" #~ msgid "Tracking" #~ msgstr "Tracking" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Tell me more" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Activity:" #~ msgid " _Day" #~ msgstr " _Day" #~ msgid " _Month" #~ msgstr " _Month" #~ msgid " _Week" #~ msgstr " _Week" #~ msgid "Overview" #~ msgstr "Overview" #~ msgid "Totals" #~ msgstr "Totals" #~ msgid "Categories:" #~ msgstr "Categories:" #~ msgid "Date interval:" #~ msgstr "Date interval:" #~ msgid "Save as HTML" #~ msgstr "Save as HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "What should be typed in the activity box?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "All" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s %(b)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Overview for %(date)s" #~ msgid "Remind also when no activity is set" #~ msgstr "Also remind when no activity is set" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s, %(Y)s" #~ msgstr "%(b)s %(d)s, %(Y)s" #~ msgctxt "overview list" #~ msgid "%(A)s, %(b)s %(d)s" #~ msgstr "%(A)s, %(b)s %(d)s" #~ msgctxt "overview graph" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgctxt "single day overview" #~ msgid "Overview for %(B)s %(d)s, %(Y)s" #~ msgstr "Overview for %(B)s %(d)s, %(Y)s" #~ msgid "Move _Down" #~ msgstr "Move _Down" #~ msgid "Move _Up" #~ msgstr "Move _Up" #~ msgid "N_ew Category" #~ msgstr "N_ew Category" #~ msgid "_New Activity" #~ msgstr "_New Activity" #~ msgid "20/01/08" #~ msgstr "20/01/08" #~ msgid "20/01/09" #~ msgstr "20/01/09" #~ msgid "3:30pm" #~ msgstr "3:30pm" #~ msgid "gtk-cancel" #~ msgstr "gtk-cancel" #~ msgid "gtk-save" #~ msgstr "gtk-save" #~ msgid "Delete activity" #~ msgstr "Delete activity" #~ msgid "Newer activities" #~ msgstr "Newer activities" #~ msgid "Show month" #~ msgstr "Show month" #~ msgid "name" #~ msgstr "name" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " #~ msgid "Activity" #~ msgstr "Activity" #~ msgid "hours" #~ msgstr "hours" #~ msgid "Category" #~ msgstr "Category" #~ msgid "Week" #~ msgstr "Week" #~ msgid "Earlier activities" #~ msgstr "Earlier activities" #~ msgid "Other" #~ msgstr "Other" #~ msgid "Time tracking for masses" #~ msgstr "Time tracking for the masses" #~ msgid "Time tracking for masses." #~ msgstr "Time tracking for the masses." #~ msgid "Overview for %s - %s" #~ msgstr "Overview for %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%d.%m.%y" #~ msgid "%d. %b" #~ msgstr "%d. %b" #~ msgid "%B %d." #~ msgstr "%B %d." hamster-3.0.3/po/eo.po000066400000000000000000000603701452646177100145640ustar00rootroot00000000000000# Esperanto translation for hamster. # Copyright (C) 2011 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Tiffany Antopolski , 2011, 2012. # Ken Price , 2011. # Kristjan SCHMIDT , 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-06 19:22-0400\n" "Last-Translator: Tiffany Antopolski \n" "Language-Team: Esperanto\n" "Language: eo\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" "X-Generator: Virtaal 0.7.1\n" "X-Project-Style: gnome\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Aldoni antaŭan activecon" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "al" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "farata" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Priskribo:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Horo:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activeco:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etikedoj:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Ĉesi ŝanĝospuri kiam la komputilo estas senaga" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Ĉesi ŝanĝospuri la aktualan aktivecon kiam la komputilo fariĝas senaga" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Ĉesi ŝanĝospuri je komputila elŝalto" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Ĉesi ŝanĝospuri la aktualan aktivecon je sistemfermo" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Rememorigi pri aktuala tasko je ĉiu x minutoj" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Rememorigi pri aktuala tasko je ĉiu specifita intervalo de minutoj. " "Malebligu memorigon per elekto de 0 aŭ pli ol 120." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Ankaŭ rememorigi kiam neniu aktiveco estas difinita" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Ankaŭ memorigi je ĉiu notify_interval minutoj se nenia aktiveco startis." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Je kiu horo komenciĝas la tago (defaŭltas al 5:30 atm)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktivecoj estos kalkulitaj kiel apartenantaj al hieraŭ se la nuna horo estas " "malpli ol la specifita tago-komenco; kaj hodiaŭ, se ĝi estas post la horo. " "Aktivecoj kiuj daŭras du tagojn, transiros al kie la plej granda parto de la " "aktiveco estas." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Ĉu transiro inter laborspacoj ekigu aktiveco-ŝanĝon" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Listo de ebligitaj ŝanĝospurilaj metodoj. \"name\" ebligos ŝanĝi activaĵojn " "per nomo difinita en workspace_mapping. \"memory\" ebligos ŝanĝi al la lasta " "aktivaĵo kiam reiranta al antaŭa laborspaco." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Ŝanĝi al alia aktivaĵo je ŝanĝo de laborspaco" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Se baskuligo per nomo estas eblegita, ĉi tiu listo difinas la aktiveconomojn " "al kiuj transiri, laborspacoj reprezentitaj per la indekso de eroj." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Montri / kaŝi fenestron de la tempo ŝanĝospurilo" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Fulmoklavoj por montri / kaŝi la tempospurilan fenestron." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Baskuligi hamster-aplikofenestron agadon" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Komando baskuligi videblecon de la hamster aplikaĵfenestro." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Baskuligi hamster-aplikofenestron" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Baskuligi videblecon de la hamster-aplikofenestro." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tempo-ŝanĝospurilo" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekto Hamster - ŝanĝospuru vian tempon" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Tempo-ŝanĝospurila superrigardo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "La superrigarda fenestro de hamster-tempo-ŝangospurilo" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Montro statistikojn" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorioj" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktivecoj" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etikedoj" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Ĉi intervalo ne havas datenojn" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Konservi raporton..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Tago" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Semajno" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Monato" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Superrigardo — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "Superrigard_o" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktiveco" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Vidi" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Sumoj" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Forigi" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Aldoni novan" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Redakti" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Agordoj de la tempo-ŝanĝspurilo" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Halti spuradon kiam la komputilo fariĝas senaga" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Rememorigi pri aktuala aktiveco je ĉiu:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Nova tago komenciĝas je" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Uzi jenan far-liston se disponebla:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrado" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Ŝanĝospurado" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorioj" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Listo de kategorioj" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Aldoni kategorion" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Forviŝi kategorion" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Redakti kategorion" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktivecoj" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Listo de aktivecoj" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Aldoni aktivecon" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Forviŝi aktivecon" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Redakti aktivecon" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etikedoj kiuj devas aperi en aŭtomata kompletigo" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorioj kaj etikedoj" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Rekomenci la antaŭan aktivecon kiam revenanta al laborspaco" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Starti novan aktivecon kiam ŝanĝanta inter laborspacoj:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Laborspacoj" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Tago:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Semajno:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Monato:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervalo:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Apliki" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Ŝanĝo_spurado" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Aldoni antaŭan aktivecon" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Superrigardo" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistikoj" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "R_edakti" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Helpo" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Enhavo" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Ĉ_esi ŝanĝospuradon" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Ŝ_anĝi" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "K_omenci ŝanĝospuradon" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Starti novan activecon" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hodiaŭ" #: ../data/today.ui.h:14 msgid "totals" msgstr "sumoj" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Montri superrigardon" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Neniu aktiveco" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorio" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Priskribo" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Komenco" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Fino" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Daŭro" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorioj" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekto Hamster - Ŝanĝospuru vian tempon" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Kopirajto © 2007–2010 Toms BAUĢIS kaj aliaj" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Retejo de la Hamster-projekto" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Pri la tempo-ŝanĝospurilo" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Tiffany ANTOPOLSKI\n" "Ken PRICE\n" "Kristjan SCHMIDT" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Neordigita" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Laboro" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Leganta novaĵojn" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Kontrolanta stokojn" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Sekretega projekto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Superregi la mondon" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Tago-al-tago" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunĉo" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Akvumadon de floroj" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stari sur la manoj" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Ĝisdatigi aktivecon" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ŝanĝospuritaj horoj sume" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Neniom" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nomo" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova kategorio" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova aktiveco" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minutoj" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Neniam" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktiveco" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "komenca horo" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "fina horo" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "daŭro en minutoj" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorio" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "priskribo" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etikedoj" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Aktiveco raporto pri %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Aktiveco raporto pri %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Aktiveco raporto pri %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Activeco raporto pri %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Ĉiutagaj sumoj" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Aktiveca protokolo" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktivecoj" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorioj" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distingi:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Dato" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Montri ŝablonon" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Vi povas transpasi ĝin per enmemorigo de via versio en %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Ĉiuj" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Ankoraŭ ne estas datumoj por generi statistikojn.\n" "Semajno da uzado estus bona!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Kolektanta datumojn — kontrolu denove post unu semajno!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Unua aktivo registriĝis je %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s jaro" msgstr[1] "%(num)s jaroj" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tempo ŝangospurita ĝis nun estas %(human_days)s homaj tagoj " "(%(human_years)s) aŭ %(working_days)s labortagoj (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Plej longa kontinua laboro estis je %(date)s kaj estis %(hours)s horo." msgstr[1] "" "Plej longa kontinua laboro estis je %(date)s kaj estis %(hours)s horoj." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Estas %s rikordo." msgstr[1] "Estas %s rikordoj." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ŝatus observi vin plu!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Kun %s elcentoj de ĉiuj aktivecoj komencitaj antaŭ 9 atm, vi ŝajnas esti " "frua birdo." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Kun %s elcentoj de ĉiuj aktivecoj komencantaj post 11 ptm, vi ŝajnas esti " "nokta strigo." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Kun %s elcentoj de ĉiuj aktivecoj estantaj malpli ol 15 minutoj, vi ŝajnas " "esti multmovema abelo." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Neniuj rikordoj hodiaŭ" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Ĵus komencita" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Konservi raporton — Tempo-ŝanĝospurilo" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-raporto" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Apartigitaj Valoroj (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Tempo-ŝanĝospuro" #~ msgid "Show activities window" #~ msgstr "Montri aktivecojn en fenestro" #~ msgid "Sto_p Tracking" #~ msgstr "Ĉ_esi ŝanĝospuradon" #~ msgid "To_day" #~ msgstr "Ho_diaŭ" #~ msgid "_Add earlier activity" #~ msgstr "_Aldoni antaŭan activecon" #~ msgid "Show _Overview" #~ msgstr "Montri superrigard_on" #~ msgid "_Preferences" #~ msgstr "_Agordoj" #~ msgid "_About" #~ msgstr "_Pri" #~ msgid "Year:" #~ msgstr "Jaro:" #~ msgid "Starts and ends" #~ msgstr "Komencas kaj finas" #~ msgid "Preferences" #~ msgstr "Agordoj" #~ msgid "Changed activity" #~ msgstr "Ŝanĝita aktiveco" #~ msgid "Switched to '%s'" #~ msgstr "Aliigis al '%s'" #~ msgid "Working on %s" #~ msgstr "Laboranta sur %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster tempo-ŝanĝospurilo. Uzo:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projekto Hamster (GNOME-Tempo-Ŝanĝospurilo)" hamster-3.0.3/po/es.po000066400000000000000000000757621452646177100146030ustar00rootroot00000000000000# Spanish Translation for GNOME hamster-time-tracker # Copyright (C) 2008 Project Hamster Team # This file is distributed under the same license as the hamster-time-tracker package. # David Prieto , 2008. # Juanje Ojeda Croissier , 2008, 2009. # Jorge González , 2008, 2009, 2010. # Daniel Mustieles , 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-12 13:19+0100\n" "Last-Translator: Daniel Mustieles \n" "Language-Team: Español \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Añadir una actividad anterior" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "hasta" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "en progreso" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descripción:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Fecha/hora:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Actividad:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetas:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Detener el registro en inactividad" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Parar la actividad actual cuando el ordenador esté inactivo" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Detener el registro al apagar" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Parar la actividad actual al apagar" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Recordar la tarea actual cada x minutos" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Recordar la tarea actual cada número de minutos especificados. Establecer a " "0 o a más de 120 para desactivar el recordatorio." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Recordar también cuando no hay actividades configuradas" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Recordar también cada intervalo de notificación («notify_interval») minutos " "si no se ha iniciado ninguna actividad." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "A qué hora comienza el día (lo predeterminado es 05:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Las actividades se contarán como si perteneciesen a ayer si la hora actual " "es anterior al día de inicio especificado; y para hoy, si es posterior. Las " "actividades que se alargan durante dos días recaerán sobre la parte donde " "más actividad se haya realizado." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Indica si al cambiar de área de trabajo se cambia de actividad" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista de métodos de seguimiento activados. «name» activará el cambio de " "actividades por nombre definido en «workspace_mapping», «memory» activará el " "cambio a la última actividad al volver al área de trabajo anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Cambiar actividad al cambiar de área de trabajo" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Si el cambio por nombre está activado, esta lista configura los nombres de " "las actividades a las que se debería cambiar; las áreas de trabajo están " "representadas por el índice del elemento." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostrar/ocultar la ventana del gestor de tiempo" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Combinación de teclas para mostrar/ocultar la ventana del gestor de tiempo." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Conmutar la acción de la ventana de aplicación Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" "Comando para conmutar la visibilidad de la ventana de la aplicación Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Conmutar la ventana de la aplicación Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Conmutar la visibilidad de la ventana de aplicación Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Gestor de tiempo" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Proyecto Hamster: gestione su tiempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Vista previa del Gestor de tiempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "La ventana de vista previa del Gestor de tiempo Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostrar estadísticas" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorías" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Actividades" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetas" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "No hay datos para este intervalo" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Guardar informe…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Día" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Semana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mes" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Resumen: Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Resumen" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Actividad" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Ver" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totales" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Quitar" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Añadir nueva" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editar" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferencias del gestor de tiempo" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Detener el registro cuando el ordenador esté inactivo" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Recordar la actividad actual cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "El nuevo día comienza a las" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Si está disponible, usar la siguiente lista de tareas:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integración" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Seguimiento" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "Categ_orías" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Lista de categorías" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Añadir categoría" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Quitar categoría" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editar categoría" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "Acti_vidades" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Lista de actividad" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Añadir una actividad" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Quitar actividad" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editar actividad" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Las etiquetas deberían aparecer en el autocompletado" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorías y etiquetas" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Resumir la última actividad al volver a un área de trabajo" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Iniciar una nueva actividad al cambiar entre áreas de trabajo:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Áreas de trabajo" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Día:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Semana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mes:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Rango:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplicar" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Seguimiento" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Añadir una actividad anterior" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Resumen" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estadísticas" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editar" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Ay_uda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Índice" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Detener el seguimiento" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Ca_mbiar" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Iniciar el seguimiento" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Iniciar una actividad nueva" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hoy" #: ../data/today.ui.h:14 msgid "totals" msgstr "totales" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostrar un resumen" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Sin actividad" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoría" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descripción" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Inicio" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Fin" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duración" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorías" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Proyecto Hamster: gestione su tiempo" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis y otros" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Página web del Proyecto Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Acerca del Gestor de tiempo" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Juanje Ojeda \n" "David Prieto " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sin clasificar" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Trabajo" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Leer las noticias" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Comprobar las existencias" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Proyecto súper secreto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominar el Mundo" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Día a día" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Almorzar" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regar las plantas" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Hacer flexiones" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualizar actividad" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B de %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Del %(start_B)s %(start_d)s del %(start_Y)s al %(end_B)s %(end_d)s de " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "Del %(start_d)s %(start_B)s al %(end_d)s %(end_B)s de %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Del %(start_B)s %(start_d)s al %(end_d)s de %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d de %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Registradas %s horas en total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ninguna" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nombre" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Categoría nueva" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Actividad nueva" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minutos" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nunca" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "actividad" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hora de inicio" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "hora de finalización" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duración en minutos" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoría" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descripción" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetas" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Registro de actividad para el %(start_d)s de %(start_B)s de %(start_Y)s " "hasta el %(end_d)s de %(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Registro de actividad para del %(start_d)s de %(start_B)s al %(end_d)s de " "%(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Registro de actividad del %(start_d)s de %(start_B)s de %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Registro de actividad de %(start_B)s, del %(start_d)s al %(end_d)s de " "%(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totales por día" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Registro de actividad" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "actividades" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorías" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinguir:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Fecha" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostrar plantilla" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Puede sobreescribirlas almacenando su versión en %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Todos" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Aún no hay datos para generar estadísticas.\n" "Una semana de uso estaría bien." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Recolectando datos: compruebe de nuevo cuando haya pasado una semana." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "La primera actividad se registró el %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s año" msgstr[1] "%(num)s años" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "El tiempo total gestionado hasta ahora es %(human_days)s días humanos " "(%(human_years)s) o %(working_days)s días de trabajo (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "La actividad más larga se registró el %(date)s y duró %(hours)s hora." msgstr[1] "" "La actividad más larga se registró el %(date)s y duró %(hours)s horas." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Existe %s registro." msgstr[1] "Existen %s registros." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster debe seguir su actividad algo más." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Con %s por ciento de todas las tareas iniciadas antes de las 9 de la mañana " "parece muy madrugador." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Con %s por ciento de todas las tareas iniciadas después de las 11 de la " "noche parece un búho." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Con %s por ciento de todas las tareas más cortas de 15 minutos parece una " "abeja obrera." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Hoy no hay registros" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Acaba de empezar" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Guardar informe: Gestor de tiempo" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Informe HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valores separados por tabuladores (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Gestor de tiempo" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "Mostrar la ventana de actividades" #~ msgid "Sto_p Tracking" #~ msgstr "_Detener el seguimiento" #~ msgid "To_day" #~ msgstr "_Hoy" #~ msgid "_Add earlier activity" #~ msgstr "_Añadir una actividad anterior" #~ msgid "Show _Overview" #~ msgstr "_Mostrar un resumen" #~ msgid "_Preferences" #~ msgstr "Prefere_ncias" #~ msgid "_About" #~ msgstr "_Acerca de" #~ msgid "Year:" #~ msgstr "Año:" #~ msgid "Starts and ends" #~ msgstr "Comienza y finaliza" #~ msgid "Preferences" #~ msgstr "Preferencias" #~ msgid "Changed activity" #~ msgstr "Actividad cambiada" #~ msgid "Switched to '%s'" #~ msgstr "Se cambió a «%s»" #~ msgid "Working on %s" #~ msgstr "Trabajando en %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Gestor de tiempo Hamster. Uso:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Proyecto Hamster (Gestor de tiempo de GNOME)" #~ msgid "Tell me more" #~ msgstr "Saber más" #~ msgid "totals by activity" #~ msgstr "totales por actividad" #~ msgid "totals by category" #~ msgstr "totales por categoría" #~ msgid "Show:" #~ msgstr "Mostrar:" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "Página web del proyecto de gestión de tiempo Hamster" #~ msgid "Move activity down" #~ msgstr "Mover actividad abajo" #~ msgid "Move activity up" #~ msgstr "Mover actividad arriba" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Añadir una actividad anterior" #~ msgid "_Today" #~ msgstr "_Hoy" #~ msgid "Export data..." #~ msgstr "Exportar datos…" #~ msgid "Save Report" #~ msgstr "Guardar informe" #~ msgid "General" #~ msgstr "General" #~ msgid "Global Hotkey" #~ msgstr "Combinación de tecla global" #~ msgid "Total Time" #~ msgstr "Tiempo total" #~ msgid "Preview:" #~ msgstr "Vista previa:" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "What should be typed in the activity box?" #~ msgstr "¿Qué escribir en la caja de actividad?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ "\n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "In the tag field, separate tags with a comma. You can use Tab button to " #~ "autocomplete first tag displayed in the dropdown, as well as click on the " #~ "tags using mouse.\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Existe una sintaxis simple que le permite añadir detalles a sus " #~ "actividades:\n" #~ " \n" #~ "El símbolo «@» marca la categoría. Ejemplo «regar las plantas@casa» " #~ "iniciará el seguimiento de la actividad «regar plantas» en la categoría " #~ "«casa».\n" #~ "\n" #~ "Las comas («,») marcan el inicio de la descripción. Ejemplo «regar las " #~ "plantas, geranios y begonias» iniciará el seguimiento de la actividad " #~ "«regar las plantas» y añadirá la descripción «geranios y begonias».\n" #~ "\n" #~ "Ambas se pueden combinar: |regar las plantas@casa, geranios y begonias» " #~ "funcionará perfectamente.\n" #~ "\n" #~ "En el campo de etiquetas, separe las etiquetas con una coma. Puede usar " #~ "la tecla Tabulador para autocompletar la primera etiqueta mostrada en la " #~ "lista desplegable, así como pulsar en las etiquetas usando el ratón.\n" #~ "Ahora puede empezar a gestionar su tiempo.\n" #~ " " #~ msgid "Switch" #~ msgstr "Cambiar" #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "Hora a la que considerar el comienzo de un día nuevo" #~ msgid "Time and Name" #~ msgstr "Hora y nombre" #~ msgid "Tags or Description" #~ msgstr "Etiquetas o descripción" #~ msgid "Total" #~ msgstr "Total" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%d %b" #~ msgid "21.12.2009 - 28.12.2009" #~ msgstr "21.12.2009 - 28.12.2009" #~ msgid "Overview" #~ msgstr "Resumen" #~ msgid "Categories:" #~ msgstr "Categorías:" #~ msgid "Date interval:" #~ msgstr "Intervalo de fechas:" #~ msgid "Totals" #~ msgstr "Totales" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Todas" #~ msgid "Activities" #~ msgstr "Actividades" #~ msgid "Day\t" #~ msgstr "Día\t" #~ msgid "Tracking" #~ msgstr "Registro" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Escriba una actividad y pulse Intro para comenzar a " #~ "gestionar su tiempo" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Aprender más" #~ msgid "_Activity:" #~ msgstr "Acti_vidad:" #~ msgid "_Stop Tracking" #~ msgstr "_Detener el registro" #~ msgid " _Day" #~ msgstr "_Día" #~ msgid " _Month" #~ msgstr "_Mes" #~ msgid " _Week" #~ msgstr "_Semana" #~ msgid "Next" #~ msgstr "Siguiente" #~ msgid "Next week" #~ msgstr "Siguiente semana" #~ msgid "Previous" #~ msgstr "Anterior" #~ msgid "Previous week" #~ msgstr "Semana anterior" #~ msgid "Show month" #~ msgstr "Mostrar un mes" #~ msgid "Show single day" #~ msgstr "Mostrar un solo día" #~ msgid "This Week" #~ msgstr "Esta semana" #~ msgid "This week" #~ msgstr "Esta semana" #~ msgid "Overview for %(date)s" #~ msgstr "Resumen para %(date)s" #~ msgid "Previous day" #~ msgstr "Día anterior" #~ msgid "Next day" #~ msgstr "Siguiente día" #~ msgid "Previous month" #~ msgstr "Mes anterior" #~ msgid "Next month" #~ msgstr "Siguiente mes" #~ msgid "This month" #~ msgstr "Este mes" #~ msgid "This Month" #~ msgstr "Este mes" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s de %(b)s" #~ msgid "Save as HTML" #~ msgstr "Guardar como HTML" #~ msgid "Remind also when no activity is set" #~ msgstr "Recordar también cuando no hay actividades configuradas" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s/%(report_b)s/%(report_Y)s" #~| msgid "_Categories" #~ msgid "All %(categories)s" #~ msgstr "Todas las %(categories)s" #~ msgid "All %(years)s" #~ msgstr "Todos los %(years)s" #~ msgid "%(first_b)s %(first_d)s" #~ msgstr "%(first_d)s %(first_b)s" #~ msgid "Move _Down" #~ msgstr "_Bajar" #~ msgid "Move _Up" #~ msgstr "_Subir" #~ msgid "N_ew Category" #~ msgstr "A_ñadir categoría" #~ msgid "_New Activity" #~ msgstr "Añadir ac_tividad" #~ msgid "Activity" #~ msgstr "Actividad" #~ msgid "hours" #~ msgstr "horas" #~ msgid "Week" #~ msgstr "Semana" #~ msgid "Delete activity" #~ msgstr "Borrar una actividad" #~ msgid "Earlier activities" #~ msgstr "Actividades anteriores" #~ msgid "Newer activities" #~ msgstr "Actividades posteriores" #~ msgid "name" #~ msgstr "nombre" #~ msgid "Other" #~ msgstr "Otras" hamster-3.0.3/po/et.po000066400000000000000000000605731452646177100145760ustar00rootroot00000000000000# Projektihamstri eesti keele tõlge. # Estonian translation of Project Hamster. # # Copyright (C) 2008–2010 The GNOME Project. # This file is distributed under the same license as the hamster-time-tracker package. # # Ivar Smolin , 2008–2010. # Mattias Põldaru , 2009–2010, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker MASTER\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-01 12:59+0200\n" "Last-Translator: Mattias Põldaru \n" "Language-Team: Estonian <>\n" "Language: et\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bits\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Varasema tegevuse lisamine" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "kuni" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "kestab edasi" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Kirjeldus:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Aeg:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Tegevus:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Sildid:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Jõudeolekul lõpetatakse jälgimine" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Jooksva tegevuse jälgimine lõpetatakse arvuti jõudeolekul" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Väljalülitamisel lõpetatakse jälgimine" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Jooksva tegevuse jälgimine lõpetatakse arvuti väljalülitamisel" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Jooksvast tegevusest antakse teada iga x minuti järel" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Jooksva tegevuse kohta antakse teada kindlaksmääratud hulga minutite järel. " "Väärtuse 0 või 120-st suurema väärtuse korral on meeldetuletaja keelatud." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Meeldetuletused ka tegevuse puudumise korral" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Meeldetuletuste kuvamine ka võtmega notify_interval määratud minutite järel " "isegi juhul, kui tegevust pole alustatud." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Mis kell algab päev (vaikimisi 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Kui praegune hetk on enne päeva algusajaks määratud aega, siis kuvatakse " "tegevused eelmisesse päeva kuuluvatena. Kui päeva alguseks määratud aeg on " "möödunud, siis aga tänasesse päeva kuuluvatena. Kahte päeva kuuluvad " "tegevused ulatuvad üle selle serva, kuhu tegevuse suurim osa jääb." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Kas tööala vahetus peaks valla päästma tegevuse vahetuse" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lubatud jälitusmeetodite loend. \"nimi\" põhjustab tegevuste vahetamise " "workspace_mapping väärtuses antud nime järgi. \"memory\" puhul lülitatakse " "eelmisele tööalale naasmisel seal toimunud tegevusele." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Tööala vahetamisel vahetatakse tegevust" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Kui nime järgi lülitumine on lubatud, siis see loend määrab tegevuste nimed, " "millele tuleks tööala vahetamisel lülituda." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Ajakasutuse jälgija akna näitamine või peitmine" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Kiirklahv ajakasutuse jälgija akna näitamiseks või peitmiseks." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Hamstri rakendusakna tegevuse sisse- ja väljalülitamine" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Hamstri rakendusakna nähtavuse sisse- ja väljalülitamise käsk." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Hamstri rakendusakna sisse- ja väljalülitamine" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Hamstri rakendusakna nähtavuse sisse- ja väljalülitamine" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Ajajälgija" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projektihamster - ajajälgija" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Ajajälgija ülevaade" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Hamstri ajajälgija ülevaateaken" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Näita statistikat" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategooriad" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Tegevused" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Sildid" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Selle vahemiku kohta andmed puuduvad" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Salvesta aruanne..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Päev" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Nädal" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Kuu" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Ülevaade — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "Üle_vaade" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Tegevus" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Vaade" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Kokku" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Eemalda" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Lisa uus" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Muuda" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Ajajälgija eelistused" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Arvuti jõudeoleku korral tegevuste jälgimine peatatakse" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Jooksvast tegevusest antakse teada iga:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Uus päev algab" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Võimalusel kasuta järgmist tegevuste nimekirja:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integratsioon" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Jälgimine" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategooriad" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategooriate nimekiri" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Kategooria lisamine" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Kategooria kustutamine" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Kategooria muutmine" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Tegevused" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Tegevuste nimekiri" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Tegevuse lisamine" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Tegevuse kustutamine" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Tegevuse muutmine" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Automaatlõpetuses kasutatavad sildid" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategooriad ja sildid" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Tööalale naasmisel jätkatakse viimase tegevusega" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Tööalade vahetamisel alustatakse uut tegevust:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Tööalad" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Päev:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Nädal:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Kuu:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Kuupäevade vahemik:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Rakenda" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Jälgimine" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Varasema tegevuse lisamine" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Ülevaade" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistika" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Muuda" #: ../data/today.ui.h:7 msgid "_Help" msgstr "A_bi" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Sisukord" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Lõpeta jälgimine" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Vaheta" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Alusta jälgimist" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Uue tegevuse käivitamine" #: ../data/today.ui.h:13 msgid "Today" msgstr "Täna" #: ../data/today.ui.h:14 msgid "totals" msgstr "kokku" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Ülevaate kuvamine" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Tegevusetu" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategooria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Kirjeldus" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Algus" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Lõpp" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Kestus" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategooriad" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projektihamster — ajajälgija" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Autoriõigused © 2007–2010 Toms Bauģis ja teised" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Projektihamstri veebisait" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Ajajälgijast lähemalt" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Ivar Smolin , 2008–2010.\n" "Mattias Põldaru , 2009–2010." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sortimata" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Töö" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Uudistelugemine" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Aktsiakursside jälgimine" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Eriti salajane projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Võimuhaaramine" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Igapäevane" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lõunatamine" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Lillede kastmine" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Kätekõverduste tegemine" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Tegevuse andmete uuendamine" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dt" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dm" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dt %dm" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s %(start_Y)s - %(end_d)s. %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s - %(end_d)s. %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s-%(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Kokku on jälgitud %s tundi" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Puudub" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nimi" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Uus kategooria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Uus tegevus" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuti järel" msgstr[1] "%(interval_minutes)d minuti järel" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Mitte kunagi" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "tegevus" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "alustamise aeg" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "lõpetamise aeg" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "kestus minutites" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategooria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "kirjeldus" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "sildid" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Tegevuste aruanne perioodi %(start_d)s. %(start_B)s %(start_Y)s - %(end_d)s. " "%(end_B)s %(end_Y)s kohta" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Tegevuste aruanne perioodi %(start_d)s. %(start_B)s - %(end_d)s. %(end_B)s " "%(end_Y)s kohta" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Tegevuste aruanne %(start_d)s. %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Tegevuste aruanne perioodi %(start_d)s-%(end_d)s %(start_B)s %(end_Y)s kohta" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d. %b.%Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Kokkuvõte päevade kaupa" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Tegevuste logi" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "tegevused" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategooriad" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Eristus:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Kuupäev" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Näita malli" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Seda on võimalik asendada, kui salvestada oma versioon kataloogi " "%(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Kõik" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Statistika genereerimiseks pole veel piisavalt andmeid.\n" "Nädalapikkune kasutamine võib aga juba midagi anda!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Andmete kogumine — vaata järgmisel nädalal uuesti!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Esimene tegevus registreeriti: %s." # Seda kasutatakse lauses "Time tracked so far..." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s aasta" msgstr[1] "%(num)s aastat" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Praeguseks on registreeritud %(human_days)s inimpäeva (%(human_years)s) ehk " "%(working_days)s tööpäeva (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Pikim katkematu töö kestis %(hours)s tundi ja selle toimumise aeg oli " "%(date)s." msgstr[1] "" "Pikim katkematu töö kestis %(hours)s tundi ja selle toimumise aeg oli " "%(date)s." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Siin on %s kirje." msgstr[1] "Siin on %s kirjet." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster võib enamatki öelda!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s protsenti kõigist tegevustest algavad enne kella üheksat hommikul. " "Tundub, et Sa oled hommikuinimene." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s protsenti kõigist tegevustest algavad õhtul pärast kella 23:00. Tundub, " "et Sa oled rohkem öökulli tüüpi." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s protsenti kõigist tegevustest on lühemad kui 15 minutit. Tundub, et Sa " "oled väga hõivatud töömesilane." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Tänase kohta pole ühtegi kirjet" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%st" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Värskelt alustatud" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Ajajälgija - aruande salvestamine" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-aruanne" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabulaatoriga eraldatud väärtused (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Ajajälgimine" #~ msgid "Show activities window" #~ msgstr "Tegevuste akna kuvamine" #~ msgid "Sto_p Tracking" #~ msgstr "_Lõpeta jälgimine" #~ msgid "To_day" #~ msgstr "_Täna" #~ msgid "_Add earlier activity" #~ msgstr "Lisa _varasem tegevus" #~ msgid "Show _Overview" #~ msgstr "_Näita ülevaadet" #~ msgid "_Preferences" #~ msgstr "_Eelistused" #~ msgid "_About" #~ msgstr "_Rakendist lähemalt" #~ msgid "Year:" #~ msgstr "Aasta:" #~ msgid "Starts and ends" #~ msgstr "Algus ja lõpp" #~ msgid "Preferences" #~ msgstr "Eelistused" #~ msgid "Changed activity" #~ msgstr "Muudeti tegevust" #~ msgid "Switched to '%s'" #~ msgstr "Lülituti tegevusele '%s'" #~ msgid "Working on %s" #~ msgstr "Jooksev tegevus: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamstri ajajälgija. Kasutamine:" hamster-3.0.3/po/eu.po000066400000000000000000000603101452646177100145640ustar00rootroot00000000000000# translation of eu.po to Basque # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Iñaki Larrañaga Murgoitio , 2008, 2009, 2010, 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: eu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-06 11:52+0100\n" "Last-Translator: Iñaki Larrañaga Murgoitio \n" "Language-Team: American English \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.0\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Gehitu aurreko jarduera" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr " - " #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "lanean" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Azalpena:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Denbora:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Jarduera:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiketak:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Gelditu jarraipena inaktibo jartzean" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Gelditu uneko jardueraren jarraipena ordenagailua inaktibo jartzean" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Gelditu jarraipena itzaltzean" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Gelditu uneko jardueraren jarraipena itzaltzean" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Gogoratu uneko ataza x minuturo" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Gogoratu uneko ataza, zehaztutako minutu kopururo. Ezarri 0 edo 120 baino " "balio handiagoarekin oroigarria desgaitzeko." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Gogorarazi baita ere jarduerarik ez denean ezarri" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Gogoratu baita ere 'notify_interval' bakoitzaren minutuak jarduerarik ez " "bada hasi." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Zein ordutan hasten da eguna (lehenetsia: 5:30 AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Jarduerak atzokoak balira bezala zenbatuko dira uneko ordua zehaztutako " "hasierako data baino lehenago bada; eta gaur denborarekin. Jarduerak bi " "egunetara zabal daitezke, jardueraren zatirik handienaren gainera jaurtiz." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Laneko areaz aldatzean jarduera aldatuko duen edo ez adierazten du." #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Gaitutako jarraipenen metodoen zerrenda. \"name\" (izena) balioak " "'workspace_mapping' gakoan definitutako izenen arabera jarduerak aldatzea " "gaitzen du. \"memory\" balioak berriz, aurreko laneko areara itzultzean " "azkenengo jarduerara aldatzea gaitzen du." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Aldatu jardueraz laneko areaz aldatzean" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Izenen arabera aldatzea gaituta badago, zerrenda honek alda daitezkeen " "jardueren izenak ezartzen ditu, elementuen indizeek laneko areak adierazten " "dituzte." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Erakutsi/Ezkutatu 'Denboraren jarraipena'ren leihoa" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Lasterbideak 'Denboraren jarraipena'ren leihoa erakusteko/ezkutatzeko." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Txandakatu hamster aplikazioaren leihoaren ekintza" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Hamster aplikazioaren leihoaren ikusgaitasuna txandakatzeko komandoa." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Txandakatu hamster aplikazioaren leihoa" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Txandakatu hamster aplikazioaren leihoaren ikusgaitasuna." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Denboraren jarraipena" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster proiektua - zure denboraren jarraipena" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Denboraren jarraipenaren aurkezpen orokorra" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Hamster denboraren jarraipenaren leihoaren aurkezpen orokorra" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Erakutsi estatistikak" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategoriak" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Jarduerak" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiketak" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Ez dago datarik barruti honentzako" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Gorde txostena..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Eguna" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Astea" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Hilabetea" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Aurkezpen orokorra - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Aurkezpen orokorra" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Jarduera" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Ikusi" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Guztira" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Kendu" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Gehitu berria" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editatu" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Denboraren jarraipenaren hobespenak" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Gelditu jarraipena ordenagailua inaktibo jartzean" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Gogoratu uneko jarduera:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Egun berriaren hasiera" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Erabili zereginen zerrenda hau erabilgarri egonez gero:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrazioa" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Jarraipena" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategoriak" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategorien zerrenda" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Gehitu kategoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Kendu kategoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editatu kategoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Jarduerak" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Jardueren zerrenda" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Gehitu jarduera" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Kendu jarduera" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editatu jarduera" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Auto-osaketan agertu beharko luketen etiketak" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategoriak eta etiketak" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Jarraitu azken jarduera laneko areara itzultzean" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Hasi jarduera berria laneko areaz aldatzean:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Laneko areak" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Eguna:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Astea:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Hilabetea:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Barrutia:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplikatu" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Jarraipena" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Gehitu aurreko jarduera" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Aurkezpen orokorra" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estatistikak" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editatu" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Laguntza" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Edukia" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Gelditu jarraipena" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Aldatu" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Hasi jarraipena" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Hasi jarduera berria" #: ../data/today.ui.h:13 msgid "Today" msgstr "Gaur" #: ../data/today.ui.h:14 msgid "totals" msgstr "guztira" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Erakutsi aurkezpen orokorra" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Jarduerarik ez" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Azalpena" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Hasi" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Amaitu" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Iraupena" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategoriak" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster proiektua - zure denboraren jarraipena" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright-a © 2007-2010 Toms Baugis eta beste batzuk" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster proiektuaren webgunea" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Denboraren jarraipenari buruz" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Iñaki Larrañaga Murgoitio " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Ordenatu gabe" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Lana" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Berriak irakurtzea" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Burtsa-baloreak begiratzea" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Oso ezkutuko X proiektua" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Munduaz jabetzea" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Egunez egun" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Bazkaria" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Uretako loreak" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Beroketak egitea" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Eguneratu jarduera" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%do" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%do %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y %B %d" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_Y)s/%(start_B)s/%(start_d)s – %(end_Y)s/%(end_B)s/%(end_d)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s/%(start_d)s – %(end_Y)s/%(end_B)s/%(end_d)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s/%(start_d)s – %(end_Y)s/%(end_d)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "'%s'(r)en jarraitutako guztirako orduak" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Bat ere ez" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Izena" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Kategoria berria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Jarduera berria" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuturo" msgstr[1] "%(interval_minutes)d minuturo" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Inoiz ez" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "jarduera" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hasierako ordua" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "amaierako ordua" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "iraupena (minututan)" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "azalpena" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiketak" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Jardueraren txostena: %(start_Y)s/%(start_B)s/%(start_d)s – %(end_Y)s/" "%(end_B)s/%(end_d)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Jardueraren txostena: %(start_d)s/%(start_B)s – %(end_Y)s/%(end_B)s/%(end_d)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Jardueraren txostena: %(start_Y)s/%(start_B)s/%(start_d)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Jardueraren txostena: %(start_B)s/%(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%Y-%b-%d" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Guztira eguneraren arabera" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Jardueren egunkaria" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "jarduerak" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategoriak" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Desberdindu:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Erakutsi txantiloia" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Gainidatz dezakezu zure bertsioa %(home_folder)s karpetan gordez" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Denak" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Ez dago daturik oraindik estatistikak sortzeko.\n" "Astebeteko erabilpena ongi legoke!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Datuak biltzen - begiratu berriro aste bat igarotakoan." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y %b %d" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Lehenbiziko jardueraren erregistroa: %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "urte %(num)s" msgstr[1] "%(num)s urte" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Jarraitutako denbora %(human_days)s egun arrunt (%(human_years)s) edo " "%(working_days)s laneko egun (%(working_years)s) da." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y %b %d" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "Jarraiako lan luzeena %(date)s eta %(hours)s ordukoa izan da." msgstr[1] "Jarraiako lan luzeena %(date)s eta %(hours)s ordutakoa izan dira" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Erregistro %s dago." msgstr[1] "%s erregistro daude." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster-ek gehiago aztertzea nahi zaitu." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "9 am aurretik hasitako jarduera guztien %s ehunekoarekin, mendizalea " "dirudizu." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "11 pm ondoren hasitako jarduera guztien %s ehunekoarekin, gautxoria dirudizu." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "15 minutu baino laburragoak izan diren jarduera guztien %s ehunekoarekin, " "lanpetutako erla dirudizu." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Gaur ez dago erregistrorik" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%so" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Hasi berria" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Gorde txostena - Denboraren jarraipena" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML txostena" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabuladorez bereiztutako balioak (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Denboraren jarraipena" #~ msgid "Show activities window" #~ msgstr "Erakutsi jardueren leihoa" #~ msgid "Show _Overview" #~ msgstr "Erakutsi _aurkezpen orokorra" #~ msgid "Sto_p Tracking" #~ msgstr "_Gelditu jarraipena" #~ msgid "To_day" #~ msgstr "_Gaur" #~ msgid "_Add earlier activity" #~ msgstr "_Gehitu aurreko jarduera" #~ msgid "_About" #~ msgstr "Honi _buruz" #~ msgid "_Preferences" #~ msgstr "_Hobespenak" #~ msgid "Starts and ends" #~ msgstr "Hasierak eta amaierak" #~ msgid "Year:" #~ msgstr "Urtea:" #~ msgid "Preferences" #~ msgstr "Hobespenak" #~ msgid "Changed activity" #~ msgstr "Aldatutako jarduera" #~ msgid "Switched to '%s'" #~ msgstr "Aldatu hona: '%s'" #~ msgid "Working on %s" #~ msgstr "%s(e)n lanean" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster denboraren jarraipena. Erabilera:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Hamster proiektua (GNOMEko denboraren jarraipena)" hamster-3.0.3/po/fi.po000066400000000000000000000676711452646177100145720ustar00rootroot00000000000000# hamster-time-tracker's Finnish translation. # Copyright (C) 2008 Timo Jyrinki. # This file is distributed under the same license as the hamster-time-tracker package. # # Timo Jyrinki , 2008. # Tommi Vainikainen , 2009-2010. # Jiri Grönroos , 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-01-22 14:55+0200\n" "Last-Translator: Jiri Grönroos \n" "Language-Team: Finnish <>\n" "Language: fi\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" "X-Generator: Lokalize 1.4\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Lisää aikaisempi toimi" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "–" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "meneillään" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Kuvaus:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Aika:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Toimi:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Tagit:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Pysäytä seuranta joutenollessa" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Pysäytä nykyisen toimen seuranta, kun tietokone on jouten" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Pysäytä seuranta sammutettaessa" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Pysäytä nykyisen toimen seuranta sammutettaessa" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Muistuta ajankohtaisista tapahtumista x minuutin välein" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Muistuta nykyisestä tehtävästä annetun minuuttimäärän välein. Aseta arvoksi " "0 tai suurempi kuin 120, jos et halua muistutuksia." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Muistuta myös kun toimea ei ole asetettu" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Muistuta myös joka notify_interval minuutin välein jos mitään toimea ei ole " "aloitettu." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Mihin aikaan päivä alkaa (oletuksena 5.30 aamulla)" #: ../data/hamster.schemas.in.h:10 #, fuzzy msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Toimet lasketaan kuuluvaksi edelliseen päivään jos sen ajankohta on aiempi " "kuin määritelty päivän alkaminen ja tähän päivään jos ajankohta on ylitetty. " "Toimet, joka kestävät toista päivää, näytetään sen päivän puolella, jona " "suurempi osa toimesta tapahtuu." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Pitäisikö työtilan vaihdon johtaa toimen vaihtoon" #: ../data/hamster.schemas.in.h:12 #, fuzzy msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Luettelo käytössä olevista seurantatavoista. ”name” ottaa käyttöön toimen " "vaihtamisen workspace_mapping:ssä määritellyn nimen perusteella. ”memory” " "ottaa käyttöön toimen vaihtamisen edelliseen toimeen kun palataan aiempaan " "työtilaan." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Vaihda toimea kun työtila vaihtuu" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Jos vaihtaminen nimellä on käytössä, tämä luettelo määritää toimien nimet, " "joihinka vaihdetaan ja työtilat edustavat kohdan indeksiä." #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "Pikanäppäin ajankäytön seurantaikkunan näyttämiseksi." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Pikanäppäin ajankäytön seurantaikkunan näyttämiseksi." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Ajankäytön seuranta" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "Hamsteriprojekti - seuraa aikaasi" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Ajankäytön seuranta" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Näytä tilastot" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Luokat" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Toimet" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Tagit" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Tältä väliltä ei ole tietoja" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Tallenna raportti..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Päivä" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Viikko" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Kuukausi" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Yleiskuva - Hamsteri" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Yleiskuva" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Toimi" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Näytä" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Yhteenveto" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Poista" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Lisää uusi" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Muokkaa" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Ajankäytön seurannan asetukset" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Pysäytä seuranta, kun tietokone on jouten" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Muistuta ajankotaisista tapahtumista joka:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Uusi päivä alkaa klo" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "Kesto" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Seuranta" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Luokat" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Luokkaluettelo" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Lisää luokka" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Poista luokka" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Muokkaa luokkaa" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "T_oimet" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Toimiluettelo" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Lisää toimi" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Poista toimi" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Muokkaa toimea" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Automaattitäydennyksessä näkyvät tagit" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Luokat ja tagit" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Palauta edellinen toimi kun palataan työtilaan" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Aloita uusi toimi kun vaihdetaan työtilaa:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Työtilat" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Päivä:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Viikko:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Kuukausi:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Ajanjakso:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Toteuta" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Seuranta" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Lisää aikaisempi toimi" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Yleiskuva" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Tilastot" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Muokkaa" #: ../data/today.ui.h:7 msgid "_Help" msgstr "O_hje" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Sisältö" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Pysäytä seuranta" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Vaihda" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Aloita seuranta" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Aloita uusi toimi" #: ../data/today.ui.h:13 msgid "Today" msgstr "Tänään" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Yhteenveto" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Näytä _yleiskuva" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Ei toimea" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Luokka" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Kuvaus" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Alku" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Loppu" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Kesto" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "luokat" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamsteriprojekti - seuraa aikaasi" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Tekijänoikeus © 2007-2010 Toms Bauģis ja muut" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamsteriprojektin WWW-sivut" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Tietoja ajankäytön seurannasta" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Timo Jyrinki , 2008." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Lajittelematon" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Työ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Uutisten luku" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Osakekurssien tarkistus" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Tosi salainen projekti X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Maailman valloitus" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Päivittäiset" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lounas" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Kukkien kastelu" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Käsilläseisonta" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Päivitä toimea" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d h" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d min" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d h %d min" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%-d. %Bta %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)sn %(start_d)s., %(start_Y)s – %(end_B)sn %(end_d)s., %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)sn %(start_d)s. – %(end_B)sn %(end_d)s., %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)sn %(start_d)s. – %(end_d)s., %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%Ana %-d. %Bta" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s tuntia yhteensä seurattu" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ei mitään" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nimi" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Uusi luokka" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Uusi toimi" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuutti" msgstr[1] "%(interval_minutes)d minuuttia" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Ei koskaan" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "toimi" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "aloitusaika" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "päättymisaika" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "kesto minuutteina" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "luokka" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "kuvaus" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "tagit" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Yleiskuva ajalle %(start_B)sn %(start_d)s., %(start_Y)s – %(end_B)sn " "%(end_d)s., %(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Yleiskuva ajalle %(start_B)sn %(start_d)s. – %(end_B)sn %(end_d)s., %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Yleiskuva päiväykselle %(start_d)s. %(start_B)sta %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Yleiskuva ajalle %(start_B)sn %(start_d)s. – %(end_d)s., %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%-d.%-m.%Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "Yhteenveto" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "Toimi" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "toimet" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "luokat" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Päiväys" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "Näytä viikko" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Kaikki" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Tilastojen tuottamiseen ei ole vielä dataa.\n" "Viikon käyttäminen olisi kiva!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Kerätään dataa — tarkista uudelleen kun viikko on kulunut!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%-d.%-m.%Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%-d.%-m." #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Ensimmäinen toimi kirjattiin %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s vuosi" msgstr[1] "%(num)s vuotta" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tähän mennessä on aikaa on seurattu %(human_days)s päivää (%(human_years)s) " "tai %(working_days)s työpäivää (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%-d.%-m.%Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Pisin yhtäjaksoisnen työskentely tapahtui %(date)s ja kesti %(hours)s tunnin." msgstr[1] "" "Pisin yhtäjaksoisnen työskentely tapahtui %(date)s ja kesti %(hours)s tuntia." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Tallessa on %s merkintä." msgstr[1] "Tallessa on %s merkintää." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamsteri haluaisi tarkkailla sinua vielä vähän!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Koska %s prosenttia kaikista alkaa ennen aamu yhdeksää, näytät olevan " "aikainen lintu." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Koska %s prosenttia kaikista alkaa kello 11 jälkeen, näytät olevan yökukkuja." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Koska %s prosenttia kaikista tehtävistä kestää alle 15 minuuttia, näytät " "olevan ahkera mehiläinen." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Ei kirjauksia tältä päivältä" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s h" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Juuri aloitettu" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Tallenna raportti – Ajankäytön seuranta" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-raportti" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Sarkainerotellut arvot (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Ajankäytön seuranta" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Hamsteriprojekti – työpöydän ajanseuranta" #~ msgid "Sto_p Tracking" #~ msgstr "_Pysäytä seuranta" #~ msgid "To_day" #~ msgstr "Tä_nään" #~ msgid "_Add earlier activity" #~ msgstr "_Lisää aikaisempi toimi" #~ msgid "_About" #~ msgstr "_Tietoja" #~ msgid "_Preferences" #~ msgstr "_Asetukset" #~ msgid "Starts and ends" #~ msgstr "Alkaa ja loppuu" #~ msgid "Year:" #~ msgstr "Vuosi:" #~ msgid "Preferences" #~ msgstr "Asetukset" #~ msgid "Changed activity" #~ msgstr "Muutettu toimi" #~ msgid "Switched to '%s'" #~ msgstr "Vaihdettu toimeen ”%s”" #~ msgid "Working on %s" #~ msgstr "Työn alla: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster - Ajankäytön seuranta. Käyttö:" #~ msgid "Show window" #~ msgstr "Näytä ikkuna" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Li_sää aikaisempi toimi" #~ msgid "Tell me more" #~ msgstr "Kerro lisää" #~ msgid "_Today" #~ msgstr "_Tänään" #~ msgid "Preview:" #~ msgstr "Esikatselu:" #~ msgid "General" #~ msgstr "Yleiset" #~ msgid "Global Hotkey" #~ msgstr "Yleinen pikanäppäin" #~ msgid "Move activity down" #~ msgstr "Siirrä toimi alemmas" #~ msgid "Move activity up" #~ msgstr "Siirrä toimi ylemmäs" #~ msgid "Total Time" #~ msgstr "Kokonaisaika" #~ msgid "Activities" #~ msgstr "Toimet" #~ msgid "Tracking" #~ msgstr "Seuranta" #~ msgid "Hamster" #~ msgstr "Hamsteri" #~ msgid "_Activity:" #~ msgstr "T_oimi:" #~ msgid " _Day" #~ msgstr " _Päivä" #~ msgid " _Month" #~ msgstr " _Kuukausi" #~ msgid " _Week" #~ msgstr " _Viikko" #~ msgid "Overview" #~ msgstr "Yleiskuva" #~ msgid "Totals" #~ msgstr "Yhteensä" #~ msgid "Categories:" #~ msgstr "Luokat:" #~ msgid "Date interval:" #~ msgstr "Päivämäärien väli:" #~ msgid "Save as HTML" #~ msgstr "Tallenna HTML-muodossa" #~ msgid "What should be typed in the activity box?" #~ msgstr "Mitä kannattaisi kirjoittaa toimilaatikkoon?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Yksinkertainen syntaksi auttaa sinua lisäämään yksityiskohtia toimiisi:\n" #~ " \n" #~ "Symboli ”@” viittaa luokkaan. Esimerkki: ”\"kukkien kastelua@kotona”\" " #~ "aloittaa seuraamaan ”kukkien kastelua” luokassa ”kotona”.\n" #~ "\n" #~ "Pilkut (”,”) merkitsee kuvauksen alkua. Esimerkki: ”kukkien kastelua, " #~ "ruusut ja liljat” aloittaa seuraamaan ”kukkien kastelua” ja lisää " #~ "kuvauksen ”ruusut ja liljat” siihen.\n" #~ "\n" #~ "Molemmat voi yhdistää: ”kukkien kastelua@kotona, ruusut ja liljat” toimii " #~ "mainiosti!\n" #~ "\n" #~ "Nyt, aloitapa seuranta!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Kaikki" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Yhteensä" #~ msgid "Overview for %(date)s" #~ msgstr "Yleiskuva päiväykselle %(date)s" #~ msgid "Move _Down" #~ msgstr "Siirrä _alas" #~ msgid "Move _Up" #~ msgstr "Siirrä _ylös" #~ msgid "N_ew Category" #~ msgstr "U_usi luokka" #~ msgid "_New Activity" #~ msgstr "_Uusi toimi" #~ msgid "Activity" #~ msgstr "Toimi" #~ msgid "hours" #~ msgstr "tuntia" #~ msgid "Delete activity" #~ msgstr "Poista toimi" #~ msgid "Newer activities" #~ msgstr "Uudemmat toimet" #~ msgid "Show month" #~ msgstr "Näytä kuukausi" #~ msgid "name" #~ msgstr "nimi" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s. %(report_b)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_d)s. %(o_b)s" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " #~ msgid "Category" #~ msgstr "Luokka" #~ msgid "Week" #~ msgstr "Viikko" #~ msgid "Earlier activities" #~ msgstr "Aiemmat toimet" #~ msgid "Show day" #~ msgstr "Näytä päivä" #~ msgid "Other" #~ msgstr "Muu" #~ msgid "Time tracking for masses" #~ msgstr "Ajankäytön seuranta kaikille" #~ msgid "Time tracking for masses." #~ msgstr "Ajankäytön seuranta kaikille vipeltäjille." #~ msgid "Overview for %s - %s" #~ msgstr "Yleiskuva ajalle %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%-d.%-m.%y" #~ msgid "%d. %b" #~ msgstr "%-d. %b" #~ msgid "%B %d." #~ msgstr "%-d. %Bta" hamster-3.0.3/po/fr.po000066400000000000000000000563051452646177100145730ustar00rootroot00000000000000# French translation of Hamster # Copyright (C) 2008-2012 The Free Software Foundation # This file is distributed under the same license as the Hamster package. # # Pierre-Luc Beaudoin , 2008. # Stéphane Raimbault , 2008. # Robert-André Mauchin , 2008. # Claude Paroz , 2008-2011. # Jonathan Ernst , 2009. # Laurent Coudeur , 2009, 2010. # Jean-Philippe Fleury , 2010. # Bruno Brouard , 2011-12. # Pierre Henry 2012 # msgid "" msgstr "" "Project-Id-Version: hamster HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-12-25 23:59+0100\n" "PO-Revision-Date: 2019-12-26 00:14+0100\n" "Last-Translator: ederag \n" "Language-Team: GNOME French Team \n" "Language: fr\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" "X-Generator: Poedit 2.2.1\n" #: data/date_range.ui:50 msgid "Today:" msgstr "Aujourd'hui :" #: data/date_range.ui:99 msgid "Week:" msgstr "Semaine :" #: data/date_range.ui:148 msgid "Month:" msgstr "Mois :" #: data/date_range.ui:196 msgid "Range:" msgstr "Période :" #: data/date_range.ui:242 msgid "to" msgstr "à" #: data/date_range.ui:288 msgid "Apply" msgstr "Appliquer" #: data/edit_activity.ui:15 msgid "Add Earlier Activity" msgstr "Ajout d'une activité antérieure" #. column title in the TSV export format #: data/edit_activity.ui:120 src/hamster/reports.py:143 msgid "description" msgstr "description" #: data/edit_activity.ui:177 msgid "start" msgstr "début" #: data/edit_activity.ui:223 msgid "start date" msgstr "date de début" #: data/edit_activity.ui:250 msgid "end" msgstr "fin" #: data/edit_activity.ui:296 msgid "end date" msgstr "date de fin" #. column title in the TSV export format #: data/edit_activity.ui:334 src/hamster/reports.py:141 msgid "category" msgstr "catégorie" #. column title in the TSV export format #: data/edit_activity.ui:376 src/hamster/reports.py:133 msgid "activity" msgstr "activité" #. column title in the TSV export format #: data/edit_activity.ui:424 src/hamster/reports.py:145 #: src/hamster/reports.py:294 msgid "tags" msgstr "étiquettes" #: data/preferences.ui:10 msgid "Time Tracker Preferences" msgstr "Préférences du gestionnaire de temps" #: data/preferences.ui:51 msgid "New day starts at" msgstr "La journée commence à" #: data/preferences.ui:89 msgid "Tracking" msgstr "Suivi" #: data/preferences.ui:132 msgid "_Categories" msgstr "_Catégories" #: data/preferences.ui:165 msgid "Category list" msgstr "Liste des catégories" #: data/preferences.ui:197 msgid "Add category" msgstr "Ajouter une catégorie" #: data/preferences.ui:222 msgid "Remove category" msgstr "Supprimer la catégorie" #: data/preferences.ui:247 msgid "Edit category" msgstr "Modifier la catégorie" #: data/preferences.ui:285 msgid "_Activities" msgstr "_Activités" #: data/preferences.ui:323 msgid "Activity list" msgstr "Liste des activités" #: data/preferences.ui:357 src/hamster/edit_activity.py:94 msgid "Add activity" msgstr "Ajouter une activité" #: data/preferences.ui:382 msgid "Remove activity" msgstr "Supprimer l'activité" #: data/preferences.ui:407 msgid "Edit activity" msgstr "Modifier l'activité" #: data/preferences.ui:479 msgid "Tags that should appear in autocomplete" msgstr "Étiquettes qui doivent apparaître dans l'auto-complétion" #: data/preferences.ui:503 msgid "Categories and Tags" msgstr "Catégories et étiquettes" #: data/hamster.desktop.in:6 msgid "Hamster" msgstr "" #: data/hamster.desktop.in:7 msgid "Your personal time keeping tool" msgstr "Votre gestionnaire de temps personnel" #: data/hamster.desktop.in:8 msgid "hamster" msgstr "" #: data/org.gnome.hamster.gschema.xml:5 data/org.gnome.hamster.gschema.xml:6 msgid "The folder the last report was saved to" msgstr "Le dernier répertoire utilisé pour enregistrer un rapport" #: data/org.gnome.hamster.gschema.xml:13 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Heure de début de journée (5 h 30 par défaut)" #: data/org.gnome.hamster.gschema.xml:14 msgid "" "The hamster day of an activity is the civil date of start time, provided " "start time is after day-start. On the contrary, if start time is earlier " "than day-start, then the activity belongs to the previous hamster day." msgstr "" #: src/hamster-cli.py:214 msgid "No activity" msgstr "Aucune activité" #: src/hamster-cli.py:236 src/hamster/reports.py:299 msgid "Activity" msgstr "Activité" #: src/hamster-cli.py:237 src/hamster/preferences.py:115 #: src/hamster/reports.py:300 msgid "Category" msgstr "Catégorie" #: src/hamster-cli.py:238 src/hamster/reports.py:301 msgid "Tags" msgstr "Étiquettes" #: src/hamster-cli.py:239 src/hamster/reports.py:305 msgid "Description" msgstr "Description" #: src/hamster-cli.py:240 src/hamster/reports.py:302 msgid "Start" msgstr "Début" #: src/hamster-cli.py:241 src/hamster/reports.py:303 msgid "End" msgstr "Fin" #: src/hamster-cli.py:242 src/hamster/reports.py:304 msgid "Duration" msgstr "Durée" #: src/hamster-cli.py:268 src/hamster/preferences.py:53 #: src/hamster/reports.py:77 src/hamster/reports.py:109 #: src/hamster/reports.py:240 src/hamster/widgets/activityentry.py:615 msgid "Unsorted" msgstr "Divers" #: src/hamster-cli.py:305 msgid "" "\n" "Actions:\n" " * start / track [start-time] [end-time]: Track an activity\n" " * stop: Stop tracking current activity.\n" " * list [start-date [end-date]]: List activities\n" " * search [terms] [start-date [end-date]]: List activities matching a " "search\n" " term\n" " * export [html|tsv|ical|xml] [start-date [end-date]]: Export activities " "with\n" " the specified format\n" " * current: Print current activity\n" " * activities: List all the activities names, one per line.\n" " * categories: List all the categories names, one per line.\n" "\n" " * overview / prefs / add / about: launch specific window\n" "\n" "Time formats:\n" " * 'YYYY-MM-DD hh:mm': If start-date is missing, it will default to " "today.\n" " If end-date is missing, it will default to start-date.\n" " * '-minutes': Relative time in minutes from the current date and time.\n" "Note:\n" " * For list/search/export a \"hamster day\" starts at the time set in " "the\n" " preferences (default 05:00) and ends one minute earlier the next day.\n" " Activities are reported for each \"hamster day\" in the interval.\n" "\n" "Example usage:\n" " hamster start bananas -20\n" " start activity 'bananas' with start time 20 minutes ago\n" "\n" " hamster search pancakes 2012-08-01 2012-08-30\n" " look for an activity matching terms 'pancakes` between 1st and 30st\n" " August 2012. Will check against activity, category, description and " "tags\n" msgstr "" #: src/hamster/about.py:33 msgid "Project Hamster — track your time" msgstr "Projet Hamster — Gérez votre emploi du temps" #: src/hamster/about.py:34 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis et autres" #: src/hamster/about.py:36 msgid "Project Hamster Website" msgstr "Site Web du projet Hamster" #: src/hamster/about.py:37 msgid "About Time Tracker" msgstr "À propos du gestionnaire de temps" #: src/hamster/about.py:47 msgid "translator-credits" msgstr "" "Pierre-Luc Beaudoin \n" "Stéphane Raimbault \n" "Claude Paroz \n" "Jonathan Ernst \n" "Laurent Coudeur \n" "Jean-Philippe Fleury \n" "Ederag " #: src/hamster/edit_activity.py:92 msgid "Update activity" msgstr "Mettre à jour l'activité" #: src/hamster/overview.py:76 msgid "Menu" msgstr "" #: src/hamster/overview.py:82 #, fuzzy msgid "Filter activities" msgstr "activités" #: src/hamster/overview.py:88 #, fuzzy msgid "Stop tracking (Ctrl-SPACE)" msgstr "_Arrêter le suivi" #: src/hamster/overview.py:94 #, fuzzy msgid "Add activity (Ctrl-+)" msgstr "Ajouter une activité" #: src/hamster/overview.py:100 #, fuzzy msgid "Export..." msgstr "Enregistrer le rapport..." #: src/hamster/overview.py:102 #, fuzzy msgid "Tracking Settings" msgstr "Suivi" #: src/hamster/overview.py:104 #, fuzzy msgid "Help" msgstr "Aid_e" #: src/hamster/overview.py:286 msgid "Click to see stats" msgstr "" #: src/hamster/overview.py:590 msgid "Failed to open {}" msgstr "" #: src/hamster/overview.py:591 msgid "Error: \"{}\" - is a help browser installed on this computer?" msgstr "" #: src/hamster/preferences.py:91 msgid "Name" msgstr "Nom" #: src/hamster/preferences.py:476 msgid "New category" msgstr "Nouvelle catégorie" #: src/hamster/preferences.py:490 msgid "New activity" msgstr "Nouvelle activité" #. column title in the TSV export format #: src/hamster/reports.py:135 msgid "start time" msgstr "heure de début" #. column title in the TSV export format #: src/hamster/reports.py:137 msgid "end time" msgstr "heure de fin" #. column title in the TSV export format #: src/hamster/reports.py:139 msgid "duration minutes" msgstr "durée en minutes" #: src/hamster/reports.py:191 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Rapport d'activité du %(start_d)s %(start_B)s %(start_Y)s au %(end_d)s " "%(end_B)s %(end_Y)s" #: src/hamster/reports.py:193 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Rapport d'activité du %(start_d)s %(start_B)s au %(end_d)s %(end_B)s " "%(end_Y)s" #: src/hamster/reports.py:195 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Rapport d'activité du %(start_d)s %(start_B)s %(start_Y)s" #: src/hamster/reports.py:197 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Rapport d'activité du %(start_d)s au %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: src/hamster/reports.py:249 src/hamster/reports.py:281 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #: src/hamster/reports.py:288 msgid "Totals by Day" msgstr "Totaux par jour" #: src/hamster/reports.py:289 msgid "Activity Log" msgstr "Journal d'activité" #: src/hamster/reports.py:290 msgid "Totals" msgstr "Totaux" #: src/hamster/reports.py:292 msgid "activities" msgstr "activités" #: src/hamster/reports.py:293 msgid "categories" msgstr "catégories" #: src/hamster/reports.py:296 msgid "Distinguish:" msgstr "Distinguer :" #: src/hamster/reports.py:298 msgid "Date" msgstr "Date" #: src/hamster/reports.py:308 msgid "Show template" msgstr "Afficher le modèle" #: src/hamster/reports.py:309 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Vous pouvez le remplacer en enregistrant votre version dans %(home_folder)s" #: src/hamster/widgets/reportchooserdialog.py:37 msgid "Save Report — Time Tracker" msgstr "Enregistrer le rapport — Gestionnaire de temps" #: src/hamster/widgets/reportchooserdialog.py:55 msgid "HTML Report" msgstr "Rapport HTML" #: src/hamster/widgets/reportchooserdialog.py:63 msgid "Tab-Separated Values (TSV)" msgstr "Valeurs séparées par des tabulations (TSV)" #: src/hamster/widgets/reportchooserdialog.py:71 msgid "XML" msgstr "XML" #: src/hamster/widgets/reportchooserdialog.py:78 msgid "iCal" msgstr "iCal" #. title in the report file name #: src/hamster/widgets/reportchooserdialog.py:95 msgid "Time track" msgstr "Gestion du temps" #~ msgid "in progress" #~ msgstr "en cours" #~ msgid "Description:" #~ msgstr "Description :" #~ msgid "Time:" #~ msgstr "Heure :" #~ msgid "Activity:" #~ msgstr "Activité :" #~ msgid "Tags:" #~ msgstr "Étiquettes :" #~ msgid "Stop tracking on idle" #~ msgstr "Arrêter le suivi en cas d'inactivité" #~ msgid "Stop tracking current activity when computer becomes idle" #~ msgstr "" #~ "Arrêter le suivi de l'activité en cours quand l'ordinateur devient inactif" #~ msgid "Stop tracking on shutdown" #~ msgstr "Arrêter le suivi à l'extinction de l'ordinateur" #~ msgid "Stop tracking current activity on shutdown" #~ msgstr "" #~ "Arrêter le suivi de l'activité en cours à l'extinction de l'ordinateur" #~ msgid "Remind of current task every x minutes" #~ msgstr "Rappeler l'activité en cours toutes les n minutes" #~ msgid "" #~ "Remind of current task every specified amount of minutes. Set to 0 or " #~ "greater than 120 to disable reminder." #~ msgstr "" #~ "Rappeler l'activité en cours chaque nombre de minutes spécifié. Définir à " #~ "0 ou à plus de 120 pour désactiver le rappel." #~ msgid "Also remind when no activity is set" #~ msgstr "Rappeler également lorsqu'aucune activité n'est définie" #~ msgid "" #~ "Also remind every notify_interval minutes if no activity has been started." #~ msgstr "" #~ "Rappeler également toutes les « notify_interval » minutes si aucune " #~ "activité n'a été commencée." #~ msgid "" #~ "Activities will be counted as to belong to yesterday if the current time " #~ "is less than the specified day start; and today, if it is over the time. " #~ "Activities that span two days, will tip over to the side where the " #~ "largest part of the activity is." #~ msgstr "" #~ "Les activités sont comptabilisées dans la journée d'hier si l'heure " #~ "actuelle précède l'heure qui est spécifiée pour le début de la journée ; " #~ "et dans celle d'aujourd'hui, si c'est après. Les activités ayant cours " #~ "sur 2 journées sont comptabilisées dans celle où la part la plus grande " #~ "est effectuée." #~ msgid "Should workspace switch trigger activity switch" #~ msgstr "" #~ "Indique si le changement d'espace de travail doit déclencher un " #~ "changement d'activité" #~ msgid "" #~ "List of enabled tracking methods. \"name\" will enable switching " #~ "activities by name defined in workspace_mapping. \"memory\" will enable " #~ "switching to the last activity when returning to a previous workspace." #~ msgstr "" #~ "Liste des méthodes de suivi actives. « name » active le changement " #~ "d'activités par nom défini dans workspace_mapping. « memory » active le " #~ "changement vers la dernière activité en cas de retour dans un espace de " #~ "travail précédent." #~ msgid "Switch activity on workspace change" #~ msgstr "Changer d'activité lorsqu'on change d'espace de travail" #~ msgid "" #~ "If switching by name is enabled, this list sets the activity names that " #~ "should be switched to, workspaces represented by the index of item." #~ msgstr "" #~ "Si le changement par nom est actif, cette liste donne les noms d'activité " #~ "auxquelles on pourra passer, les espaces de travail sont représentés par " #~ "l'indice de l'élément." #~ msgid "Show / hide Time Tracker Window" #~ msgstr "Afficher ou masquer la fenêtre du gestionnaire de temps" #~ msgid "Keyboard shortcut for showing / hiding the Time Tracker window." #~ msgstr "" #~ "Raccourci clavier pour afficher ou masquer la fenêtre du gestionnaire de " #~ "temps." #~ msgid "Toggle hamster application window action" #~ msgstr "" #~ "Action pour afficher ou masquer la fenêtre de l'application de Hamster" #~ msgid "Command for toggling visibility of the hamster application window." #~ msgstr "" #~ "Commande pour afficher ou masquer la fenêtre de l'application de Hamster." #~ msgid "Toggle hamster application window" #~ msgstr "Afficher ou masquer la fenêtre de l'application de Hamster" #~ msgid "Toggle visibility of the hamster application window." #~ msgstr "Afficher ou masquer la fenêtre de l'application de Hamster." #~ msgid "Time Tracker" #~ msgstr "Gestionnaire de temps" #~ msgid "Project Hamster - track your time" #~ msgstr "Projet Hamster - Gérez votre emploi du temps" #~ msgid "Time Tracking Overview" #~ msgstr "Résumé de la gestion du temps" #~ msgid "The overview window of hamster time tracker" #~ msgstr "La fenêtre de résumé du gestionnaire de temps hamster" #~ msgid "Show Statistics" #~ msgstr "Afficher les statistiques" #~ msgid "Categories" #~ msgstr "Catégories" #~ msgid "Activities" #~ msgstr "Activités" #~ msgid "No data for this interval" #~ msgstr "Aucune donnée pour cette période" #~ msgid "Day" #~ msgstr "Jour" #~ msgid "Week" #~ msgstr "Semaine" #~ msgid "Month" #~ msgstr "Mois" #~ msgid "Overview — Hamster" #~ msgstr "Résumé — Hamster" #~ msgid "_Overview" #~ msgstr "_Résumé" #~ msgid "_View" #~ msgstr "_Affichage" #~ msgid "Remove" #~ msgstr "Supprimer" #~ msgid "Add new" #~ msgstr "Ajouter une nouvelle" #~ msgid "Edit" #~ msgstr "Modifier" #~ msgid "Stop tracking when computer becomes idle" #~ msgstr "Arrêter le suivi quand l'ordinateur devient inactif" #~ msgid "Remind of current activity every:" #~ msgstr "Rappeler l'activité en cours toutes les :" #~ msgid "Use following todo list if available:" #~ msgstr "Utiliser la liste des tâches suivante si elle est disponible :" #~ msgid "Integration" #~ msgstr "Intégration" #~ msgid "Resume the last activity when returning to a workspace" #~ msgstr "" #~ "Reprendre la dernière activité lorsqu'on revient sur un espace de travail" #~ msgid "Start new activity when switching workspaces:" #~ msgstr "" #~ "Commencer une nouvelle activité lorsqu'on change d'espace de travail :" #~ msgid "Workspaces" #~ msgstr "Espaces de travail" #~ msgid "Day:" #~ msgstr "Jour :" #~ msgid "_Tracking" #~ msgstr "_Suivi" #~ msgid "Add earlier activity" #~ msgstr "Ajouter une activité antérieure" #~ msgid "Overview" #~ msgstr "Résumé" #~ msgid "Statistics" #~ msgstr "Statistiques" #~ msgid "_Edit" #~ msgstr "_Modifier" #~ msgid "Contents" #~ msgstr "Sommaire" #~ msgid "S_witch" #~ msgstr "C_hanger" #~ msgid "Start _Tracking" #~ msgstr "_Commencer le suivi" #~ msgid "Start new activity" #~ msgstr "Commencer une nouvelle activité" #~ msgid "totals" #~ msgstr "totaux" #~ msgid "Show Overview" #~ msgstr "Afficher le résumé" #, fuzzy #~ msgid "Uncategorized" #~ msgstr "catégories" #~ msgid "Work" #~ msgstr "Travail" #~ msgid "Reading news" #~ msgstr "Lecture de nouvelles" #~ msgid "Checking stocks" #~ msgstr "Vérification des indices boursiers" #~ msgid "Super secret project X" #~ msgstr "Projet X super secret" #~ msgid "World domination" #~ msgstr "Domination mondiale" #~ msgid "Day-to-day" #~ msgstr "Quotidien" #~ msgid "Lunch" #~ msgstr "Repas" #~ msgid "Watering flowers" #~ msgstr "Arrosage des plantes" #~ msgid "Doing handstands" #~ msgstr "Faire le poirier" #~ msgid "%dh" #~ msgstr "%d h" #~ msgid "%dmin" #~ msgstr "%d min" #~ msgid "%dh %dmin" #~ msgstr "%d h %d min" #~ msgid "%B %d, %Y" #~ msgstr "%d %B %Y" #~ msgid "" #~ "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #~ msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #~ msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #~ msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #~ msgctxt "overview list" #~ msgid "%A, %b %d" #~ msgstr "%A %d %B" #~ msgid "%s hours tracked total" #~ msgstr "%s heures suivies au total" #~ msgid "None" #~ msgstr "Aucune" #~ msgid "%(interval_minutes)d minute" #~ msgid_plural "%(interval_minutes)d minutes" #~ msgstr[0] "%(interval_minutes)d minute" #~ msgstr[1] "%(interval_minutes)d minutes" #~ msgid "Never" #~ msgstr "Jamais" #~ msgctxt "years" #~ msgid "All" #~ msgstr "Toutes" #~ msgid "" #~ "There is no data to generate statistics yet.\n" #~ "A week of usage would be nice!" #~ msgstr "" #~ "Il n'y a pas encore de données pour générer des statistiques.\n" #~ "Une semaine d'utilisation serait préférable !" #~ msgid "Collecting data — check back after a week has passed!" #~ msgstr "La collecte des données est en cours — revenez dans une semaine !" #~ msgctxt "first record" #~ msgid "%b %d, %Y" #~ msgstr "%d %b %Y" #~ msgctxt "first record" #~ msgid "%b %d" #~ msgstr "%d %b" #~ msgid "First activity was recorded on %s." #~ msgstr "La première activité a été enregistrée le %s." #~ msgid "%(num)s year" #~ msgid_plural "%(num)s years" #~ msgstr[0] "%(num)s année" #~ msgstr[1] "%(num)s années" #~ msgid "" #~ "Time tracked so far is %(human_days)s human days (%(human_years)s) or " #~ "%(working_days)s working days (%(working_years)s)." #~ msgstr "" #~ "Le temps suivi à ce jour est de %(human_days)s jours (%(human_years)s) ou " #~ "%(working_days)s jours ouvrables (%(working_years)s)." #~ msgctxt "date of the longest activity" #~ msgid "%b %d, %Y" #~ msgstr "%d %b %Y" #~ msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." #~ msgid_plural "" #~ "Longest continuous work happened on %(date)s and was %(hours)s hours." #~ msgstr[0] "" #~ "Le temps de travail continu le plus long a été enregistré le %(date)s et " #~ "était de %(hours)s heure." #~ msgstr[1] "" #~ "Le temps de travail continu le plus long a été enregistré le %(date)s et " #~ "était de %(hours)s heures." #~ msgid "There is %s record." #~ msgid_plural "There are %s records." #~ msgstr[0] "Il y a %s enregistrement." #~ msgstr[1] "Il y a %s enregistrements." #~ msgid "Hamster would like to observe you some more!" #~ msgstr "Hamster souhaite vous observer plus longtemps !" #~ msgid "" #~ "With %s percent of all activities starting before 9am, you seem to be an " #~ "early bird." #~ msgstr "" #~ "Avec %s %% d'activités commencées avant 9 h du matin, vous devez être " #~ "matinal." #~ msgid "" #~ "With %s percent of all activities starting after 11pm, you seem to be a " #~ "night owl." #~ msgstr "" #~ "Avec %s %% d'activités commencées après 11 h du soir, vous semblez être " #~ "un oiseau de nuit." #~ msgid "" #~ "With %s percent of all activities being shorter than 15 minutes, you seem " #~ "to be a busy bee." #~ msgstr "" #~ "Avec %s %% d'activités ne dépassant pas 15 minutes, vous semblez être " #~ "très occupé." #~ msgid "No records today" #~ msgstr "Aucun enregistrement aujourd'hui" #~ msgid "%(category)s: %(duration)s" #~ msgstr "%(category)s : %(duration)s" #~ msgid "%sh" #~ msgstr "%s h" #~ msgid "Just started" #~ msgstr "Vient de commencer" #~ msgid "Show activities window" #~ msgstr "Afficher la fenêtre des activités" #~ msgid "Sto_p Tracking" #~ msgstr "_Arrêter le suivi" #~ msgid "To_day" #~ msgstr "Aujourd'_hui" #~ msgid "_Add earlier activity" #~ msgstr "Ajou_ter une activité antérieure" #~ msgid "Show _Overview" #~ msgstr "Afficher le _résumé" #~ msgid "_Preferences" #~ msgstr "_Préférences" #~ msgid "_About" #~ msgstr "À pr_opos" #~ msgid "Year:" #~ msgstr "Année :" #~ msgid "Starts and ends" #~ msgstr "Débuts et fins" #~ msgid "Preferences" #~ msgstr "Préférences" #~ msgid "Changed activity" #~ msgstr "Activité changée" #~ msgid "Switched to '%s'" #~ msgstr "Passé à « %s »" #~ msgid "Working on %s" #~ msgstr "Travaille sur %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Gestionnaire de temps Hamster. Utilisation :" hamster-3.0.3/po/gl.po000066400000000000000000000710711452646177100145630ustar00rootroot00000000000000# translation of hamster.master.po to Galician # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Ignacio Casal Quinteiro , 2008. # Suso Baleato , 2009. # Antón Méixome , 2009. # Fran Diéguez , 2009, 2010, 2011. # Fran Dieguez , 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-21 11:24+0100\n" "Last-Translator: Fran Dieguez \n" "Language-Team: Galician \n" "Language: gl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Engadir unha actividade anterior" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "para" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "en progreso" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descrición:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Tempo:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Actividade:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetas:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Deter o rexistro en inactividade" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Deter a actividade actual cando o computador estea inactivo" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Deter o rexistro ao apagar" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Deter a actividade actual ao apagar" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Recordarme a tarefa actual cada x minutos" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Recordar a tarefa actual coa frecuencia especificada en minutos. Configúrea " "como 0 ou superior a 120 para desactivar o recordatorio." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Recordar tamén cando non hai actividade" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "Lembra cada notify_interval en minutos se non hai actividade iniciada." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "En que momento comeza o día (o valor predeterminado é 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "As actividades serán contadas como pertencentes a onte se o tempo actual é " "inferior ao día de inicio especificado e hoxe, se está sobre o tempo. As " "actividades con máis de dous días sacaranse ao lado onde a parte da " "actividade é máis longa." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Se debe o cambio de cambio de espazo de traballo cambiar de actividade" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista dos métodos de seguimento activados.«name» permitirá cambiar as " "actividades polo nome definido en workspace_mapping. «memory» permite " "cambiar á última actividade ao volver ao espazo de traballo anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Cambiar a actividade ao cambiar de espazo de traballo" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Se cambiar polo nome está activado, esta lista estabelece os nomes de " "actividade aos que debe cambiar, os espazos de traballo representados polo " "índice do elemento" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostrar/ocultar a xanela do xestor de tempo." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Atallo de teclado para mostrar/agochar a xanela do xestor de tempo." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Trocar a acción da xanela do aplicativo Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Orde para trocar a visibilidade da xanela do aplicativo Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Trocar a xanela do aplicativo Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Trocar a visibilidade da xanela do aplicativo Hamster" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Xestor de tempo" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Proxecto Hamster - xestione o seu tempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Vista previa do Xestor de tempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "A xanela da vista previa do Xestor de tempo Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostrar as estatísticas" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorías" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Actividades" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetas" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Non hai datos neste intervalo" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Gardar informe…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Día" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Semana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mes" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Resumo — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Resumo" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Actividade" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Ver" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totais" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Eliminar" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Engadir nova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editar" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferencias do xestor de tempo" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Deter o rexistro cando o computador esté inactivo" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Recordar a actividade actual cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Os días novos comezan en" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Se está dispoñíbel, usar a seguinte lista de tarefas:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integración" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Seguimento" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categorías" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Lista de categorías" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Engadir unha categoría" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Nova categoría" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editar a categoría" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Actividades" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Lista de actividade" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Engadir unha actividade" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Eliminar a actividade" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editar a actividade" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etiquetas que deberían aparecer no completado automático" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorías e etiquetas" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Reiniciar a última actividade ao volver ao espazo de traballo" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Iniciar unha nova actividade ao cambiar os espazos de traballo:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Espazos de traballo" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Día:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Semana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mes:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Rango de data:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplicar" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Seguimento" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Engadir unha actividade anterior" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Resumo" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estatísticas" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editar" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Axuda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Contidos" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Deter o seguimento" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "C_ambiar" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Comezar o _seguimento" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Comezar unha nova actividade" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hoxe" #: ../data/today.ui.h:14 msgid "totals" msgstr "totais" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostrar un resumo" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Sen actividade" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoría" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descrición" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Inicio" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Fin" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duración" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorías" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Proxecto Hamster - xestione o seu tempo" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis e outros" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Sitio web de Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Sobre o Xestor de tempo" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Fran Dieguez , 2009, 2010;\n" "Antón Méixome , 2009;\n" "Ignacio Casal Quinteiro , 2008;" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sen clasificar" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Traballo" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Ler as noticias" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Comprobar as existencias" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Proxecto súper secreto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominación mundial" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Día a día" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Almorzar" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regar as plantas" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Facer flexións" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualizar a actividade" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s de %(start_B)s, %(start_Y)s – %(end_d)s de %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s de %(start_d)s – %(end_B)s de %(end_d)s de %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s de %(start_d)s – %(end_d)s ao %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d de %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s horas seguidas en total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ningunha" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nome" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova categoría" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova actividade" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minutos" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nunca" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "actividade" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "tempo inicial" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "tempo final" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duración en minutos" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoría" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descrición" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetas" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Rexistro de actividade para o %(start_d)s de %(start_B)s de %(start_Y)s até " "o %(end_d)s de %(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Rexistro de actividade do %(start_d)s de %(start_B)s ao %(end_d)s de " "%(end_B)s de %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Rexistro de actividade do %(start_d)s de %(start_B)s de %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Rexistro de actividade de %(start_B)s, del %(start_d)s ao %(end_d)s de " "%(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d de %B, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totais por día" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Rexistro de actividade" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "actividades" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorías" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinguir:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostrar modelo" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Vostede pode sobrescribilos almacenando a súa versión en %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Todos" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Aínda non hai datos para xerar as estatísticas.\n" "Unha semana de uso estaría ben!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" "Aínda se están recollendo datos — comprobe de novo dentro de unha semana." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d de %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "A primeira actividade foi gravada en %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ano" msgstr[1] "%(num)s anos" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "O tempo rexistrado acada %(human_days)s días humanos (%(human_years)s anos) " "ou %(working_days)s días laborábeis (%(working_years)s anos)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d de %B, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "O traballo continuo máis longo foi o %(date)s e durou %(hours)s hora." msgstr[1] "" "O traballo continuo máis longo foi o %(date)s e durou %(hours)s horas." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Hai %s rexistro." msgstr[1] "Hai %s rexistros." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "A Hamster gustaríalle observalo a vostede algo máis!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Co %s por cento de todas as tarefas que comezan antes das 9 da mañá, parece " "que vostede é moi madrugador." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Co %s por cento de todas as tarefas que comezan despois das 11 da noite, " "parece que vostede é un moucho nocturno." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Co %s por cento de todas as tarefas máis curtas de 15 minutos, parece que " "vostede é unha abella obreira." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Hoxe non hai rexistros" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Recén comezada" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Gardar informe — Xestor de tempo" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Informe HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valores separados por tabuladores (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Xestor de tempo" #~ msgid "Show activities window" #~ msgstr "Mostrar a xanela de actividades" #~ msgid "Sto_p Tracking" #~ msgstr "_Deter o seguimento" #~ msgid "To_day" #~ msgstr "Ho_xe" #~ msgid "_Add earlier activity" #~ msgstr "Eng_adir unha actividade anterior" #~ msgid "Show _Overview" #~ msgstr "_Mostrar un resumo" #~ msgid "_Preferences" #~ msgstr "_Preferencias" #~ msgid "_About" #~ msgstr "_Sobre" #~ msgid "Year:" #~ msgstr "Ano:" #~ msgid "Starts and ends" #~ msgstr "Inicio e finalización" #~ msgid "Preferences" #~ msgstr "Preferencias" #~ msgid "Changed activity" #~ msgstr "Actividade cambiada" #~ msgid "Switched to '%s'" #~ msgstr "Cambiado a «%s»" #~ msgid "Working on %s" #~ msgstr "Traballando en %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Seguimento do tempo Hamster. Uso:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Proxecto Hamster (Xestor de tempo do GNOME)" #~ msgid "totals by activity" #~ msgstr "Totais por actividade" #~ msgid "totals by category" #~ msgstr "Totais por categoría" #~ msgid "Show:" #~ msgstr "Mostrar:" #~ msgid "Tell me more" #~ msgstr "Cónteme máis" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "Xestor de tempo Proxecto Hamster" #~ msgid "Move activity down" #~ msgstr "Baixar a actividade" #~ msgid "Move activity up" #~ msgstr "Subir a actividade" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Engadir unha actividade anterior" #~ msgid "_Today" #~ msgstr "_Hoxe" #~ msgid "Export data..." #~ msgstr "Exportar datos..." #~ msgid "General" #~ msgstr "Xeral" #~ msgid "Global Hotkey" #~ msgstr "Atallo global de teclado" #~ msgid "Total Time" #~ msgstr "Tempo total" #~ msgid "Preview:" #~ msgstr "Previsualización:" #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "Hora onde se considera o comezo dun novo día" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "Time and Name" #~ msgstr "Hora e nome" #~ msgid "Tags or Description" #~ msgstr "Etiquetas e descrición" #~ msgid "Overview" #~ msgstr "Resumo" #~ msgid "Totals" #~ msgstr "Totais" #~ msgid "What should be typed in the activity box?" #~ msgstr "Que escribir na caixa de actividade?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Dispón dunha sintaxe simple que lle permite engadir detalles ás súas " #~ "actividades:\n" #~ " \n" #~ "\"@\" categoría de marcas de símbolo. Exemplo: \"flores acuáticas@casa\" " #~ "comezará a facer o rexistro da actividade \"flores acuáticas\" na " #~ "categoría \"casa\".\n" #~ "\n" #~ "As marcas de coma (\",\") ao comezo dunha descrición. Exemplo: \"flores " #~ "acuáticas, begonias e non-me-olvides\" comezará a rexistrar a actividade " #~ "\"flores acuáticas\" e engadir a descricion \"begonias e non-me-olvides" #~ "\" a ela.\n" #~ "\n" #~ "Ambas poden ser combinadas: \"flores acuáticas@casa, begonias e non-me-" #~ "olvides\" tamén funcionará ben!\n" #~ "\n" #~ "Agora, comece o seguimento!\n" #~ " " #~ msgid "Total" #~ msgstr "Total" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%d de %b" #~ msgid "Activities" #~ msgstr "Actividades" #~ msgid "Tracking" #~ msgstr "Seguimento" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Escriba unha actividade e faga Intro para comezar o " #~ "seguimento" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Dígame máis" #~ msgid "_Activity:" #~ msgstr "_Actividade:" #~ msgid " _Day" #~ msgstr "_Día" #~ msgid " _Month" #~ msgstr " _Mes" #~ msgid " _Week" #~ msgstr " _Semana" #~ msgid "Categories:" #~ msgstr "Categorías:" #~ msgid "Date interval:" #~ msgstr "Intervalo de data:" #~ msgid "Save as HTML" #~ msgstr "Gardar como HTML" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Todas" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s de %(b)s " #~ msgid "Overview for %(date)s" #~ msgstr "Resumo do %(date)s" hamster-3.0.3/po/gu.po000066400000000000000000000673261452646177100146040ustar00rootroot00000000000000# translation of gu.po to Gujarati # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Sweta Kothari , 2008, 2009, 2011. # Ankit Patel , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: gu\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2011-02-21 12:07+0530\n" "Last-Translator: Sweta Kothari \n" "Language-Team: Gujarati\n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "પહેલાની આવૃત્તિને ઉમેરો" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "માં" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "પ્રગતિ માં" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "વર્ણન:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "સમયમ:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "પ્રવૃત્તિ:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "ટૅગ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "નિષ્ક્રિય પર શોધવાનું બંધ કરો" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "જ્યારે કમ્પ્યુટર નિષ્ક્રિય બનેલ હોય ત્યારે, હાલની પ્રવૃત્તિ શોધવાનું બંધ કરો" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "બંધ કરી રહ્યા હોય ત્યારે શોધવાનું બંધ કરો" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "બંધ કરી રહ્યા હોય ત્યારે હાલની પ્રવૃત્તિ શોધવાનું બંધ કરો" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "વર્તમાન કામને દર x મિનિટોએ યાદ અપાવે" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "દરેક કામને સ્પષ્ટ થયેલ મિનિટોના આ દરે યાદ અપાવો. ૦ માં સુયોજીત થયેલ છે અથવા યાદ " "અપાવનાર નિષ્ક્રિય કરવા માટે ૧૨૦ કરતાં વધુ." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "જ્યારે પ્રવૃત્તિ સુયોજિત ન હોય ત્યારે પણ યાદ અપાવો" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "દરેક notify_interval મિનિટોએ પણ યાદ રાખો જો પ્રવૃત્તિને શરૂ કરી ન દેવામાં આવી હોય." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "સમય શોધનાર વિન્ડો બતાવવા માટે કિબોર્ડ શોર્ટકટ." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "સમય શોધનાર વિન્ડો બતાવવા માટે કિબોર્ડ શોર્ટકટ." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "ટૉગલ હેમસ્ટર કાર્યક્રમ વિન્ડો ક્રિયા" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "ટૉગલ હેમસ્ટર કાર્યક્રમ વિન્ડો" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "હેમસ્ટર કાર્યક્રમ વિન્ડોની ટૉગલ દૃશ્યતા" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "સમય શોધનાર" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "પ્રોજેક્ટ Hamster — તમારો સમય શોધો" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "સમય શોધનાર" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "પરિસ્થિતિઓ બતાવો" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "વર્ગો" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "પ્રવૃત્તિઓ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "ટૅગ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "આ અંતરાલ માટે માહિતી નથી" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "અહેવાલને સંગ્રહો..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "દિવસ" #: ../data/overview.ui.h:3 msgid "Week" msgstr "અઠવાડિયુ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "મહિનો" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "ઝાંખી — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "ઝાંખી (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "પ્રવૃત્તિ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "દૃશ્ય (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "કુલ" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "દૂર કરો" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "નવાંને ઉમેરો" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "ફેરફાર" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "સમય શોધનાર પસંદગીઓ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "જ્યારે કમ્પ્યુટર નિષ્ક્રિય બનેલ હોય ત્યારે શોધવાનું બંધ કરો" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "વર્તમાન ક્રિયાને આ દરે યાદ અપાવો:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "નીચેની કામ કરવાની યાદીને વાપરો જો ઉપલબ્ધ હોય:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "એકત્રિકરણ" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "શોધી રહ્યા છે" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "વર્ગો (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "વર્ગ યાદી" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "વર્ગને ઉમેરો" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "વર્ગને દૂર કરો" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "વર્ગમાં ફેરફાર કરો" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "પ્રવૃત્તિઓ (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "પ્રવૃત્તિ યાદી" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "પ્રવૃત્તિ ઉમેરો" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "પ્રવૃત્તિને દૂર કરો" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "પ્રવૃત્તિમાં ફેરફાર કરો" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "વર્ગો અને ટૅગ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "નવી પ્રવૃત્તિને શરૂ કરો જ્યારે કામ કરવાની જગ્યાને બદલી રહ્યા હોય:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "કામ કરવાની જગ્યા" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "દિવસ:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "અઠવાડિયુ:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "મહિનો:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "સીમા:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "લાગુ કરો" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "શોધી રહ્યા છે (_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "પહેલાની પ્રવૃત્તિને ઉમેરો" #: ../data/today.ui.h:4 msgid "Overview" msgstr "ઝાંખી" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "પરિસ્થિતિઓ" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "ફેરફાર (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "મદદ (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "સમાવિષ્ટો" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "ટ્રેકિંગ બંધ કરો (_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "બદલો (_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "શોધવાનું શરૂ કરો (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "નવી પ્રવૃત્તિને શરૂ કરો" #: ../data/today.ui.h:13 msgid "Today" msgstr "આજે" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "કુલ" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "ઉપરછલ્લુ બતાવો (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "પ્રવૃત્તિ નથી" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "વર્ગ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "વર્ણન" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "શરૂ કરો" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "સમાપ્ત" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "સમયગાળો" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "વર્ગો" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "પ્રોજેક્ટ Hamster — તમારો સમય ટ્રેક કરો" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis અને બીજાઓ" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "પ્રોજેક્ટ Hamster વેબસાઇટ" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "સમય શોધનાર વિશે" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "શ્ર્વેતા કોઠારી " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "ક્રમમાં થયેલ નથી" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "કામ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "સમાચારો વાંચી રહ્યા છે" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "સ્ટોકો ચકાસી રહ્યા છે" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "ઉત્તમ ખાનગી પ્રોજેક્ટ X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "દુનિયામાં વર્ચસ્વ" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "રોજ-બ-રોજ" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "આરંભ કરના" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ફૂલોમાં પાણી નાંખી રહ્યા છે" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "હાથને આધાર આપી રહ્યા છે" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "પ્રવૃત્તિને સુધારો" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "કઇ નહિં" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "નામ" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "નવો વર્ગ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "નવી પ્રવૃત્તિ" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d મિનિટો" msgstr[1] "%(interval_minutes)d મિનિટો" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ક્યારેય નહિં" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "પ્રવૃત્તિ" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "શરૂઆતનો સમય" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "અંત સમય" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "મિનિટોનો સમયગાળો" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "વર્ગ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "વર્ણન" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ટૅગ" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s માટે પ્રવૃત્તિ અહેવાલ– %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s માટે પ્રવૃત્તિ અહેવાલ– %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s માટે પ્રવૃત્તિ અહેવાલ, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s માટે પ્રવૃત્તિ અહેવાલ – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "કુલ" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "પ્રવૃત્તિ લૉગ" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "પ્રવૃત્તિઓ" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "વર્ગો" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "તારીખ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "ટૅમ્પલેટને બતાવો" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "બધા" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "હજુ પરિસ્થિતિઓને ઉત્પન્ન કરવા માટે માહિતી નથી.\n" "અઠવાડિયાનો વપરાશ સારો છે!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "માહિતીનો સંગ્રહ કરી રહ્યા છે — અઠવાડિયુ પસાર થઇ જાય તે પછી પાછા ચકાસો!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "પહેલી પ્રવૃત્તિ %s પર અહેવાલ થયેલ હતો." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s વર્ષ" msgstr[1] "%(num)s વર્ષો" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "અત્યાર સુધીનો ટ્રેક કરેલો %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s) સમય." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "લાંબામાં લાંબુ ચાલતુ કાર્ય %(date)s પર બન્યુ અને %(hours)s કલાક પર હતુ." msgstr[1] "લાંબામાં લાંબુ ચાલતુ કાર્ય %(date)s પર બન્યુ અને %(hours)s કલાકો પર હતુ." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "ત્યાં %s અહેવાલ છે." msgstr[1] "ત્યાં %s અહેવાલો છે." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ને તમને થોડુ વધારે ધ્યાન આપવુ ગમે છે!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "બધી તથ્યો %s પ્રતિશત 9am પહેલાં શરૂ થાય તો તે જલ્દી આવ્યા હોય તેવુ મનાશે." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "બધા તથ્યો %s પ્રતિશત 11pm પછી શરૂ થાય તો તમે નિશાચર માનવામાં આવશે." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "બધા કાર્યો %s પ્રતિશત 15 મિનિટો કરતા ટૂંકા હોય તો તમે વ્યસ્ત છો તેવું માનવામાં આવશે." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "આજે રેકોર્ડો નથી" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "હમણાં જ શરૂ થયેલ છે" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "અહેવાલને સંગ્રહો – સમય શોધનાર" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML અહેવાલ" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "સમય શોધનાર" #~| msgid "Project Hamster Website" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "પ્રોજેક્ટ Hamster (Gnome સમય ટ્રેકર)" #~ msgid "_About" #~ msgstr "વિશે (_A)" #~ msgid "_Preferences" #~ msgstr "પસંદગીઓ (_P)" #~| msgid "_Stop Tracking" #~ msgid "Sto_p Tracking" #~ msgstr "શોધવાનું બંધ કરો (_p)" #~| msgid "Today" #~ msgid "To_day" #~ msgstr "આજે (_d)" #~| msgid "Add Earlier Activity" #~ msgid "_Add earlier activity" #~ msgstr "પહેલાની આવૃત્તિને ઉમેરો (_A)" #~| msgid "Starts and ends" #~ msgid "Starts and ends" #~ msgstr "શરૂ કરે છે અને અંત કરે છે" #~ msgid "Year:" #~ msgstr "વર્ષ:" #~| msgid "_Preferences" #~ msgid "Preferences" #~ msgstr "પસંદગીઓ" #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "બદલાયેલ પ્રવૃત્તિ" #~ msgid "Switched to '%s'" #~ msgstr "'%s' માં બદલેલ છે" #~ msgid "Working on %s" #~ msgstr "%s પર કામ કરી રહ્યા છીએ" hamster-3.0.3/po/he.po000066400000000000000000000635731452646177100145650ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Yair Hershkovitz , 2008. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: Hamster Applet\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-17 15:00+0200\n" "Last-Translator: Yaron Shahrabani \n" "Language-Team: Gezer \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" "X-Poedit-Language: Hebrew\n" "X-Poedit-Country: ISRAEL\n" "X-Poedit-SourceCharset: UTF-8\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "הוסף פעילות קודמת" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "אל" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "בתהליך" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "תיאור:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "זמן:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "פעילות:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "תויות:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stop tracking on idle" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stop tracking current activity when computer becomes idle" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "הפסק מעקב בכיבוי" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stop tracking current activity on shutdown" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Remind of current task every x minutes" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "להזכיר גם כאשר לא מוגדרת שום פעילות" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Also remind every notify_interval minutes if no activity has been started." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "At what time does the day start (defaults to 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Should workspace switch trigger activity switch" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Switch activity on workspace change" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Show / hide Time Tracker Window" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Keyboard shortcut for showing / hiding the Time Tracker window." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Toggle hamster application window action" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Command for toggling visibility of the hamster application window." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Toggle hamster application window" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Toggle visibility of the hamster application window." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "מעקב אחר הזמן" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "מיזם Hamster — מעקב אחר הזמן שלך" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "סקירת מעקב הזמן" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "חלון הסקירה של תכנית מעקב הזמן Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "הצגת סטטיסטיקה" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "קטגוריות" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "פעילויות" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "תויות" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "אין נתונים בפרק זמן זה" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "שמירת דיווח..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "יום" #: ../data/overview.ui.h:3 msgid "Week" msgstr "שבוע" #: ../data/overview.ui.h:4 msgid "Month" msgstr "חודש" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "סקירה — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_סקירה" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "פעילות" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_תצוגה" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "סך הכול" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "הסר" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "הוספת חדש" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "עריכה" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "העדפות מעקב זמן" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "הפסק מעקב כאשר המחשב לא בשימוש" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "הצגת תזכורת לפעילות הנוכחית כל:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "יום חדש מתחיל בשעה" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "יש להשתמש ברשימת המטלות שלהלן אם זמינה:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "שילוב" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "מעקב" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_קטגוריות" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "רשימת קטגוריות" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "הוסף קטגוריה" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "הסרת קטגוריה" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "עריכת קטגוריה" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_פעילויות" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "רשימת פעילות" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "הוסף פעילות" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "הסרת פעילות" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "עריכת פעילות" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "תגיות שאמורות להופיע בהשלמה האוטומטית" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "קטגוריות ותויות" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "המשך הפעילות האחרונה בעת חזרה למרחב העבודה" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "התחלת פעילות חדשה בעת מעבר בין מרחבי עבודה:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "מרחבי עבודה" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "יום:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "שבוע:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "חודש:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "טווח:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "החלה" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_מעקב" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "הוספת פעילות קודמת" #: ../data/today.ui.h:4 msgid "Overview" msgstr "סקירה" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "סטטיסטיקות" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "ע_ריכה" #: ../data/today.ui.h:7 msgid "_Help" msgstr "ע_זרה" #: ../data/today.ui.h:8 msgid "Contents" msgstr "תכנים" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "ה_פסקת המעקב" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "ה_חלפה" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "ה_תחלת מעקב" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "התחלת פעילות חדשה" #: ../data/today.ui.h:13 msgid "Today" msgstr "היום" #: ../data/today.ui.h:14 msgid "totals" msgstr "סיכומים" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "הצגת סקירה" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "אין פעילות" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "קטגוריה" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "תיאור" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "התחלה" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "סיום" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "משך" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "קטגוריות" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "מיזם Hamster - מעקב אחר הזמן שלך" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "כל הזכויות שמורות © 2007–2010 Toms Bauģis ואחרים" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "האתר של מיזם Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "על אודות Time Tracker" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "ירון שהרבני \n" "פרויקט תרגום GNOME לעברית:\n" "‏http://gnome-il.berlios.de" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "לא ממוין" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "עבודה" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "קורא חדשות" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "בודק מניות" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "פרוייקט סופר סודי S" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "שליטה עולמית" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "יום יומי" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "ארוחת צהריים" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "השקיית פרחים" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "עמידת ידיים" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "עדכון פעילות" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d שעות" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d דקות" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d שעות %d דקות" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "בוצע מעקב אחרי %s שעות סך הכול" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "ללא" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "שם" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "קטגוריה חדשה" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "פעילות חדשה" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "דקה אחת (%(interval_minutes)d)" msgstr[1] "%(interval_minutes)d דקות" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "לעולם לא" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "פעילות" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "זמן ההתחלה" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "זמן הסיום" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "משך בדקות" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "קטגוריה" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "תיאור" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "תגיות" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "דוח פעילות עבור %(start_d)s ב%(start_B)s %(start_Y)s – %(end_d)s ב%(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "דוח פעילות עבור %(start_d)s ב%(start_B)s – %(end_d)s ב%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "דוח פעילות עבור ה־%(start_d)s ב%(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "דוח פעילות עבור %(start_d)s – %(end_d)s ב%(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "ה־%d ב%b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "סך הכול לפי יום" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "יומן הפעילות" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "פעילויות" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "קטגוריות" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "הבדלה:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "תאריך" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "הצגת התבנית" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "ניתן לשכתב עליהן על ידי שמירת הגרסה שלך תחת %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "הכול" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "אין עדיין די נתונים ליצירת סטטיסטיקה.\n" "שבוע של שימוש לא יזיק!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "נאספים נתונים — יש לבדוק שוב לאחר שעבר שבוע!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "הפעילות הראשונה הוקלטה ב־%s" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "שנה אחת" msgstr[1] "%(num)s שנים" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "הזמן שאחריו נערך מעקב עד כה הוא %(human_days)s ימי אדם (%(human_years)s) או " "%(working_days)s ימי עבודה (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "זמן העבודה הממושך ביותר קרה ב־%(date)s וארך שעה אחת." msgstr[1] "זמן העבודה הממושך ביותר קרה ב־%(date)s וארך %(hours)s שעות." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "ישנה רשומה אחת (%s)." msgstr[1] "ישנן %s רשומות." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster מעוניין להסיק כלפיכם מסקנות נוספות!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "בגלל ש־%s אחוזים מכלל המשימות מתחילים לפני 9 בבוקר אתם נראים כמו משכימי קום." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "בגלל ש־%s אחוזים מכלל המשימות מתחילים לאחר 11 בלילה אתם נראים כמו פרפרי לילה." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "בגלל ש־%s אחוזים מכלל המשימות קצרים מרבע שעה אתם נראים עסוקים כנמלה." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "אין רשומות מהיום" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s שעות" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "רק התחיל" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "שמירת דוח — מעקב אחרי הזמן" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "דוח HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ערכים מופרדים בטאבים (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "מעקב אחרי הזמן" #~ msgid "Show activities window" #~ msgstr "הצגת חלון פעילויות" #~ msgid "Show _Overview" #~ msgstr "הצג _סקירה" #~ msgid "Sto_p Tracking" #~ msgstr "ה_פסקת המעקב" #~ msgid "To_day" #~ msgstr "ה_יום" #~ msgid "_Add earlier activity" #~ msgstr "הו_ספת פעילות קודמת" #~ msgid "_About" #~ msgstr "על _אודות" #~ msgid "_Preferences" #~ msgstr "_העדפות" #~ msgid "Starts and ends" #~ msgstr "התחלה וסיום" #~ msgid "Year:" #~ msgstr "שנה:" #~ msgid "Preferences" #~ msgstr "העדפות" #~ msgid "Changed activity" #~ msgstr "פעילות שהשתנתה" #~ msgid "Switched to '%s'" #~ msgstr "הוחלף ל־'%s'" #~ msgid "Working on %s" #~ msgstr "עובד על %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "מעקב אחר הזמן עם Hamster. שימוש:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "מיזם Hamster (מעקב זמנים ל־GNOME)" #~ msgid "Total" #~ msgstr "סך הכול" #~ msgid "totals by activity" #~ msgstr "סך הכול לפי פעילות" #~ msgid "totals by category" #~ msgstr "סך הכול לפי קטגוריה" #~ msgid "Show:" #~ msgstr "הצגה:" #~ msgid "Tell me more" #~ msgstr "ספרו לי עוד" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "מיזם Hamster מעקב זמנים לשולחן העבודה" #~ msgid "Move activity up" #~ msgstr "הזז פעילות למעלה" #~ msgid "Ad_d Earlier Activity" #~ msgstr "הוסף פעילות _קודמת" #~ msgid "_Today" #~ msgstr "ה_יום" #~ msgid "Export data..." #~ msgstr "ייצוא הנתונים..." #~ msgid "General" #~ msgstr "כללי" hamster-3.0.3/po/hi.po000066400000000000000000000657241452646177100145710ustar00rootroot00000000000000# translation of hamster.master.hi.po to Hindi # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Rajesh Ranjan , 2008. # Rajesh Ranjan , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.hi\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2011-03-28 13:47+0530\n" "Last-Translator: Rajesh Ranjan\n" "Language-Team: Hindi \n" "Language: hi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "\n" "\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "पूर्ववर्ती गतिविधि जोड़ें" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "को" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "प्रगति पर है" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "वर्णनः" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "समय:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "गतिविधि:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "टैगः" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "निष्क्रिय होने पर ट्रैकिंग रोकें" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "कंप्यूटर निष्क्रिय होने पर मौजूदा गतिविधि की ट्रैकिंग रोकें" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "शटडाउन पर ट्रैकिंग रोकें" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "बंद करने पर मौजूदा गतिविधि की ट्रैकिंग रोकें" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "हर x मिनट में मौजूदा कार्य का स्मार" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "मौजूदा कार्य के बारे में हर निर्दिष्ट मिनट में याद दिलाएँ. 0 या 120 से अधिक पर सेट करें यदि " "आप अनुस्मारक को निष्क्रिय करना चाहते हैं." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "साथ ही याद दिलाएँ जब कोई गतिविधि सेट नहीं है" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "हर notify_interval पर साथ ही याद दिलाएँ यदि कोई गतिविधि आरंभ की गई है यदि कोई " "गतिविधि आरंभ की गई है." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "टाइम ट्रैकर विंडो दिखाने के लिए कुंजीपटल शॉर्टकट." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "टाइम ट्रैकर विंडो दिखाने के लिए कुंजीपटल शॉर्टकट." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "टाइम ट्रेकर" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "प्रोजेक्ट हैमस्टर — अपना समय ट्रैक करें" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "टाइम ट्रेकर" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "आंकड़े दिखाएँ" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "श्रेणियाँ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "क्रियाएँ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 #, fuzzy msgid "Tags" msgstr "टैग्स" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "इस अंतराल के लिए कोई आँकड़ा नहीं" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "दिन" #: ../data/overview.ui.h:3 msgid "Week" msgstr "सप्ताह" #: ../data/overview.ui.h:4 msgid "Month" msgstr "माह" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "सारांश - हैमस्टर" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "सारांश (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "गतिविधि" #: ../data/overview.ui.h:8 msgid "_View" msgstr "देखें (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "योग" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "हटाएँ" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "नया जोड़ें" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "संपादन" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "टाइम ट्रैकर वरीयताएँ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "ट्रैकिंग रोकें जब कंप्यूटर निष्क्रिय हो जाता है" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "मौजूदा क्रियाकलाप का याद दिलाएँ हर:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "एकीकरण" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "ट्रैंकिंग रोकें (_S)" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "श्रेणी (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "श्रेणी सूची" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "श्रेणी जोड़ें" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "श्रेणी हटाएँ" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "श्रेणी संपादित करें" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "क्रियाकलाप (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "गतिविधि सूची" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "गतिविधि जोड़ें" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "क्रियाकलाप हटाएँ" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "गतिविधि संपादित करें" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "श्रेणी (_C)" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "कार्यस्थान" #: ../data/range_pick.ui.h:1 #, fuzzy msgid "Day:" msgstr "दिन:" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "सप्ताह" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "माह:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "सीमा:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "लागू करें" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "ट्रैंकिंग रोकें (_S)" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "पूर्ववर्ती गतिविधि जोड़ें" #: ../data/today.ui.h:4 msgid "Overview" msgstr "सारांश" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "आंकड़े" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "संपादन (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "मदद (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "विषय सूची" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "ट्रैंकिंग रोकें (_S)" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "स्विच (_w)" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "ट्रैंकिंग रोकें (_S)" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "नई गतिविधि" #: ../data/today.ui.h:13 msgid "Today" msgstr "आज" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "योग" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "सारांश दिखाएँ (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "कोई गतिविधि नहीं" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "श्रेणी" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "वर्णन" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "प्रारंभ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "अंत" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "अवधि" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "कोटियां" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "प्रोजेक्ट हैमस्टर — अपना समय ट्रैक करें" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "कॉपीराइट © 2007–2009 Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "प्रोजेक्ट हैमस्टर वेबसाइट" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "टाइम ट्रैकर का परिचय" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "संगीता कुमारी (sangeeta09@gmail.com)" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "बिना छांटा" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "कार्यस्थल" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "समाचार पढ़ रहा है" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "स्टॉक जाँच रहा है" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "सुपर गुप्त प्रोजेक्ट X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "दुनिया को दिखाएँ" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "दिन-प्रति-दिन" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "लंच" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "जलीय फूल" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "हैंडस्टैंड कर रहा है" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "गतिविधि अद्यतन करें" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 #, fuzzy msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s के लिए " "सारांश" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s के लिए सारांश" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s के लिए सारांश" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "कुछ नहीं" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "नाम" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "नई श्रेणी" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "नई गतिविधि" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d मिनट" msgstr[1] "%(interval_minutes)d मिनट" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "कभी नहीं" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "गतिविधि" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "आरंभ समय" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "अंत समय" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "अवधि मिनट" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "श्रेणी" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "वर्णन" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 #, fuzzy msgid "tags" msgstr "योग" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s के लिए " "सारांश" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s के लिए सारांश" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s के लिए सारांश" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s के लिए सारांश" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "योग" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "गतिविधि" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "क्रियाकलाप (_A)" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "कोटियां" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "तारीख़" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "सभी" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "सांख्यिकी निर्माण के लिए कोई आँकड़ा अब तक नहीं है.\n" "प्रयोग का एक सप्ताह बढ़िया होगा!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "अभी भी आँकड़ा जमा कर रहा है — फिर जाँचें एक सप्ताह बीतने के बाद!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "पहली गतिविधि %s पर रिकार्ड की गई थी." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s साल" msgstr[1] "%(num)s साल" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "अब तक ट्रैक किया गया %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s) समय." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "सबसे लंबा निरंतर कार्य %(date)s को हुआ था और %(hours)s घंटा का." msgstr[1] "सबसे लंबा निरंतर कार्य %(date)s को हुआ था और %(hours)s घंटे का." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s रिकार्ड हैं." msgstr[1] "%s रिकार्ड हैं." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "हैमस्टर कुछ और निरीक्षण करेगा!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "सभी तथ्य का %s प्रतिशत 9am से पहले आरंभ होगा तो आप जल्द आए हुए माने जाएँगे." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "सभी तथ्य का %s प्रतिशत 11pm से पहले आरंभ होगा तो आप निशाचर माने जाएँगे." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "सभी कार्यों का %s प्रतिशत 15 मिनट से कम होता है तो आप बहुत व्यस्त हैं." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "कोई रिकार्ड आज नहीं" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "रिपोर्ट सहेजें – टाइम ट्रैकर" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "एचटीएमएल रिपोर्ट" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "टैब से अलग किए मान (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "एक्सएमएल" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "टाइम ट्रेकर" #, fuzzy #~| msgid "Project Hamster Website" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "प्रोजेक्ट हैमस्टर वेबसाइट" #~ msgid "_About" #~ msgstr "के बारे में (_A)" #~ msgid "_Preferences" #~ msgstr "वरीयताएं (_P)" #, fuzzy #~| msgid "_Stop Tracking" #~ msgid "Sto_p Tracking" #~ msgstr "ट्रैंकिंग रोकें (_S)" #, fuzzy #~| msgid "Today" #~ msgid "To_day" #~ msgstr "आज" #, fuzzy #~| msgid "Add Earlier Activity" #~ msgid "_Add earlier activity" #~ msgstr "पूर्ववर्ती गतिविधि जोड़ें" #, fuzzy #~| msgid "Starts and ends" #~ msgid "Starts and ends" #~ msgstr "आरंभ और अंत" #~ msgid "Year:" #~ msgstr "वर्षः" #, fuzzy #~| msgid "_Preferences" #~ msgid "Preferences" #~ msgstr "वरीयताएं" #, fuzzy #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "गतिविधि जोड़ें" #~ msgid "Working on %s" #~ msgstr "%s पर काम कर रहा है" hamster-3.0.3/po/hr.po000066400000000000000000000611661452646177100145760ustar00rootroot00000000000000# Croatian translation of hamster-time-tracker # Copyright (C) 2008 Project Hamster Team # This file is distributed under the same license as the hamster-time-tracker package. # Milo Ivir , 2020. msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2023-03-27 16:44+0200\n" "Last-Translator: Milo Ivir \n" "Language-Team: \n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n" "X-Project-Style: gnome\n" "X-Generator: Poedit 3.0\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Dodaj raniju aktivnost" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "do" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "u tijeku" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Opis:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Vrijeme:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivnost:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Oznake:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Prekini praćenje kad nema aktivnosti" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Prekini praćenje trenutačne aktivnosti kad računalo ništa ne radi" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Prekini praćenje kad se računalo isključa" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Prekini praćenje trenutačne aktivnosti kad se računalo isključa" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Podsjeti o trenutačnom zadatku svakih x minuta" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Podsjeti o trenutačnom zadatku nakon određenog intervala u minutama. Postavi " "na 0 ili na više od 120 minuta za isključivanje podsjetnika." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Takođe me i podseti kada nema aktivnosti" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Ukoliko ni jedna aktivnost nije započeta podseti me nakon određenog boja " "minuta, koje određuje ključ notify_interval." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Kada počinje novi dan (podrazumevano je 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktivnosti se smatraju jučerašnjim ukoliko je trenutno vreme u prošlosti u " "odnosu na dan početka; današnjim ako je preko tog vremena. Ukoliko aktivnost " "obuhvata dva dana, ona će preći u onaj dan kada je izvršen veći deo te " "aktivnosti." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Treba li mijenjanje radnog prostora pokrenuti mijenjanje aktivnost" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Popis uključenih načina praćenja. „name“ (ime) će omogućiti mijenjanje " "aktivnosti po imenima koje su definirane u workspace_mapping. " "„memory“ (memorija) će omogućiti prebacivanje na zadnju aktivnosti pri " "povratku na prethodni radni prostor." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Promijeni aktivnost pri mijenjaju radnog prostora" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ako je mijenjanje po imenu uključeno, ovaj popis postavlja imena aktivnosti " "na koje se treba prebaciti (radni prostori predstavljeni njihovim indeksima)." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Prikaži / sakrij prozor praćenja vremena" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Tipkovni prečac za prikazivanje / skrivanje prozora praćenja vremena." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Radnja za mijenjanje vidljivosti prozora programa Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Naredba za mijenjanje vidljivosti glavnog prozora programa Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Promijeni vidljivost prozora programa" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Promijeni vidljivost prozora programa Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 ../src/hamster/about.py:40 #: ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Praćenja vremena" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster – prati svoje vreme" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Pregled praćenja vremena" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Prozor pregleda programa Hamster za praćenje vremena" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Prikaži statistiku" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorije" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktivnosti" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Oznake" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nema podataka za ovaj interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Spremi izveštaj …" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dan" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Tjedan" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mjesec" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Pregled – Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Pregled" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivnost" #: ../data/overview.ui.h:8 msgid "_View" msgstr "P_rikaz" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Ukupno" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Ukloni" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Dodaj novo" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Uredi" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Postavke praćenja vremena" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Prekini praćenje kad računalo ništa ne radi" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Podsjeti o trenutačnoj aktivnosti svakih:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Novi dan počinje u" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Koristi sljedeći popis zadataka ako je dostupan:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integracija" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Praćenje" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorije" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Popis kategorija" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Dodaj kategoriju" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Ukloni kategoriju" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Uredi kategoriju" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktivnosti" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Popis aktivnosti" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Dodaj aktivnost" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Ukloni aktivnost" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Uredi aktivnost" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Oznake koje se pojavljuju u automatskom dovršavanju" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorije i oznake" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Nastavi zadnju aktivnost pri povratku u radni prostor" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Započni novu aktivnost pri mijenjanju radnih prostora:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Radni prostori" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dan:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Tjedan:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mjesec:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Raspon:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Primijeni" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Prać_enje" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Dodaj raniju aktivnost" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Pregled" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistike" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Uredi" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Pomoć" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Sadržaj" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Prekini _praćenje" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Pro_mijeni" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Po_kreni praćenje" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Pokreni novu aktivnost" #: ../data/today.ui.h:13 msgid "Today" msgstr "Danas" #: ../data/today.ui.h:14 msgid "totals" msgstr "ukupno" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Prikaži pregled" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Nema aktivnosti" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorija" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Opis" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Početak" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Kraj" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Trajanje" #: ../src/hamster-cli:308 msgid "Uncategorized" msgstr "Nekategorizirano" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekt Hamster – prati svoje vreme" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Autorska prava © 2007. – 2010. Toms Bauģis i ostali" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Web-stranica projekta Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "O programu Praćenje vremena" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Milo Ivir " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nerazvrstano" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Posao" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Čitanje vijesti" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Provjeravanje dionica" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Super tajni projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "World domination" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Iz dana u dan" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ručak" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Zalijevanje cvijeća" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Izvođenje stoja na rukama" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Aktualiziraj aktivnost" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d h" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d min" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d h %d min" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %m. %Y." #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s. %(start_m)s. %(start_Y)s. – %(end_d)s. %(end_m)s. %(end_Y)s." #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_m)s. – %(end_d)s. %(end_m)s. %(end_Y)s." #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. – %(end_d)s. %(start_m)s. %(end_Y)s." #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %m." #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Ukupno je praćeno %s h" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ništa" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Ime" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova kategorija" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova aktivnost" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuta" msgstr[1] "%(interval_minutes)d minute" msgstr[2] "%(interval_minutes)d minuta" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nikada" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivnost" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "vrijeme početka" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "vrijeme kraja" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "trajanje u minutima" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorija" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "opis" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "oznake" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Izvještaj o aktivnostima za %(start_d)s. %(start_m)s. %(start_Y)s. – " "%(end_d)s. %(end_m)s. %(end_Y)s." #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Izvještaj o aktivnostima za %(start_d)s. %(start_m)s. – %(end_d)s. " "%(end_m)s. %(end_Y)s." #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Izvještaj o aktivnostima za %(start_d)s. %(start_m)s. %(start_Y)s." #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Izvještaj o aktivnostima za %(start_d)s – %(end_d)s. %(start_m)s. %(end_Y)s." #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d. %m. %Y." #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Ukupno po danima" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Dnevnik aktivnosti" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktivnosti" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorije" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Razlikuj:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Prikaži predložak" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Možeš ga promijeniti spremanjem tvoje verzije u mapu %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Sve" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Još nema podataka za generiranje statistike.\n" "Tjedan dana korištenja bi pomoglo!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Prikupljanje podataka – pogledaj ponovo za tjedan dana!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d. %m. %Y." #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %m." #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Prva aktivnost je zabilježena %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s godina" msgstr[1] "%(num)s godine" msgstr[2] "%(num)s godina" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Do sada praćeno vrijeme iznosi %(human_days)s dana (%(human_years)s) ili " "%(working_days)s radnih dana (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d. %m. %Y." #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sat." msgstr[1] "" "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sata." msgstr[2] "" "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sati." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Postoji %s zapis." msgstr[1] "Postoje %s zapisa." msgstr[2] "Postoji %s zapisa." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster bi te želio još malo više nadgledati!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Sa %s posto svih aktivnosti započete prije 9 sati prijepodne, izgleda da si " "ranoranilac." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Sa %s posto svih aktivnosti započete nakon 11 sati navečer, izgleda da si " "noćna ptica." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Sa %s posto svih aktivnosti kraće od 15 minuta, izgleda da si zaposlena " "pčelica." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Danas nema zapisa" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s h" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Upravo pokrenuto" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Spremi izveštaj – Praćenje vremena" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML izveštaj" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabulatorom odvojene vrijednosti (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Praćenje vremena" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Prikažite prozor aktivnosti" #~ msgid "Sto_p Tracking" #~ msgstr "Zaustavi _praćenje" #~ msgid "To_day" #~ msgstr "_Danas" #~ msgid "_Add earlier activity" #~ msgstr "Dod_aj raniju aktivnost" #~ msgid "Show _Overview" #~ msgstr "Prikaži _pregled" #~ msgid "_Preferences" #~ msgstr "_Postavke" #~ msgid "_About" #~ msgstr "_O programu" #~ msgid "Year:" #~ msgstr "Godina:" #~ msgid "Starts and ends" #~ msgstr "Početak i kraj" #~ msgid "Preferences" #~ msgstr "Postavke" #~ msgid "Changed activity" #~ msgstr "Izmenjena aktivnost" #~ msgid "Switched to '%s'" #~ msgstr "Prebačena u „%s“" #~ msgid "Working on %s" #~ msgstr "Radim na %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Vredni hrčak praćenje vremena. Korišćenje:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Vredni hrčak (Praćenje vremena za Gnom)" #~ msgid "totals by activity" #~ msgstr "ukupno po aktivnostima" #~ msgid "totals by category" #~ msgstr "ukupno po kategorijama" #~ msgid "Show:" #~ msgstr "Prikaži:" hamster-3.0.3/po/hu.po000066400000000000000000000624231452646177100145760ustar00rootroot00000000000000# Hungarian translation of hamster-time-tracker # Copyright (C) 2008, 2009, 2010, 2011 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # # Gabor Kelemen , 2008, 2009, 2010, 2011, 2012. # Avramucz Péter , 2009. # Attila Hammer , 2010. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-02-29 03:44+0100\n" "Last-Translator: Gabor Kelemen \n" "Language-Team: Magyar \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.0\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Korábbi tevékenység hozzáadása" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "eddig:" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "folyamatban" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Leírás:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Idő:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Tevékenység:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Címkék:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Nyilvántartás befejezése üresjáratban" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Az aktuális tevékenység nyilvántartásának befejezése a számítógép " "üresjáratában" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Nyilvántartás befejezése leállításkor" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Az aktuális tevékenység nyilvántartásának befejezése leállításkor" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Emlékeztető az aktuális feladatra ennyi percenként" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Emlékeztessen az adott feladatra a megadott percenként. Az emlékeztető " "letiltásához állítsa 0-ra vagy 120-nál nagyobb értékűre." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Emlékeztessen akkor is, ha nincs beállítva tevékenység" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Emlékeztessen notify_interval percenként akkor is, ha nincs elkezdve " "tevékenység." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Mikor kezdődik a nap (az alapértelmezett érték DE 5.30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "A tevékenységek a tegnapi naphoz lesznek elszámolva, ha az aktuális idő " "kisebb a megadott napkezdő időnél, ellenkező esetben a maihoz. A két napra " "nyúló tevékenységek arra a napra fognak kerülni, amelyre a nagyobb részük " "esik." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "A munkaterület-váltás együtt jár-e tevékenységváltással" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Az elérhető nyilvántartási módok listája. A „name” (név) engedélyezi a " "tevékenységek közötti név szerinti váltást a workspace_mapping kulcsban " "megadott módon. A „memory” (memória) engedélyezi az utolsó tevékenységre " "váltást, amikor visszatér az előző munkaterületre." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Tevékenységváltás munkaterület-váltáskor" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ha a váltás név szerint lehetőség engedélyezve van, ez a lista beállítja " "azon tevékenységneveket, amelyekre váltani kell. A munkaterületeket az " "elemek indexe jelzi." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Időnyilvántartó ablakának megjelenítése/elrejtése." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Gyorsbillentyű az Időnyilvántartó ablakának megjelenítéséhez/elrejtéséhez." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "A Hamster alkalmazás ablakának átváltása művelet" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "A Hamster alkalmazásablak láthatóságának átváltására szolgáló parancs." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "A Hamster alkalmazás ablakának átváltása" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "A Hamster alkalmazás ablakának láthatóságának átváltása." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Időnyilvántartó" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster projekt – időnyilvántartó" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Időnyilvántartás áttekintése" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "A Hamster időnyilvántartó áttekintés ablaka" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Statisztikák megjelenítése" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategóriák" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Tevékenységek" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Címkék" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nincsenek adatok ebben az időszakban" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Jelentés mentése…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Nap" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Hét" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Hónap" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Áttekintés – Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "Á_ttekintés" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Tevékenység" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Nézet" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Összesítés" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Eltávolítás" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Új hozzáadása" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Szerkesztés" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Időnyilvántartó tulajdonságai" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Nyilvántartás befejezése a számítógép üresjáratában" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Emlékeztessen az aktuális tevékenységre minden:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Az új nap ekkor kezdődik" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "A következő teendőlista használata, ha elérhető:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integráció" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Nyilvántartás" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategóriák" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategórialista" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Új kategória" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Kategória eltávolítása" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Kategória szerkesztése" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Tevékenységek" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Tevékenységlista" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Tevékenység hozzáadása" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Tevékenység eltávolítása" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Tevékenység szerkesztése" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Az automatikus kiegészítésben megjelenítendő címkék" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategóriák és címkék" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Az utolsó tevékenység folytatása a munkaterületre visszatéréskor" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Új tevékenység megkezdése a munkaterületek közötti váltáskor:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Munkaterületek" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Nap:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Hét:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Hónap:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Időszak:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Alkalmaz" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Nyilvántartás" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Korábbi tevékenység hozzáadása" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Áttekintés" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statisztikák" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "S_zerkesztés" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Súgó" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Tartalom" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Nyilvántartás _befejezése" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Váltás" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Nyilvántartás _megkezdése" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Új tevékenység" #: ../data/today.ui.h:13 msgid "Today" msgstr "Ma" #: ../data/today.ui.h:14 msgid "totals" msgstr "összesítés" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Áttekintés megjelenítése" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Nincs tevékenység" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategória" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Leírás" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Kezdés" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Befejezés" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Időtartam" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategóriák" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster projekt – időnyilvántartó" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis és mások" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "A Hamster projekt weboldala" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Az Időnyilvántartó névjegye" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" " Avramucz Péter Hammer Attila Kelemen Gábor " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Rendezetlen" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Munka" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Hírek olvasása" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Árfolyamok ellenőrzése" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "A szupertitkos X projekt" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Világuralom" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Mindennapi" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ebéd" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Virágok meglocsolása" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Kézenállás" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Tevékenység frissítése" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dó" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dp" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dó %dp" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y. %B %e." #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_Y)s. %(start_B)s %(start_d)s. – %(end_Y)s. %(end_B)s %(end_d)s." #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s. – %(end_B)s %(end_d)s. %(end_Y)s." #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s. – %(end_d)s. %(end_Y)s." #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %e." #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Az összesen nyilvántartott órák száma: %s" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nincs" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Név" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Új kategória" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Új tevékenység" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d perc" msgstr[1] "%(interval_minutes)d perc" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Soha" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "tevékenység" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "kezdési idő" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "befejezési idő" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "időtartam percekben" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategória" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "leírás" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "címkék" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Tevékenységjelentés: %(start_Y)s. %(start_B)s %(start_d)s. – %(end_Y)s. " "%(end_B)s %(end_d)s." #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Tevékenységjelentés: %(start_B)s %(start_d)s. – %(end_Y)s. %(end_B)s " "%(end_d)s." #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Tevékenységjelentés: %(start_Y)s. %(start_B)s %(start_d)s." #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Tevékenységjelentés: %(start_B)s %(start_d)s. – %(end_Y)s. %(end_d)s." #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%Y. %b %e." #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Napi összesítés" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Tevékenységnapló" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "tevékenységek" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategóriák" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Megkülönböztetés:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Dátum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Sablon megjelenítése" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Ezt felülbírálhatja saját verziójának %(home_folder)s alá mentésével" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Összes" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Még nincs elegendő adat a statisztikák előállításához.\n" "Legalább egy heti használat kellene." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Még folyik az adatgyűjtés – egy hét múlva nézze meg újra!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y. %b %e." #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %e" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Az első tevékenység ekkor lett rögzítve: %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s év" msgstr[1] "%(num)s év" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Eddig rögzített idő: %(human_days)s emberi nap (%(human_years)s) vagy " "%(working_days)s munkanap (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y. %b %e." #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "A leghosszabb folyamatos munka ekkor történt: %(date)s és %(hours)s órán át " "tartott." msgstr[1] "" "A leghosszabb folyamatos munka ekkor történt: %(date)s és %(hours)s órán át " "tartott." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s rekord van." msgstr[1] "%s rekord van." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "A Hamster szeretné Önt jobban megismerni." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Mivel az összes tevékenységeinek %s százaléka reggel 9 óra előtt kezdődik, " "ezért Ön valószínűleg koránkelő." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Mivel az összes tevékenységeinek %s százaléka este 11 óra után kezdődik, " "ezért Ön valószínűleg egy éjjeli bagoly." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Mivel az összes tevékenységeinek %s százaléka 15 percnél rövidebb, ezért Ön " "valószínűleg hangyaszorgalmú." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Ma nincsenek bejegyzések" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%só" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Épp megkezdődött" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Jelentés mentése – Időnyilvántartó" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML jelentés" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-bal elválasztott értékek (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Időnyilvántartás" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Tevékenységek ablak megjelenítése" #~ msgid "Sto_p Tracking" #~ msgstr "Nyilvántartás _befejezése" #~ msgid "To_day" #~ msgstr "_Ma" #~ msgid "_Add earlier activity" #~ msgstr "K_orábbi tevékenység hozzáadása" #~ msgid "Show _Overview" #~ msgstr "Áttekintés m_egjelenítése" #~ msgid "_Preferences" #~ msgstr "_Beállítások" #~ msgid "_About" #~ msgstr "_Névjegy" #~ msgid "Year:" #~ msgstr "Év:" #~ msgid "Starts and ends" #~ msgstr "Kezdet és vég" #~ msgid "Preferences" #~ msgstr "Beállítások" #~ msgid "Changed activity" #~ msgstr "Tevékenységváltás" #~ msgid "Switched to '%s'" #~ msgstr "Átváltott a következőre: „%s”" #~ msgid "Working on %s" #~ msgstr "Ezen dolgozik: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster időnyilvántartó. Használat:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Hamster időnyilvántartó" hamster-3.0.3/po/id.po000066400000000000000000000573611452646177100145630ustar00rootroot00000000000000# Translation of hamster-time-tracker to Bahasa Indonesia # Copyright (C) 2011 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Dirgita , 2011. # Andika Triwidada , 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-05-15 03:45+0700\n" "Last-Translator: Andika Triwidada \n" "Language-Team: GNOME Indonesian Translation Team \n" "Language: id\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: Lokalize 1.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Tambah Aktivitas yang Lebih Dini" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "hingga" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "sedang dikerjakan" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Deskripsi:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Waktu:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivitas:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Tag:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Berhenti melacak saat menganggur" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Berhenti melacak aktivitas ketika komputer menganggur" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Berhenti melacak saat diamtikan" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Berhenti melacak aktivitas ketika komputer dimatikan" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Mengingatkan tugas yang berlangsung setiap x menit." #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Ingatkan tugas saat ini setiap sekian menit yang dinyatakan. Tata ke 0 atau " "lebih dari 120 untuk mematikan pengingat." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Juga ingatkan bila tak ada aktivitas yang ditata" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Juga ingatkan setiap notify_interval menit bila tak ada aktivitas yang telah " "dimulai." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Pukul berapa hari dimulai (bawaan adalah 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktivitas akan dihitung milik kemarin bila waktu kini kurang dari awal hari " "yang dinyatakan; dan hari ini, bila lewat dari waktu itu. Aktivitas yang " "mencakup dua hari, akan jatuh ke sisi bagian terbesar aktivitas." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Mestikah bertukar ruang kerja memicu pertukaran aktivitas" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Daftar metoda pelacakan yang difungsikan. \"name\" akan mengaktifkan " "pertukaran aktivitas berdasarkan nama yang didefinisikan dalam " "workspace_mapping. \"memory\" akan mengaktifkan pertukaran ke aktivitas " "terakhir ketika kembali ke ruang kerja sebelumnya." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Tukar aktivitas pada perubahan ruang kerja" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Bila pertukaran berdasarkan nama diaktifkan, daftar ini menata nama " "aktivitas yang mesti dituju, ruang kerja diwakili oleh index butir." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Menampilkan/menyembunyikan Jendela Pelacak Waktu" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Tombol kombinasi pintasan untuk menampilkan/menyembunyikan jendela Pelacak " "Waktu." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Jungkitkan aksi jendela aplikasi hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Perintah untuk menjungkit kenampakan jendela aplikasi hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Jungkitkan jendela aplikasi hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Jungkitkan kenampakan jendela aplikasi hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Pelacak Waktu" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Proyek Hamster - melacak waktu kegiatan Anda" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Ringkasan Pelacakan Waktu" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Jendela ringkasan pelacak waktu hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Tampilkan Statistik" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategori" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktivitas" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Tag" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Tidak ada data untuk interval ini" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Simpan laporan..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Hari" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Minggu" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Bulan" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Ikhtisar — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Ikhtisar" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivitas" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Tampilan" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Total" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Hapus" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Tambah baru" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Sunting" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferensi Pelacak Waktu" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Berhenti melacak ketika komputer menganggur" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Ingatkan aktivitas terkini setiap:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Permulaan hari pada" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Gunakan daftar tugas berikut bila tersedia:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrasi" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Pelacakan" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategori" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Daftar kategori" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Tambah kategori" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Hapus kategori" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Sunting kategori" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktivitas" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Daftar aktivitas" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Tambah aktivitas" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Hapus aktivitas" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Sunting aktivitas" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Tag yang seharusnya muncul untuk otokomplesi" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategori dan Tag" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Lanjutkan aktivitas terakhir saat kembali ke area kerja" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Mulai aktivitas baru saat berpindah area kerja:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Area Kerja" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Hari:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Minggu:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Bulan:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Jangkauan:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Terapkan" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Pelacakan" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Tambah aktivitas lebih dini" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Ikhtisar" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistik" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Sunting" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Ba_ntuan" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Isi" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Berhenti melacak" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Tukar" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Mulai Melacak" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Mulai aktivitas baru" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hari ini" #: ../data/today.ui.h:14 msgid "totals" msgstr "total" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Tampilkan Ringkasan" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Tidak ada aktivitas" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategori" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Deskripsi" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Awal" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Akhir" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durasi" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategori" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Proyek Hamster — melacak waktu Anda" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Hak cipta © 2007–2010 Toms Bauģis dan lainnya" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Situs Web Proyek Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Tentang Pelacak Waktu" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Dirgita , 2011." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Tak terurut" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Bekerja" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Membaca berita" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Memeriksa persediaan" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Proyek sangat rahasia" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Mengambil alih dunia" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Hari-ke-hari" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Makan siang" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Menyiram bunga" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Berdiri dengan tangan" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Mutakhirkan aktivitas" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "total terlacak %s jam" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nihil" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nama" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Kategori baru" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Aktivitas baru" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d menit" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Tak pernah" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivitas" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "waktu awal" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "waktu akhir" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "menit durasi" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategori" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "deskripsi" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "tag" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Laporan aktivitas untuk %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Laporan aktivitas untuk %(start_d)s %(start_B)s – %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Laporan aktivitas untuk %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Laporan aktivitas untuk %(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Total menurut Hari" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Log Aktivitas" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktivitas" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategori" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Bedakan:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Tanggal" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Tampilkan templat" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Anda dapat menimpanya dengan menyimpan versi Anda di %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Semua" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Belum ada data untuk membuat statistik.\n" "Pakailah dulu selama satu minggu!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Mengumpulkan data — periksalah kembali setelah satu minggu!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Aktivitas pertama direkam pada %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s tahun" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Waktu yang terlacak sejauh ini adalah %(human_days)s orang hari " "(%(human_years)s) atau %(working_days)s hari kerja (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Pekerjaan terus-menerus terpanjang terjadi pada %(date)s selama %(hours)s " "jam." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Terdapat %s catatan/" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ingin mengamati Anda lebih jauh!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Dengan %s persen dari semua aktivitas dimulai sebelum pukul 9 pagi, Anda " "nampaknya rajin bangun pagi." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Dengan %s persen dari semua aktivitas dimulai setelah pukul 11 malam, Anda " "nampaknya tukang begadang." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Dengan %s persen dari semua aktivitas kurang dari 15 menit, Anda nampaknya " "orang sangat sibuk." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Tidak ada catatan hari ini" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Baru dimulai" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Simpan Laporan — Pelacak Waktu" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Laporan HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Pelacakan waktu" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Tampilkan jendela aktivitas" #~ msgid "Sto_p Tracking" #~ msgstr "_Berhenti Melacak" #~ msgid "To_day" #~ msgstr "_Hari Ini" #~ msgid "_Add earlier activity" #~ msgstr "T_ambah aktivitas yang lebih dini" #~ msgid "Show _Overview" #~ msgstr "Tampilkan _Ikhtisar" #~ msgid "_Preferences" #~ msgstr "_Preferensi" #~ msgid "_About" #~ msgstr "Tent_ang" #~ msgid "Year:" #~ msgstr "Tahun:" #~ msgid "Starts and ends" #~ msgstr "Awal dan akhir" #~ msgid "Preferences" #~ msgstr "Preferensi" #~ msgid "Changed activity" #~ msgstr "Aktivitas yang diubah" #~ msgid "Switched to '%s'" #~ msgstr "Berpindah ke '%s'" #~ msgid "Working on %s" #~ msgstr "Bekerja pada %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster pelacak waktu. Cara pakai:" hamster-3.0.3/po/it.po000066400000000000000000000647761452646177100146130ustar00rootroot00000000000000# Italian translations for hamster-time-tracker package. # Copyright (C) 2008, 2009, 2010, 2011, 2012 hamster-time-tracker copyright holder # This file is distributed under the same license as the hamster-time-tracker package. # # earlier activity -> attività precedente # si riferisce all'aggiunta di attività svolte precedentemente rispetto # la data 'odierna' # # Milo Casagrande , 2008, 2009, 2010, 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: project-hamster\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-02 17:15+0100\n" "Last-Translator: Milo Casagrande \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8-bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" # (ndt) titolo finestra #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Aggiungi attività precedente" # (ndt) separa l'orario iniziale da quello finale #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "fino alle" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "in corso" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descrizione:" # (ndt) si vede la data e l'orario... #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Data:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Attività:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etichette:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Ferma il conteggio quando inattivo" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Ferma il conteggio dell'attività corrente quando il computer diventa inattivo" # (ndt) visto che è doppia, sia chiave schema che opzione # preferisco darle lo stile per l'opzione #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Fermare il conteggio all'arresto del sistema" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Ferma il conteggio dell'attività corrente all'arresto del sistema" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Ricorda l'attività corrente ogni X minuti" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Ricorda l'attività corrente in base ai minuti specificati. Impostare a 0 o " "maggiore di 120 per disabilitare la notifica." # (ndt) opzione #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Ricordare anche quando nessuna attività è impostata" # (ndt) non capisco se quello che indicano è un valore o un nome specifico di qualche cosa oppure solo un errore di digitazione... #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Ricorda anche ogni notify_interval se non è stata avviata alcuna attività." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Orario di inizio della giornata (predefinito alle 5.30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Le attività verranno considerate: come del giorno precedente se l'ora " "corrente è minore di quella specificata come inizio della giornata, come del " "giorno attuale se supera tale ora. Le attività che si estendono su due " "giorni verranno visualizzate dove si è svolta la maggior parte dell'attività." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Indica se il cambio di spazio di lavoro debba cambiare attività" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Elenco di metodi di conteggio abilitati: \"name\" abilita il cambio di " "attività per nome, come definito in workspace_mapping; \"memory\" abilita il " "passaggio all'ultima attività quando si ritorna in uno spazio di lavoro " "precedente." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Cambia attività al cambio dello spazio di lavoro" # (ndt) l'originale fa schifo. suggerimenti sono i benvenuti... #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Indica se il cambio per nome è abilitato, questo elenco imposta i nomi delle " "attività a cui passare, gli spazi di lavoro sono rappresentati dall'indice " "dell'elemento." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostra/Nasconde la finestra dell'applicazione" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Scorciatoia per mostrare/nascondere la finestra di Conteggio tempo." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Abilita/Disabilita l'azione sulla finestra dell'applicazione" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Comando per mostrare/nascondere la finestra dell'applicazione." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Mostra/Nasconde la finestra dell'applicazione" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Mostra/Nasconde la finestra dell'applicazione." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Conteggio tempo" # (ndt) sarebbe l'unica applet ad avere il suo nome nella descrizione quando viene selezionata. Lunga, molto molto libera, ma che palle... #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Tiene traccia del tempo trascorso nello svolgere delle attività" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Riepilogo conteggio tempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "La finestra di riepilogo di Conteggio tempo" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostra statistiche" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorie" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Attività" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etichette" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nessun dato per questo intervallo" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Salva rapporto..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Giorno" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Settimana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mese" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Riepilogo — Hamster" # (ndt) pulsante #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Riepilogo" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Attività" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Visualizza" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totali" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Rimuovi" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Aggiungi nuova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Modifica" # (ndt) titolo finestra #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferenze di «Conteggio tempo»" # (ndt) opzione #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Fermare il conteggio quando il computer è inattivo" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Ricordare l'attività corrente ogni:" # (ndt) si vede tipo: La giornata inizia alle 5.30 #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "La giornata inizia alle" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Usare le seguenti to-do se disponibili:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrazione" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Conteggio" # (ndt) questo compare assieme a Nuova attività/categoria #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "Categori_e" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Elenco categorie" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Aggiungi categoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Rimuovi categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Modifica categoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Attività" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Elenco attività" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Aggiungi attività" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Rimuovi attività" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Modifica attività" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etichette per il completamento automatico" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorie ed etichette" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Riprendere l'ultima attività quando si torna a uno spazio di lavoro" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Avviare una nuova attività quando si cambia spazio di lavoro:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Spazi di lavoro" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Giorno:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Settimana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mese:" # (ndt) si vede in un menù a discesa, le altre sono tutte solo corto #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervallo:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Applica" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Conteggio" # (ndt) titolo finestra #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Aggiungi attività precedente" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Riepilogo" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistiche" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Modifica" #: ../data/today.ui.h:7 msgid "_Help" msgstr "A_iuto" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Sommario" # (ndt) pulsante # o un più semplice 'Ferma'? #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Arre_sta conteggio" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Ca_mbia" # (ndt) pulsante #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "A_vvia conteggio" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Nuova attività" #: ../data/today.ui.h:13 msgid "Today" msgstr "Oggi" #: ../data/today.ui.h:14 msgid "totals" msgstr "totali" # (ndt) pulsante #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostra riepilogo" # (ndt) questo compare nel pannello dove viene inserita # l'applet quando non sta tenendo conto delle nostre attività #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Nessuna attività" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descrizione" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Inizio" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Fine" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durata" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorie" # (ndt) sarebbe l'unica applet ad avere il suo nome nella descrizione quando viene selezionata. Lunga, molto molto libera, ma che palle... #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Tiene traccia del tempo trascorso nello svolgere delle attività" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis e altri" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Pagina web di «Poject Hamster»" # (ndt) titolo dialogo #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Informazioni su «Conteggio tempo»" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Milo Casagrande \n" "Stefano Pedretti " # (ndt) questo dovrebbe essere quello che si vede # nel riepilogo delle categorie, quando non è stata # associata una categoria a un'attività #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Non categorizzato" # (ndt) quelle che seguono sono delle attività #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Lavoro" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Lettura notizie" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Controllo azioni" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Progetto super segreto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Conquista del mondo" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Giorno per giorno" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Pranzo" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Annaffiare le piante" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Piegamenti sulle braccia" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Aggiorna attività" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%-d %B %Y" # (ndt) non mi piace molto come soluzione... # # nel dizionario non c'è la 'e' per il giorno del mese # senza lo zero iniziale # aprirò un bug... uff... #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A %-d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ore conteggiate in totale" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nessuna" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nome" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nuova categoria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nuova attività" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minuti" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Mai" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "attività" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "inizio" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "fine" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "minuti" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descrizione" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etichette" # (ndt) non mi piace molto come soluzione... # # nel dizionario non c'è la 'e' per il giorno del mese # senza lo zero iniziale #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Registro attività per %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Registro attività per %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Registro attività per %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Registro attività per %(start_d)s - %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%-d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totali per giorno" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Registro attività" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "attività" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorie" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinguere:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostra modello" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "È possibile sovrascriverlo salvando la propria versione in %(home_folder)s" # (ndt) indica gli anni... #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Tutti" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Non ci sono ancora dati per generare le statistiche.\n" "È utile usare il programma per una settimana." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Raccolta dati in corso — Controllare tra una settimana." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%-d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%-d %b" # (ndt) per evitare il problema del 'il 8 agosto' #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "La prima attività è stata registrata il giorno %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s anno" msgstr[1] "%(num)s anni" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Il tempo registrato finora è di %(human_days)s giorni uomo (%(human_years)s) " "o %(working_days)s giorni lavorativi (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%-d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Il lavoro continuativo più lungo è stato registrato il giorno %(date)s ed " "era di %(hours)s ora." msgstr[1] "" "Il lavoro continuativo più lungo è stato registrato il giorno %(date)s ed " "era di %(hours)s ore." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "C'è %s record" msgstr[1] "Ci sono %s record." # (ndt) odio le frasi originali fatte così... #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "È utile registrare altre attività." # (ndt) spero che il %% funzioni #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Con il %s%% di tutte le attività che iniziano prima delle 9 potete " "considerarvi dei veri mattinieri." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Con il %s%% di tutte le attività che iniziano dopo le 23 potete considerarvi " "dei veri nottambuli." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Con il %s%% di tutte le attività dalla durata di meno di 15 minuti potete " "considerarvi delle persone energiche." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Niente da visualizzare per oggi" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Appena iniziato" # (ndt) titolo dialogo #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Salva rapporto — Conteggio tempo" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Rapporto HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valori separati da tabulazioni (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Conteggio tempo" #~ msgid "Show activities window" #~ msgstr "Mostra la finestra delle attività" # (ndt) pulsante # o un più semplice 'Ferma'? #~ msgid "Sto_p Tracking" #~ msgstr "Arre_sta conteggio" #~ msgid "To_day" #~ msgstr "O_ggi" # (ndt) titolo finestra #~ msgid "_Add earlier activity" #~ msgstr "Aggiungi a_ttività precedente" # (ndt) pulsante #~ msgid "Show _Overview" #~ msgstr "_Mostra riepilogo" #~ msgid "_Preferences" #~ msgstr "Preferen_ze" #~ msgid "_About" #~ msgstr "I_nformazioni" #~ msgid "Year:" #~ msgstr "Anno:" #~ msgid "Starts and ends" #~ msgstr "Inizio e fine" #~ msgid "Preferences" #~ msgstr "Preferenze" #~ msgid "Changed activity" #~ msgstr "Attività modificata" #~ msgid "Switched to '%s'" #~ msgstr "Passati a «%s»" #~ msgid "Working on %s" #~ msgstr "Al lavoro su %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Uso di «Conteggio tempo»:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (Conteggio tempo)" hamster-3.0.3/po/ja.po000066400000000000000000000624551452646177100145610ustar00rootroot00000000000000# hamster-time-tracker ja.po. # Copyright (C) 2008-2012 hamster-time-tracker's COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Takeshi AIHANA , 2008. # Takayuki KUSANO , 2009-2011. # Nishio Futoshi , 2010. # Takayoshi OKANO , 2011. # Hideki Yamane , 2011. # Jiro Matsuzawa , 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-08-10 23:35+0900\n" "Last-Translator: Jiro Matsuzawa \n" "Language-Team: Japanese \n" "Language: ja\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "以前の活動を追加" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "〜" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "進行中..." #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "説明:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "時間:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "活動:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "タグ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "アイドル時に記録を停止する" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "コンピューターがアイドル状態になったら活動の記録を停止する" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "シャットダウン時は記録を停止する" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "シャットダウン時に記録を停止する" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "現在のタスクを x 分ごとに通知します" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "現在のタスクを、指定した時間(分)ごとに通知します。0または120を超える値に設定" "すると通知しません。" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "活動が設定されていない時にも通知する" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "活動が何も開始されていない場合にも、notify_interval 分毎に通知する。" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "一日の開始時間(デフォルトは午前5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "現在の時間が一日の開始時間より前の場合、活動は昨日の集計に計上され、時間を超" "えたものが今日に集計されます。2日にまたがる活動は、活動の最大部分がある側か" "ら、反転します。" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "ワークスペース切り替え時に動作を切り替えます" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "利用可能な記録手法のリストです。\"name\"は workspace_mapping で定義されている" "名前で活動を切り替え可能にします。\"memory\" は、前のワークスペースに戻るとき" "に、そこで最後の活動に変更します。" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "ワークスペースの変更時に動作を切り替えます。" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "名前で切り替え可能にする場合、このリストは切り替える活動の名前に設定し、ワー" "クスペースはアイテムのインデックスで再表示されます。" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "タイムトラッカーのウィンドウの表示/非表示" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "タイムトラッカーのウィンドウ表示・非表示を切り替えるキーボードショートカット" "です。" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "ハムスターアプリケーションウィンドウのアクションをOn/Offします。" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "ハムスターアプリケーションウィンドウの表示を切り替えるコマンド。" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "ハムスターアプリケーションウィンドウをOn/Offします。" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "ハムスターアプリケーションウィンドウの表示をOn/Offします。" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "タイムトラッカー" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "プロジェクト・ハムスター - 時間を記録" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "タイムトラッカーの概要" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "ハムスター・タイムトラッカーの概要ウィンドウ" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "統計の表示" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "カテゴリ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "活動" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "タグ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "この期間のデータはありません" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "レポートの保存..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "日間" #: ../data/overview.ui.h:3 msgid "Week" msgstr "週間" #: ../data/overview.ui.h:4 msgid "Month" msgstr "月間" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "概要 — ハムスター" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "概要(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "活動" #: ../data/overview.ui.h:8 msgid "_View" msgstr "表示(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "合計" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "削除" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "新規追加" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "編集" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "タイムトラッカーの設定" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "コンピューターがアイドル状態になったら記録を停止する" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "現在の活動を通知する間隔:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "一日の開始時間" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "可能であれば、以下のTODOリストを使用する:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "集計" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "記録" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "カテゴリ(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "カテゴリ一覧" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "新しいカテゴリを追加します" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "カテゴリを削除します" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "カテゴリを編集します" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "活動(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "活動一覧" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "活動を追加します" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "活動を削除します" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "活動を編集します" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "自動的に完了するものに表示すべきタグ" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "カテゴリとタグ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "ワークスペースに戻ると、そこでの直近の活動に戻す" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "ワークスペース切り替え時に開始する新規活動を指定:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "ワークスペース" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "日間:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "週間:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "月間:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "期間:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "適用" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "記録(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "以前の活動を追加" #: ../data/today.ui.h:4 msgid "Overview" msgstr "概要" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "統計" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "編集(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "ヘルプ(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "目次" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "記録の停止(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "切り替え(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "記録の開始(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "新しい活動の開始" #: ../data/today.ui.h:13 msgid "Today" msgstr "今日" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "合計" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "概要を表示(_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "活動なし" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "カテゴリ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "説明" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "開始" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "終了" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "経過時間" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "カテゴリ" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "プロジェクト・ハムスター - 時間を記録" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis とその他大勢の方々" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "プロジェクト・ハムスターのウェブサイト" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "このアプリケーションについて" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "相花 毅 \n" "草野 貴之 \n" "Nishio Futoshi \n" "やまねひでき \n" "日本GNOMEユーザー会 " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "未分類のもの" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "仕事" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "新聞を読む" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "株価をチェックする" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "超極秘プロジェクトX" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "世界征服" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "日課" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "昼食" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "花に水をやる" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "逆立ちをする" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "活動の更新" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d時間" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d分間" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d時間 %d分" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y年%m月%d日" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_Y)s年%(start_B)s%(start_d)s日〜%(end_Y)s年%(end_B)s%(end_d)s日の集計" "結果" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(end_Y)s年%(start_B)s%(start_d)s日〜%(end_B)s%(end_d)s日" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(end_Y)s年%(start_B)s%(start_d)s日〜%(end_d)s日" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%m月%d日 (%a)" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s 時間分を記録しました" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "何もしない" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "名前" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "新しいカテゴリ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "新しい活動" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d 分" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "しない" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "活動" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "開始時間" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "終了時間" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "要した時間(分)" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "カテゴリ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "説明" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "タグ" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_Y)s年%(start_B)s%(start_d)s日〜%(end_Y)s年%(end_B)s%(end_d)s日の活動" "レポート" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(end_Y)s年%(start_B)s%(start_d)s日〜%(end_B)s%(end_d)s日の活動レポート" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_Y)s年%(start_B)s%(start_d)s日の活動レポート" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(end_Y)s年%(start_B)s%(start_d)s日〜%(end_d)s日の活動レポート" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%Y年%m月%d日 " #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "一日の集計" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "活動記録" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "活動" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "カテゴリ" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "区分:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "日付" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "テンプレート表示" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "%(home_folder)sに保存しているものを優先させることが可能です" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "すべて" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "統計情報を生成するデータがまだありません。\n" "1週間使ってみませんか!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "データを集めています — 一週間後に調査してください!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y年%m月%d日" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%m月%d日" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "最初の活動は%sに記録されました。" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s年間" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "これまでの記録時間は、%(human_days)s日(%(human_years)s)または%(working_days)s" "作業日(%(working_years)s)。" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y年%m月%d日" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "%(date)s日の最長継続作業は、%(hours)s時間です。" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%sレコードあります。" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "ハムスターは、もう少し観察したがってます!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "午前9時以前に開始した活動は%sパーセントなので、早起きですね。" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "午後11時以降に開始した活動は%sパーセントなので、宵っ張りですね。" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "15分未満の活動が%sパーセントなので、忙しそうですね。" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "今日の記録はありません" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s時間" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "只今開始" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "レポートを保存 — タイムトラッカー" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML レポート" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "タブ区切り値 (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "タイムトラッカー" #, fuzzy #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "活動" #~ msgid "Sto_p Tracking" #~ msgstr "記録の停止(_P)" #~ msgid "To_day" #~ msgstr "今日(_D)" #~ msgid "_Add earlier activity" #~ msgstr "以前の活動を追加(_A)" #~ msgid "Show _Overview" #~ msgstr "概要を表示(_O)" #~ msgid "_Preferences" #~ msgstr "設定(_P)" #~ msgid "_About" #~ msgstr "このアプリケーションについて(_A)" #~ msgid "Year:" #~ msgstr "年:" #~ msgid "Starts and ends" #~ msgstr "開始と終了" #~ msgid "Preferences" #~ msgstr "設定" #~ msgid "Changed activity" #~ msgstr "活動を変更します" #~ msgid "Switched to '%s'" #~ msgstr "\"%s\"に切り替えます" #~ msgid "Working on %s" #~ msgstr "%sで動作中" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "ハムスター・タイムトラッカー。使い方:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "プロジェクト・ハムスター (GNOME タイムトラッカー)" hamster-3.0.3/po/kn.po000066400000000000000000001010541452646177100145640ustar00rootroot00000000000000# translation of hamster.master.kn.po to Kannada # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Shankar Prasad , 2008, 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.kn\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2009-09-20 16:32+0530\n" "Last-Translator: Shankar Prasad \n" "Language-Team: Kannada \n" "Language: kn\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "ಹಿಂದಿನ ಚಟುವಟಿಕೆಯನ್ನು ಸೇರಿಸು" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "ಗೆ" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "ಪ್ರಗತಿಯಲ್ಲಿದೆ" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "ವಿವರಣೆ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "ಸಮಯ:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "ಚಟುವಟಿಕೆ:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "ಜಡಗೊಂಡಾಗ ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸು" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "ಗಣಕವು ಜಡಗೊಂಡಾಗ ಪ್ರಸಕ್ತ ಟ್ರ್ಯಾಕಿಂಗ್ ಚಟುವಟಿಕೆಯನ್ನು ನಿಲ್ಲಿಸು" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "ಮುಚ್ಚಿದಾಗ ಟ್ರ್ಯಾಕಿಂಗನ್ನು ನಿಲ್ಲಿಸು" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "ಮುಚ್ಚಿದಾಗ ಪ್ರಸಕ್ತ ಟ್ರ್ಯಾಕಿಂಗ್ ಚಟುವಟಿಕೆಯನ್ನು ನಿಲ್ಲಿಸು" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ಪ್ರಸಕ್ತ ಕೆಲಸವನ್ನು x ನಿಮಿಷಗಳ ನಂತರ ನೆನಪಿಸುತ್ತದೆ" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "ಪ್ರಸಕ್ತ ಕೆಲಸವನ್ನು ಪ್ರತಿ ನಿಗದಿಪಡಿಸಿದ ನಿಮಿಷಗಳ ನಂತರ ನೆನಪಿಸುತ್ತದೆ. ಈ ನೆನಪು ಮಾಡುವುದನ್ನು " "ಅಶಕ್ತಗೊಳಿಸಲು ಈ ಮೌಲ್ಯವನ್ನು ೦ ಗೆ ಅಥವ ೧೨೦ಕ್ಕಿಂತ ಹೆಚ್ಚಿನದಕ್ಕೆ ಬದಲಾಯಿಸಿ." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "ಯಾವುದೆ ಚಟುವಟಿಕೆಯನ್ನು ಹೊಂದಿಸದೆ ಇದ್ದಾಗ ಕೂಡ ನೆನಪಿಸು" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "ಯಾವುದೆ ಚಟುವಟಿಕೆಗಳನ್ನು ಆರಂಭಿಸದೆ ಇದ್ದಲ್ಲಿ ಪ್ರತಿ ಸೂಚನಾ_ಕಾಲಾವಧಿಯಲ್ಲೂ ನೆನಪಿಸು." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "ಸಮಯ ಟ್ರ್ಯಾಕರ್ ವಿಂಡೋವನ್ನು ತೋರಿಸಲು ಕೀಲಿ ಮಣೆ ಶಾರ್ಟ್-ಕಟ್." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "ಸಮಯ ಟ್ರ್ಯಾಕರ್ ವಿಂಡೋವನ್ನು ತೋರಿಸಲು ಕೀಲಿ ಮಣೆ ಶಾರ್ಟ್-ಕಟ್." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "ಸಮಯದ ಟ್ರ್ಯಾಕರ್" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "ಪರಿಯೋಜನೆ Hamster — ನಿಮ್ಮ ಸಮಯದ ಜಾಡನ್ನು ಇರಿಸಿಕೊಳ್ಳಿ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "ಸಮಯದ ಟ್ರ್ಯಾಕರ್" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "ಅಂಕಿಅಂಶಗಳು" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "ವರ್ಗಗಳು(_C)" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "ಚಟುವಟಿಕೆಗಳು(_A)" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "ಈ ಕಾಲಾವಧಿಯಲ್ಲಿ ಯಾವುದೆ ದತ್ತಾಂಶವಿಲ್ಲ" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "ದಿನ" #: ../data/overview.ui.h:3 msgid "Week" msgstr "ವಾರ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "ತಿಂಗಳು" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "ಅವಲೋಕನ - ಹ್ಯಾಮ್‌ಸ್ಟರ್" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "ಅವಲೋಕನ(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "ಚಟುವಟಿಕೆ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "ಒಟ್ಟು" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "ಸಂಪಾದಿಸು" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "ಸಮಯದ ಟ್ರ್ಯಾಕರಿನ ಆದ್ಯತೆಗಳು" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "ಗಣಕವು ಜಡಗೊಂಡಾಗ ಟ್ರ್ಯಾಕಿಂಗನ್ನು ನಿಲ್ಲಿಸು" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ಪ್ರಸಕ್ತ ಚಟುವಟಿಕೆಯನ್ನು ಪ್ರತಿ ಈ ಸಮಯದ ನಂತರ ನೆನಪಿಸು:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "ಕಾಲಾವಧಿ" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸು(_S)" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ವರ್ಗಗಳು(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "ವರ್ಗದ ಪಟ್ಟಿ" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "ಹೊಸ ವರ್ಗವನ್ನು ಸೇರಿಸು" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "ವರ್ಗವನ್ನು ತೆಗೆದು ಹಾಕು" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "ವರ್ಗವನ್ನು ಪಟ್ಟಿ ಮಾಡು" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "ಚಟುವಟಿಕೆಗಳು(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "ಚಟುವಟಿಕೆ ಪಟ್ಟಿ" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "ಚಟುವಟಿಕೆಯನ್ನು ತೋರಿಸು" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "ಚಟುವಟಿಕೆಯನ್ನು ತೆಗೆದು ಹಾಕು" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "ಚಟುವಟಿಕೆಯನ್ನು ಸಂಪಾದಿಸು" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "ವರ್ಗಗಳು(_C)" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "ವಾರ" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "ತಿಂಗಳು" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸು(_S)" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "ಹಿಂದಿನ ಚಟುವಟಿಕೆಯನ್ನು ಸೇರಿಸು" #: ../data/today.ui.h:4 msgid "Overview" msgstr "ಅವಲೋಕನ" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "ಅಂಕಿಅಂಶಗಳು" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "ಸಂಪಾದಿಸು" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸು(_S)" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "ಬದಲಾಯಿಸು" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "ಟ್ರ್ಯಾಕಿಂಗ್ ಅನ್ನು ನಿಲ್ಲಿಸು(_S)" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "ಹೊಸ ಚಟುವಟಿಕೆ" #: ../data/today.ui.h:13 msgid "Today" msgstr "ಇಂದು" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "ಒಟ್ಟು" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "ಅವಲೋಕನವನ್ನು ತೋರಿಸು(_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "ಯಾವುದೆ ಚಟುವಟಿಕೆ ಇಲ್ಲ" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "ವರ್ಗ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "ವಿವರಣೆ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "ಆರಂಭ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "ಕೊನೆ" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "ಕಾಲಾವಧಿ" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "ವರ್ಗಗಳು(_C)" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "ಪರಿಯೋಜನೆ Hamster — ನಿಮ್ಮ ಸಮಯದ ಜಾಡನ್ನು ಇರಿಸಿಕೊಳ್ಳಿ" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "ಹಕ್ಕು © 2007–2009 Toms Bauģis ಹಾಗು ಇತರರು" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "ಪರಿಯೋಜನೆ ಹ್ಯಾಮ್‌ಸ್ಟರ್ ಜಾಲತಾಣ" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "ಸಮಯದ ಟ್ರ್ಯಾಕರ್ ಬಗೆಗೆ" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "ಶಂಕರ್ ಪ್ರಸಾದ್ " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "ವಿಂಗಡಿಸದಿರುವ" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "ಕೆಲಸ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "ಸುದ್ದಿಯನ್ನು ಓದಲಾಗುತ್ತಿದೆ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "ಶೇರುಗಳನ್ನು ಪರಿಶೀಲಿಸಲಾಗುತ್ತಿದೆ" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "ಅತಿ ಗುಪ್ತ ಯೋಜನೆ X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ಪ್ರಪಂಚದ ಅಧೀನತೆ" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "ಪ್ರತಿದಿನ" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "ಊಟ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ಹೂಗಳಿಗೆ ನೀರು ಹನಿಸುವಿಕೆ" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "ಕೈಮೇಲೆ ನಿಲ್ಲುವಿಕೆ" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "ಚಟುವಟಿಕೆಯನ್ನು ಅಪ್‌ಡೇಟ್ ಮಾಡು" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 #, fuzzy msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s - %(end_B)s %(end_d)s, %(end_Y)s ಗಾಗಿನ " "ಅವಲೋಕನ" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_B)s %(end_d)s, %(end_Y)s ಗಾಗಿನ ಅವಲೋಕನ" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_d)s, %(end_Y)s ಗಾಗಿನ ಅವಲೋಕನ" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "ಹೆಸರು" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "ಹೊಸ ವರ್ಗ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "ಹೊಸ ಚಟುವಟಿಕೆ" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d ನಿಮಿಷಗಳು" msgstr[1] "%(interval_minutes)d ನಿಮಿಷಗಳು" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ಎಂದೂ ಬೇಡ" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "ಚಟುವಟಿಕೆ" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "ಆರಂಭದ ಸಮಯ" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "ಅಂತ್ಯದ ಸಮಯ" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "ಕಾಲಾವಧಿಯ ನಿಮಿಷಗಳು" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "ವರ್ಗ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "ವಿವರಣೆ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s - %(end_B)s %(end_d)s, %(end_Y)s ಗಾಗಿನ " "ಅವಲೋಕನ" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_B)s %(end_d)s, %(end_Y)s ಗಾಗಿನ ಅವಲೋಕನ" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s ಗಾಗಿನ ಅವಲೋಕನ" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_d)s, %(end_Y)s ಗಾಗಿನ ಅವಲೋಕನ" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "ಒಟ್ಟು" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "ಚಟುವಟಿಕೆ" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "ಚಟುವಟಿಕೆಗಳು(_A)" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "ವರ್ಗಗಳು(_C)" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "ದಿನಾಂಕ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "ಎಲ್ಲವೂ" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "ಅಂಕಿಅಂಶದ ರೂಪದಲ್ಲಿ ಉತ್ಪಾದಿಸಲು ಇನ್ನೂ ಸಹ ಯಾವುದೆ ಮಾಹಿತಿ ಇಲ್ಲ.\n" "ಒಂದು ವಾರ ಬಳಸುವುದು ಉತ್ತಮ!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "ಇನ್ನೂ ಸಹ ಮಾಹಿತಿಯನ್ನು ಕಲೆ ಹಾಕಲಾಗುತ್ತಿದೆ — ಒಂದು ವಾರದ ನಂತರ ಮರಳಿ ಪರೀಕ್ಷಿಸಿ!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "%s ನಲ್ಲಿ ದಾಖಲಿಸಲಾದ ಮೊದಲ ಚಟುವಟಿಕೆ." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ವರ್ಷ" msgstr[1] "%(num)s ವರ್ಷಗಳು" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ಈವರೆಗೆ ಜಾಡನ್ನು ಇರಿಸಲಾದ ಸಮಯವು %(human_days)s ಮನುಷ್ಯನ ದಿನಗಳು (%(human_years)s) " "ಅಥವ %(working_days)s ಕೆಲಸದ ದಿನಗಳು (%(working_years)s) ಆಗಿವೆ." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "%(date)s ದಿನದಂದು ನಡೆದ ಕೆಲಸವು ಅತಿ ದೀರ್ಘ ಕಾಲದವರೆಗೆ ನಡೆದುದ್ದಾಗಿದೆ ಹಾಗು ಇದು " "%(hours)s ಗಂಟೆಯ ವರೆಗೆ ನಡೆದಿದೆ." msgstr[1] "" "%(date)s ದಿನದಂದು ನಡೆದ ಕೆಲಸವು ಅತಿ ದೀರ್ಘ ಕಾಲದವರೆಗೆ ನಡೆದುದ್ದಾಗಿದೆ ಹಾಗು ಇದು " "%(hours)s ಗಂಟೆಗಳ ವರೆಗೆ ನಡೆದಿದೆ." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s ದಾಖಲೆ ಇದೆ." msgstr[1] "%s ದಾಖಲೆಗಳು ಇವೆ." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ನಿಮ್ಮನ್ನು ಇನ್ನಷ್ಟು ಗಮನಿಸಲು ಬಯಸುತ್ತದೆ!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "ಒಟ್ಟು ಕಾರ್ಯಗಳಲ್ಲಿ %s ಪ್ರತಿಶತದಷ್ಟು ಕಾರ್ಯಗಳು ಬೆಳಗ್ಗೆ 9 ಕ್ಕೂ ಮೊದಲು ಆರಂಭಗೊಳ್ಳುವುದನ್ನು " "ನೋಡಿದರೆ ನೀವು ಮುಂಜಾನೆಯ ಹಕ್ಕಿ ಎಂದು ತೋರುತ್ತದೆ." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "ಒಟ್ಟು ಕಾರ್ಯಗಳಲ್ಲಿ %s ಪ್ರತಿಶತದಷ್ಟು ಕಾರ್ಯಗಳು ರಾತ್ರಿ 11 ರ ನಂತರ ಆರಂಭಗೊಳ್ಳುವುದು ನೋಡಿದರೆ " "ನೀವು ಗೂಬೆ ಎಂದು ತೋರುತ್ತದೆ." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "ಒಟ್ಟು ಕಾರ್ಯಗಳಲ್ಲಿ %s ಪ್ರತಿಶತದಷ್ಟು 15 ನಿಮಿಷಗಳಿಗಿಂತ ಕಡಿಮೆ ಇರುವುದನ್ನು ನೋಡಿದರೆ ನೀವು " "ಸದಾ ಚಟುವಟಿಕೆಯುಳ್ಳ ಜೇನುಹುಳುವನ್ನು ಹೋಲುತ್ತೀರಿ." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ಇಂದಿನ ಯಾವುದೆ ದಾಖಲೆಗಳಿಲ್ಲ" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "ವರದಿಯನ್ನು ಉಳಿಸು – ಸಮಯದ ಟ್ರ್ಯಾಕರ್" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML ವರದಿ" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ಟ್ಯಾಬ್‌ನಿಂದ ಬೇರ್ಪಡಿಸಲಾದ ಮೌಲ್ಯಗಳು (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "ಸಮಯದ ಟ್ರ್ಯಾಕರ್" #~ msgid "_About" #~ msgstr "ಇದರ ಬಗ್ಗೆ(_A)" #~ msgid "_Preferences" #~ msgstr "ಆದ್ಯತೆಗಳು(_P)" #~ msgid "Activities" #~ msgstr "ಚಟುವಟಿಕೆಗಳು" #~ msgid "Global Hotkey" #~ msgstr "ಜಾಗತಿಕ ಹಾಟ್‌ಕೀಲಿ" #~ msgid "Tracking" #~ msgstr "ಟ್ರ್ಯಾಕಿಂಗ್" #~| msgid "No activity" #~ msgid "Move activity down" #~ msgstr "ಚಟುವಟಿಕೆಯನ್ನು ಕೆಳಕ್ಕೆ ಜರುಗಿಸು" #~| msgid "No activity" #~ msgid "Move activity up" #~ msgstr "ಚಟುವಟಿಕೆಯನ್ನು ಮೇಲಕ್ಕೆ ಜರುಗಿಸು" #~ msgid "Preview:" #~ msgstr "ಮುನ್ನೋಟ:" #~ msgid "Show window" #~ msgstr "ವಿಂಡೋವನ್ನು ತೋರಿಸು" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "ಒಂದು ಚಟುವಟಿಕೆಯಲ್ಲಿ ಟೈಪಿಸಿ ಹಾಗು ಜಾಡು ಇರಿಸುವುದನ್ನು " #~ "ಆರಂಭಿಸಲು Enter ಒತ್ತಿ!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "ನನಗೆ ಇನ್ನಷ್ಟು " #~ "ತಿಳಿಸು" #~ msgid "Ad_d Earlier Activity" #~ msgstr "ಈ ಹಿಂದಿನ ಚಟುವಟಿಕೆಯನ್ನು ಸೇರಿಸು(_d)" #~ msgid "Hamster" #~ msgstr "ಹ್ಯಾಮ್‌ಸ್ಟರ್" #~ msgid "_Activity:" #~ msgstr "ಚಟುವಟಿಕೆ(_A):" #~ msgid "_Today" #~ msgstr "ಇಂದು(_T)" #~ msgid " _Day" #~ msgstr "ದಿನ(_D)" #~ msgid " _Month" #~ msgstr "ತಿಂಗಳು(_M)" #~ msgid " _Week" #~ msgstr "ವಾರ(_W)" #~ msgid "Overview" #~ msgstr "ಅವಲಲೋಕನ" #~| msgid "Date and Time" #~ msgid "Starts and ends" #~ msgstr "ಆರಂಭಗೊಳ್ಳುತ್ತದೆ ಹಾಗು ಕೊನೆಗೊಳ್ಳುತ್ತದೆ" #~ msgid "Totals" #~ msgstr "ಒಟ್ಟು" #~ msgid "Categories:" #~ msgstr "ವರ್ಗಗಳು:" #~ msgid "Date interval:" #~ msgstr "ದಿನಾಂಕದ ಕಾಲಾವಧಿ:" #~ msgid "Save as HTML" #~ msgstr "HTML ಆಗಿ ಉಳಿಸು" #~ msgid "Year:" #~ msgstr "ವರ್ಷ:" #~ msgid "Working on %s" #~ msgstr "%s ನೊಂದಿಗೆ ಕೆಲಸಮಾಡಲಾಗುತ್ತಿದೆ" #~ msgid "What should be typed in the activity box?" #~ msgstr "ಚಟುವಟಿಕೆ ಚೌಕದಲ್ಲಿ ಏನನ್ನು ಟೈಪಿಸಬೇಕು?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "ನಿಮ್ಮ ಚಟುವಟಿಕೆಗಳಿಗೆ ವಿವರಗಳನ್ನು ಸೇರಿಸುವುದನ್ನು ಶಕ್ತಗೊಳಿಸಲು ಒಂದು ಸರಳವಾದ " #~ "ಸಿಂಟ್ಯಾಕ್ಸಿದೆ :\n" #~ " \n" #~ "\"@\" ಸಂಕೇತವು ಒಂದು ವರ್ಗವನ್ನು ಸೂಚಿಸುತ್ತದೆ. ಉದಾಹರಣೆಗೆ: \"watering flowers@home" #~ "\" ಎನ್ನುವುದರಲ್ಲಿರುವ \"home\" ಪಂಗಡದಲ್ಲಿನ \"watering flowers\" ಎನ್ನುವ ಚಟುವಟಿಕೆಯ " #~ "ಜಾಡನ್ನು ಇರಿಸುತ್ತದೆ.\n" #~ "\n" #~ "ವಿರಾಮ ಚಿಹ್ನೆಗಳು (\",\") ವಿವರಣೆಯ ಆರಂಭವನ್ನು ಸೂಚಿಸುತ್ತದೆ. ಉದಾಹರಣೆಗೆ: \"watering " #~ "flowers, begonias and forgetmenots\" ಎನ್ನುವುದರಲ್ಲಿನ \"watering flowers\" " #~ "ಎನ್ನುವುದು ಚಟುವಟಿಕೆಯನ್ನು ಸೂಚಿಸಿದರೆ ಅದಕ್ಕೆ \"begonias and forgetmenots\" " #~ "ವಿವರಣೆಯನ್ನು ಸೇರಿಸಲಾಗುತ್ತದೆ.\n" #~ "\n" #~ "ಎರಡನ್ನೂ ಒಟ್ಟಿಗೆ ಸೇರಿಸಿ: \"watering flowers@home, begonias and forgetmenots" #~ "\" ಎನ್ನುವುದು ಉತ್ತಮವಾಗಿ ಕೆಲಸ ಮಾಡುತ್ತದೆ!\n" #~ "\n" #~ "ಈಗ, ಜಾಡನ್ನು ಇರಿಸುವುದನ್ನು ಆರಂಭಿಸಿ !\n" #~ " " #~ msgid "Total Time" #~ msgstr "ಒಟ್ಟು ಸಮಯ" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "ಎಲ್ಲವೂ" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "ಒಟ್ಟು" #~| msgctxt "single day overview" #~| msgid "Overview for %(B)s %(d)s, %(Y)s" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s ಗಾಗಿನ ಅವಲೋಕನ" hamster-3.0.3/po/ko.po000066400000000000000000000577471452646177100146100ustar00rootroot00000000000000# hamster-time-tracker Korean translation # This file is distributed under the same license as the hamster-time-tracker package. # # Changwoo Ryu , 2008-2012. # # 새로 번역하시는 분은 아래 translator-credits에 추가하세요. # # 주의 사항: # # - 이 프로그램의 이름인 "time tracker"는 "시간 추적"이라고 번역. # "추적기"라고 번역하지 *않는다*. # # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-10 22:55+0900\n" "Last-Translator: Changwoo Ryu \n" "Language-Team: GNOME Korea \n" "Language: Korean\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "이전 활동 추가" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "-" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "진행 중" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "설명:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "시간:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "활동:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "꼬리표:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "절전 상태에 추적 중지" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "컴퓨터가 절전 상태가 되면 현재 활동의 추적을 중지합니다" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "컴퓨터를 끄면 추적 중지" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "컴퓨터를 끄면 현재 활동의 추적을 중지합니다" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "현재 활동을 매 몇분마다 알립니다" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "현재 활동을 지정한 분마다 알립니다. 0으로 설정하거나 120보다 큰 값으로 설정하" "면 알리지 않습니다." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "활동을 설정하지 않은 경우에도 알리기" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "활동이 시작하지 않았을 때에도 매 notify_interval 분마다 알립니다." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "하루가 시작하는 시각 (기본값은 오전 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "현재 시각이 지정한 하루의 시작 시각보다 이전이면 어제 날짜의 활동으로 취급되" "고, 하루의 시작 시각보다 나중이면 오늘 날짜의 활동으로 취급됩니다. 이틀에 걸" "쳐서 이루어진 활동의 경우 시간이 긴 쪽 날짜의 활동으로 취급됩니다." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "작업 공간을 전환하면 활동을 전환합니다" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "사용하는 추적 방법 목록. \"name\"이면 workspace_mapping에서 정의한 활동으로 " "전환합니다. \"memory\"면 작업 공간으로 돌아가면 최근 활동으로 전환합니다." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "작업 공간을 바꾸면 활동 전환" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "이름으로 전환하는 경우, 이 목록에서 전환할 활동의 이름을 설정합니다. 목록의 " "항목은 순서대로 해당 번호의 작업 공간에 해당하는 활동입니다." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "시간 추적 창을 보이기 / 감추기" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "시간 추적 프로그램 창을 보이고 감추는 바로 가기 키." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "햄스터 프로그램 창 토글 동작" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "햄스터 프로그램 창을 보일지 말지 토글하는 명령." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "햄스터 프로그램 창 토글" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "햄스터 프로그램 창을 표시할지 토글합니다." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "시간 추적" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "프로젝트 햄스터 - 시간 추적" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "시간 추적 개요" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "햄스터 타임 추적의 개요 창" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "통계 표시" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "분류" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "활동" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "꼬리표" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "이 기간에 데이터가 없습니다" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "보고서 저장..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "일" #: ../data/overview.ui.h:3 msgid "Week" msgstr "주" #: ../data/overview.ui.h:4 msgid "Month" msgstr "달" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "개요 — 햄스터" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "개요(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "활동" #: ../data/overview.ui.h:8 msgid "_View" msgstr "보기(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "전체" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "제거" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "새로 추가" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "편집" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "시간 추적 기본 설정" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "컴퓨터가 절전 상태이면 추적 중지" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "현재 활동을 알려주는 시간 주기:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "하루의 시작 시각:" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "가능하면 다음 할 일 목록 사용:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "통합" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "추적" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "분류(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "분류 목록" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "분류 추가" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "분류 제거" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "분류 편집" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "활동(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "활동 목록" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "활동 추가" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "활동 제거" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "활동 편집" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "자동 완성될 꼬리표" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "분류 및 꼬리표" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "작업 공간으로 돌아오면 최근 활동 다시 시작:" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "작업 공간을 바꾸면 새 활동 시작:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "작업 공간" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "일:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "주:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "달:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "범위:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "적용" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "추적(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "이전 활동 추가" #: ../data/today.ui.h:4 msgid "Overview" msgstr "개요" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "통계" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "편집(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "도움말(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "차례" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "추적 중지(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "전환(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "추적 시작(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "새 활동 시작" #: ../data/today.ui.h:13 msgid "Today" msgstr "오늘" #: ../data/today.ui.h:14 msgid "totals" msgstr "전체" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "개요 표시" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "활동 없음" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "분류" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "설명" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "시작" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "끝" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "기간" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "분류" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "프로젝트 햄스터 — 시간 추적" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "프로젝트 햄스터 홈페이지" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "시간 추적 정보" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "류창우 " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "분류 없음" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "업무" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "뉴스 읽기" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "주식 시세 확인" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "초 극비 프로젝트 엑스" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "세계 정복" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "일일 작업" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "점심" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "꽃에 물 주기" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "물구나무서기" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "활동 업데이트" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d시간" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d분" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d시간 %d분" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y년 %B %d일" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_Y)s년 %(start_B)s %(start_d)s일 – %(end_Y)s년 %(end_B)s %(end_d)s일" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(end_Y)s년 %(start_B)s %(start_d)s일 – %(end_B)s %(end_d)s일" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(end_Y)s년 %(start_B)s %(start_d)s일 – %(end_d)s일" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%b %d일 %A" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "전체 %s시간 추적" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "없음" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "이름" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "새 분류" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "새 활동" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d분" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "하지 않음" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "활동" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "시작 시간" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "끝 시간" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "기간 (분)" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "분류" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "설명" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "꼬리표" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "활동 보고, %(start_Y)s년 %(start_B)s %(start_d)s일 – %(end_Y)s년 %(end_B)s " "%(end_d)s일" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "활동 보고, %(end_Y)s년 %(start_B)s %(start_d)s일 – %(end_B)s %(end_d)s일" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "활동 보고, %(start_Y)s년 %(start_B)s %(start_d)s일" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "활동 보고, %(end_Y)s년 %(start_B)s %(start_d)s일 – %(end_d)s일" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%Y년 %b %d일" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "날짜별 전체" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "활동 기록" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "활동" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "분류" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "구별:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "날짜" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "서식 표시" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "버전을 %(home_folder)s 위치에 저장해서 무시할 수 있습니다" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "전체" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "아직 통계를 만들 데이터가 없습니다.\n" "일주일이면 됩니다." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "데이터를 수집하는 중입니다 — 일주일이 지난 뒤에 다시 보십시오!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y년 %b %d일" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d일" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "처음 활동이 %s에 기록되었습니다." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s년" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "지금까지 추적한 시간은 전체 %(human_days)s일 (%(human_years)s) 혹은 업무일 " "%(working_days)s일 (%(working_years)s) 입니다." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y년 %b %d일" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "가장 길게 연속으로 일한 때는 %(date)s이고, 일한 시간은 %(hours)s 시간입니다." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s개 기록이 있습니다." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "햄스터에 데이터가 더 필요합니다!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "오전 9시 전에 시작한 활동이 %s 퍼센트이므로 일찍 일어나는 새입니다." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "오후 11시 후에 시작한 활동이 %s 퍼센트이므로 올빼미족입니다." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "15분 안에 끝난 활동이 %s 퍼센트이므로 바쁜 꿀벌입니다." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "오늘의 기록 없음" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s시간" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "방금 시작" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "보고서 저장 – 시간 추적" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML 보고서" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "TSV (탭으로 구분한 값 목록)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "시간 추적" #~ msgid "Show activities window" #~ msgstr "활동 창 표시" #~ msgid "Sto_p Tracking" #~ msgstr "추적 중지(_P)" #~ msgid "To_day" #~ msgstr "오늘(_D)" #~ msgid "_Add earlier activity" #~ msgstr "이전 활동 추가(_A)" #~ msgid "Show _Overview" #~ msgstr "개요 표시(_O)" #~ msgid "_Preferences" #~ msgstr "기본 설정(_P)" #~ msgid "_About" #~ msgstr "정보(_A)" #~ msgid "Year:" #~ msgstr "년:" #~ msgid "Starts and ends" #~ msgstr "시작 및 끝" #~ msgid "Preferences" #~ msgstr "기본 설정" #~ msgid "Changed activity" #~ msgstr "활동 바뀜" #~ msgid "Switched to '%s'" #~ msgstr "'%s'(으)로 전환" #~ msgid "Working on %s" #~ msgstr "%s 진행 중" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "햄스터 시간 추적 프로그램. 사용법:" hamster-3.0.3/po/ku.po000066400000000000000000000471351452646177100146040ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Erdal Ronahi , 2008. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: ku\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2008-12-13 01:17+0100\n" "Last-Translator: Erdal Ronahi \n" "Language-Team: Kurdish \n" "Language: ku\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 0.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "didome...\n" "heta\n" "li" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Rave:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "Ça_lakı:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "_Kategorî" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "Ça_lakî" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Roj" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Hefte" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Meh" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Çalakî" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "Mawe" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "Şopandinê Bi_sekinîne" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorî" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "Kategorî" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "Kategoriya Nû" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "Kategoriya Nû" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "Kategoriya Nû" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "Ça_lakî" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "Çalakî" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "Çalakiya Nû" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "_Kategorî" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "Hefte" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "Meh" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "Şopandinê Bi_sekinîne" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "Çalakiya Nû" #: ../data/today.ui.h:4 msgid "Overview" msgstr "" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "Şopandinê Bi_sekinîne" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "Şopandinê Bi_sekinîne" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "Çalakiya Nû" #: ../data/today.ui.h:13 msgid "Today" msgstr "Îro" #: ../data/today.ui.h:14 msgid "totals" msgstr "" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorî" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 #, fuzzy msgid "Description" msgstr "Rave:" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Mawe" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "_Kategorî" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Erdal Ronahi, Koma PCKurd.net" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Xebat" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nav" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Kategoriya Nû" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Çalakiya Nû" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "" msgstr[1] "" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Tu car" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "Çalakî" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "xulek" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "Kategorî" #. column title in the TSV export format #: ../src/hamster/reports.py:158 #, fuzzy msgid "description" msgstr "Rave:" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "Çalakî" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "Ça_lakî" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "_Kategorî" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "" #~ msgid "_Preferences" #~ msgstr "_Vebijêrk" #~ msgid "Activities" #~ msgstr "Çalakî" #~ msgid "Tracking" #~ msgstr "Şopandin" #~ msgid "N_ew Category" #~ msgstr "Kategoriya _Nû" #~ msgid "_New Activity" #~ msgstr "Çalakiya _Nû" #~ msgid "Activity" #~ msgstr "Çalakî" #~ msgid "Date and Time" #~ msgstr "Roj û Dem" #~ msgid "Name:" #~ msgstr "Nav:" #~ msgid "hours" #~ msgstr "demjimêr" #~ msgid "_Today" #~ msgstr "Î_ro" #~ msgid " _Day" #~ msgstr "Ro_j" #~ msgid " _Month" #~ msgstr "_Meh" #~ msgid " _Week" #~ msgstr "_Hefte" #~ msgid "Category" #~ msgstr "Kategorî" #~ msgid "Week" #~ msgstr "Hefte" #~ msgid "name" #~ msgstr "nav" #~ msgid "Other" #~ msgstr "Wekî din" hamster-3.0.3/po/lt.po000066400000000000000000000606201452646177100145760ustar00rootroot00000000000000# Translation of hamster-time-tracker # Copyright (C) 2008, 2010 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Gintautas Miliauskas , 2008. # Žygimantas Beručka , 2010. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: lt\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:20+0100\n" "PO-Revision-Date: 2012-03-26 23:16+0300\n" "Last-Translator: Aurimas Černius \n" "Language-Team: Lithuanian \n" "Language: lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n" "%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Virtaal 0.6.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Pridėti ankstesnį užsiėmimą" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr " iki " #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "vykdoma" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Aprašymas:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Laikas:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Užsiėmimas:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Žymės:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Sustabdyti sekimą, kai kompiuteris nenaudojamas" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Sustabdyti esamo užsiėmimo sekimą, kai kompiuteris nenaudojamas" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Sustabdyti sekimą išjungus" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Sustabdyti esamo užsiėmimo sekimą išjungus" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Pranešti apie esamą veiklą kas x minučių" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Pranešti apie esamą veiklą kas nurodytą minučių skaičių. Nustatykite į 0 " "arba daugiau negu 120, jei norite išjungti pranešimus." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Taip pat pranešti, kai nenustatyta veikla" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "Pranešti kas notify_interval minučių, jei joks užsiėmimas nepradėtas." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Kada prasideda diena (numatytasis nustatymas – 5:30 ryto)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Veikla bus priskiriama vakardienai, jei dabartinis laikas yra ankstesnis už " "nurodytą dienos pradžią; arba šiandienai, jei dabartinis laikas yra vėlesnis " "už dienos pradžią. Veikla, trunkanti keletą dienų, bus priskirta tai dienai, " "kuriai priklauso didžioji veiklos trukmė." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Ar darbalaukio pakeitimas turėtų pakeisti veiklą" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Įjungtų sekimo metodų sąrašas. „name“ – leidžia perjungti veiklą pagal " "pavadinimą, apibrėžtą rakte workspace_mapping. „memory“ – leidžia perjungti " "į paskutiniąją veiklą, grįžus į ankstesnį darbalaukį." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Keisti veiklą pakeitus darbalaukį" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Jei perjungimas pagal pavadinimą įjungtas, šis sąrašas nustato veiklų, į " "kurias persijungti, pavadinimus. Darbalaukius atitinka įrašų indeksai." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Rodyti / slėpti laiko apskaitos langą" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Spartusis klavišas, parodantis / paslepiantis laiko apskaitos langą." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Perjungti programos Hamster lango veiksmą" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Komanda, perjungianti Hamster programos lango matomumą." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Perjungti programos Hamster langą" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Komanda, perjungianti Hamster programos lango matomumą." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Laiko apskaita" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster projektas – sekite savo laiką" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Laiko sekimo apžvalga" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Hamster laiko sekėjo apžvalgos langas" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Rodyti statistiką" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorijos" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Užsiėmimai" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Žymės" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nėra duomenų šiam intervalui" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Įrašyti ataskaitą..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Diena" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Savaitė" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mėnuo" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Apžvalga – Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Apžvalga" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Užsiėmimas" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Rodyti" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Iš viso" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Pašalinti" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Pridėti naują" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Redaguoti" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Laiko apskaitos nustatymai" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Sustabdyti sekimą, kai kompiuteris nenaudojamas" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Pranešti apie esamą veiklą kas:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Naujos dienos pradžia" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Jei prieinamas, naudoti šį atliktinų darbų sąrašą:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integracija" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Sekimas" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorijos" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategorijų sąrašas" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Pridėti kategoriją" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Naikinti kategoriją" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Redaguoti kategoriją" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Užsiėmimai" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Užsiėmimų sąrašas" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Pridėti užsiėmimą" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Naikinti užsiėmimą" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Keisti užsiėmimą" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Žymės, rodomos automatiniame užbaigime" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorijos ir žymės" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Tęsti paskutinę veiklą grįžus į darbalaukį" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Pradėti naują veiklą perjungus darbalaukį:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Darbalaukiai" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Diena:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Savaitė:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mėnuo:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Rėžis:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Pritaikyti" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Sekimas" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Pridėti ankstesnį užsiėmimą" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Apžvalga" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistika" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Keisti" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Pagalba" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Turinys" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Sustabdyti sekimą" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Pe_rjungti" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Pradėti sekimą" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Pradėti naują užsiėmimą" #: ../data/today.ui.h:13 msgid "Today" msgstr "Šiandien" #: ../data/today.ui.h:14 msgid "totals" msgstr "sumos" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Rodyti apžvalgą" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Užsiėmimo nėra" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorija" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Aprašymas" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Pradžia" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Pabaiga" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Trukmė" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorijos" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster projektas – sekite savo laiką" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Autoriaus teisės © 2007-2010 Toms Bauģis ir kiti" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster projekto svetainė" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Apie Laiko apskaitą" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Gintautas Miliauskas " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nerikiuota" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Darbas" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Naujienų skaitymas" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Akcijų tikrinimas" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Ypač slaptas projektas X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Pasaulio užkariavimas" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Kasdieniai" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Pietūs" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Gėlių laistymas" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stovėjimas ant rankų" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Atnaujinti užsiėmimą" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Iš viso užregistruota %s valandų" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nėra" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Pavadinimas" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nauja kategorija" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Naujas užsiėmimas" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minutė" msgstr[1] "%(interval_minutes)d minutės" msgstr[2] "%(interval_minutes)d minučių" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Niekada" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "užsiėmimas" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "pradžios laikas" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "pabaigos laikas" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "trukmė minutėmis" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorija" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "aprašymas" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "žymės" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s " "užsiėmimų žurnalas" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s užsiėmimų žurnalas" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s užsiėmimų žurnalas" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s užsiėmimų žurnalas" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Iš viso pagal dieną" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Užsiėmimų žurnalas" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "užsiėmimai" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorijos" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Atskirti:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Rodyti šabloną" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Galite nustelbti jį įrašydami savąją versiją %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Visi" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Nėra duomenų statistikai generuoti.\n" "Savaitė naudojimo duomenų labai praverstų!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Vis dar renkami duomenys — grįžkite po savaitės!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Pirmasis užsiėmimas užregistruotas %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s metai" msgstr[1] "%(num)s metai" msgstr[2] "%(num)s metų" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Suskaičiuota %(human_days)s žmogaus dienų (%(human_years)s) arba " "%(working_days)s darbo dienų (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Ilgiausias tęstinis darbas buvo %(date)s ir truko %(hours)s valandą." msgstr[1] "" "Ilgiausias tęstinis darbas buvo %(date)s ir truko %(hours)s valandas." msgstr[2] "" "Ilgiausias tęstinis darbas buvo %(date)s ir truko %(hours)s valandų." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Yra %s įrašas." msgstr[1] "Yra %s įrašai." msgstr[2] "Yra %s įrašų." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster norėtų jus stebėti ilgiau" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Su %s procentų užsiėmimų pradėta prieš devynias ryto; panašu, jog esate " "vyturys." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Su %s procentų užsiėmimų pradėta po vienuoliktos vakaro; panašu, jog esate " "pelėda." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Su %s procentų užsiėmimų truko mažiau negu 15 minučių; panašu, jog esate " "devyndarbis." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Šiandienos įrašų nėra" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Tik ką pradėta" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Įrašyti ataskaitą – laiko apskaita" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML ataskaita" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabuliatoriumi atskirtos reikšmės (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Laiko apskaita" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Rodyti veiklų langą" #~ msgid "Sto_p Tracking" #~ msgstr "_Nebesekti" #~ msgid "To_day" #~ msgstr "Šian_dien" #~ msgid "_Add earlier activity" #~ msgstr "_Pridėti ankstesnį užsiėmimą" #~ msgid "Show _Overview" #~ msgstr "Rodyti _apžvalgą" #~ msgid "_Preferences" #~ msgstr "_Nustatymai" #~ msgid "_About" #~ msgstr "_Apie" #~ msgid "Year:" #~ msgstr "Metai:" #~ msgid "Starts and ends" #~ msgstr "Pradžios ir pabaigos" #~ msgid "Preferences" #~ msgstr "Nustatymai" #~ msgid "Changed activity" #~ msgstr "Pakeistas užsiėmimas" #~ msgid "Switched to '%s'" #~ msgstr "Perjungta į „%s“" #~ msgid "Working on %s" #~ msgstr "Dirbama prie %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster laiko apskaita. Naudojimas:" hamster-3.0.3/po/lv.po000066400000000000000000000714231452646177100146030ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Anita Reitere , 2010. # Rūdolfs Mazurs , 2011. # Rūdofls Mazurs , 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: lv\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-09 23:19+0200\n" "Last-Translator: Anita Reitere \n" "Language-Team: Latviešu \n" "Language: lv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : " "2);\n" "X-Generator: Lokalize 1.2\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Pievienot agrāk uzsāktu darbību" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "līdz" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "darbība turpinās" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Apraksts:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Laiks:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Darbība:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Birkas:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Pārtraukt uzskaiti dīkstāves laikā" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Pārtraukt pašreizējās darbības uzskaiti, kad dators netiek lietots" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Pārtraukt uzskaiti, datoru izslēdzot" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Pārtraukt pašreizējās darbības uzskaiti, kad dators tiek izslēgts" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Atgādināt par pašreizējo darbību ik pēc x minūtēm" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Atgādināt par pašreizējo darbību ik pēc norādītajām minūtēm. Atgādinājumus " "var izslēgt, šeit ierakstot 0 vai skaitli, kas lielāks par 120." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "atgādināt arī tad, ja darbība nav norādīta" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Atgādināt katras notify_interval minūtes arī tad, ja pašlaik nekāda darbība " "nav uzsākta." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Kad sākas diena (noklusētā vērtība ir 5:30 no rīta)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Ja pašreizējais laiks ir pirms norādītā dienas sākuma, darbības tiks " "pieskaitītas vakardienai, pretējā gadījumā - šodienai. Darbības, kas notiek " "divas dienas, tiks pieskaitītas tai dienai, kurā izdarīta lielākā daļa." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Vai darbvirsmas pārslēgšanai vajadzētu pārslēgt darbības" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Ieslēgto uzskaites metožu saraksts. \"name\" ieslēgs pārslēgšanos pēc " "workspace_mapping definētajiem nosaukumiem. \"memory\" ieslēgs pārslēgšanos " "uz pēdējo darbību, atgriežoties pie iepriekš lietotas darbvirsmas." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Pārslēgt darbību reizē ar darbvirsmu" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ja ieslēgta pārslēgšanās pēc nosaukuma, šis saraksts norāda darbību " "nosaukumus, uz kurām jāpārslēdzas. Indeksi apzīmē darbvirsmas." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Rādīt / slēpt laika uzskaites logu" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Taustiņu kombinācija laika uzskaites loga rādīšanai / slēpšanai." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Pārslēgt hamster lietotnes loga darbību" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Komanda, ar kuru pārslēdz hamster lietotnes loga redzamību." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Pārslēgt hamster lietotnes logu" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Pārslēgt hamster lietotnes loga redzamību." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Laika uzskaites programma" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekts Hamster - seko līdzi laikam" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Laika uzskaites pārskats" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Hamster laika uzskaites programmas pārskata logs" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Rādīt statistiku" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorijas" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Darbības" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Birkas" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Šajā intervālā nav datu" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Saglabāt atskaiti..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Diena" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Nedēļa" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mēnesis" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Pārskats — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Pārskats" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Darbība" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Skats" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Laika sadalījums" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Dzēst" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Pievienot jaunu" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Labot" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Laika uzskaites uzstādījumi" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Pārtraukt uzskaiti, kad dators netiek lietots" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Atgādināt par pašreizējo darbību katras:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Diena sākas" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Izmantot sekojošo darāmo lietu sarakst, ja pieejams:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrācija" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Uzskaite" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorijas" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategoriju saraksts" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Jauna kategorija" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Dzēst kategoriju" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Labot kategoriju" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Darbības" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Darbību saraksts" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Pievienot darbību" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Dzēst darbību" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Labot darbību" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Birkas, kas jāuzrāda automātiskajā papildināšanā" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorijas un birkas" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Atgriežoties pie darbvirsmas, atsākt pēdējo darbību" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Pārslēdzot darbvirsmas, sākt jaunu darbību:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Darbvirsmas" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Diena:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Nedēļa:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mēnesis:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervāls:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Pielietot" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Uzskai_te" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Pievienot agrāku darbību" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Pārskats" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistika" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "R_ediģēt" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Palīdzība" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Saturs" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Pārtraukt uzskaiti" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Pār_slēgties" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Sāk_t uzskaiti" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Uzsākt jaunu darbību" #: ../data/today.ui.h:13 msgid "Today" msgstr "Šodiena" #: ../data/today.ui.h:14 msgid "totals" msgstr "laika sadalījums" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Rādīt pārskatu" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Nekas nenotiek" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorija" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Apraksts" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Sākums" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Beigas" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Ilgums" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorijas" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekts Hamster — seko līdzi laikam" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Autortiesības © 2007–2010 Toms Bauģis un citi" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Projekta mājas lapa" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Par laika uzskaites programmu" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Toms Bauģis \n" "Anita Reitere " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nešķirotie" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Darbi" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Ziņu lasīšana" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Biržas akciju pārskats" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Superslepenais projekts X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Pasaules pārņemšana" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Ikdiena" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Pusdienas" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Puķu laistīšana" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stāvēšana uz rokām" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Labot darbību" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %b, %Y." #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s. %(start_B)s, %(start_Y)s – %(end_d)s. %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s – %(end_d)s. %(start_B)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "pavisam uzskaitītas %s stundas" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nekas" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nosaukums" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Jauna kategorija" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Jauna darbība" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minūte" msgstr[1] "%(interval_minutes)d minūtes" msgstr[2] "%(interval_minutes)d minūšu" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nekad" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "nodarbe" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "sākuma laiks" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "beigu laiks" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "ilgums minūtēs" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorija" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "apraksts" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "birkas" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Darbību atskaite periodam %(start_d)s. %(start_B)s, %(start_Y)s – %(end_d)s. " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Darbību atskaite periodam %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Darbību atskaite %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Darbību atskaite periodam %(start_d)s. %(start_B)s – %(end_d)s. " "%(start_B)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d. %b, %Y." #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Kopā pa dienu" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Darbību žurnāls" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "darbības" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorijas" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Atšķirt:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datums" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Rādīt veidni" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "To var pārrakstīt, saglabājot savu versiju mapē %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Visi" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Patlaban pietrūkst datu, lai varētu uzģenerēt statistiku.\n" "Pienāciet pēc nedēļas!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Vēl joprojām tiek vākti dati — pienāciet, kad nedēļa būs pagājusi!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d. %b, %Y." #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Pirmais ieraksts tika saglabāts %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s gads" msgstr[1] "%(num)s gadi" msgstr[2] "%(num)s gadi" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tiktāl uzskaitītas %(human_days)s cilvēkdienas (%(human_years)s) jeb " "%(working_days)s darba dienas (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d. %b, %Y." #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Garākais nepārtrauktais darbs ilga %(hours)s stundu un tika reģistrēts " "%(date)s." msgstr[1] "" "Garākais nepārtrauktais darbs ilga %(hours)s stundas un tika reģistrēts " "%(date)s." msgstr[2] "" "Garākais nepārtrauktais darbs ilga %(hours)s stundas un tika reģistrēts " "%(date)s." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Datubāzē ir %s ieraksts." msgstr[1] "Datubāzē ir %s ieraksti." msgstr[2] "Datubāzē ir %s ieraksti." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster (Kāmis) vēlētos jūs pavērot vēl kādu laiku!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Spriežot pēc tā, ka %s procenti ierakstu sākas pirms deviņiem rītā, " "izskatās, ka esat cīrulis." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Spriežot pēc tā, ka %s procenti ierakstu sākas pēc vienpadsmitiem vakarā, " "izskatās, ka esat pūce." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s procenti no visiem darbiem ir īsāki par piecpadsmit minūtēm. Izskatās, ka " "esat varen darbīgs." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Šodien ierakstu nav" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Nupat uzsākta" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Saglabāt atskaiti — Laika uzskaite" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML atskaite" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Ar tabulatoru atdalītas vērtības (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Laika uzskaite" #~ msgid "Sto_p Tracking" #~ msgstr "_Pārtraukt uzskaiti" #~ msgid "To_day" #~ msgstr "Šo_diena" #~ msgid "_Add earlier activity" #~ msgstr "Pievienot _agrāku darbību" #~ msgid "Show _Overview" #~ msgstr "_Rādīt pārskatu" #~ msgid "Year:" #~ msgstr "Gads:" #~ msgid "Starts and ends" #~ msgstr "Sākumi un beigas" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "Parādīt darbību logu" #~ msgid "_Preferences" #~ msgstr "_Iestatījumi" #~ msgid "_About" #~ msgstr "_Apraksts" #~ msgid "Preferences" #~ msgstr "Iestatījumi" #~ msgid "Changed activity" #~ msgstr "Nodarbes maiņa" #~ msgid "Switched to '%s'" #~ msgstr "Nomainīts uz '%s'" #~ msgid "Working on %s" #~ msgstr "Darbojies ar %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster laika uzskaite. Lietojums:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (GNOME laika uzskaite)" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Pievienot agrāku darbību" #~ msgid "Tell me more" #~ msgstr "Pastāstīt sīkāk" #~ msgid "_Today" #~ msgstr "Šo_diena" #~ msgid "Preview:" #~ msgstr "Priekšskats:" #~ msgid "General" #~ msgstr "Pamatiestatījumi" #~ msgid "Global Hotkey" #~ msgstr "Karstais taustiņš" #~ msgid "Move activity down" #~ msgstr "Pārvietot darbību zemāk" #~ msgid "Move activity up" #~ msgstr "Pārvietot darbību augstāk" #~| msgid "" #~| "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgid "" #~ "Overview for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " #~ "%(end_Y)s" #~ msgstr "" #~ "Pārskats %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " #~ "%(end_Y)s" #~| msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgid "" #~ "Overview for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #~ msgstr "Pārskats %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #~| msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #~ msgid "Overview for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #~ msgstr "Pārskats %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #~ msgid "Total Time" #~ msgstr "Laiks pavisam" #~ msgid "totals by activity" #~ msgstr "kopā pa darbībām" #~ msgid "totals by category" #~ msgstr "kopā pa kategorijām" #~ msgid "Activities" #~ msgstr "Darbības" #~ msgid "Tracking" #~ msgstr "Uzskaite" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Ievadiet darbību un nospiediet Enter lai sāktu " #~ "uzskaiti!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Sīkāka " #~ "informācija" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "Nodarbe:" #~ msgid " _Day" #~ msgstr "_Diena" #~ msgid " _Month" #~ msgstr "_Mēnesis" #~ msgid " _Week" #~ msgstr "_Nedēļa" #~ msgid "Overview" #~ msgstr "Pārskats" #~ msgid "Totals" #~ msgstr "Kopsummas" #~ msgid "Categories:" #~ msgstr "Kategorijas:" #~ msgid "Date interval:" #~ msgstr "Datumu intervāls:" #~ msgid "Save as HTML" #~ msgstr "Saglabāt HTML formātā" #~ msgid "What should be typed in the activity box?" #~ msgstr "Ko rakstīt darbības ievadlaukā?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Darbības ievadlauka sintakse ļauj ātri un vienkārši pievienot papildus " #~ "informāciju uzskaitāmajai darbībai:\n" #~ " \n" #~ "\"@\" simbols iezīmē kategoriju. Piemērs: \"puķu laistīšana@mājas\" " #~ "uzsāks darbības \"puķu laistīšana\" uzskaiti \"mājas\" kategorijā.\n" #~ "\n" #~ "Komats (\",\") iezīmē apraksta sākumu. Piemēram: \"puķu laistīšana, " #~ "begonijas un neaizmirstulītes\" uzsāks \"puķu laistīšana\" darbības " #~ "uzskaiti un tai pievienos aprakstu \"begonijas un neaizmirstulītes\".\n" #~ "\n" #~ "Abus iepriekšējos var kombinēt: \"puķu laistīšana@mājas, begonijas un " #~ "neaizmirstulītes\" arīdzan strādās!" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Visas" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Kopā" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s" hamster-3.0.3/po/mai.po000066400000000000000000000464471452646177100147400ustar00rootroot00000000000000# translation of hamster.master.po to Maithili # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Sangeeta Kumari , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-09-11 20:48+0530\n" "Last-Translator: Sangeeta Kumari \n" "Language-Team: Maithili \n" "Language: mai\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" "\n" "X-Generator: KBabel 1.11.4\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "मे" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "विवरण:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "समय:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "सांख्यिकी" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "श्रेणिसभ:" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "क्रियासभ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "दिन" #: ../data/overview.ui.h:3 msgid "Week" msgstr "सप्ताह" #: ../data/overview.ui.h:4 msgid "Month" msgstr "माह" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "क्रियासभ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "संपादन" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "अवधि" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "श्रेणिसभ:" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "सप्ताह" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "माह" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "" #: ../data/today.ui.h:4 msgid "Overview" msgstr "सारांश" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "सांख्यिकी" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "संपादन" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "बदलू" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "" #: ../data/today.ui.h:13 msgid "Today" msgstr "आइ" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "योग" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "सारांश" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "श्रेणी" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "विवरण" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "प्रारंभ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "अंत" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "अवधि" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "श्रेणिसभ:" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "संगीता कुमारी (sangeeta09@gmail.com)" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "बिनु छाँटल" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "कामकाज" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "नाम" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "" msgstr[1] "" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "कहियो नहि" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "क्रियासभ" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "क्रियासभ" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "श्रेणिसभ:" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "दिनांक" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "सभ" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "" #~ msgid "_About" #~ msgstr "क' संबंधमे (_A)" #~ msgid "_Preferences" #~ msgstr "वरीयतासभ (_P)" #~ msgid "Preview:" #~ msgstr "पूर्वावलोकनः" #~ msgid "Year:" #~ msgstr "वर्षः" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "सभ" hamster-3.0.3/po/mk.po000066400000000000000000000741331452646177100145720ustar00rootroot00000000000000# translation of hamster.HEAD.mk.po to Macedonian # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Jovan Naumovski , 2008. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.HEAD.mk\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-01-14 23:13+0100\n" "Last-Translator: Jovan N\n" "Language-Team: Macedonian \n" "Language: mk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Додај претходна активност" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "до" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "во тек" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Опис:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Време" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Активност:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Етикети:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Престани да следиш при неактивност" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Престани да ја следиш тековната активност кога компјутерот е неактивен" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Престани со следење при исклучување" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Престани со следење на тековната активност при исклучување" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Потсети ме за тековната задача на секои x минути" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Потсети ме за тековната задача на одреден број минути. Поставете на 0 или на " "повеќе од 120 за оневозможување на потсетникот." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Потсети ме кога не е стартувана некоја активност" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Исто така потсети ме на секои notify_interval минути ако не е стартувана " "некоја активност." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Кога започнува денот (стандардно е 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Активностите ќе се сметаат како да се од вчера ако тековното време е помало " "од одредениот почеток на денот, ако е после тоа време. Активностите кои се " "протегаат во два дена ќе се постават на денот каде што е најголем дел од " "активноста." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" "Дали менувањето на работното место треба да предизвика менување на активноста" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Листа на овозможени методи на следење. „name“ ќе овозможи преминување на " "активности дефинирани во workspace_mapping. „memory“ ќе овозможи преминување " "на последната активност при враќање на претходниот работен простор." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Смени ја активноста при промена на работното место" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ако е овозможено менување по име, оваа листа ги поставува имињата на " "активностите кои треба да се менуваат, работните простори определени со " "индексот на предметот." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Покажи / скриј го прозорецот на следачот на време" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Кратенка на тастатурата за прикажување / криење на прозорецот на следачот на " "време." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Вклучи/исклучи го дејството на прозорецот на hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" "Команда за менување на видливоста на прозорецот на апликацијата hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Вклучи/исклучи го прозорецот на hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Вклучи/исклучи видливост на прозорецот на апликацијата hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Следач на времето" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Проектот Hamster - следете го трошењето на Вашето време" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Преглед на следењето на времето" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Прозорец за преглед на следачот на време „hamster“" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Покажи статистика" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Категории" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Активности" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Етикети" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Нема податоци за овој интервал" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Зачувај извештај..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Ден" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Недела" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Месец" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Преглед — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Преглед" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Активност" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Поглед" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Вкупно" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Отстрани" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Додај нова" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Уреди" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Преференции за следачот на време" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Престани со следење кога компјутерот станува неактивен" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Потсети ме за тековната активност на секои:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Новиот ден започнува во" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Користи ја следната „да се направи“ листа ако е достапна:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Интеграција" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Следење" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Категории" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Листа на категории" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Додај категорија" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Отстрани ја категоријата" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Уреди ја категоријата" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Активности" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Листа на активности" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Додај активност" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Отстрани ја активноста" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Уреди активност" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Етикети кои ќе се покажуваат со автоматското довршување" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Категории и етикети" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Продолжи со последната активност при враќање на работниот простор" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Започни нова активност при менување на работни простори:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Работни простори" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Ден:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Недела:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Месец:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Опсег:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Примени" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Следење" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Додај претходна активност" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Преглед" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статистика" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Уреди" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Помош" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Содржина" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "П_рестани со следење" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "П_ремини" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Почни со следење" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Започни со нова активност" #: ../data/today.ui.h:13 msgid "Today" msgstr "Денес" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Вкупно" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Покажи _преглед" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Без активност" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Категорија" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Опис" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Почеток" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Крај" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Времетраење" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "категории" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Проектот Hamster — следете го трошењето на Вашето време" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Авторски права © 2007–2010 Toms Bauģis и други" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Веб сајтот на проектот Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "За следачот на времето" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Jovan Naumovski , 2008" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Несортирано" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Работа" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Читам вести" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Ја проверувам берзата" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Супер таен проект X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Светска доминација" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Секојдневни" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ручек" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Ги полевам цвеќињата" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Правам „стој на раце“" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Ажурирај активност" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dч" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dмин" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dч %dмин" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Следени се %s часа" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ништо" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Име" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Нова категорија" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Нова активност" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d минута" msgstr[1] "%(interval_minutes)d минути" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Никогаш" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "активност" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "време на почеток" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "време на крај" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "времетраење во минути" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "категорија" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "опис" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "етикети" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Извештај за активноста на %(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Извештај за активноста на %(start_d)s %(start_B)s – %(end_d)s %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Извештај за активноста на %(start_d)s %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Извештај за активноста на %(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Вкупно по ден" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Дневник на активноста" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "активности" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "категории" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Разликувај:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Датум" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Покажи шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Може да ги замените со зачувување на вашата верзија во %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Сите" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Сѐ уште нема податоци за генерирање статистика.\n" "Податоци од една седмица би биле доволни!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Собирам податоци — вратете се откако ќе помине една седмица!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Првата активност е снимана на %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s година" msgstr[1] "%(num)s години" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Вкупното следено време до сега е %(human_days)s човечки денови или " "(%(human_years)s) или %(working_days)s работни денови (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Најдолгата непрекината работа се случила на %(date)s и траеше %(hours)s час." msgstr[1] "" "Најдолгата непрекината работа се случила на %(date)s и траеше %(hours)s часа." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Има %s запис." msgstr[1] "Има %s записи." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster сака да ве набљудува повеќе!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Со %s проценти од сите активности со почеток пред 9 часот, Вие сте ранобуден/" "ранобудна." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Со %s проценти од сите активности со почеток после 11 часот, Вие сте ноќна " "птица." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Со %s проценти од сите активности пократки од 15 минути, Вие сте вредна " "пчела." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Нема записи за денес" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sч" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Само што започна" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Зачувај извештај — следач на времето" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML извештај" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Вредности разделени со Tab (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Следење на времето" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Проектот Hamster (следач на време за GNOME)" #~| msgid "_Stop Tracking" #~ msgid "Sto_p Tracking" #~ msgstr "П_рестани со следење" #~| msgid "Today" #~ msgid "To_day" #~ msgstr "_Денес" #~| msgid "Add Earlier Activity" #~ msgid "_Add earlier activity" #~ msgstr "_Додај претходна активност" #~ msgid "_About" #~ msgstr "_За" #~ msgid "_Preferences" #~ msgstr "_Преференци" #~ msgid "Starts and ends" #~ msgstr "Започнува и завршува" #~ msgid "Year:" #~ msgstr "Година:" #~| msgid "_Preferences" #~ msgid "Preferences" #~ msgstr "Преференци" #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "Променета активност" #~ msgid "Switched to '%s'" #~ msgstr "Преминав на „%s“" #~ msgid "Working on %s" #~ msgstr "Работам на %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster следач на потрошено време. Употреба:" #~ msgid "Time tracking for masses" #~ msgstr "Следач на времето за секој" #~ msgid "Activities" #~ msgstr "Активности" #~ msgid "Global Hotkey" #~ msgstr "Глобални кратенки" #~ msgid "Tracking" #~ msgstr "Следење" #~ msgid "Move _Down" #~ msgstr "Помести _надолу" #~ msgid "Move _Up" #~ msgstr "Помести _нагоре" #~ msgid "N_ew Category" #~ msgstr "Н_ова категорија" #~ msgid "_New Activity" #~ msgstr "_Нова активност" #~ msgid "Activity" #~ msgstr "Активност" #~ msgid "Date and Time" #~ msgstr "Датум и време" #~ msgid "hours" #~ msgstr "часови" #~ msgid "Show window" #~ msgstr "Покажи го прозорецот" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Д_додај активност од порано" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Today" #~ msgstr "_Денес" #~ msgid " _Day" #~ msgstr "_Ден" #~ msgid " _Month" #~ msgstr "_Месец" #~ msgid " _Week" #~ msgstr "_Недела" #~ msgid "Category" #~ msgstr "Категорија" #~ msgid "Overview" #~ msgstr "Преглед" #~ msgid "Week" #~ msgstr "Недела" #~ msgid "Delete activity" #~ msgstr "Избриши активност" #~ msgid "Earlier activities" #~ msgstr "Порани активности" #~ msgid "Generate Report" #~ msgstr "Генерирај извештај" #~ msgid "Newer activities" #~ msgstr "Понови активности" #~ msgid "Show day" #~ msgstr "Покажи ден" #~ msgid "Show month" #~ msgstr "Покажи месец" #~ msgid "Time tracking for masses." #~ msgstr "Следење на времето за секој." #~ msgid "name" #~ msgstr "име" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_b)s %(m_d)s" #~ msgid "Other" #~ msgstr "Друго" hamster-3.0.3/po/ml.po000066400000000000000000001041611452646177100145660ustar00rootroot00000000000000# translation of hamster.master.ml.po to # Copyright (C) 2008 hamster-time-tracker'S COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # Jeffrey|ജെഫ്രി Antony|ആന്റണി , 2008. # പ്രവീണ്‍ അരിമ്പ്രത്തൊടിയില്‍ , 2008. # Ani Peter | അനി പീറ്റര്‍ , 2009 #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.ml\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-09-11 16:22+0530\n" "Last-Translator: Ani Peter \n" "Language-Team: Swathantra Malayalam Computing | സ്വതന്ത്ര മലയാളം കമ്പ്യൂട്ടിങ് \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "മുമ്പത്തെ പ്രവര്‍ത്തനങ്ങള്‍ ചേര്‍ക്കുക" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "to" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "പുരോഗമിച്ചുകൊണ്ടിരിക്കുന്നു" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "വിവരണം:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "സമയം:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "പ്രവര്‍ത്തനം:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "വെറുതെയിരിക്കുമ്പോള്‍ നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "കമ്പ്യൂട്ടര്‍ വെറുതെയിരിക്കുമ്പോള്‍ ആ സമയത്തു് നടക്കുന്ന പ്രവര്‍ത്തനങ്ങളുടെ നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "കമ്പ്യൂട്ടര്‍ പ്രവര്‍ത്തനം നിറുത്തിക്കൊണ്ടിരിക്കുമ്പോള്‍ നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" "കമ്പ്യൂട്ടര്‍ നിര്‍ത്തിക്കൊണ്ടിരിക്കുമ്പോള്‍ ആ സമയത്തു് നടക്കുന്ന പ്രവര്‍ത്തനങ്ങളുടെ നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "നിലവിലുള്ള പ്രവര്‍ത്തനം എല്ലാ x മിനിട്ടിലും ഓര്‍പ്പിക്കുക" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "നിലവില്‍ ചെയ്യുന്ന ജോലി പറഞ്ഞിരിക്കുന്ന സമയത്തു് ഓര്‍പ്പിക്കുക. 0 അല്ലെങ്കില്‍ 120-നേക്കാള്‍ കൂടുതല്‍ " "നല്‍കി റിമയിണ്ടര്‍ പ്രവര്‍ത്തന രഹിതമാക്കുക." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "പ്രവര്‍ത്തനം സജ്ജമല്ലെങ്കില്‍ നിങ്ങളെ അറിയിക്കുകയും ചെയ്യുന്നു" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "ഒരു പ്രവര്‍ത്തനവും തുടങ്ങിയില്ലെങ്കില്‍, എല്ലാ notify_interval മിനിട്ടില്‍ ഓര്‍പ്പിക്കുക." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "സമയനിരീക്ഷകന്റെ ജാലകം കാണിക്കാനുള്ള കീബോര്‍ഡ് കുറുക്കുവഴി" #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "സമയനിരീക്ഷകന്റെ ജാലകം കാണിക്കാനുള്ള കീബോര്‍ഡ് കുറുക്കുവഴി" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "സമയ നിരീക്ഷകന്‍" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "ഹാമ്സ്റ്റര്‍ നിങ്ങളുടെ സമയം നിരീക്ഷിക്കുന്നു" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "സമയ നിരീക്ഷകന്‍" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "സ്ഥിതിവിവരക്കണക്കുകള്‍" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "_ഇനങ്ങള്‍" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "_പ്രവര്‍ത്തനങ്ങള്‍" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "ഈ ഇടവേളയ്ക്കുള്ള തീയതി ലഭ്യമല്ല" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "ദിവസം" #: ../data/overview.ui.h:3 msgid "Week" msgstr "ആഴ്ച" #: ../data/overview.ui.h:4 msgid "Month" msgstr "മാസം" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "ഹാംസ്റ്റര്‍- അവലോകനം" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_അവലോകനം" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "പ്രവര്‍ത്തനങ്ങള്‍" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "മൊത്തം" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "ചിട്ടപ്പെടുത്തുക" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "സമയനിരീക്ഷകന്റെ മുന്‍ഗണനകള്‍" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "കമ്പ്യൂട്ടര്‍ വെറുതെയിരിക്കുമ്പോള്‍ നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "നിലവിലുള്ള പ്രവര്‍ത്തനം ഓര്‍പ്പിക്കേണ്ടതു് എല്ലാ:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "കാലാവധി" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "_നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_ഇനങ്ങള്‍" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "ഇനങ്ങള്‍ക്കുള്ള പട്ടിക" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "ഇനം ചേര്‍ക്കുക" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "ഇനം നീക്കം ചെയ്യുക" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "യ ഇ ചിട്ടപ്പെടുത്തുകനം" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_പ്രവര്‍ത്തനങ്ങള്‍" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "പ്രവര്‍ത്തനങ്ങളുടെ പട്ടിക" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "പ്രവര്‍ത്തനങ്ങള്‍ ചേര്‍ക്കുക" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "പ്രവര്‍ത്തനം നീക്കം ചെയ്യുക" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "പ്രവര്‍ത്തനങ്ങള്‍ തിരുത്തുക" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "_ഇനങ്ങള്‍" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "ആഴ്ച" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "മാസം" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "_നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "മുമ്പത്തെ പ്രവര്‍ത്തനങ്ങള്‍ ചേര്‍ക്കുക" #: ../data/today.ui.h:4 msgid "Overview" msgstr "അവലോകനം" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "സ്ഥിതിവിവരക്കണക്കുകള്‍" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "ചിട്ടപ്പെടുത്തുക" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "_നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "മാറുക" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "_നിരീക്ഷണം നിര്‍ത്തുക" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "പുതിയ പ്രവര്‍ത്തനങ്ങള്‍" #: ../data/today.ui.h:13 msgid "Today" msgstr "ഇന്നു്" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "മൊത്തം" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "_അവലോകനം കാണിക്കുക" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "പ്രവര്‍ത്തനങ്ങള്‍ ഇല്ല " #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "ഇനം" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "വിവരണം" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "തുടക്കം" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "അവസാനം" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "കാലാവധി" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "_ഇനങ്ങള്‍" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "ഹാമ്സ്റ്റര്‍ നിങ്ങളുടെ സമയം നിരീക്ഷിക്കുന്നു" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "പകര്‍പ്പവകാശം © 2007–2009 ടോം ബോഗിസ്സും മറ്റുള്ളവരും" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "പ്രൊജക്ട് ഹാംസ്റ്റര്‍ വെബ്സൈറ്റ് " #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "സമയ നിരീക്ഷകനെപ്പറ്റി" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "ജെഫ്രി ആന്റണി \n" "പ്രവീണ്‍ അരിമ്പ്രത്തൊടിയില്‍ " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "തരംതിരിക്കാത്തവ" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "ജോലി" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "വര്‍ത്ത വായിയ്ക്കുന്നു" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "ഒഹരികള്‍ പരിശോധിക്കുന്നു " #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "അതീവരഹസ്യസംരംഭം X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ലോകാധിപത്യം" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "ദൈനംദിനം" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "ഉച്ചഭക്ഷണം" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "പൂക്കളെ നനയ്ക്കുന്നു " #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "ഹസ്തദാനം ചെയ്തുകൊണ്ടിരിയ്ക്കുന്നു" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "പ്രവര്‍ത്തനങ്ങള്‍ പുതുക്കുക" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 #, fuzzy msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s-നുള്ള " "അവലോകനം" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s-നുള്ള അവലോകനം" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s-നുള്ള അവലോകനം" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "പേരു്" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "പുതിയ ഇനം" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "പുതിയ പ്രവര്‍ത്തനങ്ങള്‍" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d മിനിറ്റുകള്‍" msgstr[1] "%(interval_minutes)d മിനിറ്റുകള്‍" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ഒരിക്കലുമില്ല" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "പ്രവര്‍ത്തനം" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "തുടങ്ങുന്ന സമയം" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "അവസാനിക്കുന്ന സമയം" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "സമയം മിനിട്ടുകളില്‍" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "വിഭാഗം" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "വിവരണം" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s-നുള്ള " "അവലോകനം" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s-നുള്ള അവലോകനം" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s-നുള്ള അവലോകനം" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s-നുള്ള അവലോകനം" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "മൊത്തം" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "പ്രവര്‍ത്തനങ്ങള്‍" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "_പ്രവര്‍ത്തനങ്ങള്‍" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "_ഇനങ്ങള്‍" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "തീയതി" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "എല്ലാം" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "സ്ഥിതിവിവരക്കണക്കുകള്‍ ലഭ്യമാക്കുവാനുള്ള തീയതി ലഭ്യമല്ല.\n" "ഒരു ആഴ്ചയുടെ കണക്കാണു് ഉത്തമം!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "ഇപ്പോഴും ഡേറ്റാ ശേഖരിക്കുന്നു — ഒരാഴ്ചയ്ക്കു് ശേഷം വീണ്ടും പരിശോധിക്കുക!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "ആദ്യ പ്രവര്‍ത്തനം %s-നു് രേഖപ്പെടുത്തിയിരിക്കുന്നു." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s year" msgstr[1] "%(num)s years" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ഇതു് വരെ നിരീക്ഷിച്ച സമയം: %(human_days)s ദിവസങ്ങള്‍ (%(human_years)s) അല്ലെങ്കില്‍ " "%(working_days)s പ്രവര്‍ത്തന ദിവസങ്ങള്‍ (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "ഏറ്റവും കൂടുതല്‍ അടുപ്പിച്ച ജോലി ചെയ്തതു് %(date)s, %(hours)s മണിക്കൂര്‍." msgstr[1] "ഏറ്റവും കൂടുതല്‍ അടുപ്പിച്ച ജോലി ചെയ്തതു് %(date)s, %(hours)s മണിക്കൂറുകള്‍." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s റിക്കോര്‍ഡുണ്ടു്." msgstr[1] "%s റിക്കോര്‍ഡുകളുണ്ടു്." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "ഹാമ്സ്റ്ററിനു് നിങ്ങളെ ഇനിയും നിരീക്ഷിക്കണം!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "%s ശതമാനം ജോലികളും രാവിലെ 9-നു് മുമ്പു് തുടങ്ങുന്നു. നിങ്ങള്‍ വളരെ ചിട്ടയുള്ള ആളാണു്." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "%s ശതമാനം ജോലികളും രാത്രി 11-നു് ശേഷം തുടങ്ങുന്നു. നിങ്ങള്‍ മൂങ്ങയെപോലെയാണു്." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "%s ശതമാനം ജോലികളും 15 മിനിറ്റില്‍ കുറവാണു്. നിങ്ങള്‍ വളരെ തിരക്കുള്ള വ്യക്തിയാണു്." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ഇന്നു് രേഖകള്‍ ഒന്നും ഇല്ല" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "സമയ നിരീക്ഷകന്‍ റിപോര്‍ട്ട് സൂക്ഷിക്കുക" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML റിപോര്‍ട്ട്" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ടാബ്-വേര്‍പെടുത്തുന്ന മൂല്ല്യങ്ങള്‍ (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "സമയ നിരീക്ഷകന്‍" #~ msgid "_About" #~ msgstr " ഹാംസ്റ്ററിനെ _കുറിച്ചു്" #~ msgid "_Preferences" #~ msgstr "_മുന്‍ഗണനകള്‍" #~ msgid "Activities" #~ msgstr "പ്രവര്‍ത്തനങ്ങള്‍" #~ msgid "Global Hotkey" #~ msgstr "പൊതുവായ കുറുക്കുവഴി" #~ msgid "Tracking" #~ msgstr "നീരീക്ഷണം" #~| msgid "No activity" #~ msgid "Move activity down" #~ msgstr "പ്രവര്‍ത്തനം താഴേക്ക് നീക്കുക" #~| msgid "No activity" #~ msgid "Move activity up" #~ msgstr "പ്രവര്‍ത്തനം മുകളിലേക്ക് നീക്കുക" #~ msgid "Preview:" #~ msgstr "തിരനോട്ടം:" #~ msgid "Show window" #~ msgstr "ജാലകം കാണിക്കുക" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "ഒരു പ്രവര്‍ത്തനം ടൈപ്പ് ചെയ്തു് അതു് നിരീക്ഷിക്കുന്നതിനായി Enter " #~ "ചെയ്യുക!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "കൂടുതല്‍ അറിയുക" #~ msgid "Ad_d Earlier Activity" #~ msgstr "മുമ്പത്തെ പ്രവര്‍ത്തനങ്ങള്‍ ചേര്‍ക്കുക" #~ msgid "Hamster" #~ msgstr "ഹാംസ്റ്റര്‍" #~ msgid "_Activity:" #~ msgstr "_പ്രവര്‍ത്തനങ്ങള്‍:" #~ msgid "_Today" #~ msgstr "_ഇന്നു് " #~ msgid " _Day" #~ msgstr "_ദിവസം" #~ msgid " _Month" #~ msgstr "_മാസം" #~ msgid " _Week" #~ msgstr "_ആഴ്ച" #~ msgid "Overview" #~ msgstr "അവലോകനം" #~| msgid "Date and Time" #~ msgid "Starts and ends" #~ msgstr "ആരംഭവും അവസാനവും" #~| msgid "Tracking" #~ msgid "Totals" #~ msgstr "മൊത്തം" #~| msgid "_Categories" #~ msgid "Categories:" #~ msgstr "ഇനങ്ങള്‍:" #~ msgid "Date interval:" #~ msgstr "ഇടവേള:" #~ msgid "Save as HTML" #~ msgstr "HTML ആയി സൂക്ഷിക്കുക" #~ msgid "Year:" #~ msgstr "വര്‍ഷം:" #~ msgid "Working on %s" #~ msgstr "%s പ്രവര്‍ത്തിക്കുന്നു" #~ msgid "What should be typed in the activity box?" #~ msgstr "പ്രവര്‍ത്തനത്തിലുള്ള ബോക്സില്‍ എന്തു് ടൈപ്പ് ചെയ്യണം?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "നിങ്ങളുടെ പ്രവര്‍ത്തനങ്ങളിലേക്ക് വിശദാംശങ്ങള്‍ ചേര്‍ക്കുന്നതിനുള്ള ഒരു ലളിതമായ സിന്റാക്സ്:\n" #~ " \n" #~ "\"@\" ഒരു ഇനം അടയാളപ്പെടുത്തുന്നു. ഉദാഹരണത്തിനു്: \"watering flowers@home\" നല്‍കുമ്പോള്‍ " #~ "\"watering flowers\" എന്ന പ്രവര്‍ത്തി \"home\" ഇനത്തില്‍ ആരംഭിക്കുന്നു.\n" #~ "\n" #~ "കോമാ (\",\") വിവരണങ്ങളുടെ ആരംഭം അടയാശപ്പെടുത്തുന്നു. ഉദാഹരണത്തിനു്: \"watering " #~ "flowers, begonias and forgetmenots\" നല്‍കുമ്പോള്‍, \"watering flowers\" എന്ന " #~ "പ്രവര്‍ത്തി നിരീക്ഷണ ആരംഭിക്കുകയും, അതിലേക്ക് \"begonias and forgetmenots\" എന്ന " #~ "വിവരണം ചേര്‍ക്കുകയും ചെയ്യുന്നു.\n" #~ "\n" #~ "രണ്ടും യോജിപ്പിക്കാം: \"watering flowers@home, begonias and forgetmenots\" " #~ "എന്നു് നല്‍കുന്നതും ശരിയാണു്!\n" #~ "\n" #~ "ഇനി നിരീക്ഷണം ആരംഭിക്കുക!\n" #~ " " #~ msgid "Total Time" #~ msgstr "ആക സമയം" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "എല്ലാം" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~| msgid "Today" #~ msgid "Total" #~ msgstr "മൊത്തം" #~| msgid "Overview for %s" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s അവലോകനം" hamster-3.0.3/po/mr.po000066400000000000000000000760571452646177100146100ustar00rootroot00000000000000# translation of mr.po to Marathi # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Sandeep Shedmake , 2008. # Sandeep Shedmake , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: mr\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-09-08 16:15+0530\n" "Last-Translator: Sandeep Shedmake \n" "Language-Team: Marathi \n" "Language: mr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "पूर्वीचे कार्य जोडा" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "करीता" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "प्रगतीत आहे" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "वर्णन:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "वेळ:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "कार्य:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "रिकामे असल्यावर मार्गनिर्देशन थांबवा" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "संगणक रिकामे झाल्यावर सध्याच्या क्रियाचे नीयंत्रण थांबवा" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "शटडाऊनवेळी मार्गनिर्देशन बंद करा" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "शटडाऊनवेळी वर्तमान कार्याचे मार्गनिर्देशन थांबवा" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "सध्याच्या कार्यविषयी प्रत्येक x मिनीटे नंतर लक्षात आणून द्या" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "सध्याच्या कार्यविषयी ठराविक मिनीटानंतर लक्षात आणून द्या. आठवण अकार्यक्षम करण्यासाठी 0 " "किंवा 120 पेक्षा जास्त असे सेट करा." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "कार्य सेट न केल्यावर लक्षात आणून द्या" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "कार्य सुरू न केल्यास, प्रत्येक notify_interval मिनीटानंतर लक्षात आणून द्या." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "वेळ मार्गनिर्देशक चौकट दर्शविण्याकरीता कळफलकवरील शार्टकट." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "वेळ मार्गनिर्देशक चौकट दर्शविण्याकरीता कळफलकवरील शार्टकट." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "वेळ मार्गनिर्देशक" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 #, fuzzy msgid "Project Hamster - track your time" msgstr "Hamster प्रकल्प— तुमचा वेळ नियंत्रीत करा" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "वेळ मार्गनिर्देशक" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 #, fuzzy msgid "Show Statistics" msgstr "आकडेवारी" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "विभाग (_C)" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "कार्य (_A)" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "या अवधीकरीता डाटा आढळला नाही" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "दिवस" #: ../data/overview.ui.h:3 msgid "Week" msgstr "आठवडा" #: ../data/overview.ui.h:4 msgid "Month" msgstr "महिना" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "पूर्वदृश्य - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "पूर्वदृष्य (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "कार्य" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "एकूण" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "संपादीत करा" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "वेळ मार्गनिर्देशक पसंती" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "संगणक रिमाके अल्यावर मार्गनिर्देशन बंद करा" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "सध्याचे कार्य दर कार्यकाळ नंतर लक्षात आणून द्या:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "अवधी" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "मार्गनिर्देशन थांबवा (_S)" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "विभाग (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "विभाग सूची" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "विभाग समावेश करा" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "विभाग काढून टाका" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "विभाग संपादीत करा" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "कार्य (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "कार्य सूची" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "कार्य समावेश करा" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "कार्य काढून टाका" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "कार्य संपादन" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "विभाग (_C)" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "आठवडा" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "महिना" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "मार्गनिर्देशन थांबवा (_S)" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "पूर्वीचे कार्य जोडा" #: ../data/today.ui.h:4 msgid "Overview" msgstr "पूर्वदृष्य" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "आकडेवारी" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "संपादीत करा" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "मार्गनिर्देशन थांबवा (_S)" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "बदलवा" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "मार्गनिर्देशन थांबवा (_S)" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "नविन कार्य" #: ../data/today.ui.h:13 msgid "Today" msgstr "आज" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "एकूण" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "पूर्वदृश्य दर्शवा (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "कार्य नाही" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "विभाग" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "वर्णन" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "सुरू करा" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "समाप्त" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "अवधी" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "विभाग (_C)" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster प्रकल्प— तुमचा वेळ नियंत्रीत करा" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "सर्वहक्काधिकार © 2007–2009 Toms Baugis व इतर" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "प्रकल्प Hamster संकेतस्थळ" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "वेळ नियंत्रक विषयी" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "संदिप शेडमाके , 2008. संदिप शेडमाके , 2009." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "विनाक्रम" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "काम" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "समाचार वाचत आहे" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "स्टॉक वरील नजर" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "सर्वात गोपनीय प्रकल्प X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "अंतराष्ट्रीय घडामोडी" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "दैनंदिन" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "जेवण" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "फुलांना पानी घालणे" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "हातावर उभे राहून करामती करणे" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "अद्ययावत कार्य" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 #, fuzzy msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s करीता " "संक्षिप्त आढवा" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s करीता संक्षिप्त आढवा" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s करीता संक्षिप्त आढवा" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "नाव" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "नविन विभाग" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "नविन कार्य" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d मिनीटे" msgstr[1] "%(interval_minutes)d मिनीटे" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "कधिच नाही" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "कार्य" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "सुरवातची वेळ" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "समाप्तीची वेळ" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "कार्यकाळ मिनीटे" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "विभाग" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "वर्णन" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s करीता " "संक्षिप्त आढवा" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s करीता संक्षिप्त आढवा" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s करीता संक्षिप्त आढवा" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s करीता संक्षिप्त आढवा" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "एकूण" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "कार्य" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "कार्य (_A)" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "विभाग (_C)" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "दिनांक" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "सर्व" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "आकडेवारी निर्माण करण्यासाठी अजूनही डाटा आढळला नाही.\n" "आठवडाभर वापरणी खूप चांगले असू शकते!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "अजूनही डाटा संग्रहीत करत आहे — आठवडा पूर्ण झाल्यावर पुनः तपासा!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 #, fuzzy msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "पहिले कार्य %s वेळी रेकॉर्ड केले गेले." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s वर्ष" msgstr[1] "%(num)s वर्ष" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "आत्तापर्यंत नियंत्रीत वेळ %(human_days)s मानवीय दिवस (%(human_years)s) किंवा " "%(working_days)s कार्यरत दिवस (%(working_years)s) आहेत." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "सर्वात लांब सतत कार्य %(date)s व %(hours)s तासप्रमाणे आढळले." msgstr[1] "सर्वात लांब सतत कार्य %(date)s व %(hours)s तास प्रमाणे आढळले." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s रेकॉर्ड आढळले." msgstr[1] "%s रेकॉर्ड्स् आढळले." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ला तुमचे कार्य आणखी वेळसाठी निरीक्षण करायला आवडेल!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "सर्व वास्तविकच्या %s टक्के 9am पूर्वी सुरू होत असल्याने तुम्ही लवकरच कार्यक्षम होता असे आढळते." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "वास्तविकच्या सर्व %s टक्के 11am नंतर सुरू होत असल्याने तुम्ही उशीरा कार्यक्षम होता असे आढळते." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "वास्तविकच्या सर्व %s टक्के 15 मिनीटांपेक्षा कमी होत असल्याने तुम्ही खूप व्यस्थ आहात असे आढळते." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "आज कुठलेही रेकॉर्ड नाही" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "अहवाल साठवा – वेळ नीयंत्रक" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML अहवाल" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab-Separated Values (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "वेळ मार्गनिर्देशक" #~ msgid "_About" #~ msgstr "विषयी (_A)" #~ msgid "_Preferences" #~ msgstr "पसंती (_P)" #~ msgid "Activities" #~ msgstr "कार्य" #~ msgid "Global Hotkey" #~ msgstr "जागतिक हॉटकि" #~ msgid "Tracking" #~ msgstr "मार्गनिर्देशन" #~| msgid "No activity" #~ msgid "Move activity down" #~ msgstr "कार्य खाली हलवा" #~| msgid "No activity" #~ msgid "Move activity up" #~ msgstr "कार्य वर सरकवा" #~ msgid "Preview:" #~ msgstr "पूर्वदृष्य:" #~ msgid "Show window" #~ msgstr "चौकट दर्शवा" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "कार्य टाइप करा व नियंत्रण सुरू करण्यासाठी एंटर दाबा!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "आणखी सांगा" #~ msgid "Ad_d Earlier Activity" #~ msgstr "पूर्वीचे कार्य जोडा (_d)" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "कार्य (_A):" #~ msgid "_Today" #~ msgstr "आज (_T)" #~ msgid " _Day" #~ msgstr "दिवस (_D)" #~ msgid " _Month" #~ msgstr "महिना (_M)" #~ msgid " _Week" #~ msgstr "आठवडा (_W)" #~ msgid "Overview" #~ msgstr "पूर्वदृश्य" #~| msgid "Date and Time" #~ msgid "Starts and ends" #~ msgstr "सुरूवात व समाप्ती" #~| msgid "Tracking" #~ msgid "Totals" #~ msgstr "एकूण" #~| msgid "_Categories" #~ msgid "Categories:" #~ msgstr "विभाग:" #~ msgid "Date interval:" #~ msgstr "दिनांक अवधी:" #~ msgid "Save as HTML" #~ msgstr "HTML प्रमाणे साठवा" #~ msgid "Year:" #~ msgstr "वर्ष:" #~ msgid "Working on %s" #~ msgstr "%s वर कार्य करत आहे" #~ msgid "What should be typed in the activity box?" #~ msgstr "कार्य पेटीत काय टाइप केले पाहिजे?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "तुमच्या कार्यात तपशील समावेश सक्षम करणयासाठी सोपी रचना आढळली:\n" #~ " \n" #~ "\"@\" चिन्ह विभागचे प्रतीक आहे. उदाहरणतया: \"watering flowers@home\" कार्य " #~ "\"watering flowers\" चे विभाग \"home\" करीता नियंत्रण करायला सुरू करतो.\n" #~ "\n" #~ "स्वल्पविराम (\",\") वर्णनच्या सुरूवातीचे प्रतीक आहे. उदाहरणतया: \"watering " #~ "flowers, begonias and forgetmenots\" कार्य \"watering flowers\" याचे नियंत्रण " #~ "व वर्णन \"begonias and forgetmenots\" समाविष्ट करायला सुरूवात करते.\n" #~ "\n" #~ "दोन्ही एकत्र केले जाऊ शकते: \"watering flowers@home, begonias and forgetmenots" #~ "\" योग्यरित्या कार्य करते!\n" #~ "\n" #~ "आत्ता, नियंत्रण सुरू करा!\n" #~ " " #~ msgid "Total Time" #~ msgstr "एकूण वेळ" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "सर्व" #~| msgid "%(m_b)s %(m_d)s" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~| msgid "Today" #~ msgid "Total" #~ msgstr "एकूण" #~| msgid "Overview - Hamster" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s करीत पूर्वदृष्य" hamster-3.0.3/po/nb.po000066400000000000000000000560101452646177100145540ustar00rootroot00000000000000# Norwegian bokmål translation of hamster. # Copyright (C) 2008 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # Kjartan Maraas , 2008-2012. # Torstein Adolf Winterseth , 2010. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-04-30 13:26+0200\n" "Last-Translator: Kjartan Maraas \n" "Language-Team: Norwegian bokmål \n" "Language: nb\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Legg til tidligere aktivitet" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "til" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "under arbeid" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Beskrivelse:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Tid:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivitet:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Tagger:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stopp sporing når datamaskinen ikke er i bruk" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stopp sporing av nåværende aktivitet når datamaskinen er inaktiv" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stopp sporing når datamaskinen slås av" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stopp sporing av pågående aktivitet når datamaskinen slås av" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Vis påminnelse om aktiv oppgave hvert x minutt" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Påminnelse om aktiv oppgave ved spesifiserte intervaller i minutter. Sett " "til 0 eller større enn 120 for å slå av påminnelse." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Vis påminnelser når ingen aktivitet er satt" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Tidspunkt for dagens start (forvalg er 05:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Hvorvidt bytte av arbeidsområde skal utløse bytte av aktivitet" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Bytt aktivitet ved bytte av arbeidsområde" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Vis / skjul vindu for tidsporing" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Slå av/på programvindu for hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Slå av/på synlighet for hamster programvinduet." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tidsporing" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Prosjekt Hamster - følg med på din tidsbruk" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Oversikt over tidsporing" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Oversiktsvindu for hamster tidsporing" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Vis statistikk" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorier" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktiviteter" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Tagger" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Ingen data for dette intervallet" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Lagre rapport …" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dag" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Uke" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Måned" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Oversikt – Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Oversikt" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivitet" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Vis" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totalt" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Fjern" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Legg til ny" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Rediger" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Brukervalg for tidsporing" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stopp sporing når datamaskinen er inaktiv" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Vis påminnelse om nåværende aktivitet:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Ny dag starter" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Bruk følgende oppgaveliste hvis tilgjengelig:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrasjon" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Sporing" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorier" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategoriliste" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Legg til kategori" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Fjern kategori" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Rediger kategori" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktiviteter" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Aktivitetsliste" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Legg til aktivitet" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Fjern aktivitet" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Rediger aktivitet" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Tagger som skal vises ved automatisk fullføring" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorier og tagger" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" "Gjenoppta tidligere aktivitet når du kommer tilbake til et arbeidsområde" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Start ny aktivitet når du bytter arbeidsområder:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Arbeidsområder" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dag:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Uke:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Måned:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Område:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Bruk" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "S_poring" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Legg til tidligere aktivitet" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Oversikt" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistikk" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "R_ediger" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Hjelp" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Innhold" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_pp sporing" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "B_ytt" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Star_t sporing" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Start ny aktivitet" #: ../data/today.ui.h:13 msgid "Today" msgstr "I dag" #: ../data/today.ui.h:14 msgid "totals" msgstr "totalt" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Vis oversikt" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Ingen aktivitet" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategori" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Beskrivelse" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Start" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Slutt" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Varighet" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorier" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Prosjekt hamster - følg med på din tidsbruk" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Opphavsrett © 2007-2010 Toms Bauǵis og andre" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Nettsted for prosjekt Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Om Tidsporing" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Kjartan Maraas \n" "Torstein Adolf Winterseth " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Usortert" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Arbeid" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Leser nyheter" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Sjekker aksjer" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Superhemmelig prosjekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Verdensherredømme" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dag til dag" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunsj" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Vanner blomster" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Står på hendene" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Oppdater aktivitet" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dt" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dt %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s - %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s - %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s timer sporet totalt" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ingen" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Navn" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Ny kategori" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Ny aktivitet" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minutt" msgstr[1] "%(interval_minutes)d minutter" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Aldri" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivitet" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "starttid" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "slutt-tid" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "varighet minutter" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategori" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "beskrivelse" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "tagger" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Aktivitetslogg for %(start_B)s %(start_d)s, %(start_Y)s - %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Aktivitetslogg for %(start_B)s %(start_d)s - %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Aktivitetslogg for %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Aktivitetslogg for %(start_B)s %(start_d)s - %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totalt per dag" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Aktivitetslogg" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktiviteter" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorier" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Bestem:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Dato" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Vis mal" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Du kan overstyre dem ved å lagre din versjon i %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Alle" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Ingen data å lage statistikk for ennå.\n" "En ukes bruk hadde vært bra!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Samler inn data - sjekk om en ukes tid!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Første aktivitet ble oppdaget på %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s år" msgstr[1] "%(num)s år" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Overvåket tid så langt er %(human_days)s dager (%(human_years)s) eller " "%(working_days)s arbeidsdager (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Lengste sammenhengende arbeidsperiode var på %(date)s og var %(hours)s time." msgstr[1] "" "Lengste sammenhengende arbeidsperiode var på %(date)s og var %(hours)s timer." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Det finnes %s oppføring." msgstr[1] "Det finnes %s oppføringer." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster vil gjerne observere deg litt lenger!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Siden %s prosent av alle aktiviter starter før ni om morgenen ser det ut til " "at du er en morgenfugl." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Siden %s prosent av alle aktiviteter starter etter elleve om kvelden ser det " "ut til at du er en nattugle." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Siden %s prosent av alle aktiviteter varer kortere enn 15 minutter ser det " "ut til at du er en flittig bie." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Ingen oppføringer i dag" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Akkurat startet" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Lagre rapport – tidsporing" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-rapport" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabulator-separerte verdier (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Tidsporing" #~ msgid "Show activities window" #~ msgstr "Vis aktivitetsvindu" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_pp sporing" #~ msgid "To_day" #~ msgstr "I _dag" #~ msgid "_Add earlier activity" #~ msgstr "_Legg til tidligere aktivitet" #~ msgid "Show _Overview" #~ msgstr "Vis _oversikt" #~ msgid "_Preferences" #~ msgstr "_Brukervalg" #~ msgid "_About" #~ msgstr "_Om" #~ msgid "Year:" #~ msgstr "År:" #~ msgid "Starts and ends" #~ msgstr "Starter og slutter" #~ msgid "Preferences" #~ msgstr "Brukervalg" #~ msgid "Changed activity" #~ msgstr "Endret aktivitet" #~ msgid "Switched to '%s'" #~ msgstr "Byttet til «%s»" #~ msgid "Working on %s" #~ msgstr "Arbeider på %s?" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster tidsporing. Bruk:" hamster-3.0.3/po/nl.po000066400000000000000000000561521452646177100145750ustar00rootroot00000000000000# Dutch translation for Hamster applet # # This file is distributed under the same license as the # hamster-time-tracker package. # # Hans de Zwart , 2008. # Hylke Bons , 2008. # Wouter Bolsterlee , 2008–2009. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: Project Hamster\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-02-14 00:15+0100\n" "Last-Translator: Wouter Bolsterlee \n" "Language-Team: Dutch \n" "Language: nl\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Eerdere activiteit toevoegen" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "aan de gang…\n" "tot\n" "voor" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Omschrijving:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "_Activiteit:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Registratie stoppen bij computerinactiviteit" #: ../data/hamster.schemas.in.h:2 #, fuzzy msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Registratie huidige activiteit stoppen als de computer niet gebruikt wordt" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stop registratie bij afsluiten" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Registratie huidige activiteit stoppen bij afsluiten computer" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Elke x minuten herinneren aan de huidige activiteit" #: ../data/hamster.schemas.in.h:6 #, fuzzy msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Om de zoveel tijd herinnerd worden aan de huidige activiteit. Zet deze " "waarde op 0 (of groter dan 120) om dit uit te schakelen." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "Sneltoets voor het tonen van het tijdregistratievenster." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Sneltoets voor het tonen van het tijdregistratievenster." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tijdregistratie" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster — uw tijd bijhouden" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Tijdregistratie" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "_Categorieën" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "_Activiteiten" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dag" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Week" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Maand" # Naam toepassing niet in venstertitel (Wouter Bolsterlee) #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "Overzicht tijdregistratie" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Overzicht" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activiteit" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totalen" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Bewerken" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Voorkeuren voor tijdschrijven" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stop registratie tijdens computerinactiviteit" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Aan huidige activiteit herinneren iedere:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "Duur" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "Registratie _stoppen" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categorieën" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "Categorie" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "Nieuwe categorie" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "Nieuwe categorie" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "Nieuwe categorie" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activiteiten" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "Activiteit" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Activiteit toevoegen" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "Geen activiteit" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Activiteit bewerken" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "_Categorieën" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "Week" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "Maand" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "Registratie _stoppen" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "Eerdere activiteit toevoegen" #: ../data/today.ui.h:4 #, fuzzy msgid "Overview" msgstr "_Overzicht" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "Bewerken" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "Registratie _stoppen" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "Wisselen" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "Registratie _stoppen" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "Nieuwe activiteit" #: ../data/today.ui.h:13 #, fuzzy msgid "Today" msgstr "_Vandaag" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Totalen" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "_Overzicht tonen" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Geen activiteit" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categorie" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Omschrijving" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Begin" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Einde" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duur" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "_Categorieën" #: ../src/hamster/about.py:42 #, fuzzy msgid "Project Hamster — track your time" msgstr "Project Hamster — uw tijd bijhouden" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2008 Toms Baugis en anderen" #: ../src/hamster/about.py:45 #, fuzzy msgid "Project Hamster Website" msgstr "Hamster-website" #: ../src/hamster/about.py:46 #, fuzzy msgid "About Time Tracker" msgstr "Tijdregistratie" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Wouter Bolsterlee\n" "Hylke Bons\n" "Hans de Zwart\n" "\n" "Kijk voor meer informatie op http://nl.gnome.org/" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Ongesorteerd" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Werk" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Nieuws lezen" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Beurskoersen bekijken" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Supergeheim project X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Wereldoverheersing" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunch" # Vrij vertaald (Wouter Bolsterlee) #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Plantjes water geven" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Jongleren" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Activiteit bijwerken" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Overzicht voor %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "Overzicht voor %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Overzicht voor %(start_d)s–%(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Naam" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nieuwe categorie" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nieuwe activiteit" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuten" msgstr[1] "%(interval_minutes)d minuten" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nooit" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "Activiteit" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "minuten" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "Categorie" #. column title in the TSV export format #: ../src/hamster/reports.py:158 #, fuzzy msgid "description" msgstr "Omschrijving" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Overzicht voor %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "Overzicht voor %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Overzicht %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Overzicht voor %(start_d)s–%(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "Totalen" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "Activiteit" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "_Activiteiten" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "_Categorieën" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "Week tonen" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Geen activiteiten vandaag" #: ../src/hamster/today.py:250 #, fuzzy, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s, " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "Tijdregistratie" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "Tijdregistratie" #~ msgid "_About" #~ msgstr "I_nfo" #~ msgid "_Preferences" #~ msgstr "_Voorkeuren" #~ msgid "Activities" #~ msgstr "Activiteiten" #~ msgid "Global Hotkey" #~ msgstr "Globale sneltoets" #~ msgid "Tracking" #~ msgstr "Registratie" #~ msgid "Move _Down" #~ msgstr "Oml_aag" #~ msgid "Move _Up" #~ msgstr "_Omhoog" #~ msgid "N_ew Category" #~ msgstr "_Nieuwe categorie" #~ msgid "_New Activity" #~ msgstr "_Nieuwe activiteit" #~ msgid "Activity" #~ msgstr "Activiteit" #~ msgid "Date and Time" #~ msgstr "Datum en tijd" #~ msgid "Name:" #~ msgstr "Naam:" # Bewust enkelvoud! (Wouter Bolsterlee) #~ msgid "hours" #~ msgstr "uur" #~ msgid "Show window" #~ msgstr "Venster tonen" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Eerdere activiteit toevoegen" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid " _Day" #~ msgstr "_Dag" #~ msgid " _Month" #~ msgstr "_Maand" #~ msgid " _Week" #~ msgstr "_Week" #~ msgid "Overview" #~ msgstr "Overzicht" #~ msgid "Delete activity" #~ msgstr "Activiteit verwijderen" #~ msgid "Earlier activities" #~ msgstr "Eerdere activiteiten" #~ msgid "Generate Report" #~ msgstr "Rapport aanmaken" #~ msgid "Newer activities" #~ msgstr "Recentere activiteit" #~ msgid "Show day" #~ msgstr "Dag tonen" #~ msgid "Show month" #~ msgstr "Maand tonen" #~ msgid "Something: 20:00, Food: 12:13" #~ msgstr "Iets: 20:00, Eten: 12:13" #~ msgid "Working on %s" #~ msgstr "Bezig met %s" #~ msgid "Day to day" #~ msgstr "Dagelijkse bezigheden" #~ msgid "name" #~ msgstr "naam" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s %(report_b)s %(report_Y)s" #~ msgid "Total Time" #~ msgstr "Totale tijd" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s %(o_d)s %(o_b)s" #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_d)s %(m_b)s" #~ msgid "Total" #~ msgstr "Totaal" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " hamster-3.0.3/po/or.po000066400000000000000000001042031452646177100145730ustar00rootroot00000000000000# translation of hamster.master.or.po to Oriya # Oriya translation of hamster.HEAD.or.pot # Copyright (C) 2009, Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Arun Mahapatra , 2009. # Manoj Kumar Giri , 2009, 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.or\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2011-03-17 14:19+0530\n" "Last-Translator: Manoj Kumar Giri \n" "Language-Team: Oriya \n" "Language: or\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.1\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "\n" "\n" "\n" "\n" "\n" "\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "ପୁର୍ବ କାର୍ଯ୍ୟକ୍ରମକୁ ଯୋଗ କରନ୍ତୁ" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "କୁ" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "ଅଗ୍ରଗତି କରୁଛି" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "ବର୍ଣ୍ଣନା:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "ସମୟ:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "କାର୍ଯ୍ୟକ୍ରମ:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "ଟ୍ଯାଗଗୁଡ଼ିକ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "ନିଷ୍କ୍ରିୟ ହେବା ମାତ୍ରେ ଅନୁସରଣକୁ ବିରାମ ଦିଅନ୍ତୁ" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "କମ୍ପ୍ଯୁଟର ନିଷ୍କ୍ରିୟ ହେବା ମାତ୍ରେ ଅନୁସରଣକୁ ବିରାମ ଦିଅନ୍ତୁ" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "ବନ୍ଦ କରିବା ପରେ ଅନୁସରଣକୁ ବିରାମ ଦିଅନ୍ତୁ" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "ବନ୍ଦ କରିବା ପରେ ସାଂପ୍ରତିକ କାର୍ୟକ୍ରମର ଅନୁସରଣକୁ ବିରାମ ଦିଅନ୍ତୁ" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ସାଂପ୍ରତିକ କାର୍ଯ୍ୟ ର ସ୍ମରଣ ପ୍ରତି x ମିନିଟରେ କରାନ୍ତୁ" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "ନିର୍ଦ୍ଦିଷ୍ଟ ମିନିଟରେ ସାଂପ୍ରତିକ କାର୍ଯ୍ୟ ସ୍ମରଣ କରନ୍ତୁ. ସ୍ମାରକକୁ ଅକ୍ଷମ କରିବା ନିମନ୍ତେ 0 ଅଥବା 120 ଠାରୁ " "ଅଧିକ ସଂଖ୍ଯା ବିନ୍ୟାସ କରନ୍ତୁ।" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "କୌଣସି କାର୍ଯ୍ୟକ୍ରମ ସେଟ କରାଯାଇଥିବା ସମୟରେ ମଧ୍ଯ ସ୍ମରଣ କରନ୍ତୁ" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "କୌଣସି କାର୍ଯ୍ୟକ୍ରମ ଆରମ୍ଭ ହୋଇନଥିଲେ ମଧ୍ଯ ପ୍ରତ୍ୟେକ ବିଜ୍ଞପ୍ତି ଅନ୍ତରାଳକୁ ମନେ ପକାଇ ଥାଏ।" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "କେତେବେଳେ ଦିନ ଆରମ୍ଭ ହୋଇଥାଏ (ପୂର୍ବନିର୍ଦ୍ଧାରିତ 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "କାର୍ଯ୍ଯକ୍ଷେତ୍ର ପରିବର୍ତ୍ତନ ହେଲେ କାର୍ଯ୍ୟକ୍ରମକୁ ବଦଳାନ୍ତୁ" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "ସମୟ ଅନୁସରଣ ୱିଣ୍ଡୋକୁ ଦର୍ଶାନ୍ତୁ / ଲୁଚାନ୍ତୁ" #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "ଅନୁସରଣ ପ୍ରଣାଳି ୱିଣ୍ଡୋ ଦେଖାଇବା ନିମନ୍ତେ ସଂକ୍ଷିପ୍ତ ଚାବି।" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "hamster ପ୍ରୟୋଗ ୱିଣ୍ଡୋର ଦର୍ଶନକୁ ଆଗପଛ କରିବା ପାଇଁ ନିର୍ଦ୍ଦେଶ।" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "hamster ପ୍ରୟୋଗ ୱିଣ୍ଡୋକୁ ହଲାନ୍ତୁ" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "ସମୟ ଅନୁସରଣ ପ୍ରଣାଳୀ" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "ପ୍ରକଲ୍ପ Hamster - ନିଜ ସମୟର ଅନୁସରଣ କରନ୍ତୁ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "ସମୟ ଅନୁସରଣ ପ୍ରଣାଳୀ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "ପରିସଂଖ୍ଯାନ ଦର୍ଶାନ୍ତୁ" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "ବିଭାଗଗୁଡ଼ିକ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "କାର୍ଯ୍ୟକ୍ରମଗୁଡ଼ିକ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "ଟ୍ଯାଗଗୁଡ଼ିକ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "ଏହି ଅନ୍ତରାଳ ପାଇଁ କୌଣସି ତଥ୍ୟ ନାହିଁ" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "ବିବରଣୀ ସଂରକ୍ଷଣ କରନ୍ତୁ..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "ଦିନ" #: ../data/overview.ui.h:3 msgid "Week" msgstr "ସପ୍ତାହ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "ମାସ" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "ସଂକ୍ଷିପ୍ତ ବିବରଣୀ - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "ସାରାଂଶ (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "କାର୍ଯ୍ୟକ୍ରମ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "ଦ୍ରୁଶ୍ଯ (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "ସର୍ବମୋଟ" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "ଅପସାରଣ କରନ୍ତୁ" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "ନୂତନକୁ ଯୋଗକରନ୍ତୁ" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "ସମ୍ପାଦନ କରନ୍ତୁ" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "ସମୟ ଅନୁସରଣ ପ୍ରଣାଳି ପସନ୍ଦ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "କମ୍ପ୍ଯୁଟର ନିଷ୍କ୍ରିୟ ହେବା ମାତ୍ରେ ଅନୁସରଣକୁ ବିରାମ ଦିଅନ୍ତୁ" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ସାଂପ୍ରତିକ କାର୍ଯ୍ୟକ୍ରମର ସ୍ମରଣ ପ୍ରତି:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "ନୂତନ ଦିବସ ଏହି ସମୟରେ ଆରମ୍ଭ ହୋଇଥାଏ" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "ଉପଲବ୍ଧ ହେଲେ ନିମ୍ନଲିଖିତ କାର୍ଯ୍ୟପନ୍ଥାକୁ ବ୍ୟବହାର କରନ୍ତୁ:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "ସମାକଳନ" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "ଅନୁସରଣ କରୁଅଛି" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ବିଭାଗଗୁଡିକ (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "ବିଭାଗ ତାଲିକା" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "ବିଭାଗ ଯୋଗକରନ୍ତୁ" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "ବିଭାଗକୁ କାଢ଼ନ୍ତୁ" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "ବିଭାଗ ସମ୍ପାଦନ କରନ୍ତୁ" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "କାର୍ଯ୍ୟକ୍ରମ (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "କାର୍ଯ୍ୟକ୍ରମ ତାଲିକା" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "କାର୍ଯ୍ୟକ୍ରମ ଯୋଗ କରନ୍ତୁ" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "କାର୍ଯ୍ୟକ୍ରମକୁ କାଢ଼ନ୍ତୁ" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "କାର୍ଯ୍ୟକ୍ରମ ସମ୍ପାଦନ କରନ୍ତୁ" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "ବିଭାଗ ଟ୍ୟାଗଗୁଡ଼ିକ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "କାର୍ଯ୍ୟକ୍ଷେତ୍ର ବଦଳାଇବା ସମୟରେ ନୂତନ କାର୍ଯ୍ୟକ୍ରମ ଆରମ୍ଭ କରନ୍ତୁ:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "କାର୍ଯ୍ଯକ୍ଷେତ୍ର" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "ଦିନ:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "ସପ୍ତାହ:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "ମାସ:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "ପରିସର:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "ପ୍ରୟୋଗ କରନ୍ତୁ" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "ଅନୁସରଣ ବିରାମ (_S)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "ପୁର୍ବ କାର୍ଯ୍ୟକ୍ରମକୁ ଯୋଗ କରନ୍ତୁ" #: ../data/today.ui.h:4 msgid "Overview" msgstr "ସମୀକ୍ଷା" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "ପରିସଂଖ୍ଯାନ" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "ସମ୍ପାଦନ କରନ୍ତୁ (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "ସହାୟତା (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "ସୂଚୀପତ୍ର" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "ଅନୁସରଣ ବିରାମ (_S)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "ପରିବର୍ତ୍ତନ କରନ୍ତୁ (_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "ଅନୁସରଣ ଆରମ୍ଭ କରନ୍ତୁ (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "ନୂତନ କାର୍ଯ୍ୟକ୍ରମ ଆରମ୍ଭ କରନ୍ତୁ" #: ../data/today.ui.h:13 msgid "Today" msgstr "ଆଜି" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "ସର୍ବମୋଟ" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "ସଂକ୍ଷିପ୍ତ ବିବରଣୀ ଦର୍ଶାନ୍ତୁ (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "କୌଣସି କାର୍ଯ୍ୟକ୍ରମ ନାହିଁ" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "ବିଭାଗ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "ବର୍ଣ୍ଣନା" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "ପ୍ରାରମ୍ଭ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "ସମାପ୍ତ" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "ଅବଧି" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "ବିଭାଗଗୁଡିକ" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "ପ୍ରକଲ୍ପ Hamster - ନିଜ ସମୟର ଅନୁସରଣ କରନ୍ତୁ" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis and others" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "ପ୍ରକଳ୍ପ Hamster ୱେବସାଇଟ" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "ସମୟ ଅନୁସରଣକାରୀ ବିଷୟରେ" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "ଅରୁଣ ମହାପାତ୍ର ମନୋଜ କୁମାର ଗିରି " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "ଅସଜଡା" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "କାର୍ଯ୍ଯ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "ଖବର ପଢ଼ୁଅଛି" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "ଭଣ୍ଡାର ଯାଞ୍ଚକରୁଅଛି" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "ଗୁପ୍ତ ପ୍ରକଳ୍ପ X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ବିଶ୍ୱ ଶାସନ" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "ଦିନ ପ୍ରତିଦିନ" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "ଆରମ୍ଭ କରନ୍ତୁ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ଫୁଲମାନଙ୍କୁ ପାଣି ଦେଉଅଛି" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Doing handstands" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "କାର୍ଯ୍ୟକ୍ରମକୁ ଅଦ୍ୟତନ କରନ୍ତୁ" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ଘଣ୍ଟାରେ ନିରୀକ୍ଷଣ ହୋଇଥିବା ସର୍ବମୋଟ" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "କିଛି ନାହିଁ" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "ନାମ" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "ନୁତନ ବିଭାଗ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "ନୂତନ କାର୍ଯ୍ୟକ୍ରମ" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d ମିନିଟ" msgstr[1] "%(interval_minutes)d ମିନିଟ" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "କେବେ ନୁହଁ" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "କାର୍ଯ୍ୟକ୍ରମ" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "ଆରମ୍ଭ ସମୟ" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "ଶେଷ ସମୟ" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "ଅବଧି ମିନିଟ" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "ବିଭାଗ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "ବର୍ଣ୍ଣନା" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ଟ୍ଯାଗଗୁଡ଼ିକ" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s ପାଇଁ କାର୍ଯ୍ୟକ୍ରମ ବିବରଣୀ – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s ପାଇଁ କାର୍ଯ୍ୟକ୍ରମ ବିବରଣୀ – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s ପାଇଁ କାର୍ଯ୍ୟକ୍ରମ ବିବରଣୀ" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s ପାଇଁ କାର୍ଯ୍ୟକ୍ରମ ବିବରଣୀ– %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "ଦିନର ସର୍ବମୋଟ" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "କାର୍ଯ୍ୟକ୍ରମ ସୂଚୀ" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "କାର୍ଯ୍ୟକ୍ରମ" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "ବିଭାଗଗୁଡିକ" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "ତାରିଖ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "ନମୁନା ଦର୍ଶାନ୍ତୁ" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "ସମସ୍ତ" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "ଏପର୍ଯ୍ୟନ୍ତ ପରିସଂଖ୍ୟାନ ସୃଷ୍ଟି କରିବା ପାଇଁ କୌଣସି ତଥ୍ୟ ନାହିଁ।\n" "ଗୋଟିଏ ସପ୍ତାହ ବ୍ୟବହାର ଭଲ ହେବ!" #: ../src/hamster/stats.py:180 #, fuzzy msgid "Collecting data — check back after a week has passed!" msgstr "ଏପର୍ଯ୍ୟନ୍ତ ତଥ୍ୟ ସଂଗ୍ରହ କରୁଅଛି — ଗୋଟିଏ ସପ୍ତାହ ପରେ ଯାଞ୍ଚ ବିତିଯାଇଛି!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "ପ୍ରଥମ କାର୍ଯ୍ୟକଳାପକୁ %s ରେ ଲିପିବଦ୍ଧ ହୋଇଥିଲା।" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ବର୍ଷ" msgstr[1] "%(num)s ବର୍ଷ" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ଏପର୍ଯ୍ୟନ୍ତ ଅନୁସରଣ କରାଯାଇଥିବା ସମୟ %(human_days)s ମନୁଷ୍ୟ ଦିବସଗୁଡ଼ିକ (%(human_years)s) " "ଅଥବା %(working_days)s କାର୍ଯ୍ୟ ଦିବସଗୁଡ଼ିକ (%(working_years)s)।" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "ଲମ୍ବା ଅବିରାମ କାର୍ଯ୍ୟ %(date)s ଏବଂ %(hours)s ଘଣ୍ଟା ହୋଇଥାଏ।" msgstr[1] "ଲମ୍ବା ଅବିରାମ କାର୍ଯ୍ୟ %(date)s ଏବଂ %(hours)s ଘଣ୍ଟା ହୋଇଥାଏ।" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "ସେଠାରେ %s ଅନୁଲିପି ଅଛି।" msgstr[1] "ସେଠାରେ %s ଅନୁଲିପି ଅଛି।" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ଆପଣଙ୍କୁ କିଛି ଅଧିକ ନିରିକ୍ଷଣ କରିବାକୁ ଚାହୁଁଛନ୍ତି!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "9am ପୂର୍ବରୁ ଆରମ୍ଭ ହେଉଥିବା %s ପ୍ରତିଶତ ସମସ୍ତ ବିଷୟ ବସ୍ତୁ ସହିତ ଆପଣ ଗୋଟିଏ ପ୍ରାକ ପକ୍ଷି ଲାଗୁଛନ୍ତି।" #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "11pm ପୂର୍ବରୁ ଆରମ୍ଭ ହେଉଥିବା %s ପ୍ରତିଶତ ସମସ୍ତ ବିଷୟ ବସ୍ତୁ ସହିତ ଆପଣ ଜଣେରାତ୍ରି ପେଚା ପରି ଲାଗୁଛନ୍ତି।" #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "15 ମିନଟ ବିଳମ୍ବ ସମସ୍ତ କାର୍ଯ୍ୟଗୁଡ଼ିକର %s ପ୍ରତିଶତ ବ୍ୟସ୍ତ ପରି ଲାଗେ।" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ଆଜିର ବିବରଣୀ ନାହିଁ" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "ବର୍ତ୍ତମାନ ଆରମ୍ଭ ହୋଇଛି" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "ବିବରଣୀ ସଂରକ୍ଷଣ କରନ୍ତୁ – ସମୟ ଅନୁସରଣକାରୀ" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML ବିବରଣୀ" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ଟ୍ୟାବ ଦ୍ୱାରା ପୃଥକ ମୂଲ୍ୟଗୁଡ଼ିକ (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "ସମୟ ଅନୁସରଣ" #~| msgid "Project Hamster Website" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "ପ୍ରକଳ୍ପ Hamster (Gnome ସମୟ ନିରୀକ୍ଷକ)" #~ msgid "_About" #~ msgstr "ବିବରଣୀ (_A)" #~ msgid "_Preferences" #~ msgstr "ପସନ୍ଦ (_P)" #, fuzzy #~| msgid "_Stop Tracking" #~ msgid "Sto_p Tracking" #~ msgstr "ଅନୁସରଣ ବିରାମ (_S)" #~| msgid "Today" #~ msgid "To_day" #~ msgstr "ଆଜି (_d)" #~| msgid "Add Earlier Activity" #~ msgid "_Add earlier activity" #~ msgstr "ପୁର୍ବ କାର୍ଯ୍ୟକ୍ରମକୁ ଯୋଗ କରନ୍ତୁ (_A)" #~| msgid "Starts and ends" #~ msgid "Starts and ends" #~ msgstr "ଆରମ୍ଭ ଏବଂ ଶେଷ" #~ msgid "Year:" #~ msgstr "ବର୍ଷ:" #~| msgid "_Preferences" #~ msgid "Preferences" #~ msgstr "ପସନ୍ଦ" #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "ପରିବର୍ତ୍ତନ ହୋଇଥିବା କାର୍ଯ୍ୟକ୍ରମ" #~ msgid "Switched to '%s'" #~ msgstr "'%s' କୁ ପରିବର୍ତ୍ତିତ ହୋଇଛି" #~ msgid "Working on %s" #~ msgstr "%s ରେ କାର୍ଯ୍ୟରତ" #~ msgid "Activities" #~ msgstr "କାର୍ଯ୍ୟକ୍ରମଗୁଡିକ" #~ msgid "Global Hotkey" #~ msgstr "ସାମଗ୍ରିକ ସଂକ୍ଷିପ୍ତ ଚାବି" #~ msgid "Tracking" #~ msgstr "ଅନୁସରଣ କରନ୍ତୁ" #~| msgid "No activity" #~ msgid "Move activity down" #~ msgstr "କାର୍ଯ୍ୟକ୍ରମକୁ ତଳକୁ ଆଣନ୍ତୁ" #~| msgid "No activity" #~ msgid "Move activity up" #~ msgstr "କାର୍ଯ୍ୟକ୍ରମକୁ ଉପରକୁ ଆଣନ୍ତୁ" #~ msgid "Preview:" #~ msgstr "ପୂର୍ବାଲୋକନ:" #~ msgid "Show window" #~ msgstr "ୱିଣ୍ଡୋ ଦର୍ଶାନ୍ତୁ" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "ଗୋଟିଏ କାର୍ଯ୍ୟକ୍ରମରେ ଟାଇପ କରନ୍ତୁ ଏବଂ ଅନୁସରଣ ଆରମ୍ଭ କରିବା ପାଇଁ " #~ "Enter ଦବାନ୍ତୁ!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "ମୋତେ ଅଧିକ କୁହନ୍ତୁ" #~ msgid "Ad_d Earlier Activity" #~ msgstr "ପୁର୍ବ କାର୍ଯ୍ୟକ୍ରମ ଯୋଗ କରନ୍ତୁ (_d)" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "କାର୍ଯ୍ୟକ୍ରମ (_A)" #~ msgid "_Today" #~ msgstr "ଆଜି (_T)" #~ msgid " _Day" #~ msgstr " ଦିନ (_D)" #~ msgid " _Month" #~ msgstr " ମାସ (_M)" #~ msgid " _Week" #~ msgstr " ସପ୍ତାହ (_W)" #~ msgid "Overview" #~ msgstr "ସଂକ୍ଷିପ୍ତ ବିବରଣୀ" #~| msgid "Tracking" #~ msgid "Totals" #~ msgstr "ସମୁଦାୟ" #~| msgid "_Categories" #~ msgid "Categories:" #~ msgstr "ବିଭାଗଗୁଡିକ:" #~ msgid "Date interval:" #~ msgstr "ତାରିଖ ଅନ୍ତରାଳ:" #~ msgid "Save as HTML" #~ msgstr "HTML ପରି ସଂରକ୍ଷଣ କରନ୍ତୁ" #~ msgid "What should be typed in the activity box?" #~ msgstr "କାର୍ଯ୍ୟକ୍ରମ ବାକ୍ସରେ କଣ ଲେଖିବା ଉଚିତ?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "ସେଠାରେ ଗୋଟିଏ ସରଳ ବାକ୍ୟ ଅଛି ଯାହାକି ଆପଣଙ୍କର କାର୍ଯ୍ୟକଳାପରେ ବିବରଣୀ ଯୋଗ କରିବା ପାଇଁ ଆପଣଙ୍କୁ " #~ "ସକ୍ରିୟ କରିଥାଏ:\n" #~ " \n" #~ "\"@\" ସଙ୍କେତ ବିଭାଗ ଚିହ୍ନଟ କରିଥାଏ। ଉଦାହରଣ: \"watering flowers@home\" କାର୍ଯ୍ୟକଳାପକୁ " #~ "ଅନୁସରଣ କରିବା ଆରମ୍ଭ କରିବ \"watering flowers\" ବିଭାଗ \"home\"ରେ।\n" #~ "\n" #~ "କମା (\",\") ବର୍ଣ୍ଣନାର ଆରମ୍ଭକୁ ଚିହ୍ନଟ କରିଥାଏ। ଉଦାହରଣ: \"watering flowers, " #~ "begonias and forgetmenots\" କାର୍ଯ୍ୟକଳାପକୁ ଅନୁସରଣ କରିବା ଆରମ୍ଭ କରିବ \"watering " #~ "flowers\" ଏବଂ ଏଥିରେ ବର୍ଣ୍ଣନା ଆରମ୍ଭ କରିଥାଏ \"begonias and forgetmenots\"।\n" #~ "\n" #~ "ଉଭୟକୁ ଯୋଗ କରାଯାଇପାରିବ: \"watering flowers@home, begonias and forgetmenots\" " #~ "ଭଲ ଭାବରେ କାର୍ଯ୍ୟକରିଥାଏ!\n" #~ "\n" #~ "ବର୍ତ୍ତମାନ, ଅନୁସରଣ ଆରମ୍ଭ କରନ୍ତୁ!\n" #~ " " #~ msgid "Total Time" #~ msgstr "ସର୍ବମୋଟ ସମୟ" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "ସମସ୍ତ" #~| msgid "%(m_b)s %(m_d)s" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~| msgid "Totals" #~ msgid "Total" #~ msgstr "ସର୍ବମୋଟ" #~| msgid "Overview for %(start_B)s %(start_d)s, %(start_Y)s" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s ପାଇଁ ସମୀକ୍ଷା" hamster-3.0.3/po/pa.po000066400000000000000000001061621452646177100145610ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Amanpreet Singh Alam , 2008. # A S Alam , 2009, 2010, 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-20 18:36+0530\n" "Last-Translator: A S Alam \n" "Language-Team: Punjabi/Panjabi \n" "Language: pa\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "ਪਹਿਲਾਂ ਸਰਗਰਮੀ ਸ਼ਾਮਲ" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "ਤੱਕ" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "ਜਾਰੀ ਹੈ" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "ਵੇਰਵਾ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "ਸਮਾਂ:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "ਸਰਗਰਮੀ:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "ਟੈਗ:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "ਵੇਹਲਾ ਹੋਵੇ ਤਾਂ ਟਰੈਕਿੰਗ ਰੋਕੋ" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "ਜਦੋਂ ਕੰਪਿਊਟਰ ਵੇਹਲਾ ਹੋਵੇ ਤਾਂ ਮੌਜੂਦਾ ਸਰਗਰਮੀ ਲਈ ਟਰੈਕਿੰਗ ਰੋਕੋ" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "ਬੰਦ ਕਰਨ ਸਮੇਂ ਟਰੈਕਿੰਗ ਬੰਦ ਕਰੋ" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "ਬੰਦ ਕਰਨ ਉੱਤੇ ਮੌਜੂਦਾ ਸਰਗਰਮੀ ਲਈ ਟਰੈਕਿੰਗ ਬੰਦ ਕਰੋ" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ਮੌਜੂਦਾ ਟਾਸਕ ਹਰੇਕ x ਮਿੰਟਾਂ ਬਾਅਦ ਚੇਤੇ ਕਰਵਾਉ" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "ਖਾਸ ਦਿੱਤੇ ਮਿੰਟਾਂ ਦੇ ਬਾਅਦ ਮੌਜੂਦਾ ਟਾਸਕ ਚੇਤੇ ਕਰਵਾਉ। ਰੀਮਾਈਡਰ ਬੰਦ ਕਰਨ ਲਈ 0 ਜਾਂ 120 ਤੋਂ ਵੱਧ ਸੈੱਟ " "ਕਰੋ।" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "ਜਦੋਂ ਕੋਈ ਸਰਗਰਮੀ ਸੈੱਟ ਨਾ ਹੋਵੇ ਤਾਂ ਵੀ ਚੇਤੇ ਕਰਵਾਓ" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "ਜੇ ਕੋਈ ਸਰਗਰਮੀ ਸ਼ੁਰੂ ਨਾ ਹੋਵੇ ਤਾਂ ਹਰੇਕ ਸੂਚਨਾ ਅੰਤਰਾਲ ਮਿੰਟ ਦੇ ਬਾਅਦ ਚੇਤੇ ਕਰਵਾਉ(_i)" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "ਸਮਾਂ, ਜਦੋਂ ਦਿਨ ਸ਼ੁਰੂ ਹੁੰਦਾ ਹੈ (ਮੂਲ ੫:੩੦ ਸਵੇਰੇ)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "ਸਰਗਰਮੀ ਨੂੰ ਕੱਲ੍ਹ ਵਾਲੀ ਨਾਲ ਸਬੰਧਿਤ ਗਿਣਿਆ ਜਾਵੇਗਾ, ਜੇ ਮੌਜੂਦਾ ਸਮਾਂ ਖਾਸ ਦਿਨ ਦੇ ਸ਼ੁਰੂ ਅਤੇ ਅੱਜਜ ਤੋਂ ਘੱਟ " "ਹੋਵੇਗਾ, ਜੇ ਇਹ ਸਮੇਂ ਤੋਂ ਵੱਧ ਹੈ। ਸਰਗਰਮੀਆਂ, ਜੋ ਦੋ ਦਿਨ ਲੈਂਦੀਆਂ ਹਨ, ਉੱਥੇ ਟਿੱਪ ਵਿੱਚ ਵੇਖਾਈਆਂ ਜਾਣਗੀਆਂ, ਜਿੱਥੇ " "ਸਰਗਰਮੀ ਦਾ ਸਭ ਤੋਂ ਵੱਡਾ ਭਾਗ ਹੁੰਦਾ ਹੈ।" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "ਕੀ ਵਰਕਸਪੇਸ ਬਦਲਣ ਨਾਲ ਐਕਟਿਵੀ ਬਦਲੀ ਜਾਵੇ" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "ਚਾਲੂ ਟਰੈਕਿੰਗ ਢੰਗਾਂ ਦੀ ਲਿਸਟ ਹੈ। \"ਨਾਂ\" workspace_mapping ਵਿੱਚ ਦਿੱਤੇ ਨਾਂ ਮੁਤਾਬਕ ਸਰਗਰਮੀ " "ਬਦਲਣਾ ਚਾਲੂ ਕਰੇਗਾ। \"ਮੈਮੋਰੀ\" ਪਿਛਲੀ ਵਰਕਸਪੇਸ ਵਿੱਚ ਜਾਣ ਸਮੇਂ ਆਖਰੀ ਸਰਗਰਮੀ ਲਈ ਬਦਲੇਗਾ।" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "ਵਰਕਸਪੇਸ ਬਦਲਣ ਨਾਲ ਸਰਗਰਮੀ ਬਦਲੋ" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "ਜੇ ਨਾਂ ਰਾਹੀਂ ਬਦਲਣਾ ਚਾਲੂ ਕੀਤਾ ਤਾਂ, ਇਹ ਲਿਸਟ ਨੂੰ ਸਰਗਰਮੀ ਨਾਲ ਲਈ ਸੈੱਟ ਕੀਤਾ ਜਾਵੇਗਾ, ਜਿਸ ਲਈ " "ਬਦਲਣਾ ਹੈ, ਵਰਕਸਪੇਸ ਆਈਟਮ ਦੇ ਇੰਡੈਕਸ ਨਾਲ ਦਰਸਾਇਆ ਜਾਂਦਾ ਹੈ।" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "ਟਾਈਮ ਟਰੈਕਰ ਵਿੰਡੋ ਵੇਖੋ / ਓਹਲੇ ਕਰੋ" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "ਟਾਈਮ ਟਰੈਕਰ ਵਿੰਡੋ ਵੇਖਣ /ਓਹਲੇ ਕਰਨ ਲਈ ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ ਹੈ।" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "ਹਮਸਟਰ ਐਪਲੀਕੇਸ਼ਨ ਵਿੰਡੋ ਕਾਰਵਾਈ ਬਦਲੋ" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "ਹਮਸਟਰ ਐਪਲੀਕੇਸ਼ਨ ਵਿੰਡੋ ਦੀ ਦਿੱਖ ਬਦਲਣ ਵਾਲੀ ਕਮਾਂਡ ਹੈ।" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "ਹਮਸਟਰ ਐਪਲੀਕੇਸ਼ਨ ਵਿੰਡੋ ਬਦਲੋ" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "ਹਮਸਟਰ ਐਪਲੀਕੇਸ਼ਨ ਵਿੰਡੋ ਦੀ ਦਿੱਖ ਬਦਲੋ।" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "ਟਾਈਮ ਟਰੈਕਰ" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "ਪਰੋਜੈਕਟ ਹਮਸਟਰ - ਆਪਣਾ ਸਮਾਂ ਟਰੈਕ ਕਰੋ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "ਟਾਈਮ ਟਰੈਕਰ ਸਾਰ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "ਹਮਸਟਰ ਸਮਾਂ ਟਰੈਕਰ ਦੀ ਸਾਰ ਵਿੰਡੋ" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "ਅੰਕੜੇ ਵੇਖੋ" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "ਕੈਟਾਗਰੀਆਂ" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "ਸਰਗਰਮੀਆਂ" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "ਟੈਗ" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "ਇਸ ਅੰਤਰਾਲ ਲਈ ਕੋਈ ਡਾਟਾ ਨਹੀਂ" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "...ਰਿਪੋਰਟ ਸੰਭਾਲੋ" #: ../data/overview.ui.h:2 msgid "Day" msgstr "ਦਿਨ" #: ../data/overview.ui.h:3 msgid "Week" msgstr "ਹਫ਼ਤਾ" #: ../data/overview.ui.h:4 msgid "Month" msgstr "ਮਹੀਨਾ" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "ਸੰਖੇਪ — ਹਮਸਟਰ" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "ਸੰਖੇਪ(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "ਸਰਗਰਮੀ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "ਵੇਖੋ(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "ਕੁੱਲ" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "ਹਟਾਓ" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "ਨਵਾਂ ਸ਼ਾਮਲ" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "ਸੋਧ" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "ਟਾਈਮ ਟਰੈਕਰ ਪਸੰਦ" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "ਜਦੋਂ ਕੰਪਿਊਟਰ ਵੇਹਲਾ ਹੋਵੇ ਤਾਂ ਟਰੈਕਿੰਗ ਬੰਦ ਕਰੋ" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ਮੌਜੂਦਾ ਸਰਗਰਮੀ ਚੇਤੇ ਕਰਾਓ ਹਰੇਕ:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "ਨਵਾਂ ਦਿਨ ਸ਼ੁਰੂ ਹੁੰਦਾ ਹੈ" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "ਹੇਠ ਦਿੱਤੀ ਟੂ-ਡੂ ਲਿਸਟ ਵਰਤੋਂ, ਜੇ ਉਪਲੱਬਧ ਹੋਵੇ:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "ਐਂਟੀਗਰੇਸ਼ਨ" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "ਟਰੈਕਿੰਗ" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ਕੈਟਾਗਰੀਆਂ(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "ਕੈਟਾਗਰੀ ਲਿਸਟ" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "ਕੈਟਾਗਰੀ ਸ਼ਾਮਲ" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "ਕੈਟਾਗਰੀ ਹਟਾਓ" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "ਕੈਟਾਗਰੀ ਸੋਧ" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "ਸਰਗਰਮੀਆਂ(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "ਸਰਗਰਮੀ ਲਿਸਟ" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "ਸਰਗਰਮੀ ਸ਼ਾਮਲ" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "ਸਰਗਰਮੀ ਹਟਾਓ" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "ਸਰਗਰਮੀ ਸੋਧ" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "ਟੈਗ, ਜੋ ਆਟੋਮੈਟਿਕ-ਪੂਰਨ ਵਿੱਚ ਦਿਖਾਈ ਦੇਵੇ" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "ਕੈਟਾਗਰੀਆਂ ਅਤੇ ਟੈਗ" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "ਜਦੋਂ ਵਰਕਸਪੇਸ ਉੱਤੇ ਵਾਪਸ ਆਉਣਾ ਹੋਵੇ ਤਾਂ ਆਖਰੀ ਸਰਗਰਮੀ ਵੇਖੋ" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "ਜਦੋਂ ਵਰਕਸਪੇਸ ਵਿੱਚ ਬਦਲਣਾ ਹੋਵੇ ਤਾਂ ਨਵੀਂ ਸਰਗਰਮੀ ਚਾਲੂ ਕਰੋ:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "ਵਰਕਸਪੇਸ" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "ਦਿਨ:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "ਹਫ਼ਤਾ:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "ਮਹੀਨਾ:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "ਰੇਜ਼:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "ਲਾਗੂ ਕਰੋ" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "ਟਰੈਕਿੰਗ(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "ਪਹਿਲਾਂ ਸਰਗਰਮੀ ਸ਼ਾਮਲ" #: ../data/today.ui.h:4 msgid "Overview" msgstr "ਸੰਖੇਪ" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "ਅੰਕੜੇ" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "ਸੋਧ(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "ਮੱਦਦ(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "ਸਮੱਗਰੀ" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "ਟਰੈਕਿੰਗ ਰੋਕੋ(_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "ਬਦਲੋ(_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "ਟਰੈਕਿੰਗ ਰੋਕੋ(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "ਨਵੀਂ ਸਰਗਰਮੀ ਸ਼ੁਰੂ" #: ../data/today.ui.h:13 msgid "Today" msgstr "ਅੱਜ" #: ../data/today.ui.h:14 msgid "totals" msgstr "ਕੁੱਲ" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "ਸਾਰ ਵੇਖੋ" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "ਕੋਈ ਸਰਗਰਮੀ ਨਹੀਂ" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "ਕੈਟਾਗਰੀ" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "ਵੇਰਵਾ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "ਸ਼ੁਰੂ" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "ਖਤਮ" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "ਅੰਤਰਾਲ" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "ਕੈਟਾਗਰੀਆਂ" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "ਪਰੋਜੈਕਟ ਹਮਸਟਰ - ਆਪਣਾ ਸਮਾਂ ਟਰੈਕ ਕਰੋ" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "ਕਾਪੀਰਾਈਟ © ੨੦੦੭-੨੦੧੦ Toms Baugis ਅਤੇ ਹੋਰ" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "ਪਰੋਜੈਕਟ ਹਮਸਟਰ ਵੈੱਬਸਾਈਟ" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "ਟਾਈਮ ਟਰੈਕਰ ਬਾਰੇ" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "ਅਮਨਪਰੀਤ ਸਿੰਘ ਆਲਮ\n" "Punjabi Open Source Team\n" "http://www.satluj.com/" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "ਬਿਨਾਂ-ਲੜੀਬੱਧ" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "ਕੰਮ" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "ਖ਼ਬਰਾਂ ਪੜ੍ਹ ਰਿਹਾ/ਰਹੀ ਹੈ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "ਸਟਾਕ ਚੈੱਕ ਕਰ ਰਿਹਾ/ਰਹੀ ਹਾਂ" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "ਬਹੁਤ ਹੀ ਗੁਪਤ ਪਰੋਜੈੱਕਟ X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ਸੰਸਾਰ ਤਾਕਤ" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "ਦਿਨ ਤੋਂ ਦਿਨ" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "ਦੁਪਹਿਰ ਦਾ ਖਾਣਾ" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣ ਰਿਹਾ/ਰਹੀ ਹਾਂ" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "ਹੱਥ ਠੀਕ ਕਰ ਰਿਹਾ/ਰਹੀ ਹਾਂ" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "ਸਰਗਰਮੀ ਅੱਪਡੇਟ" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ਘੰਟੇ ਟਰੈਕਿੰਗ ਕੁੱਲ" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "ਕੋਈ ਨਹੀਂ" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "ਨਾਂ" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "ਨਵੀਂ ਕੈਟਾਗਰੀ" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "ਨਵੀਂ ਸਰਗਰਮੀ" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d ਮਿੰਟ" msgstr[1] "%(interval_minutes)d ਮਿੰਟ" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ਕਦੇ ਨਹੀਂ" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "ਸਰਗਰਮੀ" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "ਸ਼ੁਰੂ ਸਮਾਂ" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "ਅੰਤ ਸਮਾਂ" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "ਅੰਤਰਾਲ ਮਿੰਟ" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "ਕੈਟਾਗਰੀ" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "ਵੇਰਵਾ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ਟੈਗ" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s ਲਈ " "ਰਿਪੋਰਟ ਸਰਗਰਮੀ" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s ਲਈ ਰਿਪੋਰਟ ਸਰਗਰਮੀ" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s ਲਈ ਰਿਪੋਰਟ ਸਰਗਰਮੀ" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s ਲਈ ਰਿਪੋਰਟ ਸਰਗਰਮੀ" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "ਦਿਨ ਨਾਲ ਕੁੱਲ" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "ਸਰਗਰਮੀ ਲਾਗ" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "ਸਰਗਰਮੀਆਂ" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "ਕੈਟਾਗਰੀਆਂ" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "ਵਿਲੱਖਣ:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "ਮਿਤੀ" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "ਟੈਪਲੇਟ ਵੇਖੋ" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "ਤੁਸੀਂ ਇਸ ਨੂੰ %(home_folder)s ਵਿੱਚ ਆਪਣਾ ਵਰਜਨ ਸੰਭਾਲ ਕੇ ਅਣਡਿੱਠਾ ਕਰ ਸਕਦੇ ਹੋ" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "ਸਭ" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "ਅੰਕੜਿਆਂ ਤੋਂ ਕੋਈ ਵੀ ਡਾਟਾ ਤਿਆਰ ਨਹੀਂ ਹੋਇਆ ਹੈ।\n" "ਇੱਕ ਹਫ਼ਤਾ ਇਸ ਵਾਸਤੇ ਕਾਫ਼ੀ ਹੈ!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "ਹਾਲੇ ਵੀ ਡਾਟਾ ਲਿਆ ਜਾ ਰਿਹਾ ਹੈ — ਹਫ਼ਤੇ ਦੇ ਬਾਅਦ ਚੈੱਕ ਕਰੋ!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "%s ਉੱਤੇ ਪਹਿਲੀ ਸਰਗਰਮੀ ਵੇਖੀ ਗਈ।" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ਸਾਲ" msgstr[1] "%(num)s ਸਾਲ" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ਹੁਣ ਤੱਕ ਟਰੈਕ ਕੀਤਾ ਸਮਾਂ %(human_days)s ਇਨਸਾਨੀ ਸਾਲ (%(human_years)s) ਜਾਂ " "%(working_days)s ਵਰਕਿੰਗ ਦਿਨ (%(working_years)s) ਹਨ।" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "ਸਭ ਤੋਂ ਲੰਮਾ ਲਗਾਤਾਰ ਕੰਮ %(date)s ਨੂੰ ਹੋਇਆ ਅਤੇ %(hours)s ਘੰਟਾ ਲੰਮਾ ਹੈ।" msgstr[1] "ਸਭ ਤੋਂ ਲੰਮਾ ਲਗਾਤਾਰ ਕੰਮ %(date)s ਨੂੰ ਹੋਇਆ ਅਤੇ %(hours)s ਘੰਟੇ ਚੱਲਿਆ।" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s ਰਿਕਾਰਡ ਹੈ" msgstr[1] "%s ਰਿਕਾਰਡ ਹਨ।" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "ਹਮਸਟਰ ਤੁਹਾਡਾ ਕੁਝ ਹੋਰ ਧਿਆਨ ਰੱਖਣਾ ਚਾਹੁੰਦਾ ਹੈ!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "ਸਭ ਸਰਗਰਮੀਆਂ ਵਿੱਚੋਂ %s ਫੀਸਦੀ ਸਵੇਰੇ 9 ਵਜੇ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ੁਰੂ ਹੁੰਦੀਆਂ ਹਨ, ਤੁਸੀਂ ਤਾਂ ਸਵੇਰੇ ਸਵੇਰੇ ਕੰਮ ਕਰਨ " "ਵਾਲੇ ਹੋ।" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "ਸਭ ਸਰਗਰਮੀਆਂ ਵਿੱਚੋਂ %s ਫੀਸਦੀ ਆਥਣੇ 11 ਵਜੇ ਤੋਂ ਪਹਿਲਾਂ ਸ਼ੁਰੂ ਹੁੰਦੀਆਂ ਹਨ, ਤੁਸੀਂ ਤਾਂ ਰਾਤ ਨੂੰ ਜਾਣ ਵਾਲੇ ਹੋ।" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "ਸਭ ਸਰਗਰਮੀਆਂ ਵਿੱਚੋਂ %s ਫੀਸਦੀ 15 ਮਿੰਟ ਤੋਂ ਛੋਟੀਆਂ ਹਨ, ਤੁਸੀਂ ਬਹੁਤ ਹੀ ਰੁੱਝੇ ਹੋਏ ਲੱਗਦੇ ਹੋ।" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ਅੱਜ ਕੋਈ ਰਿਕਾਰਡ ਨਹੀਂ" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "ਹਾਲੇ ਸ਼ੁਰੂ ਹੀ ਹੋਇਆ" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "ਰਿਪੋਰਟ ਸੰਭਾਲੋ — ਟਾਈਮ ਟਰੈਕਰ" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML ਰਿਪੋਰਟ" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "ਟੈਬ ਨਾਲ ਵੱਖ ਮੁੱਲ (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "ਟਾਈਮ ਟਰੈਕਰ" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "ਸਰਗਰਮ ਵਿੰਡੋ ਵੇਖੋ" #~ msgid "Sto_p Tracking" #~ msgstr "ਟਰੈਕਿੰਗ ਰੋਕੋ(_p)" #~ msgid "To_day" #~ msgstr "ਅੱਜ(_d)" #~ msgid "_Add earlier activity" #~ msgstr "ਪਹਿਲਾਂ ਸਰਗਰਮੀ ਸ਼ਾਮਲ(_A)" #~ msgid "Show _Overview" #~ msgstr "ਸੰਖੇਪ ਵੇਖੋ(_O)" #~ msgid "_Preferences" #~ msgstr "ਮੇਰੀ ਪਸੰਦ(_P)" #~ msgid "_About" #~ msgstr "ਇਸ ਬਾਰੇ(_A)" #~ msgid "Year:" #~ msgstr "ਸਾਲ:" #~ msgid "Starts and ends" #~ msgstr "ਸ਼ੁਰੂ ਅਤੇ ਸਮਾਪਤ" #~ msgid "Preferences" #~ msgstr "ਮੇਰੀ ਪਸੰਦ" #~ msgid "Changed activity" #~ msgstr "ਸਰਗਰਮੀ ਬਦਲੋ" #~ msgid "Switched to '%s'" #~ msgstr "'%s' ਉੱਤੇ ਜਾਓ" #~ msgid "Working on %s" #~ msgstr "%s ਉੱਤੇ ਕੰਮ ਜਾਰੀ" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "ਹਮਸਟਰ ਟਾਈਮ ਟਰੈਕਰ। ਵਰਤੋਂ:" #~| msgid "Project Hamster (Gnome Time Tracker)" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "ਪਰੋਜੈਕਟ ਹਮਸਟਰ (ਗਨੋਮ ਸਮਾਂ ਟਰੈਕਰ)" #~ msgid "Ad_d Earlier Activity" #~ msgstr "ਪਹਿਲਾਂ ਸਰਗਰਮੀ ਸ਼ਾਮਲ(_d)" #~ msgid "Tell me more" #~ msgstr "ਮੈਨੂੰ ਹੋਰ ਦੱਸੋ" #~ msgid "_Today" #~ msgstr "ਅੱਜ(_T)" #~ msgid "Preview:" #~ msgstr "ਝਲਕ:" #~ msgid "General" #~ msgstr "ਆਮ" #~| msgid "Global Hotkey" #~ msgid "Global Hotkey" #~ msgstr "ਗਲੋਬਲ ਹਾਟ-ਕੀ" #~ msgid "Move activity down" #~ msgstr "ਸਰਗਰਮੀ ਹੇਠਾਂ ਭੇਜੋ" #~ msgid "Move activity up" #~ msgstr "ਸਰਗਰਮੀ ਉੱਤੇ ਭੇਜੋ" #~ msgid "Total Time" #~ msgstr "ਕੁੱਲ ਸਮਾਂ" #~ msgid "Activities" #~ msgstr "ਸਰਗਰਮੀਆਂ" #~ msgid "Tracking" #~ msgstr "ਟਰੈਕਿੰਗ" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "ਸਰਗਰਮੀ ਲਿਖੋ ਅਤੇ ਟਰੈਕ ਕਰਨਾ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਐਂਟਰ ਦੱਬੋ।!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "ਹੋਰ ਚੇਤੇ ਕਰਵਾਉ" #~ msgid "Hamster" #~ msgstr "ਹਮਸਟਰ" #~ msgid "_Activity:" #~ msgstr "ਸਰਗਰਮੀ(_A):" #~ msgid " _Day" #~ msgstr "ਦਿਨ(_D)" #~ msgid " _Month" #~ msgstr "ਮਹੀਨਾ(_M)" #~ msgid " _Week" #~ msgstr "ਹਫ਼ਤਾ(_W)" #~ msgid "Overview" #~ msgstr "ਸੰਖੇਪ" #~ msgid "Totals" #~ msgstr "ਕੁੱਲ" #~ msgid "Categories:" #~ msgstr "ਕੈਟਾਗਰੀਆਂ:" #~ msgid "Date interval:" #~ msgstr "ਮਿਤੀ ਅੰਤਰਾਲ:" #~ msgid "Save as HTML" #~ msgstr "HTML ਵਾਂਗ ਸੰਭਾਲੋ" #~ msgid "What should be typed in the activity box?" #~ msgstr "ਸਰਗਰਮੀ ਬਾਕਸ ਵਿੱਚ ਕੀ ਲਿਖਣਾ ਹੈ?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "ਇੱਕ ਸੰਟੈਕਸ ਉਦਾਹਰਨ ਹੈ, ਜੋ ਕਿ ਤੁਹਾਨੂੰ ਤੁਹਾਡੀਆਂ ਸਰਗਰਮੀਆਂ ਲਈ ਵੇਰਵਾ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਸਹਾਇਕ ਹੈ:\n" #~ " \n" #~ "\"@\" ਨਿਸ਼ਾਨ ਕੈਟਾਗਰੀ ਨਿਸ਼ਾਨਬੱਧ ਕਰਦਾ ਹੈ। ਜਿਵੇਂ ਕਿ \"@ਘਰ ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣਾ\" ਨਾਲ \"ਘਰ" #~ "\" ਕੈਟਾਗਰੀ ਵਿੱਚ \"ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣਾ\" ਸਰਗਰਮੀ ਟਰੈਕ ਕੀਤੀ ਜਾਵੇਗੀ।\n" #~ "\n" #~ "ਕੌਮਾ (\",\" ਵੇਰਵਾ ਸ਼ੁਰੂ ਕਰਨ ਦਾ ਨਿਸ਼ਾਨ ਹੈ। ਜਿਵੇਂ ਕਿ: \"ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣਾ, ਬੋਗਵੀਲੀਆ ਅਤੇ " #~ "ਗੁਲਾਬ ਨੂੰ\" ਨਾਲ \"ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣਾ\" ਸਰਗਰਮੀ ਸ਼ੁਰੂ ਹੋਵੇਗੀ ਅਤੇ \"ਬੋਗਵੀਲੀਆ ਅਤੇ ਗੁਲਾਬ\" ਇਸ " #~ "ਲਈ ਵੇਰਵਾ ਹੋਵੇਗਾ।\n" #~ "\n" #~ "ਦੋਵਾਂ ਨੂੰ ਇੱਕਠਾ ਜੋੜਿਆ ਵੀ ਜਾ ਸਕਦਾ ਹੈ: \"@ਘਰ ਫੁੱਲਾਂ ਨੂੰ ਪਾਣੀ ਦੇਣਾ, ਬੋਗਵੀਲੀਆ ਅਤੇ ਗੁਲਾਬ\" ਠੀਕ " #~ "ਤਰ੍ਹਾਂ ਕੰਮ ਕਰਨਗੇ!\n" #~ "\n" #~ "ਹੁਣ ਟਰੈਕਿੰਗ ਸ਼ੁਰੂ ਕਰੋ!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "ਸਭ" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "ਕੁੱਲ" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s ਲਈ ਸੰਖੇਪ" #~ msgid "Remind also when no activity is set" #~ msgstr "ਜਦੋਂ ਕੋਈ ਸਰਗਰਮੀ ਸੈੱਟ ਨਾ ਹੋਵੇ ਤਾਂ ਵੀ ਚੇਤੇ ਕਰਵਾਓ" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "Move _Down" #~ msgstr "ਹੇਠਾਂ ਭੇਜੋ(_D)" #~ msgid "Move _Up" #~ msgstr "ਉੱਤੇ ਭੇਜੋ(_U)" #~ msgid "N_ew Category" #~ msgstr "ਨਵੀਂ ਕੈਟਾਗਰੀ(_e)" #~ msgid "_New Activity" #~ msgstr "ਨਵੀਂ ਸਰਗਰਮੀ(_N)" #~ msgid "Activity" #~ msgstr "ਸਰਗਰਮੀ" #~ msgid "hours" #~ msgstr "ਘੰਟੇ" #~ msgid "Category" #~ msgstr "ਕੈਟਾਗਰੀ" #~ msgid "Week" #~ msgstr "ਹਫ਼ਤਾ" #~ msgid "Delete activity" #~ msgstr "ਸਰਗਰਮੀ ਹਟਾਓ" #~ msgid "Earlier activities" #~ msgstr "ਪੁਰਾਣੀਆਂ ਸਰਗਰਮੀਆਂ" #~ msgid "Newer activities" #~ msgstr "ਨਵੀਆਂ ਸਰਗਰਮੀਆਂ" #~ msgid "Show day" #~ msgstr "ਦਿਨ ਵੇਖੋ" #~ msgid "Show month" #~ msgstr "ਮਹੀਨਾ ਵੇਖੋ" #~ msgid "name" #~ msgstr "ਨਾਂ" #~ msgid "Other" #~ msgstr "ਹੋਰ" hamster-3.0.3/po/pl.po000066400000000000000000000630031452646177100145700ustar00rootroot00000000000000# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # Aviary.pl # Jeśli masz jakiekolwiek uwagi odnoszące się do tłumaczenia lub chcesz # pomóc w jego rozwijaniu i pielęgnowaniu, napisz do nas: # gnomepl@aviary.pl # -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- # Tomasz Dominikowski , 2008-2009. # Łukasz Jernaś , 2009. # Piotr Drąg , 2010-2012. # Aviary.pl , 2008-2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-09-04 01:58+0200\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" "X-Poedit-Language: Polish\n" "X-Poedit-Country: Poland\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Dodaj wcześniejszą czynność" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "do" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "w trakcie" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Opis:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Czas:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Czynność:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etykiety:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Zatrzymanie czasu podczas bezczynności" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Zatrzymanie śledzenia bieżącej czynności podczas bezczynności komputera" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Zatrzymanie śledzenia przy wyłączeniu komputera" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Zatrzymanie śledzenia bieżącej czynności przy wyłączeniu komputera" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Przypominanie o bieżącej czynności co x minut" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Przypominanie o bieżącej czynności co określoną liczbę minut. Ustawienie " "wartości na 0 lub więcej niż 120, wyłącza przypominanie." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Przypominanie również, gdy nie ustawiono żadnej czynności" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Przypominanie co notify_interval minut nawet, jeśli nie uruchomiono żadnej " "czynności." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Kiedy powinien rozpoczynać się dzień (domyślnie o 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Czynności będą liczone jako należące do dnia poprzedniego, jeśli bieżący " "czas jest wcześniejszy niż określony czas rozpoczęcia danego dnia, a jako " "należące do dnia dzisiejszego, jeśli ten czas minął. Czynności rozdzielone " "na dwa dni będą przesuwane na ten dzień, w którym odbyło się większość czasu " "czynności." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" "Określa, czy przełączenie obszaru roboczego wywołuje przełączenie czynności" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista włączonych metod śledzenia. Wartość \"name\" włączy przełączanie " "czynności według nazwy określonej w kluczu \"workspace_mapping\". Wartość " "\"memory\" włączy przełączanie na ostatnią czynność podczas powracania na " "poprzedni obszar roboczy." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Przełączenie czynności po zmianie obszaru roboczego" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Jeśli włączone jest przełączanie według nazwy, to ta lista ustawia nazwy " "czynności, na które można się przełączyć, z obszarem roboczym prezentowanym " "przez indeks elementów." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Wyświetlanie/ukrywanie okna zarządzania czasem" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Skrót klawiszowy do wyświetlenia/ukrywania okna zarządzania czasem." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Przełączenie czynności okna programu Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Polecenie do przełącznika widoczności okna programu Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Przełączenie okna programu Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Przełączenie widoczności okna programu Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Zarządzanie czasem" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster - zarządzanie czasem" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Okno podglądu zarządzania czasem" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Okno podglądu programu do zarządzania czasem Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Wyświetl statystyki" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorie" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Czynności" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etykiety" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Brak danych dla tego przedziału czasowego" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Zapisz sprawozdanie..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dzień" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Tydzień" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Miesiąc" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Przegląd — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Przegląd" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Czynność" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Widok" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Ogółem" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Usuń" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Dodaj nową" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Zmodyfikuj" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferencje programu zarządzania czasem" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Zatrzymanie śledzenia podczas bezczynności komputera" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Przypominanie o bieżącej czynności co:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Nowy dzień rozpoczyna się o" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Użycie następującej listy czynności do wykonania, jeśli jest dostępna:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integracja" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Śledzenie" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorie" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Lista kategorii" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Dodaje kategorię" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Usuwa kategorię" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Modyfikuje kategorię" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Czynności" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Lista czynności" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Dodaje czynność" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Usuwa czynność" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Modyfikuje czynność" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" "Etykiety, które powinny pojawiać się podczas automatycznego uzupełniania" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorie i etykiety" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Wznawia ostatnią czynność po powrocie do obszaru roboczego" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Rozpoczyna nową czynność podczas przełączania obszarów roboczych:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Obszary robocze" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dzień:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Tydzień:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Miesiąc:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Zakres:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Zastosuj" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Śl_edzenie" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Dodaj wcześniejszą czynność" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Przegląd" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statystyki" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Edycja" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Pomo_c" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Spis treści" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Zatrzymaj śledzenie" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Przełącz" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Rozpocznij śledzenie" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Rozpocznij nową czynność" #: ../data/today.ui.h:13 msgid "Today" msgstr "Dzisiaj" #: ../data/today.ui.h:14 msgid "totals" msgstr "ogółem" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Wyświetl podgląd" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Brak czynności" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Opis" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Rozpoczęcie" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Zakończenie" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Czas trwania" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorie" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekt Hamster — zarządzanie czasem" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis i inni" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Witryna programu Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "O programie do zarządzania czasem" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Tomasz Dominikowski , 2008-2009\n" "Łukasz Jernaś , 2009\n" "Piotr Drąg , 2010-2012\n" "Aviary.pl , 2008-2012" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Bez sortowania" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Praca" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Czytanie wiadomości" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Sprawdzanie notowań giełdowych" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Supertajny projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominacja nad światem" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dzień za dniem" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Obiad" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Podlewanie kwiatów" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stanie na rękach" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Aktualizowanie czynności" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Ogółem prześledzono %s godzin" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Brak" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nazwa" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nowa kategoria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nowa czynność" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuta" msgstr[1] "%(interval_minutes)d minuty" msgstr[2] "%(interval_minutes)d minut" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nigdy" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "czynność" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "początek" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "koniec" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "czas trwania w minutach" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "opis" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etykiety" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Raport czynności dla %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Raport czynności dla %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Raport czynności dla %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Raport czynności dla %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Ogółem według dni" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Dziennik czynności" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "czynności" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorie" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Rozróżnienie:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Wyświetlanie szablonu" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Można go zastąpić przez umieszczenie swojej wersji w %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Wszystkie" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Brak wystarczającej ilości danych do wygenerowania statystyk.\n" "Potrzeba przynajmniej tygodnia danych." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" "Zbieranie danych — proszę zajrzeć tutaj ponownie po upływie jednego tygodnia." #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Data zarejestrowania pierwszej czynności: %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s rok" msgstr[1] "%(num)s lata" msgstr[2] "%(num)s lat" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Do chwili obecnej prześledzono czynności o łącznym czasie trwania " "%(human_days)s dni (%(human_years)s) lub %(working_days)s dni roboczych " "(%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Najdłuższa czynność została odnotowana dnia %(date)s i trwała %(hours)s " "godzinę." msgstr[1] "" "Najdłuższa czynność została odnotowana dnia %(date)s i trwała %(hours)s " "godziny." msgstr[2] "" "Najdłuższa czynność została odnotowana dnia %(date)s i trwała %(hours)s " "godzin." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Odnaleziono %s zapis." msgstr[1] "Odnaleziono %s zapisy." msgstr[2] "Odnaleziono %s zapisów." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Program Hamster musi zebrać więcej danych." #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Jako że %s procent wszystkich czynności rozpoczyna się przed 9 rano, więc " "użytkownik wydaje się być rannym ptaszkiem." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Jako że %s procent wszystkich czynności zaczyna się po 11 popołudniu, więc " "użytkownik wydaje się być nocnym markiem." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Jako że %s procent wszystkich czynności jest krótsza niż 15 minut, więc " "użytkownik wydaje się być pracowitą pszczółką." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Brak zapisów na dzisiaj" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Dopiero rozpoczęto" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Zapisywanie sprawozdania — zarządzanie czasem" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Raport w formacie HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Wartości oddzielone znakami tabulatora (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Zarządzanie czasem" #~ msgid "Show activities window" #~ msgstr "Wyświetlanie okna czynności" #~ msgid "Sto_p Tracking" #~ msgstr "_Zatrzymaj śledzenie" #~ msgid "To_day" #~ msgstr "_Dzisiaj" #~ msgid "_Add earlier activity" #~ msgstr "Dod_aj wcześniejszą czynność" #~ msgid "Show _Overview" #~ msgstr "Wyświetl p_odgląd" #~ msgid "_Preferences" #~ msgstr "P_referencje" #~ msgid "_About" #~ msgstr "_O programie" #~ msgid "Year:" #~ msgstr "Rok:" #~ msgid "Starts and ends" #~ msgstr "Rozpoczęcia i zakończenia" #~ msgid "Preferences" #~ msgstr "Preferencje" #~ msgid "Changed activity" #~ msgstr "Zmieniono czynność" #~ msgid "Switched to '%s'" #~ msgstr "Przełączono na \"%s\"" #~ msgid "Working on %s" #~ msgstr "Wykonywana czynność: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Program do zarządzania czasem Hamster. Użycie:" hamster-3.0.3/po/pt.po000066400000000000000000000722471452646177100146120ustar00rootroot00000000000000# hamster-time-tracker's Portuguese translation. # Copyright © 2008, 2009, 2010, 2011, 2012 hamster-time-tracker # This file is distributed under the same license as the hamster-time-tracker package. # Duarte Loreto , 2008, 2009, 2010, 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: 3.4\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-15 00:05+0000\n" "Last-Translator: Duarte Loreto \n" "Language-Team: Portuguese \n" "Language: pt\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Adicionar Actividade Anterior" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "para" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "em curso" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descrição:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Hora:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Actividade:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetas:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Parar de registar ao ficar inactivo" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Parar de registar a actividade actual quando o computador ficar inactivo" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Parar de registar ao desligar" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Parar de registar a actividade actual ao desligar" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Recordar a tarefa actual a cada x minutos" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Recordar a tarefa actual repetidamente a cada determinado número de minutos. " "Definir como 0 ou maior do que 120 para desactivar o lembrete." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Recordar também quando não estiver nenhuma actividade definida" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Recordar também a cada notify_interval minutos caso não esteja nenhuma " "actividade iniciada." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "A que horas começa o dia (por omissão às 5h30 da manhã)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "As actividades serão contabilizadas como pertencendo a ontem se a data " "actual for inferior ao início do dia; e a hoje se já passar dessa hora. " "Actividades que se prolonguem durante dois dias serão consideradas no dia em " "que ocorrer mais tempo de actividade." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" "Deverá a alteração da área de trabalho causar uma alteração de actividade" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista dos métodos de registo activos. \"name\" irá activar a alternância de " "actividades por nome definido na chave workspace_mapping. \"memory\" permite " "a alternância para a última actividade ao regressar a uma área de trabalho " "anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Alterar a actividade ao alternar de área de trabalho" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Se estiver activa a alternância manual, esta lista define os nomes das " "actividades para as quais se deveria alternar, áreas de trabalho " "representadas pelo índice no item." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Apresentar / esconder a Janela de Registo de Horas." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Atalho de teclado para apresentar / esconder a janela do Registo de Horas." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Alternar a acção da janela da aplicação hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Comando para alternar a visibilidade da janela da aplicação hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Alternar a janela da aplicação hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Alternar a visibilidade da janela da aplicação hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Registo de Horas" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projecto Hamster - registe as suas horas" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Resumo do Registo de Horas" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "A janela de resumo do registo de horas no hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Apresentar Estatísticas" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorias" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Actividades" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetas" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nenhuns dados para este intervalo" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Gravar relatório..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dia" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Semana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mês" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Resumo — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Resumo" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Actividade" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Ver" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totais" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Remover" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Adicionar nova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editar" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferências do Registo de Horas" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Parar de registar quando o computador estiver inactivo" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Recordar a actividade actual a cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Novo dia inicia-se às" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Utilizar a seguinte lista de tarefas, se disponível:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integração" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Registo" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categorias" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Lista de categorias" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Adicionar categoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Remover a categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editar categoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Actividades" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Lista de actividades" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Adicionar actividade" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Remover a actividade" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editar actividade" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etiquetas que deveriam surgir no completar automaticamente" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorias e Etiquetas" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Retomar a última actividade ao regressar a uma área de trabalho" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Iniciar uma nova actividade ao alternar áreas de trabalho:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Áreas de Trabalho" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dia:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Semana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mês:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervalo:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplicar" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Registar" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Adicionar actividade anterior" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Resumo" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estatísticas" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editar" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Ajuda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Conteúdo" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Parar de registar" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Alterar" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Iniciar o _Registo" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Iniciar uma nova actividade" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hoje" #: ../data/today.ui.h:14 msgid "totals" msgstr "totais" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Apresentar o Resumo" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Nenhuma actividade" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descrição" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Início" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Final" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duração" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorias" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projecto Hamster — registe as suas horas" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis e outros" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Página do Projecto Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Sobre o Registo de Horas" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Duarte Loreto " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Não ordenado" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Trabalho" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Ler notícias" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Verificar mercados financeiros" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Projecto super secreto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominar o mundo" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dia-a-dia" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Almoço" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regar as plantas" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Fazer elevações" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualizar actividade" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B de %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s de %(start_B)s de %(start_Y)s – %(end_d)s de %(end_B)s de " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s de %(start_B)s – %(end_d)s de %(end_B)s de %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s de %(start_B)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s horas registadas no total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nenhuma" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nome" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova categoria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova actividade" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minutos" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nunca" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "actividade" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hora de início" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "hora de término" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "duração em minutos" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descrição" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetas" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Resumo de actividade para %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Resumo de actividade para %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Resumo de actividade para %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Resumo de actividade para %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totais por Dia" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Registo de Actividade" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "actividades" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorias" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinção:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Apresentar modelo" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Pode substituí-lo armazenando a sua versão em %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Todos" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Ainda não existem dados para gerar estatísticas.\n" "Seria aconselhável uma semana de utilização!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "A reunir dados — verifique novamente após decorrer uma semana!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d de %b de %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "A primeira actividade foi gravada a %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ano" msgstr[1] "%(num)s anos" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "O tempo registado até agora ascende a %(human_days)s dias humanos " "(%(human_years)s) ou %(working_days)s dias úteis (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "A actividade contínua mais extensa ocorreu a %(date)s e durou %(hours)s hora." msgstr[1] "" "A actividade contínua mais extensa ocorreu a %(date)s e durou %(hours)s " "horas." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Existe %s registo." msgstr[1] "Existem %s registos." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "O Hamster gostaria de o observar um pouco mais!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Com %s porcento de todas as actividades a começar antes das 9h da manhã, " "parece ser madrugador." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Com %s porcento de todas as actividades a começar depois das 23h, parece ser " "noctívago." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Com %s porcento de todas as actividades a durarem menos de 15 minutos, " "parece ter dias agitados." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Nenhum registo hoje" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Iniciado agora" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Gravar Relatório – Registo de Horas" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Relatório HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valores Separados por Tabulador (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Registo de horas" #~ msgid "Show activities window" #~ msgstr "Apresentar a janela de actividades" #~ msgid "Sto_p Tracking" #~ msgstr "_Parar de Registar" #~ msgid "To_day" #~ msgstr "_Hoje" #~ msgid "_Add earlier activity" #~ msgstr "_Adicionar actividade anterior" #~ msgid "Show _Overview" #~ msgstr "Apresentar o _Resumo" #~ msgid "_Preferences" #~ msgstr "_Preferências" #~ msgid "_About" #~ msgstr "_Sobre" #~ msgid "Year:" #~ msgstr "Ano:" #~ msgid "Starts and ends" #~ msgstr "Inicia-se e termina" #~ msgid "Preferences" #~ msgstr "Preferências" #~ msgid "Changed activity" #~ msgstr "Actividade alterada" #~ msgid "Switched to '%s'" #~ msgstr "Alternada para '%s'" #~ msgid "Working on %s" #~ msgstr "A trabalhar em %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Registo de horas Hamster. Utilização:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projecto Hamster (Registo de Horas do GNOME)" #~ msgid "totals by activity" #~ msgstr "totais por actividade" #~ msgid "totals by category" #~ msgstr "totais por categoria" #~ msgid "Show:" #~ msgstr "Apresentar:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "A_dicionar Actividade Anterior" #~ msgid "Tell me more" #~ msgstr "Quero saber mais" #~ msgid "_Today" #~ msgstr "_Hoje" #~ msgid "Preview:" #~ msgstr "Antever:" #~ msgid "General" #~ msgstr "Geral" #~ msgid "Global Hotkey" #~ msgstr "Tecla de Atalho Global" #~ msgid "Move activity down" #~ msgstr "Mover a actividade abaixo" #~ msgid "Move activity up" #~ msgstr "Mover a actividade acima" #~ msgid "Total Time" #~ msgstr "Tempo Total" #~ msgid "Activities" #~ msgstr "Actividades" #~ msgid "Tracking" #~ msgstr "Registo" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Introduza uma actividade e prima Enter para começar " #~ "a acompanhá-la!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Desejo saber " #~ "mais" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Actividade:" #~ msgid " _Day" #~ msgstr " _Dia" #~ msgid " _Month" #~ msgstr " _Mês" #~ msgid " _Week" #~ msgstr " _Semana" #~ msgid "Overview" #~ msgstr "Resumo" #~ msgid "Totals" #~ msgstr "Totais" #~ msgid "Categories:" #~ msgstr "Categorias:" #~ msgid "Date interval:" #~ msgstr "Intervalo de datas:" #~ msgid "Save as HTML" #~ msgstr "Gravar como HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "O que deverá ser introduzido na caixa de actividade?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Existe uma sintaxe simples que lhe permite adicionar detalhes às suas " #~ "actividades:\n" #~ " \n" #~ "O símbolo \"@\" marca a categoria. Por exemplo: \"regar as flores@casa\" " #~ "irá iniciar o registo da actividade \"regar as flores\" na categoria " #~ "\"casa\".\n" #~ "\n" #~ "Vírgulas (\",\") marcam o início de uma descrição. or exemplo: \"regar as " #~ "flores. begónias e malmequeres\" irá iniciar o registo da actividade " #~ "\"regar as flores\" e adicionar-lhe a descrição \"begónias e malmequeres" #~ "\".\n" #~ "\n" #~ "Ambas podem ser combinadas: \"regar as flores@casa, begónias e malmequeres" #~ "\" irá funcionar correctamente!\n" #~ "\n" #~ "Agora, comece a registar!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Todas" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Resumo de %(date)s" #~ msgid "Move _Down" #~ msgstr "Mover _Abaixo" #~ msgid "Move _Up" #~ msgstr "Mover Aci_ma" #~ msgid "N_ew Category" #~ msgstr "Nov_a Categoria" #~ msgid "_New Activity" #~ msgstr "_Nova Actividade" #~ msgid "Activity" #~ msgstr "Actividade" #~ msgid "hours" #~ msgstr "horas" #~ msgid "Category" #~ msgstr "Categoria" #~ msgid "Week" #~ msgstr "Semana" #~ msgid "Delete activity" #~ msgstr "Apagar actividade" #~ msgid "Earlier activities" #~ msgstr "Actividades anteriores" #~ msgid "Newer activities" #~ msgstr "Actividades mais recentes" #~ msgid "Show month" #~ msgstr "Apresentar o mês" #~ msgid "name" #~ msgstr "nome" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #~ msgid "Other" #~ msgstr "Outro" #~ msgid "Time tracking for masses" #~ msgstr "Registo do tempo dispendido acessível a qualquer um" #~ msgid "Time tracking for masses." #~ msgstr "Registo do tempo dispendido acessível a qualquer um." #~ msgid "Overview for %s - %s" #~ msgstr "Resumo de %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%d.%m.%y" #~ msgid "%d. %b" #~ msgstr "%d. %b" #~ msgid "%B %d." #~ msgstr "%B %d." hamster-3.0.3/po/pt_BR.po000066400000000000000000000724741452646177100151770ustar00rootroot00000000000000# Brazilian Portuguese Translation of Hamster Applet # This file is distributed under the same license as the hamster-time-tracker package. # Copyright (C) 2008 Free Software Foundation, Inc. # Enrico Nicoletto , 2008. # Henrique P. Machado , 2008, 2009. # Leonardo Ferreira Fontenelle , 2008. # Vladimir Melo , 2009. # Djavan Fagundes , 2009. # Fábio Nogueira , 2009. # Daniel S. Koda , 2010. # Og Maciel , 2010-2011. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-14 18:36-0300\n" "Last-Translator: Antonio Fernandes C. Neto \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Adicionar atividade anterior" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "para" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "em curso" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descrição:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Hora:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Atividade:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiquetas:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Para de registrar quando ocioso" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Para o registro da atividade atual, quando o computador estiver ocioso" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Para de registrar ao desligar" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Para o registro da atividade atual ao desligar" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Lembra da tarefa atual a cada x minutos" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Lembra da tarefa atual em períodos especificados em minutos. Defina como 0 " "ou mais de 120 para desabilitar o notificador." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Lembrar também quando não houver atividade definida" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Lembrar também a cada notify_interval em minutos se não houver atividade " "iniciada." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "A que hora o dia inicia (padrão para 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Atividades serão contadas como se pertencessem a ontem se o horário atual " "for anterior ao início do dia especificado; e a hoje, se for depois desse " "horário. Atividades que durem dois dias serão colocadas no lado onde a maior " "parte das atividades estiver." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "A troca do espaço de trabalho deve acionar troca de atividade" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista dos métodos de registro habilitados. \"name\" habilitará a troca de " "atividades por nome definidas no workspace_mapping. \"memory\" habilitará a " "troca para a última atividade ao retornar para o espaço de trabalho anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Troca atividade ao alterar o espaço de trabalho" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Se a troca por nomes estiver habilitada, esta lista define os nomes das " "atividades para as quais devem ser trocadas, com os espaços de trabalho " "representados pelo índice do item." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Mostra / oculta a janela do gestor de tempo" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Atalho de teclado para mostrar / ocultar a janela do gestor de tempo." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Alterna a ação da janela do aplicativo hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Comando para alternar a visibilidade da janela do aplicativo hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Alterna a janela do aplicativo hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Alterna a visibilidade da janela do aplicativo hamster" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Gestor de tempo" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projeto Hamster - gerencie seu tempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Visão geral do gestor de tempo" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Janela da visão geral do gestor de tempo hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Mostrar estatísticas" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorias" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Atividades" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiquetas" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nenhum dado para este intervalo" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Salvar relatório..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dia" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Semana" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mês" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Visão geral — Hamster" # Visão Geral ou Resumo. #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Visão geral" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Atividade" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Ver" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totais" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Remover" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Adicionar nova" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editar" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferências do Gestor de tempo" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Parar de registrar quando o computador estiver ocioso" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Lembrar da atividade atual a cada:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Novo dia inicia às" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Usar a seguinte lista de afazeres se estiver disponível:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integração" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Registrando" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categorias" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Lista de categorias" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Adicionar categoria" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Remover categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editar categoria" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Atividades" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Lista de atividades" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Adicionar atividade" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Remover atividade" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editar atividade" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etiquetas que devem aparecer em auto-completar" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorias e etiquetas" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Continuar a última atividade ao retornar para um espaço de trabalho" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Iniciar nova atividade ao trocar o espaço de trabalho:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Espaços de trabalho" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dia:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Semana:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mês:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervalo:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplicar" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Registrando" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Adicionar atividade anterior" # Visão Geral ou Resumo. #: ../data/today.ui.h:4 msgid "Overview" msgstr "Visão geral" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Estatísticas" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editar" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Aj_uda" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Conteúdos" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Pa_rar registro" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Trocar" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Iniciar re_gistro" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Iniciar nova atividade" #: ../data/today.ui.h:13 msgid "Today" msgstr "Hoje" #: ../data/today.ui.h:14 msgid "totals" msgstr "totais" # Visão Geral ou Resumo. #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Mostrar visão geral" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Sem atividade" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descrição" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Início" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Término" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Duração" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorias" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projeto Hamster — gerencie seu tempo" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2010 Toms Bauģis e outros" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Site do projeto Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Sobre o Gestor de tempo" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Enrico Nicoletto \n" "Henrique P. Machado \n" "Leonardo Ferreira Fontenelle \n" "Vladimir Melo \n" "Djavan Fagundes \n" "Fábio Nogueira \n" "Daniel S. Koda " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sem classificação" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Trabalho" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Ler as notícias" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Verificar ações" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Projeto super secreto X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dominar o mundo" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dia-a-dia" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Almoçar" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Regar as flores" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Fazer flexões" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Atualizar atividade" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d de %B de %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s de %(start_B)s, %(start_Y)s - %(end_d)s de %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s de %(start_B)s - %(end_d)s de %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s de %(start_B)s - %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d de %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s horas registradas no total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Nenhuma" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nome" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova categoria" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova atividade" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minuto" msgstr[1] "%(interval_minutes)d minutos" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nunca" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "atividade" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "hora de início" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "hora de término" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "minutos de duração" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descrição" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiquetas" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Registro de atividades para %(start_d)s de %(start_B)s, %(start_Y)s – " "%(end_d)s de %(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Registro de atividades para %(start_d)s de %(start_B)s - %(end_d)s de " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Registro de atividades para %(start_d)s de %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Registro de atividades para %(start_d)s – %(end_d)s de %(start_B)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totais por dia" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Registro de atividades" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "atividades" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorias" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Destinguir:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Mostrar modelo" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Vocẽ pode sobrescrevê-la armazenando sua versão em %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Todos" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Não há dados para gerar estatísticas ainda.\n" "Uma semana de uso seria razoável!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Coletando dados — verifique novamente daqui a uma semana!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d de %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "A primeira atividade foi registrada em %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s ano" msgstr[1] "%(num)s anos" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "O tempo registrado distante equivale a %(human_days)s dias humanos " "(%(human_years)s) ou %(working_days)s dias úteis (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "O trabalho contínuo mais longo ocorreu em %(date)s e foi de %(hours)s hora." msgstr[1] "" "O trabalho contínuo mais longo ocorreu em %(date)s e foi de %(hours)s horas." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Existe %s registro." msgstr[1] "Existem %s registros." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "O Hamster gostaria de observá-lo um pouco mais!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Com %s porcento de todos as atividades iniciadas antes das 9am, você parece " "ser um madrugador." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Com %s porcento de todas as atividades iniciadas após as 11pm, você parece " "uma coruja noturna." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Com %s porcento de todas as atividades em menos de 15 minutos, você parece " "uma abelha ocupada." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Nenhum registro hoje" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Já iniciada" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Salvar relatório — Gestor de tempo" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Relatório em HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valores separados por Tab (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Gestor de tempo" #~ msgid "Show activities window" #~ msgstr "Mostrar janela de atividades" # Visão Geral ou Resumo. #~ msgid "Show _Overview" #~ msgstr "Mostrar vi_são geral" #~ msgid "Sto_p Tracking" #~ msgstr "Pa_rar registro" #~ msgid "To_day" #~ msgstr "H_oje" #~ msgid "_Add earlier activity" #~ msgstr "_Adicionar atividade anterior" #~ msgid "_About" #~ msgstr "_Sobre" #~ msgid "_Preferences" #~ msgstr "_Preferências" #~ msgid "Starts and ends" #~ msgstr "Inícios e términos" #~ msgid "Year:" #~ msgstr "Ano:" #~ msgid "Preferences" #~ msgstr "Preferências" #~ msgid "Changed activity" #~ msgstr "Atividade trocada" #~ msgid "Switched to '%s'" #~ msgstr "Trocado para \"%s\"" #~ msgid "Working on %s" #~ msgstr "Trabalhando em %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Gestor de tempo Hamster. Uso:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projeto Hamster (gestor de tempo do GNOME)" #~ msgid "totals by activity" #~ msgstr "Totais por atividade" #~ msgid "totals by category" #~ msgstr "Totais por categoria" #~ msgid "Show:" #~ msgstr "Mostrar:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Ad_icionar atividade anterior" #~ msgid "Tell me more" #~ msgstr "Conte-me mais" #~ msgid "_Today" #~ msgstr "_Hoje" #~ msgid "Preview:" #~ msgstr "Visualização:" #~ msgid "General" #~ msgstr "Geral" #~ msgid "Global Hotkey" #~ msgstr "Tecla de atalho global" #~ msgid "Move activity down" #~ msgstr "Mover atividade abaixo" #~ msgid "Move activity up" #~ msgstr "Mover atividade acima" #~ msgid "Total Time" #~ msgstr "Tempo total" #~ msgid "Activities" #~ msgstr "Atividades" #~ msgid "Tracking" #~ msgstr "Registros" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Digite uma atividade e pressione Enter para começar " #~ "a registrar!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Conta mais" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "A_tividade:" #~ msgid " _Day" #~ msgstr " _Dia" #~ msgid " _Month" #~ msgstr " _Mês" #~ msgid " _Week" #~ msgstr " Se_mana" #~ msgid "Overview" #~ msgstr "Visão geral" #~ msgid "Totals" #~ msgstr "Totais" #~ msgid "Categories:" #~ msgstr "Categorias:" #~ msgid "Date interval:" #~ msgstr "Intervalo de datas:" #~ msgid "Save as HTML" #~ msgstr "Salvar como HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "O que escrever na caixa de atividade?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Existe uma sintaxe simples que o permite a você adicionar detalhes as " #~ "suas atividades:\n" #~ " \n" #~ "O símbolo \"@\" marca categoria. Exemplo: \"regando flores@casa\" " #~ "começará a registrar a atividade \"regando flores\" na categoria \"casa" #~ "\".\n" #~ "\n" #~ "A vírgula (\",\") marca o começo da descrição. Exemplo: \"regando flores, " #~ "begônias e florais da Califórnia\" começará a registrar \"regando flores" #~ "\" e adiciona a descrição \"begônias e florais da Califórnia\" ao " #~ "registro.\n" #~ "\n" #~ "Ambas podem ser combinadas: \"regando flores@casa, begônias e florais da " #~ "Califórnia\" funcionará corretamente!\n" #~ "\n" #~ "Agora, comece a registrar!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Todas" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s %(b)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Resumo para %(date)s" #~ msgid "Remind also when no activity is set" #~ msgstr "Lembrar também quando não houver atividade definida:" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s %(report_b)s, %(report_Y)s" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s, %(Y)s" #~ msgstr "%(d)s %(b)s, %(Y)s" #~ msgctxt "overview list" #~ msgid "%(A)s, %(b)s %(d)s" #~ msgstr "%(A)s, %(d)s %(b)s" #~ msgctxt "overview graph" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s %(b)s" #~ msgctxt "single day overview" #~ msgid "Overview for %(B)s %(d)s, %(Y)s" #~ msgstr "Visão geral de %(d)s %(B)s, %(Y)s" #~ msgid "Move _Down" #~ msgstr "Mover para _baixo" #~ msgid "Move _Up" #~ msgstr "Mover para _cima" #~ msgid "N_ew Category" #~ msgstr "N_ova categoria" #~ msgid "_New Activity" #~ msgstr "_Nova atividade" #~ msgid "Delete activity" #~ msgstr "Exclui atividade" #~ msgid "Newer activities" #~ msgstr "Atividades novas" hamster-3.0.3/po/ro.po000066400000000000000000000706351452646177100146060ustar00rootroot00000000000000# This file is distributed under the same license as the gnome-user-share package. # Alex Szasz # Adi Roiban https://launchpad.net/~adiroiban, 2009 # Lucian Adrian Grijincu , 2009, 2010. # Mișu Moldovan , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: Gnome\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2010-12-04 21:25+0200\n" "Last-Translator: Adi Roiban \n" "Language-Team: Romanian Gnome Team \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " "20)) ? 1 : 2);;\n" "X-Generator: Virtaal 0.6.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Adăugare activitate anterioară" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "pînă la" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "în curs" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Descriere:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Durată:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Activitate:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etichete:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Oprește pontarea în inactivitate" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Oprește pontarea activității curente când calculatorul devine inactiv" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Oprește pontarea când e oprit calculatorul" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Oprește pontarea activității curente când calculatorul este oprit" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Amintește sarcina curentă la fiecare x minute" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Amintește sarcina curentă la un interval de minute specificat. Pentru " "dezactivare, definiți ca 0 sau mai mare de 120." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Amintește atunci când nu există o activitate definită" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "De asemenea, amintește la fiecare notify_interval minute dacă nu s-a pornit " "o activitate." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "La ce oră începe ziua (implicit 5:30AM)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Activitățile vor fi contabilizate pentru ziua precedentă dacă timpul curent " "este mai mic decât startul zilei specificat și pentru astăzi dacă depășește " "timpul. Activitățile care se întind pe două zile vor fi contorizate pentru " "ziua în care este cea mai mare parte a activității." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Dacă comutarea spațiului de lucru declanșează o comutare a activității" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Listă de metode de urmărire activate. „name” va activa comutarea " "activităților după nume definit în workspace_mapping. „memory” va activa " "comutarea la ultima activitate la întoarcerea într-un spațiu de lucru " "anterior." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Comută activitatea la comutarea spațiului de lucru" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Dacă comutarea după nume este activată, această listă definește numele " "activităților la care se comută, spațiile de lucru reprezentate prin indexul " "elementului." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Arată / ascunde fereastra de pontare" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Combinație de taste pentru afișarea / ascunderea ferestrei de pontare." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Acțiune comutare fereastră aplicație hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Comandă pentru comutarea vizibilității ferestrei aplicației hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Comută fereastra aplicației hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Comută vizibilitatea ferestrei aplicației hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Pontaj activități" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Proiectul Hamster - pontați-vă activitățile" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Pontaj activități" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Arată statistici" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Categorii" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Activități" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etichete" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nicio dată pentru acest interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Salvează raportul..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Zi" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Săptămână" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Lună" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Sumar — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "P_rivire generală" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Activitate" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Vizualizare" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totaluri" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Elimină" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Adaugă activitate nouă" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Editare" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferințe pontaj activități" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Oprește pontarea când e inactiv calculatorul" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Amintește activitatea curentă la fiecare:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Ziua începe la" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Utilizează următoarea listă de lucruri de făcut dacă este disponibilă:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integrare" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Pontare" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Categorii" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Listă de categorii" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Adaugă o categorie" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Elimină categoria" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Editare categorie" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Activități" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Listă de activități" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Adaugă o activitate" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Elimină activitatea" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Editare activitate" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Etichete ce ar trebui să apară la autocompletare" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Categorii și etichete" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Reia ultima activitate la întoarcerea într-un spațiu de lucru" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Începe o nouă activitate la comutarea spațiilor de lucru:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Spații de lucru" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Zi:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Săptămână:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Lună:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Interval dată:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Aplică" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Pon_tare" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Adăugă activitate anterioară" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Sumar" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistici" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Editare" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Ajutor" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Conținut" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "O_prește pontarea" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Com_utare" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Porneș_te pontarea" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Începe o activitate nouă" #: ../data/today.ui.h:13 msgid "Today" msgstr "Astăzi" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Totaluri" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Arată _sumarul" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Fără activitate" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Categorie" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Descriere" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Începere" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Terminare" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Durată" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "categorii" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Proiectul Hamster – pontați-vă activitățile" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Drepturi de autor © 2007-2010 Tomis Baugis și alții" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Pagina web a proiectului Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Despre „Pontaj activități”" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Adi Roiban \n" "Alexandru Szasz \n" "Lucian Adrian Grijincu \n" "Mișu Moldovan " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nesortate" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Serviciu" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Citit presa" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Verificat stocuri" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Proiectul ultrasecret X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Cucerirea lumii" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Zi de zi" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Prânz" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Udat flori" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Genoflexiuni" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Actualizare activitate" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ore pontate în total" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Niciuna" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Nume" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Categorie nouă" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Activitate nouă" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minute" msgstr[1] "%(interval_minutes)d minute" msgstr[2] "%(interval_minutes)d minute" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Niciodată" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "activitate" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "timp de începere" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "timp de terminare" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "durată în minute" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "categorie" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "descriere" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etichete" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Raport de activitate pentru %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Raport de activitate pentru %(start_d)s %(start_B)s – %(end_d)s %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Raport de activitate pentru %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "" "Raport de activitate pentru %(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totaluri pe zi" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Sumar activitate" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "activități" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "categorii" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Distinge:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Dată" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Afișează șablonul" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "O puteți înlocui, stocând versiunea proprie în %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Toți" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Nu există suficiente date pentru generarea statisticilor.\n" "Încercați după o săptămână de utilizare." #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" "Se colectează date – verificați după trecerea unei săptămâni de la începutul " "pontării!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Prima activitate a fost înregistrată pe %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s an" msgstr[1] "%(num)s ani" msgstr[2] "%(num)s de ani" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Timpul pontat până acum %(human_days)s zile umane (%(human_years)s) sau " "%(working_days)s zile de muncă (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Cea mai lungă activitate continuă a avut loc în data de %(date)s și a durat " "%(hours)s oră." msgstr[1] "" "Cea mai lungă activitate continuă a avut loc în data de %(date)s și a durat " "%(hours)s ore." msgstr[2] "" "Cea mai lungă activitate continuă a avut loc în data de %(date)s și a durat " "%(hours)s de ore." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Există %s înregistrare." msgstr[1] "Există %s înregistrări." msgstr[2] "Există %s de înregistrări." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster ar dori să vă observe mai mult!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Cu %s procente din toate activitățile începând înainte de ora 9, se pare că " "sunteți matinal." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Cu %s procente din toate activitățile începând după ora 23, se pare că " "sunteți nocturn." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Cu %s procente din toate activitățile mai scurte de 15 minute, se pare că " "sunteți o albinuță harnică." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Nu există înregistrări pentru astăzi" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s, " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Tocmai începută" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Salvare raport — Pontaj activități" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Raport HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Valori separate prin taburi (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Pontaj" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "Proiectul Hamster (Pontaj activități în GNOME)" #~ msgid "_About" #~ msgstr "_Despre" #~ msgid "_Preferences" #~ msgstr "_Preferințe" #~ msgid "Sto_p Tracking" #~ msgstr "O_prește pontarea" #~ msgid "To_day" #~ msgstr "Astă_zi" #~ msgid "_Add earlier activity" #~ msgstr "_Adăugă activitate anterioară" #~ msgid "Starts and ends" #~ msgstr "Start și stop" #~ msgid "Year:" #~ msgstr "An:" #~ msgid "Preferences" #~ msgstr "Preferințe" #~ msgid "Changed activity" #~ msgstr "Activitate modificată" #~ msgid "Switched to '%s'" #~ msgstr "Comutat la „%s”" #~ msgid "Working on %s" #~ msgstr "Se lucrează la %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Pontaj activități Hamster. Utilizare:" #~ msgid "totals by activity" #~ msgstr "totaluri după activitate" #~ msgid "totals by category" #~ msgstr "totaluri după categorie" #~ msgid "Show:" #~ msgstr "Arată:" #~ msgid "Show window" #~ msgstr "Arată fereastra" #~ msgid "Ad_d Earlier Activity" #~ msgstr "A_daugă o activitate anterioară" #~ msgid "Tell me more" #~ msgstr "Vreau să aflu mai multe" #~ msgid "_Today" #~ msgstr "As_tăzi" #~ msgid "Preview:" #~ msgstr "Previzualizare:" #~ msgid "General" #~ msgstr "General" #~ msgid "Global Hotkey" #~ msgstr "Tastă rapidă globală" #~ msgid "Move activity down" #~ msgstr "Mută activitatea în jos" #~ msgid "Move activity up" #~ msgstr "Mută activitatea în sus" #~ msgid "Total Time" #~ msgstr "Timp total" #~ msgid "Activities" #~ msgstr "Activități" #~ msgid "Tracking" #~ msgstr "Pontare" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Scrieți o activitate și apăsați Enter pentru a " #~ "începe pontarea!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Spune-mi mai " #~ "multe" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Activitate:" #~ msgid " _Day" #~ msgstr "_Zi" #~ msgid " _Month" #~ msgstr "_Lună" #~ msgid " _Week" #~ msgstr "_Săptămână" #~ msgid "Overview" #~ msgstr "Sumar" #~ msgid "Totals" #~ msgstr "Totaluri" #~ msgid "Categories:" #~ msgstr "Categorii:" #~ msgid "Date interval:" #~ msgstr "Interval de timp:" #~ msgid "Save as HTML" #~ msgstr "Salvează ca HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "Ce trebuie scris în căsuța de activități?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Aceasta este o sintaxă simplă ce vă permite să adăugați detalii " #~ "activităților:\n" #~ " \n" #~ "simbolul „@” marchează o categorie. De exemplu: „udat florile@acasă” va " #~ "începe pontarea pentru activitatea de „udat florile” în categoria " #~ "„acasă”.\n" #~ "\n" #~ "Virgulele („,”) marchează începutul unei descrieri. De exemplu: „udat " #~ "florile, lalelele și florile de nu-mă-uita” va începe activitatea de " #~ "„udat florile” și va adăuga descrierea „lalelele și florile de nu-mă-" #~ "uita”.\n" #~ "\n" #~ "Ambele pot fi combinate: „udat florile@acasă, lalelele și florile de nu-" #~ "mă-uita” va funcționa fără probleme!\n" #~ "\n" #~ "Și acum, începeți pontajul!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Toate" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Total" #~ msgid "Overview for %(date)s" #~ msgstr "Sumar pentru %(date)s" hamster-3.0.3/po/ru.po000066400000000000000000000673571452646177100146230ustar00rootroot00000000000000# Russian Translation for GNOME hamster-time-tracker # Copyright (C) 2009 Free Software Foundation Inc. # # This file is distributed under the same license as the project-hamster package. # Sasha Shveik , 2008 # Alexander Saprykin , 2010. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: Hamster 0.6.1\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-11 19:03+0300\n" "Last-Translator: Yuri Myasoedov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Russian\n" "X-Poedit-Country: Russia\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Добавить раннее занятие" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "до" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "выполняется" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Описание:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Время:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Занятие:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Метки:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Прекращать учёт при бездействии" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Прекращать учёт текущего занятия при бездействии компьютера" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Прекращать учёт при выключении компьютера" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Прекращать учёт текущего занятия при выключении компьютера" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Напоминание о текущей задаче периодически через заданное число минут" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Напоминание о текущей задаче каждые несколько минут. Значение 0 или более " "120 отключает напоминание." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Также напоминать, когда занятие не установлено" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Также напоминать каждые notify_interval минут, если ни одно занятие не " "начато." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Со скольки начинается день (по умолчанию с 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Занятия будут учитываться за вчерашний день, если текущее время меньше " "указанного начала дня, и за сегодняшний день, если больше этого времени. " "Занятия, которые перекрывают два дня, относятся к тому дню, на который " "пришлась большая часть времени." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Должно ли переключение рабочего места переключать задачу" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Список используемых методов учёта. «name» — включить переключение занятий по " "именам, определённым в workspace_mapping; «memory» — включить переключение " "на последнее занятие при возвращении к предыдущему рабочему месту." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Переключать занятие при смене рабочего места" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Если включено переключение по имени, этот список устанавливает названия " "занятий, которые следует переключать. Рабочие места представлены индексом " "элемента." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Показывать или скрывать окно учёта времени." #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Клавиатурное сокращение для отображения или скрытия окна учёта времени." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Переключить окно приложения hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Команда переключения окна приложения hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Переключить окно приложения hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Переключить окно приложения hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Учёт времени" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Проект Hamster — следите за временем" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Обзор учёта времени" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Окно с обзором учёта времени" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Показать статистику" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Категории" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Занятия" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Метки" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Данные за этот интервал недоступны" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Сохранить отчёт…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "День" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Неделя" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Месяц" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Обзор — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Обзор" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Занятие" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Вид" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Всего" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Удалить" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Добавить" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Править" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Параметры апплета учёта времени" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Прекращать учёт при бездействии компьютера" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Напоминать о текущем занятии каждые:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Новый день начинается с" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Использовать следующий список дел, если доступно:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Интеграция" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Учёт" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Категории" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Список категорий" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Добавить категорию" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Удалить категорию" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Изменить категорию" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Занятия" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Список занятий" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Добавить занятие" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Удалить занятие" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Изменить занятие" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Метки, появляющиеся при автодополнении" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Категории и метки" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Восстанавливать предыдущее занятие при возвращении на рабочее место" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Начинать новое занятие при переключении рабочих мест:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Рабочие места" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "День:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Неделя:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Месяц:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Период времени:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Применить" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Учёт" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Добавить раннее занятие" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Обзор" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статистика" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Править" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Справка" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Содержание" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Прекратить _учёт" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Сменить" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Начать _учёт" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Начать новое занятие" #: ../data/today.ui.h:13 msgid "Today" msgstr "Сегодня" #: ../data/today.ui.h:14 msgid "totals" msgstr "всего" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Показать обзор" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Нет занятий" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Категория" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Описание" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Начало" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Окончание" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Длительность" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "категории" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Проект Hamster — следите за своим временем" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Авторское право © 2007-2010 Toms Bauģis и другие" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Веб-сайт апплета для учёта времени" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Об апплете" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Sasha Shveik\n" "Юрий Пенкин \n" "Alexander Saprykin , 2010" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Несортированные" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Работа" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Чтение новостей" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Проверка курса ценных бумаг" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Суперсекретный проект Х" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Мировое господство" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Ежедневная рутина" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Обед" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Полив цветов" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Стояние на голове" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Обновить занятие" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d ч" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d мин" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d ч %d мин" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Всего часов учтено: %s" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Нет" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Название" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Новая категория" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Новое занятие" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d минута" msgstr[1] "%(interval_minutes)d минуты" msgstr[2] "%(interval_minutes)d минут" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Никогда" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "занятие" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "время начала" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "время окончания" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "длительность в минутах" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "категория" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "описание" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "метки" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Отчёт о занятости за %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Отчёт о занятости за %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Отчёт о занятости за %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Отчёт о занятости за %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Итоги за день" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Журнал деятельности" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "занятость" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "категории" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Различать:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Дата" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Показать шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Вы можете заменить его, сохранив свою версию в %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Все" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Пока ещё нет данных для создания статистики.\n" "Было бы неплохо попользоваться неделю!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Сбор данных — выполните проверку через неделю!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Первое занятие записано %s" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s год" msgstr[1] "%(num)s года" msgstr[2] "%(num)s лет" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Уже учтено времени в человеческих днях: %(human_days)s (%(human_years)s), в " "рабочих днях: %(working_days)s (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "Самая продолжительная работа была %(date)s и длилась %(hours)s час." msgstr[1] "" "Самая продолжительная работа была %(date)s и длилась %(hours)s часа." msgstr[2] "" "Самая продолжительная работа была %(date)s и длилась %(hours)s часов." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s запись." msgstr[1] "%s записи." msgstr[2] "%s записей." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster хочет понаблюдать за вами немного дольше!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s процент событий начинались ранее 9:00, это значит, что вы — «жаворонок»." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "%s процент событий начинались ранее 9:00, это значит, что вы — «сова»." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s процент занятий продолжались менее 15 минут, это значит, что вы — " "«трудолюбивая пчёлка»." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Нет записей за сегодня" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s ч" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Только начавшееся" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Сохранить отчёт — учёт времени" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Отчёт HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Значения, разделённые табуляцией (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Учёт времени" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Показать окно занятости" #~ msgid "Sto_p Tracking" #~ msgstr "Остановить _учёт" #~ msgid "To_day" #~ msgstr "_Сегодня" #~ msgid "_Add earlier activity" #~ msgstr "_Добавить прошлое занятие" #~ msgid "Show _Overview" #~ msgstr "Показать _обзор" #~ msgid "_Preferences" #~ msgstr "_Параметры" #~ msgid "_About" #~ msgstr "_О программе" #~ msgid "Year:" #~ msgstr "Год:" #~ msgid "Starts and ends" #~ msgstr "Начинается и заканчивается" #~ msgid "Preferences" #~ msgstr "Параметры" #~ msgid "Changed activity" #~ msgstr "Изменённое занятие" #~ msgid "Switched to '%s'" #~ msgstr "Переключено на «%s»" #~ msgid "Working on %s" #~ msgstr "Текущая задача: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Программа учёта времени Hamster. Использование:" hamster-3.0.3/po/si.po000066400000000000000000000617121452646177100145750ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Danishka Navin , 2009. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.gnome-2-24\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-02-23 11:35+0530\n" "Last-Translator: Danishka Navin \n" "Language-Team: Sinhalese \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 0.3\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "පෙර ක්‍රියාදාමය ඇතුළත් කරන්න" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "සැකසෙමින් පවතී...\n" "තුරු\n" "තිස්සෙ" #: ../data/edit_activity.ui.h:4 #, fuzzy msgid "Description:" msgstr "කාල පරතරය" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "ක්‍රියාදාමය: (_A)" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "" #: ../data/hamster.schemas.in.h:2 #, fuzzy msgid "Stop tracking current activity when computer becomes idle" msgstr "පරිඝණකය අකර්මන්‍ය අවස්ථාවලදී tracking කිරීම නවත්වන්න" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "shutdown කරන විටදී tracking කිරීම නවත්වන්න" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "කාල මාන කවුළුව දර්ශනය කිරීම සඳහා යතුරු පුවරු කෙටි මං " #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "කාල මාන කවුළුව දර්ශනය කිරීම සඳහා යතුරු පුවරු කෙටි මං " #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "කාල මානය" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "කාල මානය" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "ප්‍ර‍භේදයන් (_C)" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "ක්‍රියාදාමයන් (_A)" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "දිනය" #: ../data/overview.ui.h:3 msgid "Week" msgstr "සතිය" #: ../data/overview.ui.h:4 msgid "Month" msgstr "මාසය" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "Hamster - විෂ්ලේෂණය " #: ../data/overview.ui.h:6 #, fuzzy msgid "_Overview" msgstr "විෂ්ලේෂණය පෙන්වන්න (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "ක්‍රියාදාමය" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "කාල මාන අභිප්‍රේත" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "පරිඝණකය අකර්මන්‍ය අවස්ථාවලදී tracking කිරීම නවත්වන්න" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "කාල පරතරය" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "Tracking නවතන්න (_S)" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ප්‍ර‍භේදයන් (_C)" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "ප්‍ර‍භේදය" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "නව ප්‍ර‍භේදය" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "නව ප්‍ර‍භේදය" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "නව ප්‍ර‍භේදය" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "ක්‍රියාදාමයන් (_A)" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "ක්‍රියාදාමය" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "ක්‍රියාදාමය ඇතුළත් කරන්න" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "ක්‍රියාදාම ‍නැත" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "ක්‍රියාදාමය සංස්කරණය කරන්න" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "ප්‍ර‍භේදයන් (_C)" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "සතිය" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "මාසය" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "Tracking නවතන්න (_S)" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "පෙර ක්‍රියාදාමය ඇතුළත් කරන්න" #: ../data/today.ui.h:4 #, fuzzy msgid "Overview" msgstr "විෂ්ලේෂණය පෙන්වන්න (_O)" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "Tracking නවතන්න (_S)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "Tracking නවතන්න (_S)" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "නව ක්‍රියාදාමය" #: ../data/today.ui.h:13 msgid "Today" msgstr "අද" #: ../data/today.ui.h:14 msgid "totals" msgstr "" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "විෂ්ලේෂණය පෙන්වන්න (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "ක්‍රියාදාම ‍නැත" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "ප්‍ර‍භේදය" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 #, fuzzy msgid "Description" msgstr "කාල පරතරය" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "අරඹන්න" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "අවසන් කරන්න" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "කාල පරතරය" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "ප්‍ර‍භේදයන් (_C)" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "ප්‍රකාශන හිමිකම් © 2007-2008 Toms Baugis සහ වෙනත් අය" #: ../src/hamster/about.py:45 #, fuzzy msgid "Project Hamster Website" msgstr "Hamster වෙබ් " #: ../src/hamster/about.py:46 #, fuzzy msgid "About Time Tracker" msgstr "කාල මානය" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "රන්දික රතුගම " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "වර්ග නොකරන ලද" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "කාර්යය" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "පුවත් කියවීම" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "තොග පරික්ෂා කිරිම" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "අති රහසිගත ව්‍යාපෘතිය" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ලොව ප්‍රමුකත්වය" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "දිවා අාහාරය" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "මල් වලට වතුර දැමීම" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "ලෝක " #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "ක්‍රියාදාමය යාවත්කාල කරන්න" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "විෂ්ලේෂණය %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "විෂ්ලේෂණය %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "විෂ්ලේෂණය %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "නම" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "නව ප්‍ර‍භේදය" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "නව ක්‍රියාදාමය" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "" msgstr[1] "" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "ක්‍රියාදාමය" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "මිනිත්තු" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "ප්‍ර‍භේදය" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "විෂ්ලේෂණය %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "විෂ්ලේෂණය %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "විෂ්ලේෂණය %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "විෂ්ලේෂණය %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "ක්‍රියාදාමය" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "ක්‍රියාදාමයන් (_A)" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "ප්‍ර‍භේදයන් (_C)" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "දවස" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "සතිය පෙන්වන්න" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "අද දිනය සඳහා වාර්තා නැත" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "කාල මානය" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "කාල මානය" #~ msgid "Time tracking for masses" #~ msgstr "‍පොදු ජනයා සඳහා කාල tracking " #~ msgid "_About" #~ msgstr "කාල මානය ගැන (_A)" #~ msgid "_Preferences" #~ msgstr "ඔඛ කැමති ලෙස (_P)" #~ msgid "Activities" #~ msgstr "ක්‍රියාදාමයන්" #~ msgid "Global Hotkey" #~ msgstr "" #~ msgid "Tracking" #~ msgstr "Tracking" #~ msgid "Move _Down" #~ msgstr "පහළට ගෙනයන්න (_D)" #~ msgid "Move _Up" #~ msgstr "ඉහළට ගෙනයන්න (_U)" #~ msgid "N_ew Category" #~ msgstr "නව ප්‍ර‍භේදය (_e)" #~ msgid "_New Activity" #~ msgstr "නව ක්‍රියාදාමය (_N)" #~ msgid "Activity" #~ msgstr "ක්‍රියාදාමය" #~ msgid "Date and Time" #~ msgstr "කාලය සහ දිනය" #~ msgid "hours" #~ msgstr "පැය" #~ msgid "Show window" #~ msgstr "කවුළුව දර්ශනය කරන්න" #~ msgid "Ad_d Earlier Activity" #~ msgstr "‍පෙර කරන ලද ක්‍රියාදාමය ඇතුළත් කරන්න" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Today" #~ msgstr "අද (_T)" #~ msgid " _Day" #~ msgstr "දවස (_D)" #~ msgid " _Month" #~ msgstr "මාසය (_M)" #~ msgid " _Week" #~ msgstr "සතිය (_W)" #~ msgid "Category" #~ msgstr "ප්‍ර‍භේදයන්" #~ msgid "Overview" #~ msgstr "‍දළ විෂ්ලේෂණය" #~ msgid "Week" #~ msgstr "සතිය" #~ msgid "Delete activity" #~ msgstr "ක්‍රියාදාමය ඉවත් කරන්න" #~ msgid "Earlier activities" #~ msgstr "පෙර කළ ක්‍රියාදාමයන්" #~ msgid "Generate Report" #~ msgstr "වාර්තා ජනනය කරන්න" #~ msgid "Newer activities" #~ msgstr "නවතම ක්‍රියාදාමයන්" #~ msgid "Show day" #~ msgstr "දිනය පෙන්වන්න" #~ msgid "Show month" #~ msgstr "මාසය පෙන්වන්න" #~ msgid "Time tracking for masses." #~ msgstr "‍පොදු ජනයා සඳහා කාල tracking " #~ msgid "Day to day" #~ msgstr "එදිනෙදා" #~ msgid "name" #~ msgstr "නම" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_b)s %(m_d)s" #~ msgid "Other" #~ msgstr "වෙනත්" hamster-3.0.3/po/sl.po000066400000000000000000000737431452646177100146070ustar00rootroot00000000000000# Slovenian translations for hamster. # Copyright (C) 2005-2006 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # # Matej Urbančič , 2008 - 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker master\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-15 20:24+0100\n" "Last-Translator: Matej Urbančič \n" "Language-Team: Slovenian GNOME Translation Team \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n" "%100==4 ? 3 : 0);\n" "X-Poedit-Language: Slovenian\n" "X-Poedit-Country: SLOVENIA\n" "X-Poedit-SourceCharset: utf-8\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Dodaj zgodnejšo dejavnost" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "za" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "v teku" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Opis:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Čas:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Dejavnost:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Oznake:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Zaustavi sledenje ob nedejavnosti" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Zaustavi sledenje trenutne dejavnosti, kadar računalnik ni dejaven" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Zaustavi sledenje ob izklopu računalnika" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Zaustavi sledenje trenutni dejavnosti ob izklopu računalnika" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Opomni na trenutno nalogo vsakih x minut" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Opomni na trenutno dejavnost vsakih toliko minut. Vrednost 0 in vrednost " "večja od 120 onemogoči opomnik." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Opozori kadar ni določenih dejavnosti" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "Opozori vsakih _nekaj minut, če ni nobene začete dejavnosti." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Ob kateri uri se dan začne (privzeto 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Dejavnosti bodo označene kot včerajšnje, ko je trenutni čas manjši od časa " "določenega za začetek novega dne, sicer bodo označene kot današnje. " "Dejavnosti, ki trajajo več dni bodo označene glede na večinski del trajanja " "dneva." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Ali naj preklop delovne površine preklopi dejavnosti" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Seznam omogočenih načinov sledenja. \"Ime\" omogoči preklop dejavnosti po " "imenu določenem med možnostmi workspace_mapping, \"pomnilnik\" pa preklopi " "zadnjo dejavnost ob vračanju na predhodno delovno površino." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Preklopi dejavnost ob preklopu delovne površine" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "V primeru, da je omogočen preklop po imenu, se s seznamom določijo imena " "dejavnosti, ki bodo preklopljene, delovne površine pa so predstavljene z " "določili predmeta." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Pokaži / Skrij okno sledenja časa" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Tipkovna bližnjica za skrivanje in prikaz okna sledenja času." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Dejanje preklopa okna programa Hamster" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Ukaz za preklapljanje vidnosti okna programa Hamster." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Preklopi okno programa Hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Preklapljanje vidnosti okna programa Hamster." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Sledenje času" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekt Hamster - sledenje času" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Pregled časovnega sledenja" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Okno pregleda sledenja času" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Pokaži statistiko" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorije" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Dejavnosti" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Oznake" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Ni podatkov za časovni razmik" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Shrani poročilo ..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dan" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Teden" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mesec" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Pregled - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Pregled" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Dejavnost" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Pogled" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Skupno" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Odstrani" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Dodaj novo" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Uredi" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Možnosti sledenja časa" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Zaustavi sledenje, ko računalnik ni dejaven" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Opomni na trenutno dejavnost vsakih:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Nov dan se začne ob" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Poskusi uporabiti seznam opravil:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Združevanje" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Sledenje" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorije" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Seznam kategorij" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Dodaj kategorijo" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Odstrani kategorijo" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Uredi kategorijo" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Dejavnosti" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Seznam dejavnosti" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Dodaj dejavnost" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Odstrani dejavnost" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Uredi dejavnost" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Oznake, ki se pokažejo med samodejnim dopolnjevanjem" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorije in oznake" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Obnovi zadnjo dejavnost ob vrnitvi na delovno površino" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Začni novo dejavnost ob preklopu delovne površine:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Delovne površine" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dan:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Teden:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mesec:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Obseg:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Uporabi" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Sledenje" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Dodaj zgodnejšo dejavnost" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Pregled" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistika" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Uredi" #: ../data/today.ui.h:7 msgid "_Help" msgstr "Pomo_č" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Vsebina" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Zaustavi sledenje" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Preklopi" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Začni s _sledenjem" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Začni novo dejavnost" #: ../data/today.ui.h:13 msgid "Today" msgstr "Danes" #: ../data/today.ui.h:14 msgid "totals" msgstr "skupno" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Pokaži pregled" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Ni dejavnosti" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorija" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Opis" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Začetek" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Konec" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Trajanje" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorije" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekt Hamster - sledenje času" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Avtorske pravice © 2007-2010 Toms Bauģis in drugi" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Spletna stran programa Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "O sledenju časa" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Matej Urbančič " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nerazvrščeno" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Služba" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Branje novic" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Preverjanje delnic" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Tajni projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Zavlada svetu" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Iz dneva v dan" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Kosilo" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Zalivanje rož" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stoja na glavi" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Posodobi dejavnost" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_d)s. %(start_B)s, %(start_Y)s – %(end_d)s. %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s. – %(end_d)s. %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d. %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s ur skupno sledenja" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Brez" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Ime" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova kategorija" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova dejavnost" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minuta" msgstr[2] "%(interval_minutes)d minuti" msgstr[3] "%(interval_minutes)d minute" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nikoli" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "dejavnost" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "čas pričetka" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "čas zaključka" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "trajanje" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorija" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "opis" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "oznake" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Dnevnik dejavnosti za %(start_d)s. %(start_B)s %(start_Y)s - %(end_d)s " "%(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Dnevnik dejavnosti za %(start_d)s. %(start_B)s - %(end_d)s. %(end_B)s leta " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Poročilo dejavnosti za %(start_d)s. %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Poročilo dejavnosti za %(start_d)s. - %(end_d)s. %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d.%m.%Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "skupno po dnevih" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Dnevnik dejavnosti" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "dejavnosti" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorije" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Razlikovanje:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Pokaži predlogo" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" "Možnost lahko prepišete s shranjevanjem različice v mapo %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Vse" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Na voljo ni dovolj podatkov za izračunavanje statistike.\n" "Pustite program vsaj še en teden delovati!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Še vedno poteka zbiranje podatkov - ponovno preverite čez en teden!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d.%m.%Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d. %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Dejavnost je bila prvič zabeležena %s" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s let" msgstr[1] "%(num)s leto" msgstr[2] "%(num)s leti" msgstr[3] "%(num)s leta" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Čas se beleži %(human_days)s človeških dni (%(human_years)s) ali " "%(working_days)s delovnih dni (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d.%m.%Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Najdaljše neprekinjeno dejanje je bilo %(date)s in je trajalo %(hours)s ur." msgstr[1] "" "Najdaljše neprekinjeno dejanje je bilo %(date)s in je trajalo %(hours)s uro." msgstr[2] "" "Najdaljše neprekinjeno dejanje je bilo %(date)s in je trajalo %(hours)s uri." msgstr[3] "" "Najdaljše neprekinjeno dejanje je bilo %(date)s in je trajalo %(hours)s ure." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Zabeleženih je %s dejavnosti." msgstr[1] "Zabeležena je %s dejavnost." msgstr[2] "Zabeleženi sta %s dejavnosti." msgstr[3] "Zabeleženih so %s dejavnosti." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Program mora še naprej slediti vašim dejavnostim!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Videti je, da večino dela opravite zgodaj, saj je %s odstotkov vseh opravil " "pred deveto uro zjutraj." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Videti je, da pogosto delate ponoči, saj opravite %s odstotkov vseh opravil " "po enajsti uri zvečer." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Videti je, da ste zelo zaposleni, saj imate kar %s odstotkov vseh opravil " "krajših od 15 minut." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Za današnji dan ni zapisov" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Pričeto" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Shrani poročilo - sledenje času" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Poročilo HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "S presledki ločene vrednosti" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Časovno sledenje" #~ msgid "Show activities window" #~ msgstr "Pokaži okno dejavnosti" #~ msgid "Sto_p Tracking" #~ msgstr "_Zaustavi sledenje" #~ msgid "To_day" #~ msgstr "_Danes" #~ msgid "_Add earlier activity" #~ msgstr "Dodaj _zgodnejšo dejavnost" #~ msgid "Show _Overview" #~ msgstr "Pokaži _pregled" #~ msgid "_Preferences" #~ msgstr "_Možnosti" #~ msgid "_About" #~ msgstr "_O Programu" #~ msgid "Year:" #~ msgstr "Leto:" #~ msgid "Starts and ends" #~ msgstr "Začetki in zaključki" #~ msgid "Preferences" #~ msgstr "Možnosti" #~ msgid "Changed activity" #~ msgstr "Spremenjena dejavnost" #~ msgid "Switched to '%s'" #~ msgstr "Preklopljeno na '%s'" #~ msgid "Working on %s" #~ msgstr "Delo na %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Sledilnik časa Hamster. Uporaba:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Projekt Hamster (sledenje času)" #~ msgid "Tell me more" #~ msgstr "Več podrobnosti" #~ msgid "totals by activity" #~ msgstr "skupno po dejavnosti" #~ msgid "totals by category" #~ msgstr "skupno po kategorijah" #~ msgid "Show:" #~ msgstr "Pokaži:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Dodaj zgodnejšo dejavnost" #~ msgid "_Today" #~ msgstr "_Danes" #~ msgid "Save Report" #~ msgstr "Shrani poročilo" #~ msgid "Move activity down" #~ msgstr "Premakni dejavnost navzdol" #~ msgid "Move activity up" #~ msgstr "Premakni dejavnost navzgor" #~ msgid "General" #~ msgstr "Splošno" #~ msgid "Global Hotkey" #~ msgstr "Splošne hitre tipke" #~ msgid "Total Time" #~ msgstr "Skupni čas" #~ msgid "Preview:" #~ msgstr "Predogled:" #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "Čas, ki se določi kot začetek novega dne." #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "Time and Name" #~ msgstr "Čas in ime" #~ msgid "Tags or Description" #~ msgstr "Oznake ali opisi" #~ msgid "Reports" #~ msgstr "Poročila" #~ msgid "Next" #~ msgstr "Naslednji" #~ msgid "Previous" #~ msgstr "Predhodni" #~ msgid "This Week" #~ msgstr "Ta teden" #~ msgid " _Day" #~ msgstr "_Dan" #~ msgid " _Month" #~ msgstr "_Mesec" #~ msgid " _Week" #~ msgstr "_Teden" #~ msgid "Overview" #~ msgstr "Pregled" #~ msgid "Categories:" #~ msgstr "Kategorije:" #~ msgid "Date interval:" #~ msgstr "Datumsko območje" #~ msgid "Show month" #~ msgstr "Pokaži mesec" #~ msgid "Totals" #~ msgstr "Skupno" #~ msgid "What should be typed in the activity box?" #~ msgstr "kaj natipkati v polje dejavnosti?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "S pomočjo enostavne skladnje lahko dodate podrobnosti vašim dejavnostim:\n" #~ " \n" #~ "\"@\" oznaka določa kategorije. Primer: \"zalivanje rož@doma\" sledi " #~ "dejavnosti \"zalivanja rož\" v kategoriji \"doma\".\n" #~ "\n" #~ "Z vejico (\",\") označimo začetek opisa. Primer: \"zalivanje rož, begonij " #~ "in spominčic\" začne s sledenjem dejavnosti \"zalivanja rož\" in doda " #~ "opis \"begonije in spominčice\".\n" #~ "\n" #~ "Obe oznaki je mogoče združiti: \"zalivanje rož@doma, begonije in " #~ "spominčice\"!\n" #~ "\n" #~ "Preizkusite skladnjo!\n" #~ " " #~ msgid "Total" #~ msgstr "Skupno" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%d. %b" #~ msgid "Totals for %(date)s" #~ msgstr "Skupno za %(date)s" #~ msgid "Previous day" #~ msgstr "Predhodni dan" #~ msgid "Next day" #~ msgstr "Naslednji dan" #~ msgid "Previous week" #~ msgstr "Predhodni teden" #~ msgid "Next week" #~ msgstr "Naslednji teden" #~ msgid "This week" #~ msgstr "Ta teden" #~ msgid "Previous month" #~ msgstr "Predhodni mesec" #~ msgid "Next month" #~ msgstr "Naslednji mesec" #~ msgid "This month" #~ msgstr "Ta mesec" #~ msgid "This Month" #~ msgstr "Ta mesec" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Vse" #~ msgid "Show single day" #~ msgstr "Pokaži en dan" #~ msgid "Activities" #~ msgstr "Dejavnosti" #~ msgid "Day\t" #~ msgstr "Dan\t" #~ msgid "Tracking" #~ msgstr "Merjenje časa" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Vtipkajte dejavnost in pritisnite vnosno tipko za " #~ "sledenje!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Več podrobnosti" #~ msgid "_Activity:" #~ msgstr "_Dejavnost:" #~ msgid "_Stop Tracking" #~ msgstr "_Zaustavi merjenje" #~ msgid "Save as HTML" #~ msgstr "Shrani kot HTML" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s. %(b)s" #~ msgid "Delete activity" #~ msgstr "Izbriši dejavnost" #~ msgid "Newer activities" #~ msgstr "Kasnejše dejavnosti" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s.%(report_b)s.%(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_d)s. %(o_b)s" #~ msgid "Move _Down" #~ msgstr "Premakni _dol" #~ msgid "Move _Up" #~ msgstr "Premakni _gor" #~ msgid "N_ew Category" #~ msgstr "_Nova kategorija" #~ msgid "_New Activity" #~ msgstr "_Nova dejavnost" #~ msgid "Activity" #~ msgstr "Dejavnost" #~ msgid "hours" #~ msgstr "ure" #~ msgid "Week" #~ msgstr "Teden" #~ msgid "Earlier activities" #~ msgstr "Zgodnejše dejavnosti" #~ msgid "name" #~ msgstr "ime" #~ msgid "Other" #~ msgstr "Ostalo" #~ msgid "Time tracking for masses" #~ msgstr "Časomer za množice." #~ msgid "Time tracking for masses." #~ msgstr "Časomer za množice." #~ msgid "Overview for %s - %s" #~ msgstr "Pregled za %s - %s" #~ msgid "%d.%m.%y" #~ msgstr "%d.%m.%y" #~ msgid "%d. %b" #~ msgstr "%d. %b" #~ msgid "%B %d." #~ msgstr "%d. %B" hamster-3.0.3/po/sq.po000066400000000000000000000554141452646177100146070ustar00rootroot00000000000000# Përkthimi i hamster-time-tracker në shqip. # Copyright (C) 2008 THE hamster-time-tracker'S COPYRIGHT HOLDER # This file is distributed under the same license as the hamster-time-tracker package. # # Laurent Dhima , 2008. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2008-09-20 12:38+0200\n" "Last-Translator: Laurent Dhima \n" "Language-Team: albanian \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Shto aktivitetin e mëparshëm" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "në progres...\n" "deri në\n" "për" #: ../data/edit_activity.ui.h:4 #, fuzzy msgid "Description:" msgstr "Kohëzgjatja" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "_Aktiviteti:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Ndalo numërimin kur jo aktiv" #: ../data/hamster.schemas.in.h:2 #, fuzzy msgid "Stop tracking current activity when computer becomes idle" msgstr "" "Ndalo llogaritjen e kohës së aktivitetit të tanishëm kur kompjuteri nuk " "është aktiv" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Ndalon numërimin kur sistemi shuhet" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "" "Ndalo llogaritjen e kohës së aktivitetit të tanishëm kur sistemi shuhet" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "" "Kombinim përshpejtues nga tastiera për të shfaqur dritaren e Llogaritjes së " "kohës." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Kombinim përshpejtues nga tastiera për të shfaqur dritaren e Llogaritjes së " "kohës." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Llogaritja e kohës" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Llogaritja e kohës" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "_Kategoritë" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "_Aktivitete" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dita" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Java" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Muaji" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "Përmbledhja - Hamster" #: ../data/overview.ui.h:6 #, fuzzy msgid "_Overview" msgstr "Shfaq përmbledhjen" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktiviteti" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Preferimet e «Llogaritjes së kohës»" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Ndalon numërimin kur kompjuteri nuk kryen asnjë aktivitet" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "Kohëzgjatja" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "_Ndalo numërimin" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategoritë" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "Kategoria" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "Kategori e re" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "Kategori e re" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "Kategori e re" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktivitete" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "Aktiviteti" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Shto aktivitetin" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "Asnjë aktivitet" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Ndrysho aktivitetin" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "_Kategoritë" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "Java" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "Muaji" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "_Ndalo numërimin" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "Shto aktivitetin e mëparshëm" #: ../data/today.ui.h:4 #, fuzzy msgid "Overview" msgstr "Shfaq përmbledhjen" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "_Ndalo numërimin" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "_Ndalo numërimin" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "Aktivitet i ri" #: ../data/today.ui.h:13 msgid "Today" msgstr "Sot" #: ../data/today.ui.h:14 msgid "totals" msgstr "" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Shfaq përmbledhjen" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Asnjë aktivitet" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategoria" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 #, fuzzy msgid "Description" msgstr "Kohëzgjatja" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Fillimi" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Mbarimi" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Kohëzgjatja" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "_Kategoritë" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007-2008 Toms Baugis dhe të tjerë" #: ../src/hamster/about.py:45 #, fuzzy msgid "Project Hamster Website" msgstr "Faqja web e Hamster" #: ../src/hamster/about.py:46 #, fuzzy msgid "About Time Tracker" msgstr "Llogaritja e kohës" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Laurent Dhima , 2008" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Pa kategorizuar" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Punë" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Lexim lajmesh" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Kontrolli i aksioneve" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Projekti super sekret X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Pushtimi i botës" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Dreka" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Uitja e luleve" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Ulje-ngritje me dy duar" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Përditëso aktivitetin" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Përmbledhja për %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Përmbledhja për %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Përmbledhja për %(start_d)s - %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Emri" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Kategori e re" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Aktivitet i ri" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "" msgstr[1] "" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "Aktiviteti" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "minuta" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "Kategoria" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Përmbledhja për %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Përmbledhja për %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Përmbledhja për %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Përmbledhja për %(start_d)s - %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "Aktiviteti" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "_Aktivitete" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "_Kategoritë" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Data" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "Shfaq javën" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Asgjë për sot" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "Llogaritja e kohës" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "Llogaritja e kohës" #~ msgid "Time tracking for masses" #~ msgstr "Instrument për llogaritjen e kohës" #~ msgid "_About" #~ msgstr "_Informacione" #~ msgid "_Preferences" #~ msgstr "_Preferime" #~ msgid "Activities" #~ msgstr "Aktivitete" #~ msgid "Global Hotkey" #~ msgstr "Pulsant i zgjedhjes së shpejtë" #~ msgid "Tracking" #~ msgstr "Numërimi" #~ msgid "Move _Down" #~ msgstr "Lëviz _poshtë" #~ msgid "Move _Up" #~ msgstr "Lëviz _sipër" #~ msgid "N_ew Category" #~ msgstr "Kategori e r_e" #~ msgid "_New Activity" #~ msgstr "Aktivitet i _ri" #~ msgid "Activity" #~ msgstr "Aktiviteti" #~ msgid "Date and Time" #~ msgstr "Data dhe ora" #~ msgid "hours" #~ msgstr "orë" #~ msgid "Show window" #~ msgstr "Shfaq dritaren" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Sh_to aktivitet të mëparshëm" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Today" #~ msgstr "So_t" #~ msgid " _Day" #~ msgstr " _Dita" #~ msgid " _Month" #~ msgstr " _Muaji" #~ msgid " _Week" #~ msgstr " _Java" #~ msgid "Category" #~ msgstr "Kategoria" #~ msgid "Overview" #~ msgstr "Përmbledhja" #~ msgid "Week" #~ msgstr "Java" #~ msgid "Delete activity" #~ msgstr "Elemino aktivitetin" #~ msgid "Earlier activities" #~ msgstr "Aktivitete të mëparshëm" #~ msgid "Generate Report" #~ msgstr "Krijo raport" #~ msgid "Newer activities" #~ msgstr "Aktivitetet e fundit" #~ msgid "Show day" #~ msgstr "Shfaq ditën" #~ msgid "Show month" #~ msgstr "Shfaq muajin" #~ msgid "Time tracking for masses." #~ msgstr "Instrument për llogaritjen e kohës." #~ msgid "Day to day" #~ msgstr "Dita për ditë" # #-#-#-#-# glib.HEAD.sq.po (glib HEAD) #-#-#-#-# # (pofilter) untranslated: checks whether a string has been translated at all #~ msgid "name" #~ msgstr "emri" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s %(report_b)s %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s %(o_d)s %(o_b)s" #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_d)s %(m_b)s" #~ msgid "Other" #~ msgstr "Tjetër" hamster-3.0.3/po/sr.po000066400000000000000000000716031452646177100146060ustar00rootroot00000000000000# Serbian translation of hamster-time-tracker # Courtesy of Prevod.org team (http://prevod.org/) -- 2008—2012. # This file is distributed under the same license as the hamster-time-tracker package. # Мирко Спасић # Горан Ракић  # Translated on 2010-08-27 by: Бранко Кокановић # Милош Поповић , 2010. # Мирослав Николић , 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-19 15:13+0200\n" "Last-Translator: Мирослав Николић \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Project-Style: gnome\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Додај ранију активност" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "до" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "у току" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Опис:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Време:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Активност:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Ознаке:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Заустави праћење када нема активности" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Заустави праћење текуће активности, када рачунар постане неупослен" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Заустави праћење при гашењу" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Заустави праћење текуће активности при гашењу" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Подсети на тренутни посао сваких x минута" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Подсети на тренутни посао након временског интервала затдатог у минутама. " "Ставите на 0 или на више од 120 минута да онемогућите подсетник." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Такође ме и подсети када нема активности" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Уколико ни једна активност није започета подсети ме након одређеног боја " "минута, које одређује кључ notify_interval." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Када почиње нови дан (подразумевано је 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Активности се сматрају јучерашњим уколико је тренутно време у прошлости у " "односу на дан почетка; данашњим ако је преко тог времена. Уколико активност " "обухвата два дана, она ће прећи у онај дан када је извршен већи део те " "активности." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Да ли прекидач радног простора треба да укључује и активност" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Списак укључених начина праћења. „name“ (назив) ће омогућити пребацивање " "активности по именима из workspace_mapping. „memory“ (меморија) ће омогућити " "пребацивање на последњу активности при повратку на претходни радни простор." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Промени активност при промени радног простора" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Уколико је укључено пребацивање по имену, овај списак поставља имена " "активности на које се треба пребацити (радни простори представљени њиховим " "индексима)." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Прикажи / сакриј прозор Пратиоца времена" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Пречица на тастатури за приказивање / сакривање прозора Пратиоца времена" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Акција промене видљивости главног прозора Вредног хрчка" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Наредба за промену видљивости главног прозора Вредног хрчка." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Промена видљивости главног прозора Вредног хрчка" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Промени видљивост главног прозора Вредног хрчка" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Пратилац времена" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Пројекат Вредни хрчак - пратите ваше време" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Преглед праћења времена" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Прозор прегледа праћења времена вредног хрчка" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Прикажи статистику" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Категорије" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Активности" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Ознаке" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Нема података за овај интервал" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Сачувај извештај..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Дан" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Седмица" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Месец" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Преглед — Вредни хрчак" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Преглед" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Активност" #: ../data/overview.ui.h:8 msgid "_View" msgstr "П_реглед" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Укупно" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Уклони" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Додај нову" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Измени" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Поставке праћења времена" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Заустави праћење када рачунар ленчари" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Подсети ме на тренутну активност сваких:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Нови дан почиње у" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Користи следећи списак задатака ако је доступан:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Интеграција" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Праћење" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Категорије" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Списак категорија" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Додај категорију" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Уклони категорију" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Измени категорију" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Активности" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Списак активности" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Додај активност" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Уклони активност" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Уреди активност" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Ознаке за приказ у самодопуњавању" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Категорије и ознаке" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Настави последњу активност по повратку у радни простор" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Започни нову активност при промени радног простора:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Радни простори" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Дан:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Седмица:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Месец:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Временски интервал:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Примени" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Праћ_ење" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Додај ранију активност" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Преглед" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статистике" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Уређивање" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Помоћ" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Садржај" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Заустави праћење" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Пре_баци" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "З_апочни праћење" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Започни нову активност" #: ../data/today.ui.h:13 msgid "Today" msgstr "Данас" #: ../data/today.ui.h:14 msgid "totals" msgstr "укупно" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Прикажи преглед" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Без активности" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Категорија" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Опис" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Почетак" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Крај" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Трајање" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "категорије" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Пројекат Вредни хрчак — пратите ваше време" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Ауторска права © 2007-2010 Toms Bauģis и остали" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Веб место Вредног хрчка" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "О пратиоцу времена" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Мирко Спасић \n" "Бранко Кокановић \n" "\n" "Превод.орг — превод на српски језик." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Непоређано" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Посао" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Читање вести" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Провера акција" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Супер тајни пројекат X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Освајање света" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Из дана у дан" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ручак" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Заливање цвећа" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Превођење Гнома на српски" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Ажурирај активност" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dс" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dмин" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dс %dмин" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B, %Y." #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s. – %(end_B)s %(end_d)s, %(end_Y)s." #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s." #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s." #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d.%b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Укупно је праћено је %s сати" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ништа" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Име" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Нова категорија" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Нова активност" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d минут" msgstr[1] "%(interval_minutes)d минута" msgstr[2] "%(interval_minutes)d минута" msgstr[3] "%(interval_minutes)d минут" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Никад" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "активност" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "време почетка" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "време завршетка" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "трајање у минутима" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "категорија" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "опис" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "ознаке" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Дневник активности за %(start_d)s.%(start_B)s.%(start_Y)s – %(end_d)s." "%(end_B)s.%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Дневник активности за %(start_d)s.%(start_B)s – %(end_d)s.%(end_B)s.%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Дневник активности за %(start_d)s.%(start_B)s.%(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Дневник активности за %(start_d)s - %(end_d)s.%(start_B)s.%(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Укупно по данима" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Дневник активности" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "активности" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "категорије" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Разликуј:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Датум" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Прикажи шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Можете га премостити смештањем вашу верзију у %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Све" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Још нема података за израду статистике.\n" "Недељу дана коришћења би помогло!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Сакупљам податке — проверите поново након недељу дана!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b. %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Прва активност је забележена %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s година" msgstr[1] "%(num)s године" msgstr[2] "%(num)s година" msgstr[3] "%(num)s година" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "До сада праћено време износи %(human_days)s дана (%(human_years)s) или " "%(working_days)s радних дана (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "Најдужи непрекидни посао је био %(date)s и трајао је %(hours)s сат." msgstr[1] "" "Најдужи непрекидни посао је био %(date)s и трајао је %(hours)s сата." msgstr[2] "" "Најдужи непрекидни посао је био %(date)s и трајао је %(hours)s сати." msgstr[3] "Најдужи непрекидни посао је био %(date)s и трајао је %(hours)s сат." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Постоји %s запис." msgstr[1] "Постоји %s записа." msgstr[2] "Постоји %s записа." msgstr[3] "Постоји %s запис." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Вредни хрчак би волео да те још мало надгледа!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Са %s процената свих ствари које сте започели пре 9 преподне, изгледа да сте " "раноранилац." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Са %s процената свих ствари које сте започели после 11 увече, изгледа да сте " "ноћна птица." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Са %s процената свих ствари које су трајале мање од 15 минута, изгледа да " "сте пчелица Маја." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Данас нема записа" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sс" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Управо започела" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Чување извештаја — Пратилац времена" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "ХТМЛ извештај" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Вредности одвојене табулатором (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "ХМЛ" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "иКол" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Праћење времена" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Прикажите прозор активности" #~ msgid "Sto_p Tracking" #~ msgstr "Заустави _праћење" #~ msgid "To_day" #~ msgstr "_Данас" #~ msgid "_Add earlier activity" #~ msgstr "Дод_ај ранију активност" #~ msgid "Show _Overview" #~ msgstr "Прикажи _преглед" #~ msgid "_Preferences" #~ msgstr "_Поставке" #~ msgid "_About" #~ msgstr "_О програму" #~ msgid "Year:" #~ msgstr "Година:" #~ msgid "Starts and ends" #~ msgstr "Почетак и крај" #~ msgid "Preferences" #~ msgstr "Поставке" #~ msgid "Changed activity" #~ msgstr "Измењена активност" #~ msgid "Switched to '%s'" #~ msgstr "Пребачена у „%s“" #~ msgid "Working on %s" #~ msgstr "Радим на %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Вредни хрчак праћење времена. Коришћење:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Вредни хрчак (Праћење времена за Гном)" #~ msgid "totals by activity" #~ msgstr "укупно по активностима" #~ msgid "totals by category" #~ msgstr "укупно по категоријама" #~ msgid "Show:" #~ msgstr "Прикажи:" hamster-3.0.3/po/sr@latin.po000066400000000000000000000621161452646177100157350ustar00rootroot00000000000000# Serbian translation of hamster-time-tracker # Courtesy of Prevod.org team (http://prevod.org/) -- 2008—2012. # This file is distributed under the same license as the hamster-time-tracker package. # Mirko Spasić # Goran Rakić  # Translated on 2010-08-27 by: Branko Kokanović # Miloš Popović , 2010. # Miroslav Nikolić , 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-19 15:13+0200\n" "Last-Translator: Miroslav Nikolić \n" "Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Project-Style: gnome\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Dodaj raniju aktivnost" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "do" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "u toku" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Opis:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Vreme:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivnost:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Oznake:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Zaustavi praćenje kada nema aktivnosti" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Zaustavi praćenje tekuće aktivnosti, kada računar postane neuposlen" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Zaustavi praćenje pri gašenju" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Zaustavi praćenje tekuće aktivnosti pri gašenju" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Podseti na trenutni posao svakih x minuta" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Podseti na trenutni posao nakon vremenskog intervala zatdatog u minutama. " "Stavite na 0 ili na više od 120 minuta da onemogućite podsetnik." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Takođe me i podseti kada nema aktivnosti" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Ukoliko ni jedna aktivnost nije započeta podseti me nakon određenog boja " "minuta, koje određuje ključ notify_interval." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Kada počinje novi dan (podrazumevano je 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktivnosti se smatraju jučerašnjim ukoliko je trenutno vreme u prošlosti u " "odnosu na dan početka; današnjim ako je preko tog vremena. Ukoliko aktivnost " "obuhvata dva dana, ona će preći u onaj dan kada je izvršen veći deo te " "aktivnosti." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Da li prekidač radnog prostora treba da uključuje i aktivnost" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Spisak uključenih načina praćenja. „name“ (naziv) će omogućiti prebacivanje " "aktivnosti po imenima iz workspace_mapping. „memory“ (memorija) će omogućiti " "prebacivanje na poslednju aktivnosti pri povratku na prethodni radni prostor." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Promeni aktivnost pri promeni radnog prostora" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Ukoliko je uključeno prebacivanje po imenu, ovaj spisak postavlja imena " "aktivnosti na koje se treba prebaciti (radni prostori predstavljeni njihovim " "indeksima)." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Prikaži / sakrij prozor Pratioca vremena" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "Prečica na tastaturi za prikazivanje / sakrivanje prozora Pratioca vremena" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Akcija promene vidljivosti glavnog prozora Vrednog hrčka" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Naredba za promenu vidljivosti glavnog prozora Vrednog hrčka." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Promena vidljivosti glavnog prozora Vrednog hrčka" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Promeni vidljivost glavnog prozora Vrednog hrčka" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Pratilac vremena" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Projekat Vredni hrčak - pratite vaše vreme" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Pregled praćenja vremena" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Prozor pregleda praćenja vremena vrednog hrčka" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Prikaži statistiku" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorije" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktivnosti" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Oznake" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Nema podataka za ovaj interval" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Sačuvaj izveštaj..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dan" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Sedmica" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Mesec" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Pregled — Vredni hrčak" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Pregled" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivnost" #: ../data/overview.ui.h:8 msgid "_View" msgstr "P_regled" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Ukupno" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Ukloni" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Dodaj novu" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Izmeni" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Postavke praćenja vremena" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Zaustavi praćenje kada računar lenčari" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Podseti me na trenutnu aktivnost svakih:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Novi dan počinje u" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Koristi sledeći spisak zadataka ako je dostupan:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integracija" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Praćenje" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorije" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Spisak kategorija" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Dodaj kategoriju" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Ukloni kategoriju" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Izmeni kategoriju" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktivnosti" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Spisak aktivnosti" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Dodaj aktivnost" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Ukloni aktivnost" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Uredi aktivnost" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Oznake za prikaz u samodopunjavanju" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorije i oznake" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Nastavi poslednju aktivnost po povratku u radni prostor" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Započni novu aktivnost pri promeni radnog prostora:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Radni prostori" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dan:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Sedmica:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Mesec:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Vremenski interval:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Primeni" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "Prać_enje" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Dodaj raniju aktivnost" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Pregled" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistike" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Uređivanje" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Pomoć" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Sadržaj" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Zaustavi praćenje" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Pre_baci" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Z_apočni praćenje" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Započni novu aktivnost" #: ../data/today.ui.h:13 msgid "Today" msgstr "Danas" #: ../data/today.ui.h:14 msgid "totals" msgstr "ukupno" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Prikaži pregled" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Bez aktivnosti" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategorija" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Opis" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Početak" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Kraj" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Trajanje" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorije" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Projekat Vredni hrčak — pratite vaše vreme" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Autorska prava © 2007-2010 Toms Bauģis i ostali" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Veb mesto Vrednog hrčka" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "O pratiocu vremena" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Mirko Spasić \n" "Branko Kokanović \n" "\n" "Prevod.org — prevod na srpski jezik." #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Nepoređano" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Posao" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Čitanje vesti" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Provera akcija" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Super tajni projekat X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Osvajanje sveta" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Iz dana u dan" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ručak" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Zalivanje cveća" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Prevođenje Gnoma na srpski" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Ažuriraj aktivnost" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%ds" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%ds %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d. %B, %Y." #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s. – %(end_B)s %(end_d)s, %(end_Y)s." #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s." #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s." #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d.%b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Ukupno je praćeno je %s sati" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ništa" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Ime" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Nova kategorija" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Nova aktivnost" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minuta" msgstr[2] "%(interval_minutes)d minuta" msgstr[3] "%(interval_minutes)d minut" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Nikad" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivnost" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "vreme početka" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "vreme završetka" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "trajanje u minutima" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategorija" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "opis" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "oznake" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Dnevnik aktivnosti za %(start_d)s.%(start_B)s.%(start_Y)s – %(end_d)s." "%(end_B)s.%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Dnevnik aktivnosti za %(start_d)s.%(start_B)s – %(end_d)s.%(end_B)s.%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Dnevnik aktivnosti za %(start_d)s.%(start_B)s.%(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Dnevnik aktivnosti za %(start_d)s - %(end_d)s.%(start_B)s.%(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Ukupno po danima" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Dnevnik aktivnosti" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktivnosti" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorije" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Razlikuj:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Prikaži šablon" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Možete ga premostiti smeštanjem vašu verziju u %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Sve" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Još nema podataka za izradu statistike.\n" "Nedelju dana korišćenja bi pomoglo!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Sakupljam podatke — proverite ponovo nakon nedelju dana!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b. %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Prva aktivnost je zabeležena %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s godina" msgstr[1] "%(num)s godine" msgstr[2] "%(num)s godina" msgstr[3] "%(num)s godina" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Do sada praćeno vreme iznosi %(human_days)s dana (%(human_years)s) ili " "%(working_days)s radnih dana (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d.%b.%Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sat." msgstr[1] "" "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sata." msgstr[2] "" "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sati." msgstr[3] "Najduži neprekidni posao je bio %(date)s i trajao je %(hours)s sat." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Postoji %s zapis." msgstr[1] "Postoji %s zapisa." msgstr[2] "Postoji %s zapisa." msgstr[3] "Postoji %s zapis." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Vredni hrčak bi voleo da te još malo nadgleda!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Sa %s procenata svih stvari koje ste započeli pre 9 prepodne, izgleda da ste " "ranoranilac." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Sa %s procenata svih stvari koje ste započeli posle 11 uveče, izgleda da ste " "noćna ptica." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Sa %s procenata svih stvari koje su trajale manje od 15 minuta, izgleda da " "ste pčelica Maja." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Danas nema zapisa" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%ss" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Upravo započela" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Čuvanje izveštaja — Pratilac vremena" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML izveštaj" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Vrednosti odvojene tabulatorom (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "HML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iKol" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Praćenje vremena" #~| msgid "activities" #~ msgid "Show activities window" #~ msgstr "Prikažite prozor aktivnosti" #~ msgid "Sto_p Tracking" #~ msgstr "Zaustavi _praćenje" #~ msgid "To_day" #~ msgstr "_Danas" #~ msgid "_Add earlier activity" #~ msgstr "Dod_aj raniju aktivnost" #~ msgid "Show _Overview" #~ msgstr "Prikaži _pregled" #~ msgid "_Preferences" #~ msgstr "_Postavke" #~ msgid "_About" #~ msgstr "_O programu" #~ msgid "Year:" #~ msgstr "Godina:" #~ msgid "Starts and ends" #~ msgstr "Početak i kraj" #~ msgid "Preferences" #~ msgstr "Postavke" #~ msgid "Changed activity" #~ msgstr "Izmenjena aktivnost" #~ msgid "Switched to '%s'" #~ msgstr "Prebačena u „%s“" #~ msgid "Working on %s" #~ msgstr "Radim na %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Vredni hrčak praćenje vremena. Korišćenje:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Vredni hrčak (Praćenje vremena za Gnom)" #~ msgid "totals by activity" #~ msgstr "ukupno po aktivnostima" #~ msgid "totals by category" #~ msgstr "ukupno po kategorijama" #~ msgid "Show:" #~ msgstr "Prikaži:" hamster-3.0.3/po/sv.po000066400000000000000000000751311452646177100146120ustar00rootroot00000000000000# Swedish translation of hamster. # Copyright (C) 2008-2012 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Kalle Persson , 2008. # Daniel Nylander , 2008, 2009, 2010, 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-19 10:50+0100\n" "Last-Translator: Daniel Nylander \n" "Language-Team: Swedish \n" "Language: sv\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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Lägg till tidigare aktivitet" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "till" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "pågående" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Beskrivning:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Tid:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Aktivitet:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Taggar:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Stoppa tidmätning vid inaktivitet" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Stoppa tidmätning av aktuell aktivitet när datorn blir overksam" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Stoppa tidmätning vid avstängning" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Stoppa tidmätning av aktuell aktivitet vid avstängning" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Påminn om aktuell uppgift var x minuter" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Påminn om aktuell uppgift varje angivet antal minuter. Ställ in till 0 eller " "större än 120 för att inaktivera påminnelser." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Påminn även när ingen aktivitet är inställd" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Påminn även varje notify_interval minuter om ingen aktivitet har startats." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "Vid vilken tidpunkt som dagen börjar (standard är 05.30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Aktiviteter kommer att räknas som gårdagens om den aktuella tiden är mindre " "än den angivna dagens start, och idag, om den går över tiden. Aktiviteter " "som spänner över två dagar kommer att tippa över till den sida där den " "största delen av aktiviteten är." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Ska växling av arbetsyta generera aktivitetsväxling" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Lista över aktiverade mätmetoder. \"name\" kommer att aktivera växling av " "aktivitet efter namn i workspace_mapping. \"memory\" kommer att aktivera " "växling till senaste aktivitet vid när man återvänder till en tidigare " "arbetsyta." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Växla aktivitet vid byte av arbetsyta" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Om växling efter namn är aktiverat kommer denna lista att ställa in " "aktivitetsnamnen som ska växlas till, arbetsytor representeras av indexet " "för objektet." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Visa / dölj Tidmätare-fönstret" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Tangentbordsgenväg för att visa /dölja Tidmätare-fönstret." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Växla fönsteråtgärd för hamster-programmet" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Kommando för att växla fönstersynlighet för hamster-programmet." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Växla programfönstret för hamster" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Växla fönstersynlighet för hamster-programmet." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Tidmätare" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster-projektet - mät din tid" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Översikt för Tidmätare" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Översiktsfönstret för tidmätaren Hamster" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Visa statistik" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategorier" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Aktiviteter" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Taggar" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Inget data för detta intervall" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Spara rapport..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Dag" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Vecka" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Månad" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Översikt — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Översikt" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Aktivitet" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Visa" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Totalt" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Ta bort" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Lägg till ny" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Redigera" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Inställningar för Tidmätare" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Stoppa tidmätning när datorn är inaktiv" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Påminn om aktuell aktivitet var:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Ny dag startar klockan" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Använd följande attgöra-lista om tillgänglig:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Integration" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Tidmätning" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategorier" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategorilista" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Lägg till kategori" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Ta bort kategori" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Redigera kategori" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Aktiviteter" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Aktivitetslista" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Lägg till aktivitet" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Ta bort aktivitet" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Redigera aktivitet" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Taggar som ska visas i automatisk komplettering" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategorier och taggar" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Återuppta senaste aktivitet vid återvändande till en arbetsyta" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Starta ny aktivitet när arbetsytor växlas:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Arbetsytor" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Dag:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Vecka:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Månad:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Intervall:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Verkställ" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Tidmätning" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Lägg till tidigare aktivitet" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Översikt" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Statistik" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "R_edigera" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Hjälp" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Innehåll" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Sto_ppa tidmätning" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Vä_xla" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Starta _tidmätning" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Starta ny aktivitet" #: ../data/today.ui.h:13 msgid "Today" msgstr "Idag" #: ../data/today.ui.h:14 msgid "totals" msgstr "totalt" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Visa översikt" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Ingen aktivitet" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategori" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Beskrivning" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Start" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Slut" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Längd" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategorier" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster-projektet - mät din tid" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Copyright © 2007–2010 Toms Bauģis och andra" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Webbplatsen för Projekt Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Om Tidmätare" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Daniel Nylander \n" "Kalle Persson\n" "\n" "Skicka synpunkter på översättningen till\n" "" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Osorterat" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Arbete" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Läser nyheter" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Kontrollerar aktier" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Superhemligt projekt X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Världsherravälde" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Dag för dag" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Lunch" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Vattna blommorna" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Stå på händerna" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Uppdatera aktivitet" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s, %(start_Y)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "%s timmar har mäts totalt" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Ingen" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Namn" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Ny kategori" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Ny aktivitet" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minut" msgstr[1] "%(interval_minutes)d minuter" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Aldrig" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "aktivitet" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "starttid" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "sluttid" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "längd i minuter" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategori" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "beskrivning" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "taggar" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Aktivitetsrapport för %(start_Y)s %(start_B)s %(start_d)s – %(end_Y)s " "%(end_B)s %(end_d)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Aktivitetsrapport för %(start_d)s %(start_B)s – %(end_d)s %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Aktivitetsrapport för %(start_d)s %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Aktivitetsrapport för %(start_d)s %(start_B)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Totalt per dag" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Aktivitetslogg" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "aktiviteter" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategorier" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Kommentar:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Datum" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Visa mall" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Du kan åsidosätta det genom att lagra din version i %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Alla" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Det finns ingen data för att generera statistik än.\n" "En veckas användning hade varit trevligt!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Samlar in data — kontrollera igen efter en vecka!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Första aktiviteten registrerades den %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s år" msgstr[1] "%(num)s år" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Tidmätningen än så länge är %(human_days)s dagar (%(human_years)s år) eller " "%(working_days)s arbetsdagar (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Längsta oavbrutna arbete skedde den %(date)s och var %(hours)s timme." msgstr[1] "" "Längsta oavbrutna arbete skedde den %(date)s och var %(hours)s timmar." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Det finns %s post." msgstr[1] "Det finns %s poster." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster vill observera dig mer!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Eftersom %s procent av alla aktiviteter börjar före klockan 09.00 så verkar " "det som du är morgonpigg." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Eftersom %s procent av alla aktiviteter börjar efter 23.00 så verkar det som " "om du är en nattuggla." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Eftersom %s procent av alla aktiviteter är kortare än 15 minuter så verkar " "det som om du är en arbetsmyra." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Inga poster idag" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Precis startad" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Spara rapport — Tidmätare" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML-rapport" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tabulatorseparerade värden (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Tidmätare" #~ msgid "Show activities window" #~ msgstr "Visa aktivitetsfönster" #~ msgid "Sto_p Tracking" #~ msgstr "Sto_ppa tidmätning" #~ msgid "To_day" #~ msgstr "_Idag" #~ msgid "_Add earlier activity" #~ msgstr "_Lägg till tidigare aktivitet" #~ msgid "Show _Overview" #~ msgstr "Visa _översikt" #~ msgid "_Preferences" #~ msgstr "_Inställningar" #~ msgid "_About" #~ msgstr "_Om" #~ msgid "Year:" #~ msgstr "År:" #~ msgid "Starts and ends" #~ msgstr "Startar och slutar" #~ msgid "Preferences" #~ msgstr "Inställningar" #~ msgid "Changed activity" #~ msgstr "Ändrade aktivitet" #~ msgid "Switched to '%s'" #~ msgstr "Växlade till \"%s\"" #~ msgid "Working on %s" #~ msgstr "Arbetar på %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Tidmätaren Hamster. Användning:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Hamster-projektet (GNOME-tidmätning)" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Lä_gg till tidigare aktivitet" #~ msgid "Tell me more" #~ msgstr "Berätta mer" #~ msgid "_Today" #~ msgstr "_Idag" #~ msgid "Preview:" #~ msgstr "Förhandsvisa:" #~ msgid "Add" #~ msgstr "Lägg till" #~ msgid "Save Report" #~ msgstr "Spara rapport" #~ msgid "General" #~ msgstr "Allmänt" #~ msgid "Global Hotkey" #~ msgstr "Allmän snabbtangent" #~ msgid "Move activity down" #~ msgstr "Flytta aktivitet nedåt" #~ msgid "Move activity up" #~ msgstr "Flytta aktivitet uppåt" #~ msgid "Total Time" #~ msgstr "Total tid" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "Switch" #~ msgstr "Växla" #~ msgid "Time and Name" #~ msgstr "Tid och namn" #~ msgid "Tags or Description" #~ msgstr "Taggar eller beskrivning" #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "Klockslag när en ny dag anses börja" #~ msgid "Activities" #~ msgstr "Aktiviteter" #~ msgid "Tracking" #~ msgstr "Tidmätning" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Ange en aktivitet och tryck på Enter för att börja " #~ "mäta!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Berätta mer" #~ msgid "_Activity:" #~ msgstr "_Aktivitet:" #~ msgid "_Stop Tracking" #~ msgstr "_Stoppa tidmätning" #~ msgid " _Day" #~ msgstr "_Dag" #~ msgid " _Month" #~ msgstr "_Månad" #~ msgid " _Week" #~ msgstr "_Vecka" #~ msgid "Overview" #~ msgstr "Översikt" #~ msgid "Totals" #~ msgstr "Totalt" #~ msgid "Categories:" #~ msgstr "Kategorier:" #~ msgid "Date interval:" #~ msgstr "Datumintervall:" #~ msgid "Next" #~ msgstr "Nästa" #~ msgid "Next week" #~ msgstr "Nästa vecka" #~ msgid "Previous" #~ msgstr "Föregående" #~ msgid "Previous week" #~ msgstr "Föregående vecka" #~ msgid "Show month" #~ msgstr "Visa månad" #~ msgid "Show single day" #~ msgstr "Visa enstaka dag" #~ msgid "This Week" #~ msgstr "Denna vecka" #~ msgid "This week" #~ msgstr "Denna vecka" #~ msgid "What should be typed in the activity box?" #~ msgstr "Vad ska skrivas in i aktivitetsrutan?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Det finns en enkel syntax som gör att du kan lägga till detaljer till " #~ "dina aktiviteter:\n" #~ " \n" #~ "Symbolen \"@\" markerar kategori. Exempel: \"vattna blommorna@hemma\" " #~ "kommer att börja mäta aktiviteten \"vattna blommorna\" i kategorin \"hemma" #~ "\".\n" #~ "\n" #~ "Kommatecken (\",\") markerar börjar av en beskrivning. Exempel: \"vattna " #~ "blommorna, kaktus och tagetes\" kommer att börja mäta aktiviteten " #~ "\"vattna blommorna\" och lägga till beskrivningen \"kaktus och tagetes\" " #~ "till den.\n" #~ "\n" #~ "Båda kan kombineras: \"vattna blommorna@hemma, kaktus och tagetes\" " #~ "kommer att fungera alldeles finfint!\n" #~ "\n" #~ "Börja nu att mäta din tid!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Alla" #~ msgid "Total" #~ msgstr "Totalt" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%d %b" #~ msgid "Overview for %(date)s" #~ msgstr "Översikt för %(date)s" #~ msgid "Previous day" #~ msgstr "Föregående dag" #~ msgid "Next day" #~ msgstr "Nästa dag" #~ msgid "Previous month" #~ msgstr "Föregående månad" #~ msgid "Next month" #~ msgstr "Nästa månad" #~ msgid "This month" #~ msgstr "Denna månad" #~ msgid "This Month" #~ msgstr "Denna månad" #~ msgid "Save as HTML" #~ msgstr "Spara som HTML" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s %(b)s" #~ msgid "Remind also when no activity is set" #~ msgstr "Påminn även när ingen aktivitet är inställd" #~ msgid "%.1fh" #~ msgstr "%.1fh" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s %(report_b)s %(report_Y)s" #~ msgid "%(first_b)s %(first_d)s" #~ msgstr "%(first_d)s %(first_b)s" #, fuzzy #~ msgid "Averages" #~ msgstr "Översikt" #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration).1f, " #~ msgid "Move _Down" #~ msgstr "Flytta _nedåt" #~ msgid "Move _Up" #~ msgstr "Flytta _uppåt" #~ msgid "N_ew Category" #~ msgstr "N_y kategori" #~ msgid "_New Activity" #~ msgstr "_Ny aktivitet" #~ msgid "Activity" #~ msgstr "Aktivitet" #~ msgid "hours" #~ msgstr "timmar" #~ msgid "minutes" #~ msgstr "minuter" #~ msgid "Category" #~ msgstr "Kategori" #~ msgid "Week" #~ msgstr "Vecka" #~ msgid "Delete activity" #~ msgstr "Ta bort aktivitet" #~ msgid "Earlier activities" #~ msgstr "Tidigare aktiviteter" #~ msgid "Newer activities" #~ msgstr "Nyare aktiviteter" #~ msgid "name" #~ msgstr "namn" #~ msgid "Other" #~ msgstr "Övriga" #~ msgid "Summary of Activities" #~ msgstr "Sammandrag av aktiviteter" #~ msgid "Time tracking for masses" #~ msgstr "Tidmätning för alla" #~ msgid "Time tracking for masses." #~ msgstr "Tidmätning för alla." #~ msgid "Overview for %s - %s" #~ msgstr "Översikt för %s - %s" #~ msgid "Idle minutes:" #~ msgstr "Inaktivitet i minuter:" #~ msgid "" #~ "After how many minutes hamster should stop tracking activity when " #~ "computer is idle. Set to 0 to disable." #~ msgstr "" #~ "Efter hur många minuter som Hamster ska stoppa tidmätning av aktiviteten " #~ "när datorn är inaktiv. Ställ in till 0 för att inaktivera." #~ msgid "Add an older fact" #~ msgstr "Lägg till en äldre händelse" #~ msgid "Ad_d Older Fact" #~ msgstr "Läg_g till äldre händelse" #~ msgid "Edit Activities" #~ msgstr "Redigera aktiviteter" #~ msgid "Add custom fact - Hamster" #~ msgstr "Lägg till anpassad händelse - Hamster" #~ msgid "Nedarbi" #~ msgstr "Pusdienas" hamster-3.0.3/po/ta.po000066400000000000000000001144451452646177100145700ustar00rootroot00000000000000# translation of hamster.master.ta.po to Tamil # translation of hamster.po to # translation of hamster.HEAD-ta.po to # Tamil Translation for GNOME hamster-time-tracker # Copyright (C) 2008 Project Hamster Team # This file is distributed under the same license as the hamster-time-tracker package. # # Kannan Subramanian , 2008. # Shakthi Kannan , 2008. # I. Felix , 2008, 2009. # Dr.T.vasudevan , 2009. # Dr.T.Vasudevan , 2009, 2010, 2011, 2012. # Dr,T,Vasudevan , 2009, 2010, 2011. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.ta\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-28 17:27+0530\n" "Last-Translator: Dr.T.Vasudevan \n" "Language-Team: American English \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.1\n" "Plural-Forms: nplurals=2; plural=(n!=1);\\n\n" "\n" "\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "முந்தைய செயல்பாட்டைச் சேர்க்கவும்" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "வரை" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "முன்னேற்றத்தில் உள்ளது" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "விவரம்:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "நேரம்:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "செயல்பாடு:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "குறிகள்:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "இயக்கமற்ற நிலையில் தடத்தொடர்தல் நிறுத்தவும்" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "கணினி வெறுமையாக இருக்கும் போது தற்போதைய செயல்பாட்டுத் தடத்தொடர்தல் நிறுத்தவும்" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "முடித்து வைத்ததும் தடத்தொடர்தல் நிறுத்தவும்" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "முடித்து வைத்ததும் தற்போதைய செயல்பாட்டுத் தடத்தொடர்தல் நிறுத்தவும்" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ஒவ்வொரு x நிமிடங்களும் நடப்பு வேலையை நினைவுறுத்துக" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "நடப்பு பணியின் நினைவூட்டல் ஒவ்வொரு குறிப்பிட்ட அளவு நிமிடங்களுக்கு. 0 அல்லது 120 " "அதிகமாக அமைத்து நினைவூட்டலை செயல்நீக்கவும்." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "செயல் அமைக்காத போதும் நினைவுறுத்துக" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "செயல் துவக்கப்படாத போதும் நினைவுறுத்த வேண்டிய இடைவெளியில் நினைவுறுத்துக (_i)" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "நாளில் எந்த நேரத்தில் துவங்க வேண்டும்? (முன்னிருப்பு காலை ஐந்தரை)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "நடப்பு நேரம் குறிப்பிட்ட துவக்க நாளை விட குறைவாக இருந்தால் செயல்கள் நேற்றையதாக " "கொள்ளப்படும். அதிகமாக இருப்பின் இன்றையதாக கொள்ளப்படும். இரு நாட்களில் வியாபிக்கும் செய்ல்கள் " "அதிக நேரம் இருக்கும் நாளுக்கு தள்ளப்படும்." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "வேலைக்களம் மாற்றுவது செயலையும் பாதிக்க வேண்டுமா?" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "தடத்தொடர்தலுக்கு செயலாக்கிய முறைகளின் பட்டியல். \"பெயர்\" என்பது workspace_mapping " "இல் அறுதியான பெயரால் மாற்றும் செயல்களை நடத்தும். \"நினைவகம்\"என்பது முந்தைய " "வேலைக்களத்தின் கடைசி மாற்றும் செயலுக்கு செயலாக்கும். " #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "செயலை வேலைக்கள் மாற்றத்துக்கு மாற்றவும்." #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "பெயரால் மாற்றுவது செயலில் உள்ளது. இந்த பட்டியல் மாற்ற வேண்டிய செயல் பெயரை அமைக்கிறது. " "வேலைக்களங்கள் உருப்படியின் அட்டவணையால் காட்டப்படும்." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "நேரத் தடம் தேடல் சாளரத்தைக் காட்டு / மறை" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "நேரத் தடம் தேடல் சாளரத்தைக் காட்டுவதற்கான /மூடுவதற்கான விசைப் பலகைக் குறுக்கு வழி" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "ஹாம்ஸ்டர் பயன்பாட்டு சாளர செயலை நிலை மாற்றுக" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "ஹாம்ஸ்டர் பயன்பாட்டு சாளரத்தின் வெளிப்பாட்டை நிலை மாற்ற கட்டளை" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "ஹாம்ஸ்டர் பயன்பாட்டு சாளரத்தை நிலை மாற்றுக" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "ஹாம்ஸ்டர் பயன்பாட்டு சாளரத்தின் வெளிப்பாட்டை நிலை மாற்றுக" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "நேரத் தடம் தேடல்" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "ஹாம்ஸ்டர் திட்டம் - உங்கள் நேரத்தை கண்காணிக்க" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "நேரத் தடம் தொடர்வி மேலோட்டம்" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "ஹாம்ஸ்டர் நேரத்தட தொடர்வியின் மேலோட்ட சாளரம்" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "புள்ளிவிவரங்களை காட்டு" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "வகைகள்" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "செயல்பாடுகள்" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "குறிகள் (Tags)" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "இந்த இடைவெளிக்கு தரவு ஏதும் இல்லை." #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "அறிக்கையை சேமி..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "நாள்" #: ../data/overview.ui.h:3 msgid "Week" msgstr "வாரம்" #: ../data/overview.ui.h:4 msgid "Month" msgstr "மாதம்" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "கண்ணோட்டம் — ஹாம்ஸ்டர்" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "(_O) மேல்பார்வை" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "செயல்பாடு" #: ../data/overview.ui.h:8 msgid "_View" msgstr "பார்வை (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "மொத்தங்கள்" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "நீக்கு" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "புதியதை சேர்" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "திருத்து" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "நேரத் தடம் தேடல் முன்னுரிமைகள்" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "கணினி இயக்கம் நின்றதும் தடத்தொடர்தலை நிறுத்தவும்" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "தற்போதைய செயலை நினைவுறுத்த இடைவெளி:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "புதிய நாள் துவங்குவது" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "பின்வரும் செய்ய வேண்டியன பட்டியலை கிடத்தால் பயன்படுத்துக:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "ஒருங்கிணைப்பு" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "தொடர்வது" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "வகைகள் (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "வகை பட்டியல்" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "வகை சேர் " #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "வகையை நீக்கு" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "வகை திருத்தி அமைக்கவும்" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "செயல்பாடுகள் (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "செயல்பாடு பட்டியல்" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "செயல்பாட்டைச் சேர்க்கவும்" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "செயலை நீக்கு" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "செயல்பாட்டைத் திருத்தி அமைக்கவும்" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "தானியங்கிபூர்த்தியில் காண வேண்டிய குறி ஒட்டுக்கள்" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "வகைகள் மற்றும் குறிகள்" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "வேலைக்களத்துக்கு திரும்பினால் கடைசி செயலை மீள் துவக்குக." #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "வேலைக்களத்தை மாற்றினால் புதிய செயலை துவக்குக" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "வேலைக்களங்கள்" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "நாள்:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "வாரம்:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "மாதம்:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "வீச்சு:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "செயல்படுத்துக" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "தொடர்வது (_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "முந்தைய செயல்பாட்டைச் சேர்க்கவும்" #: ../data/today.ui.h:4 msgid "Overview" msgstr "கண்ணோட்டம்" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "புள்ளி விவரம்" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_E திருத்து" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_H உதவி" #: ../data/today.ui.h:8 msgid "Contents" msgstr "உள்ளடக்கங்கள்" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "தொடர்வதை நிறுத்தவும் (_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "(_w)மாற்றி" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "தொடர்வதை துவக்கவும் (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "புதிய செயல்பாடு துவக்கு" #: ../data/today.ui.h:13 msgid "Today" msgstr "இன்று" #: ../data/today.ui.h:14 msgid "totals" msgstr "மொத்தங்கள்" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "மேலோட்டத் தோற்றம் காட்டவும்" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "செயல்பாடு இல்லை" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "வகை" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "விவரணம்" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "துவக்கம்" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "முடிவு" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "காலஅளவு" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "வகைகள்" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Project Hamster — உங்கள் நேரத்தை கண்காணிக்க" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "காப்புரிமை © 2007–2010 டாம் பாஜிஸ் மற்றும் இதரர்" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "ஹாம்ஸ்டர் திட்ட வலைப்பக்கம்" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "நேரத் தடம் தேடல் பற்றி " #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "I. Felix . Dr. T. Vasudevan shakthi " "kannan, 2008-2009, Dr. T. Vasudevan 2010" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "இனம் பிரிக்கப்படாதவை" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "பணி" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "செய்திகள் வாசிப்பு" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "வணிகப் பங்குகள் சரிபார்த்தல்" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "மிக ரகசியத் திட்டம் எக்ஸ்" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "உலக ஆதிக்கம்" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "அன்றாடம்" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "மதிய உணவு" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "பூக்களுக்குத் தண்ணீர் பாய்ச்சுதல்" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "தலைகீழாய் நிற்றல்" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "செயல்பாட்டை நிகழ்நிலைப்படுத்தவும்" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr " '%s' மணிகள் மொத்தம் தடத்தொடர்வு செய்யப்பட்டது." #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "எதுவுமில்லை" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "பெயர்" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "புதிய வகை" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "புதிய செயல்பாடு" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d minute" msgstr[1] "%(interval_minutes)d minutes" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "எப்போதுமில்லை" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "செயல்பாடு" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "துவக்க நேரம்" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "முடிவு நேரம்" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "காலஅளவு நிமிடங்களில்" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "வகை" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "விவரணம்" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "குறிகள் (Tags)" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" " %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s க்கு " "செயல் பதிவேடு" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s க்கு செயல் பதிவேடு" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s க்கு செயல் பதிவேடு" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s க்கு செயல் பதிவேடு" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "மொத்தங்கள் நாள் கணக்கில்" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "செயல்பாடு பதிவேடு" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "செயல்பாடுகள்" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "வகைகள்" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "பாகுபடுத்து" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "தேதி" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "வார்ப்புருவை காட்டு" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "உங்கள் பதிப்பை %(home_folder)s இல் சேமித்து அதை வற்புறுத்தி மேல் செயலாக்கலாம்." #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "எல்லாம்" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "புள்ளி விவரம் தர இன்னும் தரவு இல்லை.\n" "ஒரு வார பயன்பாடு நல்லா இருக்கும்!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "தரவை சேமிக்கிறது. - இன்னும் ஒரு வாரம் கழித்து வாங்க!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr " %s இல் பதிவு செய்த முதல் செயல்பாடு" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s வருடம்" msgstr[1] "%(num)s வருடங்கள்" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "இது வரை தொடர்ந்த நேரம் %(human_days)s மனித நாட்கள் (%(human_years)s வருடங்கள்) " "அல்லது %(working_days)s வேலை நாட்கள் (%(working_years)s வருடங்கள்)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "நீண்ட தொடர்ச்சியாக வேலை நடந்தது %(date)s மற்றும் %(hours)s மணி." msgstr[1] "நீண்ட தொடர்ச்சியாக வேலை நடந்தது %(date)s மற்றும் %(hours)s மணிகள்." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s பதிவு உள்ளது" msgstr[1] "%s பதிவுகள் உள்ளன" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "ஹாம்ஸ்டர் உங்களை இன்னும் கவனிக்க விரும்புகிறது!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" " %s சதவிகித செயல்கள் காலை 9 மணிக்கு முன் ஆரம்பிக்கின்றன. நீங்க ரொம்ப சுறுசுறுப்புதான்." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr " %s சதவிகித செயல்கள் இரவு 11 மணிக்கு பின் ஆரம்பிக்கின்றன. நீங்க ஆந்தை போல." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr " %s சதவிகித வேலைகள் 15 நிமிடங்களுக்கும் குறைவு. நீங்க ரொம்ப சுறுசுறுப்புதான்." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "இன்று பதிவுக் குறிப்புகள் எதுவும் இல்லை" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "இப்போதுதான் துவக்கியது" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "அறிக்கையை சேமி — நேரத் தடம் தேடல்" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "ஹெச்டிஎம்எல்(HTML) அறிக்கை" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "தத்தல்-பிரித்த மதிப்புகள் (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "எக்ஸ்எம்எல்" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "ஐகால்" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "நேரத் தடம் தேடல்" #~ msgid "Show activities window" #~ msgstr "செயல்கள் சாளரத்தைக் காட்டவும்" #~ msgid "Show _Overview" #~ msgstr "மேலோட்டத் தோற்றம் காட்டவும் (_O)" #~ msgid "Sto_p Tracking" #~ msgstr "தொடர்வதை நிறுத்தவும் (_p)" #~ msgid "To_day" #~ msgstr "_d இன்று" #~ msgid "_Add earlier activity" #~ msgstr "_A முந்தைய செயல்பாட்டைச் சேர்க்கவும்" #~ msgid "_About" #~ msgstr "பற்றி (_A)" #~ msgid "_Preferences" #~ msgstr "முன்னுரிமைகள் (_P)" #~ msgid "Starts and ends" #~ msgstr "துவக்கம் மற்றும் நிறுத்தம்" #~ msgid "Year:" #~ msgstr "வருடம்:" #~ msgid "Preferences" #~ msgstr "முன்னுரிமைகள்" #~ msgid "Changed activity" #~ msgstr "செயல்பாட்டை மாற்றவும்" #~ msgid "Switched to '%s'" #~ msgstr " '%s' க்கு மாற்றப்பட்டது" #~ msgid "Working on %s" #~ msgstr "வேலை செய்வது இதில்%s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "ஹாம்ஸ்டர் நேர தொடர்வி பயன்பாடு:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "ஹாம்ஸ்டர் திட்டம் (க்னோம் நேர தொடர்வி)" #~ msgid "Tell me more" #~ msgstr "இன்னும் அதிகம் சொல்லுங்க!" #~ msgid "totals by activity" #~ msgstr "செயல்பாடு ரீதியாக மொத்தம்" #~ msgid "totals by category" #~ msgstr "வகை ரீதியாக மொத்தம்" #~ msgid "Show:" #~ msgstr "காட்டு:" #~ msgid "Ad_d Earlier Activity" #~ msgstr "முந்தைய செயல்பாட்டைச் சேர்க்கவும் (_d)" #~ msgid "_Today" #~ msgstr "இன்று (_T)" #~ msgid "Preview:" #~ msgstr "முன்பார்வை:" #~ msgid "Save Report" #~ msgstr "அறிக்கையை சேமி" #~ msgid "General" #~ msgstr "பொது" #~ msgid "Global Hotkey" #~ msgstr "முழுதளாவிய தூண்டு விசை" #~ msgid "Move activity down" #~ msgstr "செயலை கீழே நகர்த்து " #~ msgid "Move activity up" #~ msgstr "செயலை மேலே நகர்த்து " #~ msgid "Total Time" #~ msgstr "மொத்த நேரம்" #~ msgid "Activities" #~ msgstr "செயல்பாடுகள்" #~ msgid "Tracking" #~ msgstr "தேடல்" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ " செயலை உள்ளிட்டுவிட்டு கண்காணிக்க என்டர் விசையை அமுக்கவும்." #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "மேலும் சொல்லுக" #~ msgid "Hamster" #~ msgstr "ஹாம்ஸ்டர்" #~ msgid "_Activity:" #~ msgstr "செயல்பாடு (_A):" #~ msgid " _Day" #~ msgstr " நாள் (_D)" #~ msgid " _Month" #~ msgstr "மாதம் (_M)" #~ msgid " _Week" #~ msgstr "வாரம் (_W)" #~ msgid "Overview" #~ msgstr "கண்ணோட்டம்" #~ msgid "Totals" #~ msgstr "மொத்தங்கள்" #~ msgid "Categories:" #~ msgstr "வகைகள்:" #~ msgid "Date interval:" #~ msgstr "இடைவெளி தேதி:" #~ msgid "Next" #~ msgstr "அடுத்த" #~ msgid "Next week" #~ msgstr "அடுத்த வாரம்" #~ msgid "Previous" #~ msgstr "முந்தைய" #~ msgid "Previous week" #~ msgstr "முந்தைய வாரம்" #~ msgid "Show month" #~ msgstr "மாதத்தை காட்டு" #~ msgid "Show single day" #~ msgstr "ஒரு நாளை காட்டு" #~ msgid "This Week" #~ msgstr "இந்த வாரம் " #~ msgid "This week" #~ msgstr "இந்த வாரம் " #~ msgid "What should be typed in the activity box?" #~ msgstr "செயல் பெட்டியில் என்ன உள்ளிட வேண்டும்?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "உங்கள் செயல்பாடுகளுக்கு விவரங்கள் சேர்க்க இப்போது எளிய சொற்றொடர் உள்ளது.:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "எல்லாம்" #~ msgid "Total" #~ msgstr "மொத்தம்" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%b %d" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)sக்கான கண்ணோட்டம்" #~ msgid "Previous day" #~ msgstr "முந்தைய நாள்" #~ msgid "Next day" #~ msgstr "அடுத்த நாள்" #~ msgid "Previous month" #~ msgstr "முந்தைய மாதம்" #~ msgid "Next month" #~ msgstr "அடுத்த மாதம்" #~ msgid "This month" #~ msgstr "இந்த மாதம் " #~ msgid "This Month" #~ msgstr "இந்த மாதம் " #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Save as HTML" #~ msgstr "ஹெச்டிஎம்எல்(HTML) ஆக சேமி " hamster-3.0.3/po/te.po000066400000000000000000001120511452646177100145630ustar00rootroot00000000000000# translation of hamster.master.te.po to Telugu # Copyright (C) 2012 Swecha Telugu Localisation Team . # This file is distributed under the same license as the hamster-time-tracker package. # # Krishna Babu K , 2009. # Hari Krishna , 2011. # Sasi Bhushan Boddepalli, 2012 # Gōpāla Kr̥ṣṇa Kōḍūri , 2012. # Praveen Illa , 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster.master.te\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-09-03 00:13+0530\n" "Last-Translator: Praveen Illa \n" "Language-Team: Telugu \n" "Language: te\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 2.91.5\n" "Plural-Forms: nplurals=2; plural=(n!=1);\n" "\n" "\n" "\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "ముందలి కార్యాన్ని జతచేయండి" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "నుంచి, ఇంతవరకు:" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "నడుస్తోంది" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "వివరణ:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "సమయం:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "కార్యం:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "కొసలు:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "నిష్క్రియగా ఉన్నప్పుడు జాడతీయకు" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "కంప్యూటర్ నిష్క్రియగా ఉన్నప్పుడు, ప్రస్తుత కార్యాన్ని జాడతీయకు" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "విద్యుత్ ఆపివేసినప్పుడు జాడతీయడం ఆపివేయి" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "విద్యుత్ ఆపివేసినప్పుడు ప్రస్తుత కార్యాన్ని జాడతీయడం ఆపివేయి" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ప్రస్తుత కర్తవ్యాన్ని ప్రతి x నిముషాలకు ఒకసారి గుర్తుచేయి" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "తెలుపబడినన్ని నిముషాలకొకసారి ప్రస్తుత కర్తవ్యాన్ని గుర్తుచేస్తుంది. గుర్తుచేయకుండా ఉండడానికి0 లేదా 120 " "కన్నా ఎక్కువకు అమర్చండి." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "ఏ కార్యమూ లేకున్నా గుర్తుచేయాలి" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "ఏ కార్యము ప్రారంభించకపోతే ప్రతి notify_interval నిమిషాలకొకసారి గుర్తుచేయి." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "ఏ సమయానికి రోజు మొదలవుతుంది (5:30AM అప్రమేయం)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "ఇవ్వాళ్టి సమయం మొదలవ్వక ముందే కార్యకలాపాలు మొదలుపెడెతే అవి నిన్నటికి చెందినవిగా,దాటాక మొదలుపెడితే రేపటికి " "చెందినవిగా గుర్తించబడతాయి.ఏవైనా కార్యకలాపాలు రెండు రోజుల పైబడి ఉంటే, ప్రధాన భాగం ఉన్న రోజుకిఅవి " "చెందుతాయి." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "కార్యస్థలం మారితే కార్యం మారినట్టు గుర్తించాలా" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "సశక్తంగా ఉన్న జాడకాల బాజితా. \"పేరు\" ద్వారా కార్యకలాపాల మధ్య, వాటికి కార్యస్థలాల మ్యాపింగ్ (_m) లో " "నిర్దేశించినపేర్లను బట్టి మారవచ్చు. \"జ్ఞాపకం\" ద్వారా మునుపటి కార్యస్థలానికి తిరిగివెళ్ళినప్పుడు అక్కడి చివరి " "కార్యానికి మారవచ్చు." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "కార్యస్థలం మారినప్పుడు కార్యం మార్చు" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "పేరు ద్వారా మార్చడానికి అమర్చినట్టైతే, మారడానికి ఉన్న ఆయా కార్యకలాపాల పేర్లను ఈ జాబితా పొందుచేస్తుంది. " "కార్యస్థలాలు వాటివాటి సూచీలతో గుర్తించబడతాయి." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "సమయ జాడక కిటికీని చూపు / దాచు" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "సమయ జాడక కిటికీ చూపుటకు / దాచుటకు కీబోర్డు లఘువు." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "హామ్‌స్టర్ అనువర్తన కిటికీ చూపి/దాచే చర్య" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "హామ్‌స్టర్ అనువర్తన కిటికీ దృశ్యత మార్చే ఆదేశము." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "హామ్‌స్టర్ అనువర్తన కిటికీని చూపు/దాచు" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "హామ్‌స్టర్ అనువర్తన కిటికీ దృశ్యత మార్చు." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "సమయ జాడకము" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "ప్రోజెక్టు హామ్‌స్టర్ - మీ సమయాన్ని జాడపడుతుంది" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "సమయ జాడకం యొక్క అవలోకనం" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "హామ్‌స్టర్ సమయ జాడకం యొక్క అవలోకనాన్ని చూపే కిటికీ" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "గణాంకాలు చూపించు" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "విభాగాలు" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "కార్యకలాపాలు" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "కొసలు" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "ఈ నిడివికి సమాచారము లేదు" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "నివేదికని భద్రపరుచు..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "రోజు" #: ../data/overview.ui.h:3 msgid "Week" msgstr "వారం" #: ../data/overview.ui.h:4 msgid "Month" msgstr "నెల" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "అవలోకనం — హామ్‌స్టర్" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "అవలోకనం (_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "కార్యకలాపం" #: ../data/overview.ui.h:8 msgid "_View" msgstr "వీక్షణం (_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "సమస్తం" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "తీసివేయి" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "కొత్తది జతచేయి" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "సవరించు" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "సమయ జాడకం అభీష్టాలు" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "కంప్యూటర్ నిష్క్రియగా ఉన్నప్పుడు జాడతీయకు" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ప్రస్తుత కర్తవ్యాన్ని ప్రతి x నిముషాలకు ఒకసారి గుర్తుచేయి." #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "రోజు మొదలయ్యేది" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "ఈ పనుల జాబితా లభ్యమైతే అది ఉపయోగించు:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "సమన్వయం" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "జాడతీయుట" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "వర్గాలు (_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "వర్గాల జాబితా" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "వర్గమును జతచేయి" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "వర్గమును తీసివేయు" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "వర్గమును సరికూర్చు" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "కార్యకలాపాలు (_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "కార్యకలాపాల జాబితా" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "కార్యాన్ని జతచేయి" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "కార్యాన్ని తీసివేయు" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "కార్యాన్ని సవరించు" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "స్వయంచాలక జాబితాలో కనబడాల్సిన కొసలు" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "విభాగాలు మరియు కొసలు" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "ఒక కార్యస్థలానికి మరలి వచ్చినప్పుడు అక్కడి ఆఖరి కార్యాన్ని కొనసాగించు" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "కార్యస్థలం మారినప్పుడు కొత్త కార్యాన్ని మొదలపెట్టు:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "కార్యస్థలాలు" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "రోజు:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "వారం:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "నెల:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "వ్యవధి:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "వర్తించు" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "జాడతీయుట(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "మునుపటి కార్యాన్ని జతచేయి" #: ../data/today.ui.h:4 msgid "Overview" msgstr "అవలోకనం" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "గణాంకాలు" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "సవరణ (_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "సహాయం (_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "విషయ సంగ్రహం" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "జాడతీయుట ఆపు (_p)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "మారు(_w)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "జాడపట్టుట మొదలుపెట్టు (_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "కొత్త కార్యం మొదలపెట్టు" #: ../data/today.ui.h:13 msgid "Today" msgstr "ఈ రోజు" #: ../data/today.ui.h:14 msgid "totals" msgstr "సమస్తం" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "అవలోకనం చూపించు (_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "ఏ కార్యాకలాపము లేదు" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "విభాగం" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "వివరణ" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "మొదలు" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "సమాప్తం" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "నిడివి" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "వర్గాలు" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "ప్రోజెక్టు హామ్‌స్టర్ — మీ సమయం జాడ తెలుసుకోండి" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "ముద్రణాధికారం © 2007–2010 టామ్స్ బౌగిస్ మరియు ఇతరులు" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "ప్రాజెక్ట్ హామ్‌స్టర్ వెబ్‌సైటు" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "సమయ జాడకం గురించి" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "KrishnaBabu K 2008.\n" "Praveen Illa , 2011.\n" "Gōpāla Kr̥ṣṇa Kōḍūri , 2012" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "క్రమపరచని" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "పని" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "వార్తలు చదవడం" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "స్టాక్‌లను పరిశీలించడం" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "చాలా రహస్యమైన ప్రాజెక్ట్" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "పెత్తనాలు" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "రోజూవారీ" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "మధ్యాహ్న భోజనం" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "పూలమొక్కలకు నీళ్ళు" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "బస్కీలు తీయడం" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "కార్యాన్ని నవీకరించండి" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dగం" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dని" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dగం %dని" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d, %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "మొత్తం %s గంటలు జాడ తీయబడినవి" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "ఏమీలేదు" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "పేరు" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "కొత్త వర్గం" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "కొత్త కార్యం" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d నిముషం" msgstr[1] "%(interval_minutes)d నిముషాలు" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ఎప్పటికీ వద్దు" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "కార్యం" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "ప్రారంభ సమయం" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "ముగింపు సమయం" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "నిడివి నిమిషాలలో" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "వర్గం" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "వివరణ" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "కొసలు" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s కి " "కార్యకలాపాల నివేదిక" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s కి కార్యకలాపాల నివేదిక" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s కి కార్యకలాపాల నివేదిక" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s కి కార్యకలాపాల నివేదిక" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "ఒక్కోరోజుకి సమస్త వివరాలు" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "కార్యకలాపాల పద్దు" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "కార్యాలు" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "వర్గాలు" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "భేదమును చూపించు" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "తేది" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "మాదిరిని చూపించు" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "మీ పాఠాంతరాన్ని %(home_folder)s లో భద్రపరిచి దీనిని రద్దుచేయుము" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "అన్నీ" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "గణాంకాలు ఉత్పాదించడానికి తగినంత సమాచారం అందుబాటులో లేదు.\n" "దీనికోసం కనీసం ఒక వారం ఉపయోగిస్తే బావుంటుంది!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "సమాచారాన్ని సేకరిస్తోంది — ఒక వారం గడిచిన తర్వాత పరిశీలించండి!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "మొదటి కార్యకలాపం %s నందు నమోదైంది." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s సంవత్సరం" msgstr[1] "%(num)s సంవత్సరాలు" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ఇంత వరకు జాడతీసిన సమయం %(human_days)s మానవీయ రోజులు (%(human_years)s) లేదా " "%(working_days)s పనుల రోజులు (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d, %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "%(date)s న ఏకబిగిన %(hours)s గంట పాటు అన్నిటికన్నా దీర్ఘతరమైన పని జరిగింది." msgstr[1] "%(date)s న ఏకబిగిన %(hours)s గంటల పాటు అన్నిటికన్నా దీర్ఘతరమైన పని జరిగింది." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s కార్యపట్టిక ఉంది." msgstr[1] "%s కార్యపట్టికలు ఉన్నాయి." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "హామ్‌స్టర్ మిమ్మల్ని యింకా గమనించాలని కొరుకుంటోంది!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "ఉ. 9 గం॥ ల ముందే %s శాతం కార్యకలాపాలు ఉన్నాయి, బహుశా మీరు త్వరగా నిద్రలేస్తారేమో." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "రా. 11 గం॥ ల తర్వాత %s శాతం కార్యకలాపాలు ఉన్నాయి, బహుశా మీకు రాత్రివేళ పని చేయడం ఇష్టమేమో." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s శాతం కార్యకలాపాలు 15 నిముషాల కన్నా తక్కువ నిడివి ఉన్నాయి, బహుశా మీరు చాలా పనులు చూస్కుంటూ " "ఉంటారేమో." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ఈరోజు ఏమీ నమోదు కాలేదు" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sగం" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "ఇప్పుడే మొదలైంది" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "నివేదిక భద్రపరుచు — సమయ జాడకం" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML నివేదిక" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "టాబ్‌-విభజిత విలువలు (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "సమయ జాడకం" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "కార్యకలాపాల కిటికీని చూపించు" #~ msgid "Sto_p Tracking" #~ msgstr "జాడపట్టుట ఆపు (_p)" #~ msgid "To_day" #~ msgstr "ఈరోజు(_d)" #~ msgid "_Add earlier activity" #~ msgstr "ముందలి కార్యాన్ని జతచేయండి (_A)" #~ msgid "Show _Overview" #~ msgstr "అవలోకనం చూపించు (_O)" #~ msgid "_Preferences" #~ msgstr "ప్రాధాన్యతలు (_P)" #~ msgid "_About" #~ msgstr "గురించి (_A)" #~ msgid "Year:" #~ msgstr "సంవత్సరం:" #~ msgid "Starts and ends" #~ msgstr "ప్రారంభం మరియు ముగింపు" #~ msgid "Preferences" #~ msgstr "ప్రాధాన్యతలు" #~ msgid "Changed activity" #~ msgstr "సవరించబడిన కార్యము" #~ msgid "Switched to '%s'" #~ msgstr "'%s' కు మార్చబడింది" #~ msgid "Working on %s" #~ msgstr "%s పై పనిచేస్తున్నది" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "హామ్‌స్టర్ సమయ జాడకం. ఉపయోగించుట:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "ప్రోజెక్టు హామ్‌స్టర్(గ్నొం టైం ట్రాకర్)" #~ msgid "Activities" #~ msgstr "కార్యకలాపములు" #~ msgid "Global Hotkey" #~ msgstr "గ్లోబల్ హాట్‌కీ" #~ msgid "Tracking" #~ msgstr "ట్రాక్‌చేయుచున్నది" #~ msgid "Move activity down" #~ msgstr "క్రియాకలాపమును క్రిందకి కదుల్చుము" #~ msgid "Move activity up" #~ msgstr "క్రియాకలాపమును పైనకు కదుల్చుము" #~ msgid "Preview:" #~ msgstr "ఉపదర్శనము:" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "ట్రాక్ చేయుట ప్రారంభించుటకు క్రియాకలాపమునందు టైపు చేసి Enter " #~ "కొట్టండి!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "ఇంకా చెప్పండి" #~ msgid "Ad_d Earlier Activity" #~ msgstr "ముందలి క్రియాకలాపమును జతచేయుము (_d)" #~ msgid "Hamster" #~ msgstr "హామ్‌స్టర్" #~ msgid "_Activity:" #~ msgstr "క్రియాకలాపము (_A):" #~ msgid "_Today" #~ msgstr "ఈ రోజు(_T)" #~ msgid " _Day" #~ msgstr " రోజు (_D)" #~ msgid " _Month" #~ msgstr " నెల (_M)" #~ msgid " _Week" #~ msgstr " వారము (_W)" #~ msgid "Overview" #~ msgstr "ఉపరితలదర్శనం" #~ msgid "Totals" #~ msgstr "మొత్తములు" #~ msgid "Categories:" #~ msgstr "వర్గములు:" #~ msgid "Date interval:" #~ msgstr "తేదీ విరామము:" #~ msgid "Save as HTML" #~ msgstr "HTML వలె దాయుము" #~ msgid "What should be typed in the activity box?" #~ msgstr "క్రియాకలాపము పెట్టెనందు యేమి ప్రవేశపెట్టవలెను?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "మీ క్రియాకలాపములకు వివరములను జతచేయుగలుగుటకు సరళమైన సిన్టాక్సు వొకటి వుంది:\n" #~ " \n" #~ "\"@\" చిహ్నము వర్గమువలె గుర్తుంచబడుతుంది. ఉదాహరణ: \"పువ్వులకు నీళ్ళుజల్లుట@ఇంటివద్ద\" " #~ "అనునది క్రియాకలాపము \"పువ్వులకు నీళ్ళుజల్లుట\" ను వర్గము \"ఇంటివద్ద\" నందు ట్రాక్ చేయుట " #~ "ప్రారంభిస్తుంది.\n" #~ "\n" #~ "కామాలు (\",\") వివరణ యొక్క ప్రారంభమును గుర్తుంచుతాయి. ఉదాహరణ: \"పువ్వులకు నీళ్ళుజల్లుట, " #~ "గులాబీలు మరియు చామంతులు\" అనునది క్రియాకలాపము \"పువ్వులకు నీళ్ళుజల్లుట\"ను ట్రాక్‌చేయుట " #~ "ప్రారంభిస్తుంది మరియు వివరణ \"గులాబీలు మరియు చామంతులు\" ను దానికి జతచేస్తుంది.\n" #~ "\n" #~ "రెండూ కలుపవచ్చును: \"పువ్వులకు నీళ్ళుజల్లుట@ఇంటివద్ద, గులాబీలు మరియు చామంతులు\" కూడా " #~ "చక్కగా పనిచేస్తుంది!\n" #~ "\n" #~ "ఇప్పుడు, ట్రాక్ చేయుట ప్రారంభించండి!\n" #~ " " #~ msgid "Total Time" #~ msgstr "మొత్తము సమయం" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "అన్ని" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "మొత్తము" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s కొరకు వుపరితలదర్శనము" hamster-3.0.3/po/th.po000066400000000000000000000642071452646177100145770ustar00rootroot00000000000000# Thai translation of hamster. # Copyright (C) 2008-2009 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Theppitak Karoonboonyanan , 2008-2009. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-02-12 21:21+0700\n" "Last-Translator: Theppitak Karoonboonyanan \n" "Language-Team: Thai \n" "Language: th\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "เพิ่มกิจกรรมในอดีต" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "กำลังดำเนินการ...\n" "ถึง\n" "เป็นเวลา" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "คำบรรยาย:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "_กิจกรรม:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "หยุดติดตามเมื่อไม่มีการโต้ตอบกับเครื่อง" #: ../data/hamster.schemas.in.h:2 #, fuzzy msgid "Stop tracking current activity when computer becomes idle" msgstr "หยุดติดตามกิจกรรมที่ดำเนินอยู่เมื่อไม่มีการโต้ตอบกับเครื่อง" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "หยุดติดตามเมื่อปิดเครื่อง" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "หยุดติดตามกิจกรรมที่ดำเนินอยู่เมื่อปิดเครื่อง" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "แจ้งเตือนภารกิจปัจจุบันทุกๆ x นาที" #: ../data/hamster.schemas.in.h:6 #, fuzzy msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "แจ้งเตือนภารกิจปัจจุบันทุกๆ ช่วงจำนวนนาทีที่กำหนด กำหนดเป็นค่า 0 หรือมากกว่า 120 " "หากต้องการปิดการแจ้งเตือน" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "ปุ่มลัดสำหรับแสดงหน้าต่างเครื่องมือติดตามการใช้เวลา" #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "ปุ่มลัดสำหรับแสดงหน้าต่างเครื่องมือติดตามการใช้เวลา" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "ติดตามการใช้เวลา" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "โครงการ Hamster - ติดตามการใช้เวลาของคุณ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "ติดตามการใช้เวลา" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "ห_มวด" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "_กิจกรรม" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "รายวัน" #: ../data/overview.ui.h:3 msgid "Week" msgstr "รายสัปดาห์" #: ../data/overview.ui.h:4 msgid "Month" msgstr "รายเดือน" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "ภาพรวม - Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_ภาพรวม" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "กิจกรรม" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "เวลารวม" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "แก้ไข" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "ปรับแต่งเครื่องมือติดตามการใช้เวลา" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "หยุดติดตามเมื่อไม่มีการโต้ตอบกับเครื่อง" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "แจ้งเตือนกิจกรรมปัจจุบันทุกๆ:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "ระยะเวลา" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "_หยุดติดตาม" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "ห_มวด" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "หมวด" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "หมวดใหม่" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "หมวดใหม่" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "หมวดใหม่" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_กิจกรรม" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "กิจกรรม" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "เพิ่มกิจกรรม" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "ไม่มีกิจกรรม" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "แก้ไขกิจกรรม" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "ห_มวด" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "รายสัปดาห์" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "รายเดือน" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "_หยุดติดตาม" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "เพิ่มกิจกรรมในอดีต" #: ../data/today.ui.h:4 #, fuzzy msgid "Overview" msgstr "_ภาพรวม" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "แก้ไข" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "_หยุดติดตาม" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "สลับ" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "_หยุดติดตาม" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "กิจกรรมใหม่" #: ../data/today.ui.h:13 msgid "Today" msgstr "วันนี้" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "เวลารวม" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "แสดง_ภาพรวม" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "ไม่มีกิจกรรม" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "หมวด" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "คำบรรยาย" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "เริ่ม" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "สิ้นสุด" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "ระยะเวลา" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "ห_มวด" #: ../src/hamster/about.py:42 #, fuzzy msgid "Project Hamster — track your time" msgstr "โครงการ Hamster - ติดตามการใช้เวลาของคุณ" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "สงวนลิขสิทธิ์ © 2007-2008 Toms Baugis และคนอื่นๆ" #: ../src/hamster/about.py:45 #, fuzzy msgid "Project Hamster Website" msgstr "เว็บไซต์ของ Hamster" #: ../src/hamster/about.py:46 #, fuzzy msgid "About Time Tracker" msgstr "ติดตามการใช้เวลา" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "เทพพิทักษ์ การุญบุญญานันท์ " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "ไม่แยกหมวด" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "งาน" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "อ่านข่าว" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "ตรวจสอบราคาหุ้น" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "โครงการลับสุดยอด" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "ครองโลก" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "อาหารเที่ยง" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "รดน้ำต้นไม้" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "หกคะเมน" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "ปรับข้อมูลกิจกรรม" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "ภาพรวมสำหรับ %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "ภาพรวมสำหรับ %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "ภาพรวมสำหรับ %(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "ชื่อ" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "หมวดใหม่" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "กิจกรรมใหม่" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d นาที" msgstr[1] "%(interval_minutes)d นาที" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ไม่แจ้ง" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "กิจกรรม" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "นาที" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "หมวด" #. column title in the TSV export format #: ../src/hamster/reports.py:158 #, fuzzy msgid "description" msgstr "คำบรรยาย" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "ภาพรวมสำหรับ %(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "ภาพรวมสำหรับ %(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "ภาพรวมสำหรับ %(start_d)s %(start_B)s %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "ภาพรวมสำหรับ %(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "เวลารวม" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "กิจกรรม" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "_กิจกรรม" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "ห_มวด" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "วันที่" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "แสดงข้อมูลรายสัปดาห์" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" msgstr[1] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" msgstr[1] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" msgstr[1] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "ไม่มีข้อมูลสำหรับวันนี้" #: ../src/hamster/today.py:250 #, fuzzy, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s, " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "ติดตามการใช้เวลา" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "ติดตามการใช้เวลา" #~ msgid "_About" #~ msgstr "เ_กี่ยวกับ" #~ msgid "_Preferences" #~ msgstr "_ปรับแต่ง" #~ msgid "Activities" #~ msgstr "กิจกรรม" #~ msgid "Global Hotkey" #~ msgstr "ปุ่มลัดสำหรับเรียก" #~ msgid "Tracking" #~ msgstr "การติดตาม" #~ msgid "Move _Down" #~ msgstr "เลื่อน_ลง" #~ msgid "Move _Up" #~ msgstr "เลื่อน_ขึ้น" #~ msgid "N_ew Category" #~ msgstr "หมวดใ_หม่" #~ msgid "_New Activity" #~ msgstr "กิ_จกรรมใหม่" #~ msgid "Activity" #~ msgstr "กิจกรรม" #~ msgid "Date and Time" #~ msgstr "วันที่และเวลา" #~ msgid "Name:" #~ msgstr "ชื่อ:" #~ msgid "hours" #~ msgstr "ชั่วโมง" #~ msgid "Show window" #~ msgstr "แสดงหน้าต่าง" #~ msgid "Ad_d Earlier Activity" #~ msgstr "เพิ่มกิจกรรมใน_อดีต" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Today" #~ msgstr "วัน_นี้" #~ msgid " _Day" #~ msgstr "ราย_วัน" #~ msgid " _Month" #~ msgstr "รายเ_ดือน" #~ msgid " _Week" #~ msgstr "ราย_สัปดาห์" #~ msgid "Category" #~ msgstr "หมวด" #~ msgid "Overview" #~ msgstr "ภาพรวม" #~ msgid "Week" #~ msgstr "สัปดาห์" #~ msgid "Delete activity" #~ msgstr "ลบกิจกรรม" #~ msgid "Earlier activities" #~ msgstr "กิจกรรมก่อนหน้า" #~ msgid "Generate Report" #~ msgstr "สร้างรายงาน" #~ msgid "Newer activities" #~ msgstr "กิจกรรมถัดไป" #~ msgid "Show day" #~ msgstr "แสดงข้อมูลรายวัน" #~ msgid "Show month" #~ msgstr "แสดงข้อมูลรายเดือน" #~ msgid "Working on %s" #~ msgstr "กำลังทำภารกิจ %s" #~ msgid "Day to day" #~ msgstr "กิจวัตรประจำวัน" #~ msgid "name" #~ msgstr "name" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_d)s %(report_b)s %(report_Y)s" #~ msgid "Total Time" #~ msgstr "เวลารวม" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s %(o_d)s %(o_b)s" #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_d)s %(m_b)s" #~ msgid "Other" #~ msgstr "อื่นๆ" #~ msgid "Time tracking for masses" #~ msgstr "เครื่องมือติดตามการใช้เวลาสำหรับมหาชน" #~ msgid "Time tracking for masses." #~ msgstr "เครื่องมือติดตามการใช้เวลาสำหรับมหาชน" hamster-3.0.3/po/tr.po000066400000000000000000000673411452646177100146130ustar00rootroot00000000000000# Turkish translation of hamster-time-tracker application # Copyright (C) 2008 # This file is distributed under the same license as the hamster-time-tracker package. # # Baris Cicek , 2008, 2009. # Fatih Ergüven , 2009. # Muhammet Kara , 2011. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2011-04-29 01:55+0300\n" "Last-Translator: Muhammet Kara \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "\n" "\n" "Plural-Forms: nplurals=1; plural=0;\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Önceki Etkinliği Ekle" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "devam ediyor" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Tanım:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Süre:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Etkinlik:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Etiketler:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Beklemede takibi durdur" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Bilgisayar boşta olduğunda mevcut etkinliği takip etmeyi durdur" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Kapatıldığında takibi durdur" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Bilgisayar kapatıldığında mevcut etkinliği takip etmeyi durdur" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Mevcut görevi her x dakikada hatırlat" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Mevcut görevi belirtilen miktardaki dakikada hatırlat. 0 ya da 120'den daha " "büyük bir değer atayarak hatırlatıcıyı kapatabilirsiniz." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Hiçbir etkinlik ayarlanmadığında ayrıca hatırlat" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Ayrıca, hiçbir etkinlik başlatılmadığında her notify_interval dakikada bir " "hatırlat." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Zaman Takipçisi Penceresini Göster / Gizle" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Zaman Takipçisi penceresini göstermek / gizlemek için klavye kısayolu." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Zaman Takipçisi" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Proje Hamster - zamanınızı takip edin" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Zaman Takipçisi" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "İstatistikleri Göster" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Kategoriler" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Etkinlikler" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Etiketler" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Bu aralık için veri yok" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Raporu kaydet..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "Gün" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Hafta" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Ay" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Genel Görünüm — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Genel Görünüm" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Etkinlik" #: ../data/overview.ui.h:8 msgid "_View" msgstr "_Görüntüle" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Toplamlar" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Sil" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Yeni ekle" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Düzenle" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Zaman Takipçisi Tercihleri" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Bilgisayar beklemedeyken takibi durdur" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Mevcut etkinliği hatırlatma sıklığı:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Eğer kullanılabilir durumdaysa şu yapılacaklar listesini kullan:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Bütünleşme" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Takip" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Kategoriler" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Kategori listesi" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Kategori ekle" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Kategoriyi sil" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Kategoriyi düzenle" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Etkinlikler" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Etkinlik listesi" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Etkinlik ekle" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Etkinliği sil" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Etkinliği düzenle" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Kategoriler ve Etiketler" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Çalışma Alanları" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "Gün:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Hafta:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Ay:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Aralık:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Uygula" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Takip" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Daha önceki etkinliği ekle" #: ../data/today.ui.h:4 msgid "Overview" msgstr "Genel Görünüm" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "İstatistikler" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "_Düzenle" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Yardım" #: ../data/today.ui.h:8 msgid "Contents" msgstr "İçerik" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "Taki_bi durdur" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "Ge_çiş Yap" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "_Takibi Başlat" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Yeni etkinlik başlat" #: ../data/today.ui.h:13 msgid "Today" msgstr "Bugün" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Toplamlar" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "_Genel Görünümü Göster" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Etkinlik yok" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Kategori" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Tanım" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Başlangıç" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Bitiş" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Süre" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "kategoriler" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Proje Hamster — zamanınızı takip edin" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Telif Hakkı © 2007-2010 Toms Bauģis ve diğerleri" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Proje Hamster Web Sitesi" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Zaman Takipçisi Hakkında" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Barış Çiçek \n" "Fatih Ergüven \n" "Muhammet Kara " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Sırasız" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "İş" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Haberleri okuma" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Borsayı kontrol" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Çok gizli proje X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Dünyayı ele geçirme" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Günden güne" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Öğle Yemeği" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Çiçekleri sulama" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Amuda kalkma" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Etkinliği güncelle" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dsa" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%ddk" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dsa %ddk" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s için " "gözden geçirme" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s için gözden geçirme" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s için gözden geçirme" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Toplam %s saat takip edildi" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Hiçbiri" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "İsim" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Yeni kategori" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Yeni etkinlik" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d dakika" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Asla" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "etkinlik" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "başlama zamanı" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "bitiş zamanı" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "süreç dakikaları" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "kategori" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "açıklama" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "etiketler" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s için " "gözden geçirme" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s için gözden geçirme" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s için gözden geçirme" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s için gözden geçirme" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "Toplamlar" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Etkinlik Günlüğü" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "etkinlikler" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "kategoriler" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Tarih" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Şablonu göster" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Hepsi" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "İstatistikleri oluşturmak için henüz veri yok.\n" "Bir haftalık kullanım iyi olurdu!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Veri toplanıyor — bir hafta geçtikten sonra tekrar bakın!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "İlk etkinlik %s tarihinde kaydedildi." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s yıl" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Şu ana kadar %(human_days)s normal gün (%(human_years)s) ya da " "%(working_days)s iş günü (%(working_years)s) takip edildi." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "En uzun devam eden görev %(date)s tarihinde gerçekleşti ve %(hours)s saat " "sürdü." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s adet kayıt var." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster sizi biraz daha gözlemlemek istiyor!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "Tüm görevlerin yüzde %s'si sabah 9'dan önce başlıyor, erkenci biri gibi " "gözüküyorsun." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "Tüm görevlerin yüzde %s'si gece 11'den sonra başlıyor, gece kuşu gibi " "gözüküyorsun." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "Tüm görevlerin yüzde %s'si 15 dakikadan daha kısa, meşgul bir arı gibi " "gözüküyorsun." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Bugün hiçbir kayıt yok" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%ssa" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Yeni başladı" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "Raporu kaydet – Zaman Takipçisi" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML Raporu" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Sekmeyle Ayrılmış Değerler (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Zaman takibi" #~| msgid "Project Hamster Website" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "Proje Hamster (Gnome Zaman Takipçisi)" #~ msgid "_About" #~ msgstr "_Hakkında" #~ msgid "_Preferences" #~ msgstr "_Tercihler" #~| msgid "_Stop Tracking" #~ msgid "Sto_p Tracking" #~ msgstr "Taki_bi Durdur" #~| msgid "Today" #~ msgid "To_day" #~ msgstr "Bu _gün" #~| msgid "Add Earlier Activity" #~ msgid "_Add earlier activity" #~ msgstr "_Daha önceki etkinliği ekle" #~| msgid "Starts and ends" #~ msgid "Starts and ends" #~ msgstr "Başlayor ve bitiyor" #~ msgid "Year:" #~ msgstr "Yıl:" #~| msgid "_Preferences" #~ msgid "Preferences" #~ msgstr "Tercihler" #~| msgid "Add activity" #~ msgid "Changed activity" #~ msgstr "Etkinlik değiştirildi" #~ msgid "Switched to '%s'" #~ msgstr "'%s'e geçiş yapıldı" #~ msgid "Working on %s" #~ msgstr "%s üzerinde çalışılıyor" #~ msgid "Activities" #~ msgstr "Etkinlikler" #~ msgid "Global Hotkey" #~ msgstr "Genel Kısayol Tuşu" #~ msgid "Tracking" #~ msgstr "Takip" #~| msgid "No activity" #~ msgid "Move activity down" #~ msgstr "Etkinliği aşağı taşı" #~| msgid "No activity" #~ msgid "Move activity up" #~ msgstr "Etkinliği yukarı taşı" #~ msgid "Preview:" #~ msgstr "Önizleme:" #~ msgid "Show window" #~ msgstr "Pencere göster" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Bir etkinlik yazın ve Enter'a basıp takibe başlayın!" #~ "" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Daha detaylı " #~ "bilgi ver" #~ msgid "Ad_d Earlier Activity" #~ msgstr "_Daha Önceki Etkinliği Ekle" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "_Activity:" #~ msgstr "_Etkinlik:" #~ msgid "_Today" #~ msgstr "_Bugün" #~ msgid " _Day" #~ msgstr " _Gün" #~ msgid " _Month" #~ msgstr " _Ay" #~ msgid " _Week" #~ msgstr " _Hafta" #~ msgid "Overview" #~ msgstr "Genel Görünüm" #~| msgid "Tracking" #~ msgid "Totals" #~ msgstr "Toplamlar" #~| msgid "_Categories" #~ msgid "Categories:" #~ msgstr "Kategoriler" #~ msgid "Date interval:" #~ msgstr "Tarih aralığı:" #~ msgid "Save as HTML" #~ msgstr "HTML olarak kaydet" #~ msgid "What should be typed in the activity box?" #~ msgstr "Etkinlik kutusuna ne yazılmalı?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Etkinliklerinize detaylar ekleyebilmenize olanak veren basit yazım " #~ "biçimi:\n" #~ " \n" #~ "\"@\" sembolü bir kategori belirtir. Örneğin: \"çiçekleri sula@ev\", " #~ "\"çicekleri sula\" etkinliğini \"ev\" kategorisi içerisinde takibe " #~ "başlayacaktır.\n" #~ "\n" #~ "Virgül (\",\") bir açıklamanın başlangıç işaretidir. Örneğin: \"çiçekleri " #~ "sula, begonyalar ve unutma beni çiçekleri\", \"çiçekleri sula\" " #~ "etkinliğini takibe başlayacak ve \"begonyalar ve unutma beni çiçekleri\" " #~ "notunu ekleyecektir.\n" #~ "\n" #~ "Her iki kullanım da birleştirilebilir: \"çiçekleri sula@ev, begonyalar ve " #~ "unutmabeni çiçekleri\" gayet güzel çalışacaktır.\n" #~ "\n" #~ "Şimdi, takibe başla!\n" #~ " " #~ msgid "Total Time" #~ msgstr "Toplam Zaman" #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Tümü" #~| msgid "%(m_b)s %(m_d)s" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(b)s %(d)s" #~ msgid "Total" #~ msgstr "Toplam" #~| msgid "Overview for %s" #~ msgid "Overview for %(date)s" #~ msgstr "%(date)s için genel görünüm" #~ msgid "Move _Down" #~ msgstr "_Aşağı Taşı" #~ msgid "Move _Up" #~ msgstr "_Yukarı Taşı" #~ msgid "N_ew Category" #~ msgstr "_Yeni Kategori" #~ msgid "_New Activity" #~ msgstr "_Yeni Etkinlik" #~ msgid "Delete activity" #~ msgstr "Etkinlik sil" #~ msgid "Generate Report" #~ msgstr "Rapor Oluştur" #~ msgid "Newer activities" #~ msgstr "Yeni etkinlikler" #~ msgid "Show month" #~ msgstr "Ay göster" #~ msgid "name" #~ msgstr "isim" #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" #, fuzzy #~ msgid "%(category)s: %(duration).1f, " #~ msgstr "%(category)s: %(duration)s, " #~ msgid "Activity" #~ msgstr "Etkinlik" #~ msgid "hours" #~ msgstr "saat" #~ msgid "Category" #~ msgstr "Kategori" #~ msgid "Week" #~ msgstr "Hafta" #~ msgid "Earlier activities" #~ msgstr "Daha önceki etkinlikler" #~ msgid "Show day" #~ msgstr "Gün göster" #~ msgid "Other" #~ msgstr "Diğer" #~ msgid "Time tracking for masses" #~ msgstr "Kitleler için zaman takibi" #~ msgid "Time tracking for masses." #~ msgstr "Kitleler için zaman takibi." #~ msgid "Overview for %s - %s" #~ msgstr "%s için genel görünüm - %s" hamster-3.0.3/po/ug.po000066400000000000000000000665711452646177100146050ustar00rootroot00000000000000# Uyghur translation for hamster. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # Gheyret Kenji,2010. # Sahran , 2010. # Zeper , 2010. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2011-04-25 16:48+0600\n" "Last-Translator: Sahran \n" "Language-Team: Uyghur Computer Science Association \n" "Language: \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "ئىلگىرىكى پائالىيەتنى قوش" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "غا" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "بىر تەرەپ قىلىۋاتىدۇ" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "چۈشەندۈرۈش:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "ۋاقتى:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "پائالىيەت:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "خەتكۈچلەر:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "بىكار بولغاندا ئىزلاشنى توختات" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "كومپيۇتېر بىكار بولغاندا ھازىرقى پائالىيەتنى ئىزلاشنى توختات" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "تاقىغاندا ئىزلاشنى توختات" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "تاقىغاندا ھازىرقى پائالىيەتنى ئىزلاشنى توختات" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "ھازىرقى ۋەزىپىنى ھەر x مىنۇتتا ئەسكەرت" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "ھازىرقى ۋەزىپىنى بەلگىلەنگەن مىنۇتتا ئەسكەرتىپ تۇرىدۇ. 0 ياكى 120 دىن چوڭ " "قىلىپ بېكىتىلسە ئەسكەرتىش ئىناۋەتسىز بولىدۇ." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "پائالىيەت بەلگىلەنمىگەندىمۇ ئەسكەرت" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "ئەگەر پائالىيەت باشلانمىغان بولسا يەنىلا ھەر قېتىملىق بەلگىلەنگەن ئەسكەرتىش " "ئارىلىقىدا ئەسكەرتىدۇ." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "كۈن سائەت قانچىدە باشلىنىدۇ(سۈكۈت: 5:30 چۈشتىن بۇرۇن)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "ھازىرقى ۋاقىت كۈنىنىڭ باشلىنىش ۋاقتىدىن كىچىك بولسا، پائالىيەتلەر تۈنۈگۈنگە " "تەۋە بولىدۇ. ئەگەر ئۇنىڭدىن ئۆتۈپ كەتسە پائالىيەتلەر ئىككى كۈنگە تەۋە " "بولىدۇ، ھەم كۆرسەتمىلەر قايسى كۈندىكى پائالىيەت ۋاقتى ئۇزۇن بولسا شۇنىڭدا " "كۆرسىتىلىدۇ." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "خىزمەت بوشلۇقى ئايلاندۇرۇش پائالىيەت ئالماشتۇرۇشنى كەلتۈرۈپ چىقىرىدۇ" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "ئىزلاشقا يول قويىدىغان ئۇسۇل تىزىمى. \"name\" خىزمەت رايونى تەسۋىرىدە " "ئېنىقلانغان ئات ئارقىلىق پائالىيەت ئايلاندۇرۇشقا يول قويىدۇ. \"memory\" " "ئالدىنقى خىزمەت رايونىغا قايتقاندا ئالدىنقى قېتىملىق پائالىيەتكە " "ئالماشتۇرىدۇ." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "خىزمەت بوشلۇقى ئۆزگەرگەندە پائالىيەتنى ئالماشتۇر" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "ئەگەر ئات بويىچە ئۆزگەرتىش قوزغىتىلسا، بۇ تىزىم ئايلاندۇرۇلىدىغان پائالىيەت " "ئاتى، تۈرنىڭ ئىندېكسىنىڭ ۋەكىللىك قىلىدىغان خىزمەت رايونىنى تەڭشەيدۇ" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "ۋاقىت ئىزلىغۇچى(Time Tracker) كۆزنەكنى كۆرسەت/يوشۇر" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "" "ۋاقىت ئىزلىغۇچى(Time Tracker) كۆزنەكنى كۆرسىتىدىغان ياكى يوشۇرىدىغان " "ھەرپتاختا تېزلەتمىسى." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "hamster پروگرامما كۆزنىكىنى مەشغۇلاتىنى ئالماشتۇر" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "hamster پروگرامما كۆزنىكىنىڭ كۆرۈنۈشچانلىقىنى ئالماشتۇرۇش بۇيرۇقى." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "hamster پروگرامما كۆزنىكىنى ئالماشتۇر" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "hamster پروگرامما كۆزنىكىنىڭ كۆرۈنۈشچانلىقىنى ئالماشتۇرىدۇ." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "ۋاقىت ئىزلىغۇچى" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster قۇرۇلۇشى - ۋاقتىڭىزنى ئىزلاڭ" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "ۋاقىت ئىزلىغۇچى" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "ستاتىستىكا كۆرسەت" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "كاتېگورىيە" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "پائالىيەتلەر" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "خەتكۈشلەر" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "بۇ ئارىلىقتا سانلىق-مەلۇمات يوق" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "دوكلاتنى ساقلاش…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "كۈن" #: ../data/overview.ui.h:3 msgid "Week" msgstr "ھەپتە" #: ../data/overview.ui.h:4 msgid "Month" msgstr "ئاي" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "قىسقىچە بايان—Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "ئورتاق(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "ئاكتىپ" #: ../data/overview.ui.h:8 msgid "_View" msgstr "كۆرۈنۈش(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "ئومۇمىي سانى" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "چىقىرىۋەت" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "يېڭىدىن قوش" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "تەھرىر" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "ۋاقىت ئىزلىغۇچى مايىللىقى" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "كومپيۇتېر بىكار بولغاندا ئىزلاشنى توختات" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "ھازىرقى پائالىيەتنى ئەسكەرتىپ تۇرۇش ۋاقتى:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "يېڭى كۈننىڭ باشلىنىش ۋاقتى" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "ئەگەر بار بولسا تۆۋەندىكى پىلانغا ئەگەش:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "توپلاشتۇرۇش" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "ئىزلاۋاتىدۇ" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "كاتېگورىيە(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "كاتېگورىيە تىزىمى" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "تۈر قوش" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "كاتېگورىيىنى چىقىرىۋەت" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "كاتېگورىيە تەھرىرلە" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "پائالىيەتلەر(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "پائالىيەت تىزىمى" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "پائالىيەت قوش" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "پائالىيەتنى چىقىرىۋەت" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "تەھرىرلەش مەشغۇلاتى" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "ئاپتوماتىك تولۇقلاشتا كۆرۈنىدىغان خەتكۈچلەر" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "كاتېگورىيىلەر ۋە بەتكۈچلەر" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "خىزمەت بوشلۇقىغا قايتىپ كەلگەندە ئەڭ ئاخىرقى پائالىيەتنى داۋاملاشتۇر" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "خىزمەت بوشلۇقى ئالماشقاندا يېڭى پائالىيەت باشلا:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "خىزمەت رايونى" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "كۈن:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "ھەپتە:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "ئاي:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "دائىرە:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "قوللان" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "ئىزلا(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "ئىلگىرىكى پائالىيەتنى قوش" #: ../data/today.ui.h:4 msgid "Overview" msgstr "قىسقىچە بايان" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "ستاتىستىكا" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "تەھرىر(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "ياردەم(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "مەزمۇن" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "ئىزلاشنى توختات(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "ئالماشتۇر(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "ئىزلاشنى باشلا(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "يېڭى پائالىيەت باشلا" #: ../data/today.ui.h:13 msgid "Today" msgstr "بۈگۈن" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "ئومۇمىي سانى" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "قىسقىچە باياننى كۆرسەت(_O)" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "پائالىيەت يوق" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "كاتېگورىيە" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "چۈشەندۈرۈش" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "باشلا" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "تامام" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "ۋاقتى" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "كاتېگورىيىلەر" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster قۇرۇلۇشى — ۋاقتىڭىزنى ئىزلاڭ" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "نەشر ھوقۇقى © 2007–2010 Toms Bauģis ۋە باشقىلارغا تەۋە" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster قۇرۇلۇشى تورتۇراسى" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Time Tracker ھەققىدە" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Gheyret Kenji \n" "Sahran" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "تەرتىپلەنمىگەن" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "ئىش" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "خەۋەر ئوقۇۋاتىدۇ" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "پايچېكى تەكشۈرۈش" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "ئالاھىدە مەخپىي قۇرۇلۇش X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "دۇنيانى بويسۇندۇرۇش" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "كۈنسېرى" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "چۈشلۈك تاماق" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "گۈلگە سۇ قويۇش" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "قولدا تىك تۇرۇش" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "يېڭىلاش پائالىيىتى" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dh" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dmin" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dh %dmin" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%B %d، %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s، %(start_Y)s – %(end_B)s %(end_d)s، %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s، %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s، %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A، %b %d" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "جەمئىي %s سائەت ئىزلىدى" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "يوق" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "ئاتى" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "يېڭى كاتېگورىيە" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "يېڭى پائالىيەت" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d مىنۇت" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "ھەرگىز" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "پائالىيەت" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "باشلىنىش ۋاقتى" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "ئاخىرلىشىش ۋاقتى" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "ۋاقتى(مىنۇت)" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "كاتېگورىيە" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "چۈشەندۈرۈش" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "خەتكۈش" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s دىكى " "پائالىيەت دوكلاتى" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s دىكى پائالىيەت " "دوكلاتى" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s دىكى پائالىيەت دوكلاتى" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s دىكى پائالىيەت دوكلاتى" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d، %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "كۈنلۈك خۇلاسە" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "پائالىيەت خاتىرىسى" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "پائالىيەتلەر" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "كاتېگورىيىلەر" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "پەرق:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "چېسلا" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "قېلىپ كۆرسەت" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "ئۆزىڭىزنىڭكىنى %(home_folder)s غا ساقلاش ئارقىلىق ئۇنى قاپلىۋېتەلەيسىز" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "ھەممىسى" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "ستاتىستىكا قىلغۇدەك سانلىق-مەلۇمات يوق.\n" "ھەپتىلىك ستاتىستىكا قىلىش ياخشىراق!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "سانلىق-ئاساسلارنى توپلاش—بىر ھەپتە ئۆتكەندە قايتا تەكشۈرۈڭ" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%b %d، %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%bنىڭ %-d-كۈنى" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "تۇنجى پائالىيەتنىڭ خاتىرىلەنگەن ۋاقتى %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s يىل" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "ۋاقىت ھازىر %(human_days)s تەبىئىي كۈن (%(human_years)s) ياكى " "%(working_days)s خىزمەت كۈنى (%(working_years)s) ئىزلىدى." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%b %d، %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "ئەڭ ئۇزۇن ئىشلىگەن كۈن %(date)s بولۇپ جەمئىي %(hours)s." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "%s دانا خاتىرە بار." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster سىزنى كۆپرەك كۆزەتمەكچى!" #: ../src/hamster/stats.py:409 #, fuzzy, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "%s نىڭ خىزمىتى ئەتىگەن سائەت 9 دىن ئىلگىرى باشلىنىدۇ، قارىغاندا سىز " "سەھەردىكى خوراز ئوخشايسىز." #: ../src/hamster/stats.py:412 #, fuzzy, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "%s نىڭ خىزمىتى كەچ سائەت 9 دىن كېيىن باشلىنىدۇ، قارىغاندا سىز مۈشۈكياپىلاق " "ئوخشايسىز." #: ../src/hamster/stats.py:415 #, fuzzy, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "%s نىڭ خىزمىتى 15 مىنۇت ئىچىدە، قارىغاندا سىز ئىشچان ھەسەل ھەرىسى ئوخشايسىز." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "بۈگۈن خاتىرە يوق" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sh" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "ھازىرلا باشلانغان" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "مەلۇمات ساقلاش—ۋاقىت ئىزلىغۇچى" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML مەلۇماتلىرى" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Tab بىلەن ئايرىلغان قىممەتلەر(TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "ۋاقىت ئىزلاش" #~ msgid "Project Hamster (Gnome Time Tracker)" #~ msgstr "Hamster قۇرۇلۇشى(Gnome ۋاقىت ئىزلىغۇچى)" #~ msgid "_About" #~ msgstr "ھەققىدە(_A)" #~ msgid "_Preferences" #~ msgstr "مايىللىق(_P)" #~ msgid "Sto_p Tracking" #~ msgstr "ئىزلاشنى توختات(_P)" #~ msgid "To_day" #~ msgstr "بۈگۈن(_D)" #~ msgid "_Add earlier activity" #~ msgstr "ئىلگىرىكى پائالىيەتنى قوش(_A)" #~ msgid "Starts and ends" #~ msgstr "بەشى ۋە ئاخىرى" #~ msgid "Year:" #~ msgstr "يىلى:" #~ msgid "Preferences" #~ msgstr "مايىللىق" #~ msgid "Changed activity" #~ msgstr "ئۆزگەرگەن پائالىيەتلەر" #~ msgid "Switched to '%s'" #~ msgstr "«%s» غا ئالماشتى" #~ msgid "Working on %s" #~ msgstr "%s غا ئىشلەۋاتىدۇ" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster ۋاقىت ئىزلىغۇچى. ئىشلىتىش ئۇسۇلى:" hamster-3.0.3/po/uk.po000066400000000000000000001002001452646177100145630ustar00rootroot00000000000000# Ukrainian translation of hamster. # Copyright (C) Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # Maxim Dziumanenko , 2009-2010 # wanderlust , 2009. # Korostil Daniel , 2011, 2012. #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-18 18:58+0300\n" "Last-Translator: Korostil Daniel \n" "Language-Team: translation@linux.org.ua\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Virtaal 0.7.1\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Додати іншу діяльність" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "до" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "у процесі" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Опис:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "Час:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "Діяльність:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "Ярлики:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Припинити стеження при бездіяльності" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "Припинити стеження за поточною дією при бездіяльності комп'ютера" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Припиняти стеження при вимиканні комп'ютера" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Припинити стеження за поточною дією при вимиканні комп'ютера" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Періодично нагадувати про поточну задачу через вказане число хвилин" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Вмикає нагадування про поточну задачу періодично через вказане число хвилин. " "Значення 0 або більше 120 вимикає нагадування" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "Також нагадати коли не встановлено діяльність" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" "Нагадувати з інтервалом notify_interval у хвилинах, якщо дію не було " "розпочато." #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "О котрій починається день (типово 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "Дії будуть записані на вчорашній день, якщо поточний час менший за вказаний " "у полі початок дня, і будуть записані на сьогодні, якщо час більший за " "початок дня. Дії, що охоплюють два дні, приписуються до дня, у якому " "зроблено більшу частину дії." #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "Чи потрібно перемикати робочого місця перемикати задачу" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "Список використаних способів звіту. Значення «name» враховує перемикання " "зайнята за назвами, визначеннями у workspace_mapping. Значення «memory» " "враховує перемикання на останнє заняття при повернені до попереднього " "робочого простору." #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "Перемикати зайняття при зміні робочого місця" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "Якщо увімкнено, перемикання за назвою, цей список встановлює назви занять, " "які слід перемикати. Робочі місця представлені індексом елементи." #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "Показати / сховати вікно обліку за часом" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Клавіатурне скорочення для показу / ховання вікна обліку за часом." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "Перемкнути дії вікна програми" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "Команда для перемикання видимості вікна програми." #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "Перемкнути вікно програми" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "Перемкнути видимість вікна програми." #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Облік часу" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Проект Hamster — слідкуй за своїм часом" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "Перегляд обліку часу" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Попередній перегляд вікна обліку часу" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "Показати статистику" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "Категорії" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "Дії" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "Мітки" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "Дані за цей інтервал недоступні" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "Зберегти звіт…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "День" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Тиждень" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Місяць" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "Огляд — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "_Огляд" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Діяльність" #: ../data/overview.ui.h:8 msgid "_View" msgstr "П_ерегляд" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Всього" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "Вилучити" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "Додати нову" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Редагування" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Параметри аплету стеження за часом" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Припиняти стеження при бездіяльності комп'ютера" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Нагадувати про кожну дію кожні:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "Новий день починається о" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "Використовувати такий список завдань, якщо такий доступний:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "Взаємодія" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "Облік" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Категорії" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "Список категорій" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "Додати категорію" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "Вилучити категорію" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "Змінити категорію" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Дії" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "Список дій" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Додати діяльність" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "Вилучити дію" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Редагувати діяльність" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "Ярлики які з'являються при автодоповненні" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "Категорії та ярлики" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "Відновити попереднє зайняття при поверненні на робочий місце" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "Починати нове зайняття при перемиканні робочих місць:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "Робочі простори" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "День:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "Тиждень:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "Місяць:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "Діапазон:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "Застосувати" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "_Облік" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "Додати іншу діяльність" #: ../data/today.ui.h:4 msgid "Overview" msgstr "_Огляд" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "Статистика" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "З_міни" #: ../data/today.ui.h:7 msgid "_Help" msgstr "_Довідка" #: ../data/today.ui.h:8 msgid "Contents" msgstr "Зміст" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "_Припинити облік" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "_Змінити" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "Почати _облік" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "Почати нове зайнятті" #: ../data/today.ui.h:13 msgid "Today" msgstr "_Сьогодні" #: ../data/today.ui.h:14 msgid "totals" msgstr "усього" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "Показати перегляд" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Немає дій" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Категорія" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Опис" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Початок" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Кінець" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Тривалість" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "Категорії" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Проект Hamster - слідкуй за своїм часом" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "© 2007–2010 Toms Bauģis та інші" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Сайт проекту Hamster" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "Про програму" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Максим Дзюманенко Daniel Korostil " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Без сортування" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Робота" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Читання новин" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Перевірка курсу цінних паперів" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Жахливо таємний проект Х" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Світове панування" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "Щоденна рутина" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Обід" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Полити квіти" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Стояння на голові" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Оновити діяльність" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%dг" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%dхв" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%dг %dхв" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%d %B %Y" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s %(start_Y)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_d)s %(start_B)s – %(end_d)s %(end_B)s %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_d)s – %(end_d)s %(start_B)s %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%A, %d %b" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "Всього враховано годин: %s" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "Немає" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Назва" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Створити категорію" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Створити дію" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d хвилина" msgstr[1] "%(interval_minutes)d хвилини" msgstr[2] "%(interval_minutes)d хвилин" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Ніколи" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "діяльність" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "час початку" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "час завершення" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "тривалість (хв.)" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "категорія" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "опис" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "позначки" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Звіт діяльності за %(start_d)s %(start_B)s, %(start_Y)s — %(end_d)s " "%(end_B)s, %(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Звіт про діяльність за %(start_d)s %(start_B)s — %(end_d)s %(end_B)s, " "%(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Звіт про діяльність за %(start_d)s %(start_B)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Звіт про діяльність за %(start_d)s %(start_B)s — %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%d %b %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "Всього за день" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "Журнал діяльності" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "дії" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "Категорії" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "Розрізняють:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Дата" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "Показати шаблон" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "Можете змінити це, записавши вашу версію в %(home_folder)s" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "Всі" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "Відсутні дані для генерування статистики.\n" "Було б добре мати дані хоча б за тиждень!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "Триває збір даних - перевірте наступного тижня!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%d %b %Y" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%d %b" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "Запис про першу діяльність датується %s." #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s рік" msgstr[1] "%(num)s рік" msgstr[2] "%(num)s рік" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "Наразі час слідкування складає %(human_days)s календарних днів " "(%(human_years)s років) або %(working_days)s робочих днів (%(working_years)s " "років)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%d %b %Y" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" "Найдовший безперервний тиждень був %(date)s і тривав %(hours)s годину." msgstr[1] "" "Найдовший безперервний тиждень був %(date)s і тривав %(hours)s години." msgstr[2] "" "Найдовший безперервний тиждень був %(date)s і тривав %(hours)s годин." #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "Існує %s запис." msgstr[1] "Існує %s записи." msgstr[2] "Існує %s записів." #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster хотів би слідкувати за Вами більше!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" "На основі аналізування %s відсотків усіє діяльності, які трапилися до 9 " "ранку, вас можна назвати жайворонком." #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" "На основі аналізування %s відсотків усієї діяльності, які трапилися після 11 " "вечора, вас можна назвати совою." #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" "На основі аналізування %s відсотків усієї діяльності, яка тривали менше за " "15 хвилин, вас можна назвати працьовитою бджілкою." #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Немає записів за сьогодні" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%sг" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "Щойно розпочато" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "Зберегти звіт — облік часу" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "Звіт у форматі HTML" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "Значення розділені табуляцією (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "Облік часу" #~ msgid "Show activities window" #~ msgstr "Показати вікно діяльності" #~ msgid "Sto_p Tracking" #~ msgstr "_Припинити облік" #~ msgid "To_day" #~ msgstr "_Сьогодні" #~ msgid "_Add earlier activity" #~ msgstr "_Додати ранішу діяльність" #~ msgid "Show _Overview" #~ msgstr "Показати _огляд" #~ msgid "_Preferences" #~ msgstr "П_араметри" #~ msgid "_About" #~ msgstr "_Про програму" #~ msgid "Year:" #~ msgstr "Рік:" #~ msgid "Starts and ends" #~ msgstr "Початок та завершення" #~ msgid "Preferences" #~ msgstr "Параметри" #~ msgid "Changed activity" #~ msgstr "Змінене зайняття" #~ msgid "Switched to '%s'" #~ msgstr "Переключено на «%s»" #~ msgid "Working on %s" #~ msgstr "Поточна задача: %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Облік часу Hamster. Використання:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Проект Hamster (облік часу в GNOME)" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Д_обдати іншу діяльність" #~ msgid "Tell me more" #~ msgstr "Піднатися докладніше" #~ msgid "_Today" #~ msgstr "_Сьогодні" #~ msgid "Preview:" #~ msgstr "Попередній перегляд:" #~ msgid "Add" #~ msgstr "Додати" #~ msgid "General" #~ msgstr "Загальні" #~ msgid "Global Hotkey" #~ msgstr "Глобальні комбінації клавіш<" #~ msgid "Move activity down" #~ msgstr "Перемістити дію вниз" #~ msgid "Move activity up" #~ msgstr "Перемістити дію вгору" #~ msgid "Total Time" #~ msgstr "Загальний час" #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "Час, коли починається новий день" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "Time and Name" #~ msgstr "Час та назва" #~ msgid "Tags or Description" #~ msgstr "Ярлики та опис" #~ msgid "Activities" #~ msgstr "Діяльність" #~ msgid "Tracking" #~ msgstr "Облік" #~ msgid "" #~ "Type in an activity and hit Enter to start tracking!" #~ "" #~ msgstr "" #~ "Введіть активність та натисніть Enter, щоб " #~ "розпочати стеження!" #~ msgid "" #~ "Tell me more" #~ msgstr "" #~ "Докладніше" #~ msgid "_Activity:" #~ msgstr "_Активність:" #~ msgid " _Day" #~ msgstr "_День" #~ msgid " _Month" #~ msgstr "_Місяць" #~ msgid " _Week" #~ msgstr " _Тиждень" #~ msgid "Overview" #~ msgstr "Огляд" #~ msgid "Totals" #~ msgstr "Підсумки" #~ msgid "Categories:" #~ msgstr "_Категорії:" #~ msgid "Date interval:" #~ msgstr "Проміжок часу:" #~ msgid "Save as HTML" #~ msgstr "Зберегти у форматі HTML" #~ msgid "What should be typed in the activity box?" #~ msgstr "Що вводити у полі діяльності?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ " \n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "Є простий синтаксис, що дозволяє додавати подробиці до ваших дій:\n" #~ " \n" #~ "«@» - символ означає категорію. Приклад: «полити квіти@дім» призведе до " #~ "стеження за активністю «полити квіти» у категорії «дім».\n" #~ "\n" #~ "Кома («,») означає початок опису. Наприклад: «полити квіти, бегонії та " #~ "кактуси» почне стеження за дією «полити квіти» та додасть опис «бегонії " #~ "та кактуси» до неї.\n" #~ "\n" #~ "Символи можна об'єднувати: «полити квіти@дім, бегонії та кактуси» також " #~ "буде працювати!\n" #~ "\n" #~ "Тож, починайте стеження за часом!\n" #~ " " #~ msgctxt "categories" #~ msgid "All" #~ msgstr "Всі" #~ msgctxt "first record" #~ msgid "%(b)s %(d)s" #~ msgstr "%(d)s %(b)s" #~ msgid "Total" #~ msgstr "Загалом" #~ msgid "Overview for %(date)s" #~ msgstr "Огляд %(date)s" hamster-3.0.3/po/vi.po000066400000000000000000000563631452646177100146060ustar00rootroot00000000000000# Vietnamese translation for Hamster Applet. # Copyright © 2009 GNOME I18N Project for Vietnamese. # Clytie Siddall , 2009. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker TRUNK\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2009-02-09 17:29+1030\n" "Last-Translator: Clytie Siddall \n" "Language-Team: Vietnamese \n" "Language: vi\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: LocFactoryEditor 1.8\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "Thêm hoạt động trước" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "" #: ../data/edit_activity.ui.h:3 #, fuzzy msgid "in progress" msgstr "" "đang tiến hành...\n" "đến\n" "trong" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "Mô tả:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "" #: ../data/edit_activity.ui.h:6 #, fuzzy msgid "Activity:" msgstr "_Hoạt động:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "Đừng theo dõi khi nghỉ" #: ../data/hamster.schemas.in.h:2 #, fuzzy msgid "Stop tracking current activity when computer becomes idle" msgstr "Dừng theo dõi hoạt động hiện thời khi máy tính vào tình trạng nghỉ" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "Dừng theo dõi khi tắt máy" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "Dừng theo dõi hoạt động hiện thời khi tắt máy" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "Nhắc nhở về tác vụ hiện thời mỗi x phút" #: ../data/hamster.schemas.in.h:6 #, fuzzy msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "" "Nhắc nhở về tác vụ hiện thời mỗi số phút đã ghi rõ. Đặt thành 0 hay hơn 120 " "để tắt chức năng nhắc nhở." #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" #: ../data/hamster.schemas.in.h:15 #, fuzzy msgid "Show / hide Time Tracker Window" msgstr "Phím tắt hiển thị cửa sổ Theo dõi Thời gian." #: ../data/hamster.schemas.in.h:16 #, fuzzy msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "Phím tắt hiển thị cửa sổ Theo dõi Thời gian." #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "Theo dõi Thời gian" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Dự án Hamster — theo dõi thời gian làm" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 #, fuzzy msgid "Time Tracking Overview" msgstr "Theo dõi Thời gian" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "" #: ../data/overview_totals.ui.h:2 #, fuzzy msgid "Categories" msgstr "_Loại" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 #, fuzzy msgid "Activities" msgstr "_Hoạt động" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "" #: ../data/overview.ui.h:2 msgid "Day" msgstr "Ngày" #: ../data/overview.ui.h:3 msgid "Week" msgstr "Tuần" #: ../data/overview.ui.h:4 msgid "Month" msgstr "Tháng" #: ../data/overview.ui.h:5 #, fuzzy msgid "Overview — Hamster" msgstr "Toàn cảnh — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "T_oàn cảnh" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "Hoạt động" #: ../data/overview.ui.h:8 msgid "_View" msgstr "" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "Tổng số" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "Sửa" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "Tùy thích Theo dõi Thời gian" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "Dừng theo dõi khi máy tính bắt đầu nghỉ" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "Nhắc nhở về hoạt động hiện thời mỗi:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "" #: ../data/preferences.ui.h:8 #, fuzzy msgid "Integration" msgstr "Thời gian" #: ../data/preferences.ui.h:9 #, fuzzy msgid "Tracking" msgstr "_Dừng theo dõi" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "_Loại" #: ../data/preferences.ui.h:11 #, fuzzy msgid "Category list" msgstr "Loại" #: ../data/preferences.ui.h:12 #, fuzzy msgid "Add category" msgstr "Loại mới" #: ../data/preferences.ui.h:13 #, fuzzy msgid "Remove category" msgstr "Loại mới" #: ../data/preferences.ui.h:14 #, fuzzy msgid "Edit category" msgstr "Loại mới" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "_Hoạt động" #: ../data/preferences.ui.h:16 #, fuzzy msgid "Activity list" msgstr "Hoạt động" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "Thêm hoạt động" #: ../data/preferences.ui.h:18 #, fuzzy msgid "Remove activity" msgstr "Không có hoạt động" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "Sửa hoạt động" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "" #: ../data/preferences.ui.h:21 #, fuzzy msgid "Categories and Tags" msgstr "_Loại" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "" #: ../data/range_pick.ui.h:2 #, fuzzy msgid "Week:" msgstr "Tuần" #: ../data/range_pick.ui.h:3 #, fuzzy msgid "Month:" msgstr "Tháng" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "" #: ../data/today.ui.h:2 #, fuzzy msgid "_Tracking" msgstr "_Dừng theo dõi" #: ../data/today.ui.h:3 #, fuzzy msgid "Add earlier activity" msgstr "Thêm hoạt động trước" #: ../data/today.ui.h:4 #, fuzzy msgid "Overview" msgstr "T_oàn cảnh" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "" #: ../data/today.ui.h:6 #, fuzzy msgid "_Edit" msgstr "Sửa" #: ../data/today.ui.h:7 msgid "_Help" msgstr "" #: ../data/today.ui.h:8 msgid "Contents" msgstr "" #: ../data/today.ui.h:9 #, fuzzy msgid "Sto_p tracking" msgstr "_Dừng theo dõi" #: ../data/today.ui.h:10 #, fuzzy msgid "S_witch" msgstr "Chuyển đổi" #: ../data/today.ui.h:11 #, fuzzy msgid "Start _Tracking" msgstr "_Dừng theo dõi" #: ../data/today.ui.h:12 #, fuzzy msgid "Start new activity" msgstr "Hoạt động mới" #: ../data/today.ui.h:13 #, fuzzy msgid "Today" msgstr "Hô_m nay" #: ../data/today.ui.h:14 #, fuzzy msgid "totals" msgstr "Tổng số" #: ../data/today.ui.h:16 #, fuzzy msgid "Show Overview" msgstr "Hiện T_oàn cảnh" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "Không có hoạt động" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "Loại" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "Mô tả" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "Đầu" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "Cuối" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "Thời gian" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "_Loại" #: ../src/hamster/about.py:42 #, fuzzy msgid "Project Hamster — track your time" msgstr "Dự án Hamster — theo dõi thời gian làm" #: ../src/hamster/about.py:43 #, fuzzy msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "Tác quyền © năm 2007-2008 của Toms Baugis và người khác" #: ../src/hamster/about.py:45 #, fuzzy msgid "Project Hamster Website" msgstr "Trang Web Hamster" #: ../src/hamster/about.py:46 #, fuzzy msgid "About Time Tracker" msgstr "Theo dõi Thời gian" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "Nhóm Việt hóa GNOME " #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "Chưa sắp xếp" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "Chỗ làm" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "Đang đọc tin tức" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "Đang kiểm tra các chứng khoán" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "Dự án rất mật X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "Thống trị thố giới" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "Ăn trưa" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "Đang tưới các hoa" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "Đang tư thế trồng chuối" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "Cập nhật hoạt động" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "" "Toàn cảnh về %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "Toàn cảnh về %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, fuzzy, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Toàn cảnh về %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "Tên" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "Loại mới" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "Hoạt động mới" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, fuzzy, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d phút" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "Không bao giờ" #. column title in the TSV export format #: ../src/hamster/reports.py:148 #, fuzzy msgid "activity" msgstr "Hoạt động" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "" #. column title in the TSV export format #: ../src/hamster/reports.py:154 #, fuzzy msgid "duration minutes" msgstr "phút" #. column title in the TSV export format #: ../src/hamster/reports.py:156 #, fuzzy msgid "category" msgstr "Loại" #. column title in the TSV export format #: ../src/hamster/reports.py:158 #, fuzzy msgid "description" msgstr "Mô tả" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "" #: ../src/hamster/reports.py:207 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "Toàn cảnh về %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, fuzzy, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "Toàn cảnh về %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "Toàn cảnh về %(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, fuzzy, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "Toàn cảnh về %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 #, fuzzy msgid "Totals by Day" msgstr "Tổng số" #: ../src/hamster/reports.py:307 #, fuzzy msgid "Activity Log" msgstr "Hoạt động" #: ../src/hamster/reports.py:310 #, fuzzy msgid "activities" msgstr "_Hoạt động" #: ../src/hamster/reports.py:311 #, fuzzy msgid "categories" msgstr "_Loại" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "Ngày" #: ../src/hamster/reports.py:326 #, fuzzy msgid "Show template" msgstr "Hiển thị tuần" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "Không tìm thấy" # Variable: don't translate/Biến: đừng dịch #: ../src/hamster/today.py:250 #, fuzzy, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s: %(duration)s, " #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:39 #, fuzzy msgid "Save Report — Time Tracker" msgstr "Theo dõi Thời gian" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 #, fuzzy msgid "Time track" msgstr "Theo dõi Thời gian" #~ msgid "_About" #~ msgstr "G_iới thiệu" #~ msgid "_Preferences" #~ msgstr "Tù_y thích" #~ msgid "Activities" #~ msgstr "Hoạt động" #~ msgid "Global Hotkey" #~ msgstr "Phím tắt Toàn cục" #~ msgid "Tracking" #~ msgstr "Theo dõi" #~ msgid "Move _Down" #~ msgstr "Đưa _Xuống" #~ msgid "Move _Up" #~ msgstr "Đưa _Lên" #~ msgid "N_ew Category" #~ msgstr "Loại mớ_i" #~ msgid "_New Activity" #~ msgstr "Hoạt động mớ_i" #~ msgid "Activity" #~ msgstr "Hoạt động" #~ msgid "Date and Time" #~ msgstr "Ngày và Giờ" #~ msgid "Name:" #~ msgstr "Tên:" #~ msgid "hours" #~ msgstr "giờ" #~ msgid "Show window" #~ msgstr "Hiện cửa sổ" #~ msgid "Ad_d Earlier Activity" #~ msgstr "Thêm hoạt động t_rước" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid " _Day" #~ msgstr " _Ngày" #~ msgid " _Month" #~ msgstr " T_háng" #~ msgid " _Week" #~ msgstr " _Tuần" #~ msgid "Category" #~ msgstr "Phân loại" #~ msgid "Overview" #~ msgstr "Toàn cảnh" #~ msgid "Week" #~ msgstr "Tuần" #~ msgid "Delete activity" #~ msgstr "Xoá hoạt động" #~ msgid "Earlier activities" #~ msgstr "Hoạt động trước" #~ msgid "Generate Report" #~ msgstr "Tạo báo cáo" #~ msgid "Newer activities" #~ msgstr "Hoạt động mới" #~ msgid "Show day" #~ msgstr "Hiển thị ngày" #~ msgid "Show month" #~ msgstr "Hiển thị tháng" #~ msgid "Working on %s" #~ msgstr "Đang làm %s" #~ msgid "Day to day" #~ msgstr "Hằng ngày" #~ msgid "name" #~ msgstr "tên" # Variable: don't translate/Biến: đừng dịch #~ msgid "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgstr "%(report_b)s %(report_d)s, %(report_Y)s" #~ msgid "Total Time" #~ msgstr "Tổng thời gian" # Variable: don't translate/Biến: đừng dịch #~ msgid "%(o_A)s, %(o_b)s %(o_d)s" #~ msgstr "%(o_A)s, %(o_b)s %(o_d)s" # Variable: don't translate/Biến: đừng dịch #~ msgid "%(m_b)s %(m_d)s" #~ msgstr "%(m_b)s %(m_d)s" #~ msgid "Other" #~ msgstr "Khác" hamster-3.0.3/po/wscript000066400000000000000000000002201452646177100152230ustar00rootroot00000000000000#!/usr/bin/env python2 # encoding: utf-8 # Thomas Nagy, 2006-2009 (ita) def build(bld): bld(features = 'intltool_po', appname = 'hamster') hamster-3.0.3/po/zh_CN.po000066400000000000000000000653661452646177100151740ustar00rootroot00000000000000# Chinese(Simplified) translation of hamster-time-tracker # Copyright (C) 2008 Free Software Foundation, Inc. # This file is distributed under the same license as the hamster-time-tracker package. # QAed by Funda Wang , 2008. # 甘露(Gan Lu) , 2009. # Ray Wang , 2009, 2010. # Tao Wang , 2010. # YunQiang Su , 2011, 2012. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker HEAD\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-03-21 01:12+0800\n" "Last-Translator: YunQiang Su \n" "Language-Team: Chinese (simplified) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bits\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Poedit-Language: Chinese\n" "X-Poedit-Country: CHINA\n" "X-Poedit-SourceCharset: utf-8\n" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "添加较早的活动" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "到" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "正在进行中" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "描述:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "时间:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "活动:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "标签:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "空闲时停止跟踪" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "当计算机处于空闲时停止跟踪当前活动" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "关机时停止跟踪" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "关机时停止跟踪当前活动" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "每隔几分钟提醒一次当前任务" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "每隔几分钟提醒一次当前任务。设定为 0 或大于 120 代表禁止提醒。" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "没有任何活动时仍然提醒" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "如果没有活动开始,仍然每隔设定的提醒间隔时间进行提醒。" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "一天的起始时间在何时 (默认时间到早上5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "如果当前时间少于从指定天开始到今天,则活动将被计算到昨天。如果活动跨了两天," "则翻到活动时间最长的那天。" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "应该是工作区转换触发活动转换" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "允许跟踪的方法列表。 \"name\" 将允许通过在工作区映射中定义的名字来转换活" "动。“memory\" 将允许当返回到之前的工作区时转换到上一次活动。" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "当工作区改变时,转换活动" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "如果启用按名称转换,该列表会设置应该被转换的活动名称,条目的索引代表工作区" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "显示/隐藏时间跟踪窗口" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "用于显示/隐藏时间跟踪窗口的快捷键。" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "切换 hamster 应用程序窗口动作" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "切换 hamster 应用程序窗口的可见性的命令。" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "切换 hamster 应用程序窗口" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "切换 hamster 应用程序窗口的可见性。" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "时间跟踪器" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Hamster 项目 - 跟踪您的时间" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "时间跟踪概要" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "Hamster 时间跟踪器的概要窗口" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "显示统计" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "类别" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "活动" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "标签" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "没有针对这个时间间隔的数据" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "保存报告..." #: ../data/overview.ui.h:2 msgid "Day" msgstr "天" #: ../data/overview.ui.h:3 msgid "Week" msgstr "周" #: ../data/overview.ui.h:4 msgid "Month" msgstr "月" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "概要 — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "概要(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "活动" #: ../data/overview.ui.h:8 msgid "_View" msgstr "查看(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "合计" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "删除" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "添加新的活动" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "编辑" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "时间跟踪器首选项" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "当计算机处于空闲时停止跟踪" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "提醒当前活动每:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "新一天开始于" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "如果可用,使用下面的 TODO 列表:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "集成" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "跟踪" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "类别(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "类别列表" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "添加类别" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "删除类别" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "编辑类别" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "活动(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "活动列表" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "添加活动" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "删除活动" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "编辑活动" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "应在自动完成中显示的标签" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "类别和标签" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "当返回到一个工作区后恢复上一次活动" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "当转换工作区时开始新的活动:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "工作区" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "天:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "周:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "月:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "日期范围:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "应用" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "跟踪(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "添加较早的活动" #: ../data/today.ui.h:4 msgid "Overview" msgstr "概要" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "统计" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "编辑(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "帮助(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "内容" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "停止跟踪(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "切换(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "开始跟踪(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "开始新活动" #: ../data/today.ui.h:13 msgid "Today" msgstr "今天" #: ../data/today.ui.h:14 msgid "totals" msgstr "合计" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "显示概要" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "没有活动" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "类别" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "描述" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "开始" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "结束" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "持续时间" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "类别" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster 项目 - 跟踪你的时间" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "版权 © 2007-2010 Toms Bauģis 和其他人" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster 项目网站" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "关于时间跟踪器" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "Ray Wang , 2008\n" "Funda Wang , 2008\n" "Tao Wang , 2010" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "未分类" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "工作" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "阅读新闻" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "查看股票" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "进行绝密项目" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "征服世界" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "日常" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "午饭" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "浇花" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "玩倒立" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "更新活动" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d 时" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d 分" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d 时·%d 分" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y年%m月%d日" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%m月%d日,%A" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "总计已跟踪 %s 小时" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "空" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "名称" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "新建类别" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "新建活动" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d 分" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "从不" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "活动" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "开始时间" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "结束时间" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "持续时间" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "类别" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "描述" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "标签" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "活动报告:%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, " "%(end_Y)s" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "活动报告:%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "活动报告:%(start_B)s %(start_d)s, %(start_Y)s" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "活动报告:%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%Y年%m月%d日" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "按天合计" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "活动日志" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "活动" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "类别" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "区别:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "日期" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "显示模板" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "您可以通过在 %(home_folder)s 中保存您的版本来覆盖它。" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "所有" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "目前还没有用于产生统计的数据。\n" "一周的使用将会很好!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "正在收集数据 — 一个星期过后再来检查!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y年%m月%d日" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%m月%d日" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "第一次的活动记录在%s。" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s年" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "时间目前跟踪了 %(human_days)s 自然日 (%(human_years)s) 或 %(working_days)s 工" "作日 (%(working_years)s)." #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y年%m月%d日" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "最长持续的工作持续了 %(hours)s 小时,发生于 %(date)s。" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "有 %s 个记录。" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster 想观察你多一些!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "有 %s 的活动开始于早上9点之前,你看起来是个早起的鸟儿。" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "有 %s 的活动开始于晚上11点之后,你看起来是个夜猫子。" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "有 %s 的活动在15分钟之内,你看起来是只忙碌的小蜜蜂。" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "今天没有记录" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s:%(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s小时" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "刚刚开始" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "保存报告 — 时间跟踪器" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML 报告" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "制表符分隔值 (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "时间跟踪器" #~| msgid "Show window" #~ msgid "Show activities window" #~ msgstr "显示活动窗口" #~ msgid "Sto_p Tracking" #~ msgstr "停止跟踪(_P)" #~ msgid "To_day" #~ msgstr "今天(_D)" #~ msgid "_Add earlier activity" #~ msgstr "添加较早的活动(_A)" #~ msgid "Show _Overview" #~ msgstr "显示概要(_O)" #~ msgid "_Preferences" #~ msgstr "首选项(_P)" #~ msgid "_About" #~ msgstr "关于(_A)" #~ msgid "Year:" #~ msgstr "年份:" #~ msgid "Starts and ends" #~ msgstr "开始和结束" #~ msgid "Preferences" #~ msgstr "首选项" #~ msgid "Changed activity" #~ msgstr "改变活动" #~ msgid "Switched to '%s'" #~ msgstr "切换到 '%s'" #~ msgid "Working on %s" #~ msgstr "工作在 %s?" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster 时间跟踪器。用法:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Hamster 项目(Gnome 时间跟踪)" #~ msgid "Tell me more" #~ msgstr "更多信息" #~ msgid "totals by activity" #~ msgstr "按活动合计" #~ msgid "totals by category" #~ msgstr "按类别合计" #~ msgid "Show:" #~ msgstr "显示:" #~ msgid "Project Hamster desktop time tracking" #~ msgstr "Hamster 桌面时间跟踪项目" #~ msgid "Move activity down" #~ msgstr "下移活动" #~ msgid "Move activity up" #~ msgstr "上移活动" #~ msgid "Ad_d Earlier Activity" #~ msgstr "添加较早的活动(_D)" #~ msgid "_Today" #~ msgstr "今天(_T)" #~ msgid "General" #~ msgstr "常规" #~ msgid "Global Hotkey" #~ msgstr "全局热键" #~ msgid "Preview:" #~ msgstr "预览:" #~ msgid "Total Time" #~ msgstr "合计时间" #~ msgid "Hamster" #~ msgstr "Hamster" #~ msgid "What should be typed in the activity box?" #~ msgstr "在活动输入框中应该输入什么?" #~ msgid "" #~ "There is a simple syntax that enables you to add details to your " #~ "activities:\n" #~ "\n" #~ "\"@\" symbol marks a category. Example: \"watering flowers@home\" will " #~ "start tracking the activity \"watering flowers\" in the category \"home" #~ "\".\n" #~ "\n" #~ "Commas (\",\") mark beginning of a description. Example: \"watering " #~ "flowers, begonias and forgetmenots\" will start tracking the activity " #~ "\"watering flowers\" and add the description \"begonias and forgetmenots" #~ "\" to it.\n" #~ "\n" #~ "Both can be combined: \"watering flowers@home, begonias and forgetmenots" #~ "\" will work just fine!\n" #~ "\n" #~ "In the tag field, separate tags with a comma. You can use Tab button to " #~ "autocomplete first tag displayed in the dropdown, as well as click on the " #~ "tags using mouse.\n" #~ "Now, start tracking!\n" #~ " " #~ msgstr "" #~ "这允许您使用简单的句法来添加详细信息到您的活动中:\n" #~ "\n" #~ "“@”表示类别。例如:“watering flowers@home”将开始在“home”类别中跟踪 " #~ "“watering flowers”活动。\n" #~ "\n" #~ "逗号(“,”)表示描述的开始。例如:“watering flowers, begonias and " #~ "forgetmenots”将开始跟踪“watering flowers”活动并且添加描述“begonias and " #~ "forgetmenots”到其中去。\n" #~ "\n" #~ "二者可以合并成:“watering flowers@home, begonias and forgetmenots”将正常工" #~ "作!\n" #~ "\n" #~ "在标签栏里,用逗号分隔标签。你可以用 Tab 键来自动完成在下拉列表里显示的第" #~ "一个标签,同时也可以用鼠标点击标签来进行自动完成。\n" #~ "现在开始跟踪!\n" #~ " " #~ msgid "Time at witch to consider beginning of new day" #~ msgstr "认为是新一天开始的时间" #~ msgid "Time and Name" #~ msgstr "时间和名称" #~ msgid "Tags or Description" #~ msgstr "标签或说明" #~ msgid "Total" #~ msgstr "合计" #~ msgctxt "overview graph" #~ msgid "%b %d" #~ msgstr "%m月%d日" #~ msgid "Reports" #~ msgstr "报告" #~ msgid "Next" #~ msgstr "下一个" #~ msgid "Previous" #~ msgstr "前一个" #~ msgid "This Week" #~ msgstr "本周" #~ msgid " _Month" #~ msgstr "月(_M)" #~ msgid " _Week" #~ msgstr "周(_W)" #~ msgid "Overview" #~ msgstr "概要" #~ msgid "Categories:" #~ msgstr "类别:" #~ msgid "Date interval:" #~ msgstr "日期间隔:" #~ msgid "Totals" #~ msgstr "合计" hamster-3.0.3/po/zh_HK.po000066400000000000000000000566101452646177100151660ustar00rootroot00000000000000# Chinese (Hong Kong) translation of hamster. # Copyright (C) 2003-06 Free Software Foundation, Inc. # Chao-Hsiung Liao , 2008. # Tryneeds translation team, 2009. # Cheng-Chia Tseng , 2010. # Wei-Lun Chao , 2010. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker 2.29.93\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-25 11:06+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese (Hong Kong) \n" "Language: \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "加入較早的活動" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "到" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "進行中" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "描述:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "時間:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "活動:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "標籤:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "閒置時停止追蹤" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "當電腦為閒置狀態時停止追蹤目前的活動" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "關機時停止追蹤" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "關機時停止追蹤目前的活動" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "每 x 分鐘提醒目前的工作" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "在每次指定的分鐘數後提醒目前的工作。設為 0 或大於 120 時表示停用提醒。" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "當沒有設定活動時也提醒" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "如果沒有活動開始,仍在每 notify_interval 分鐘提醒我。" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "這天開始的時刻 (預設為上午 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "如果目前的時間尚未達到指定日子開始的時候,那麼活動會被算在昨天。跨越兩天的活" "動會跳到活動佔絕大的部分那天。" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "工作區的切換是否應觸發活動的切換" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "已啟用追蹤方法的清單。「name」(名稱) 會啟用根據 workspace_mapping 中定義的名" "稱切換活動。「memory」(記憶) 會啟用在返回上一個工作區時切換到上次的活動。" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "工作區改變時切換活動" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "如果啟用根據名稱切換,這個清單設定了應該被切換的活動名稱,項目的索引代表工作" "區。" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "顯示或隱藏時間追蹤程式視窗" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "用來顯示或隱藏時間追蹤程式視窗的鍵盤捷徑鍵。" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "切換 hamster 應用程式視窗動作" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "切換 hamster 應用程式視窗可見與否的指令。" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "切換 hamster 應用程式視窗" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "切換 hamster 應用程式視窗可見與否。" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "時間追蹤程式" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster - 追蹤你的時間" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "時間追蹤概覽" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "hamster 時間追蹤程式的概覽視窗" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "顯示統計" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "分類" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "活動" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "標籤" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "這個間隔中沒有資料" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "儲存報告…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "日" #: ../data/overview.ui.h:3 msgid "Week" msgstr "週" #: ../data/overview.ui.h:4 msgid "Month" msgstr "月" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "概覽 — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "概覽(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "活動" #: ../data/overview.ui.h:8 msgid "_View" msgstr "檢視(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "總計" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "移除" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "新增" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "編輯" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "時間追蹤程式偏好設定" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "當電腦為閒置狀態時停止追蹤" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "提醒目前的活動於每:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "新的一天開始於" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "如果可用的話,使用下列代辦清單:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "整合" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "追蹤" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "分類(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "分類清單" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "加入分類" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "移除分類" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "編輯分類" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "活動(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "活動清單" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "加入活動" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "移除活動" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "編輯活動" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "在自動補齊中要顯示的標籤:" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "分類和標籤" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "在返回工作區時繼續上次的活動" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "當切換工作區時開始新的活動:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "工作區" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "日:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "週:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "月:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "範圍:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "套用" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "追蹤(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "加入較早的活動" #: ../data/today.ui.h:4 msgid "Overview" msgstr "概覽" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "統計" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "編輯(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "求助(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "內容" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "停止追蹤(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "切換(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "開始追蹤(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "開始新的活動" #: ../data/today.ui.h:13 msgid "Today" msgstr "今天" #: ../data/today.ui.h:14 msgid "totals" msgstr "總計" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "顯示概覽" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "沒有活動" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "分類" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "描述" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "開始" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "結束" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "期間" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "分類" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster 專案 - 追蹤你的時間" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "版權所有 © 2007-2010 Toms Bauģis 和其他開發者" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster 專案網址" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "關於時間追蹤程式" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "如對翻譯有任何意見,請送一封電子郵件給\n" "以下地址,GNOME 翻譯隊伍會盡快回覆你:\n" "zh-l10n@lists.linux.org.tw\n" "\n" "Chao-Hsiung Liao , 2008" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "未排序" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "工作" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "閱讀新聞" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "查看股票" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "超級祕密專案 X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "支配世界" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "每日" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "午餐" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "澆花" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "倒立" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "更新活動" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d時" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d分" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d時 %d分" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y %B %d" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%b %d %A" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "總計已追蹤 %s 小時" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "無" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "名稱" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "新增分類" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "新增活動" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d 分鐘" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "永不" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "活動" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "開始時刻" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "結束時刻" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "持續分鐘" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "分類" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "描述" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "標籤" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s 的活動" "日誌" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s 的活動日誌" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s 的活動日誌" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s 的活動日誌" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "根據日總計" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "活動日誌" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "活動" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "分類" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "區別:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "日期" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "顯示模板" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "你可以藉由於 %(home_folder)s 儲存你自己的版本來凌駕它" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "全部" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "還沒有足夠的資料來產生統計表。\n" "建議最好有一個星期的使用資料!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "還在收集資料中 — 請過一星期後再檢查!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y %b %d" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "第一個活動被記錄於 %s。" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s 年" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "到目前為止追蹤的時間有 %(human_days)s 天(%(human_years)s 年)或 " "%(working_days)s 工作天(%(working_years)s 年)。" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y %b %d" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "最長的連續工作發生於 %(date)s ,有 %(hours)s 小時。" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "總共有 %s 個紀錄。" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster 會更仔細的觀察你!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "在所有活動中有 %s % 在早上 9 點前開始,看起來你是早起的鳥兒。" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "在所有活動中有 %s % 在晚上 11 點後開始,看起來你是個夜貓子。" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "在所有工作中有 %s % 短於 15 分鐘,看起來你是忙碌的蜜蜂。" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "今天沒有紀錄" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s:%(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s時" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "剛剛開始" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "儲存報告 - 時間追蹤程式" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML 報告" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "以 Tab 分隔的數值 (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "時間追蹤" #~ msgid "Show activities window" #~ msgstr "顯示活動視窗" #~ msgid "Show _Overview" #~ msgstr "顯示概覽(_O)" #~ msgid "Sto_p Tracking" #~ msgstr "停止追蹤(_P)" #~ msgid "To_day" #~ msgstr "今日(_D)" #~ msgid "_Add earlier activity" #~ msgstr "加入較早的活動(_A)" #~ msgid "_About" #~ msgstr "關於(_A)" #~ msgid "_Preferences" #~ msgstr "偏好設定(_P)" #~ msgid "Starts and ends" #~ msgstr "開始與結束" #~ msgid "Year:" #~ msgstr "年:" #~ msgid "Preferences" #~ msgstr "偏好設定" #~ msgid "Changed activity" #~ msgstr "改變的活動" #~ msgid "Switched to '%s'" #~ msgstr "已切換為「%s」" #~ msgid "Working on %s" #~ msgstr "運作於 %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster 時間追蹤程式。用法:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (Gnome 時間追蹤程式)" hamster-3.0.3/po/zh_TW.po000066400000000000000000000565771452646177100152320ustar00rootroot00000000000000# Chinese (Taiwan) translation of hamster. # Copyright (C) 2003-06 Free Software Foundation, Inc. # Chao-Hsiung Liao , 2008. # Tryneeds translation team, 2009. # Cheng-Chia Tseng , 2010. # Wei-Lun Chao , 2010. # #: ../src/hamster-cli:342 msgid "" msgstr "" "Project-Id-Version: hamster-time-tracker 2.29.93\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2012-12-02 19:21+0100\n" "PO-Revision-Date: 2012-02-18 20:28+0800\n" "Last-Translator: Chao-Hsiung Liao \n" "Language-Team: Chinese/Traditional \n" "Language: \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" #: ../data/edit_activity.ui.h:1 ../data/today.ui.h:15 msgid "Add Earlier Activity" msgstr "加入較早的活動" #: ../data/edit_activity.ui.h:2 ../data/range_pick.ui.h:5 msgid "to" msgstr "到" #: ../data/edit_activity.ui.h:3 msgid "in progress" msgstr "進行中" #: ../data/edit_activity.ui.h:4 msgid "Description:" msgstr "描述:" #: ../data/edit_activity.ui.h:5 msgid "Time:" msgstr "時間:" #: ../data/edit_activity.ui.h:6 msgid "Activity:" msgstr "活動:" #: ../data/edit_activity.ui.h:7 msgid "Tags:" msgstr "標籤:" #: ../data/hamster.schemas.in.h:1 msgid "Stop tracking on idle" msgstr "閒置時停止追蹤" #: ../data/hamster.schemas.in.h:2 msgid "Stop tracking current activity when computer becomes idle" msgstr "當電腦為閒置狀態時停止追蹤目前的活動" #: ../data/hamster.schemas.in.h:3 ../data/preferences.ui.h:2 msgid "Stop tracking on shutdown" msgstr "關機時停止追蹤" #: ../data/hamster.schemas.in.h:4 msgid "Stop tracking current activity on shutdown" msgstr "關機時停止追蹤目前的活動" #: ../data/hamster.schemas.in.h:5 msgid "Remind of current task every x minutes" msgstr "每 x 分鐘提醒目前的工作" #: ../data/hamster.schemas.in.h:6 msgid "" "Remind of current task every specified amount of minutes. Set to 0 or " "greater than 120 to disable reminder." msgstr "在每次指定的分鐘數後提醒目前的工作。設為 0 或大於 120 時表示停用提醒。" #: ../data/hamster.schemas.in.h:7 ../data/preferences.ui.h:4 msgid "Also remind when no activity is set" msgstr "當沒有設定活動時也提醒" #: ../data/hamster.schemas.in.h:8 msgid "" "Also remind every notify_interval minutes if no activity has been started." msgstr "如果沒有活動開始,仍在每 notify_interval 分鐘提醒我。" #: ../data/hamster.schemas.in.h:9 msgid "At what time does the day start (defaults to 5:30AM)" msgstr "這天開始的時刻 (預設為上午 5:30)" #: ../data/hamster.schemas.in.h:10 msgid "" "Activities will be counted as to belong to yesterday if the current time is " "less than the specified day start; and today, if it is over the time. " "Activities that span two days, will tip over to the side where the largest " "part of the activity is." msgstr "" "如果目前的時間尚未達到指定日子開始的時候,那麼活動會被算在昨天。跨越兩天的活" "動會跳到活動佔絕大的部分那天。" #: ../data/hamster.schemas.in.h:11 msgid "Should workspace switch trigger activity switch" msgstr "工作區的切換是否應觸發活動的切換" #: ../data/hamster.schemas.in.h:12 msgid "" "List of enabled tracking methods. \"name\" will enable switching activities " "by name defined in workspace_mapping. \"memory\" will enable switching to " "the last activity when returning to a previous workspace." msgstr "" "已啟用追蹤方法的清單。「name」(名稱) 會啟用依 workspace_mapping 中定義的名稱" "切換活動。「memory」(記憶) 會啟用在返回上一個工作區時切換到上次的活動。" #: ../data/hamster.schemas.in.h:13 msgid "Switch activity on workspace change" msgstr "工作區改變時切換活動" #: ../data/hamster.schemas.in.h:14 msgid "" "If switching by name is enabled, this list sets the activity names that " "should be switched to, workspaces represented by the index of item." msgstr "" "如果啟用依名稱切換,這個清單設定了應該被切換的活動名稱,項目的索引代表工作" "區。" #: ../data/hamster.schemas.in.h:15 msgid "Show / hide Time Tracker Window" msgstr "顯示或隱藏時間追蹤程式視窗" #: ../data/hamster.schemas.in.h:16 msgid "Keyboard shortcut for showing / hiding the Time Tracker window." msgstr "用來顯示或隱藏時間追蹤程式視窗的鍵盤捷徑鍵。" #: ../data/hamster.schemas.in.h:17 msgid "Toggle hamster application window action" msgstr "切換 hamster 應用程式視窗動作" #: ../data/hamster.schemas.in.h:18 msgid "Command for toggling visibility of the hamster application window." msgstr "切換 hamster 應用程式視窗可見與否的指令。" #: ../data/hamster.schemas.in.h:19 msgid "Toggle hamster application window" msgstr "切換 hamster 應用程式視窗" #: ../data/hamster.schemas.in.h:20 msgid "Toggle visibility of the hamster application window." msgstr "切換 hamster 應用程式視窗可見與否。" #: ../data/hamster.desktop.in.in.h:1 #: ../data/hamster-windows-service.desktop.in.in.h:1 ../data/today.ui.h:1 #: ../src/hamster-cli:133 ../src/hamster/about.py:39 #: ../src/hamster/about.py:40 ../src/hamster/today.py:63 msgid "Time Tracker" msgstr "時間追蹤程式" #: ../data/hamster.desktop.in.in.h:2 #: ../data/hamster-windows-service.desktop.in.in.h:2 msgid "Project Hamster - track your time" msgstr "Project Hamster - 追蹤您的時間" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:1 msgid "Time Tracking Overview" msgstr "時間追蹤概覽" #: ../data/hamster-time-tracker-overview.desktop.in.in.h:2 msgid "The overview window of hamster time tracker" msgstr "hamster 時間追蹤程式的概覽視窗" #: ../data/overview_totals.ui.h:1 msgid "Show Statistics" msgstr "顯示統計" #: ../data/overview_totals.ui.h:2 msgid "Categories" msgstr "分類" #: ../data/overview_totals.ui.h:3 ../data/overview.ui.h:9 msgid "Activities" msgstr "活動" #: ../data/overview_totals.ui.h:4 ../src/hamster-cli:278 #: ../src/hamster/reports.py:319 ../src/hamster/today.py:150 msgid "Tags" msgstr "標籤" #: ../data/overview_totals.ui.h:5 msgid "No data for this interval" msgstr "這個間隔中沒有資料" #: ../data/overview.ui.h:1 msgid "Save report..." msgstr "儲存報告…" #: ../data/overview.ui.h:2 msgid "Day" msgstr "日" #: ../data/overview.ui.h:3 msgid "Week" msgstr "週" #: ../data/overview.ui.h:4 msgid "Month" msgstr "月" #: ../data/overview.ui.h:5 msgid "Overview — Hamster" msgstr "概覽 — Hamster" #: ../data/overview.ui.h:6 msgid "_Overview" msgstr "概覽(_O)" #: ../data/overview.ui.h:7 ../src/hamster-cli:276 #: ../src/hamster/preferences.py:212 ../src/hamster/reports.py:317 #: ../src/hamster/today.py:144 msgid "Activity" msgstr "活動" #: ../data/overview.ui.h:8 msgid "_View" msgstr "檢視(_V)" #: ../data/overview.ui.h:10 ../src/hamster/reports.py:308 msgid "Totals" msgstr "總計" #: ../data/overview.ui.h:11 msgid "Remove" msgstr "移除" #: ../data/overview.ui.h:12 msgid "Add new" msgstr "新增" #: ../data/overview.ui.h:13 msgid "Edit" msgstr "編輯" #: ../data/preferences.ui.h:1 msgid "Time Tracker Preferences" msgstr "時間追蹤程式偏好設定" #: ../data/preferences.ui.h:3 msgid "Stop tracking when computer becomes idle" msgstr "當電腦為閒置狀態時停止追蹤" #: ../data/preferences.ui.h:5 msgid "Remind of current activity every:" msgstr "提醒目前的活動於每:" #: ../data/preferences.ui.h:6 msgid "New day starts at" msgstr "新的一天開始於" #: ../data/preferences.ui.h:7 msgid "Use following todo list if available:" msgstr "如果可用的話,使用下列代辦清單:" #: ../data/preferences.ui.h:8 msgid "Integration" msgstr "整合" #: ../data/preferences.ui.h:9 msgid "Tracking" msgstr "追蹤" #: ../data/preferences.ui.h:10 msgid "_Categories" msgstr "分類(_C)" #: ../data/preferences.ui.h:11 msgid "Category list" msgstr "分類清單" #: ../data/preferences.ui.h:12 msgid "Add category" msgstr "加入分類" #: ../data/preferences.ui.h:13 msgid "Remove category" msgstr "移除分類" #: ../data/preferences.ui.h:14 msgid "Edit category" msgstr "編輯分類" #: ../data/preferences.ui.h:15 msgid "_Activities" msgstr "活動(_A)" #: ../data/preferences.ui.h:16 msgid "Activity list" msgstr "活動清單" #: ../data/preferences.ui.h:17 msgid "Add activity" msgstr "加入活動" #: ../data/preferences.ui.h:18 msgid "Remove activity" msgstr "移除活動" #: ../data/preferences.ui.h:19 msgid "Edit activity" msgstr "編輯活動" #: ../data/preferences.ui.h:20 msgid "Tags that should appear in autocomplete" msgstr "在自動補齊中要顯示的標籤:" #: ../data/preferences.ui.h:21 msgid "Categories and Tags" msgstr "分類和標籤" #: ../data/preferences.ui.h:22 msgid "Resume the last activity when returning to a workspace" msgstr "在返回工作區時繼續上次的活動" #: ../data/preferences.ui.h:23 msgid "Start new activity when switching workspaces:" msgstr "當切換工作區時開始新的活動:" #: ../data/preferences.ui.h:24 msgid "Workspaces" msgstr "工作區" #: ../data/range_pick.ui.h:1 msgid "Day:" msgstr "日:" #: ../data/range_pick.ui.h:2 msgid "Week:" msgstr "週:" #: ../data/range_pick.ui.h:3 msgid "Month:" msgstr "月:" #: ../data/range_pick.ui.h:4 msgid "Range:" msgstr "範圍:" #: ../data/range_pick.ui.h:6 msgid "Apply" msgstr "套用" #: ../data/today.ui.h:2 msgid "_Tracking" msgstr "追蹤(_T)" #: ../data/today.ui.h:3 msgid "Add earlier activity" msgstr "加入較早的活動" #: ../data/today.ui.h:4 msgid "Overview" msgstr "概覽" #: ../data/today.ui.h:5 msgid "Statistics" msgstr "統計" #: ../data/today.ui.h:6 msgid "_Edit" msgstr "編輯(_E)" #: ../data/today.ui.h:7 msgid "_Help" msgstr "求助(_H)" #: ../data/today.ui.h:8 msgid "Contents" msgstr "內容" #: ../data/today.ui.h:9 msgid "Sto_p tracking" msgstr "停止追蹤(_P)" #: ../data/today.ui.h:10 msgid "S_witch" msgstr "切換(_W)" #: ../data/today.ui.h:11 msgid "Start _Tracking" msgstr "開始追蹤(_T)" #: ../data/today.ui.h:12 msgid "Start new activity" msgstr "開始新的活動" #: ../data/today.ui.h:13 msgid "Today" msgstr "今天" #: ../data/today.ui.h:14 msgid "totals" msgstr "總計" #: ../data/today.ui.h:16 msgid "Show Overview" msgstr "顯示概覽" #: ../src/hamster-cli:254 ../src/hamster/today.py:289 msgid "No activity" msgstr "沒有活動" #: ../src/hamster-cli:277 ../src/hamster/preferences.py:155 #: ../src/hamster/reports.py:318 msgid "Category" msgstr "分類" #: ../src/hamster-cli:279 ../src/hamster/reports.py:323 msgid "Description" msgstr "描述" #: ../src/hamster-cli:280 ../src/hamster/reports.py:320 msgid "Start" msgstr "開始" #: ../src/hamster-cli:281 ../src/hamster/reports.py:321 msgid "End" msgstr "結束" #: ../src/hamster-cli:282 ../src/hamster/reports.py:322 msgid "Duration" msgstr "期間" #: ../src/hamster-cli:308 #, fuzzy msgid "Uncategorized" msgstr "分類" #: ../src/hamster/about.py:42 msgid "Project Hamster — track your time" msgstr "Hamster 專案 - 追蹤您的時間" #: ../src/hamster/about.py:43 msgid "Copyright © 2007–2010 Toms Bauģis and others" msgstr "版權所有 © 2007-2010 Toms Bauģis 和其他開發者" #: ../src/hamster/about.py:45 msgid "Project Hamster Website" msgstr "Hamster 專案網址" #: ../src/hamster/about.py:46 msgid "About Time Tracker" msgstr "關於時間追蹤程式" #: ../src/hamster/about.py:56 msgid "translator-credits" msgstr "" "如對翻譯有任何意見,請送一封電子郵件給\n" "以下地址,GNOME 翻譯團隊會盡快回覆您:\n" "zh-l10n@lists.linux.org.tw\n" "\n" "Chao-Hsiung Liao , 2008" #: ../src/hamster/db.py:288 ../src/hamster/db.py:298 ../src/hamster/db.py:354 #: ../src/hamster/db.py:658 ../src/hamster/db.py:845 #: ../src/hamster/edit_activity.py:59 ../src/hamster/preferences.py:58 #: ../src/hamster/reports.py:88 ../src/hamster/reports.py:127 #: ../src/hamster/reports.py:256 ../src/hamster/today.py:275 msgid "Unsorted" msgstr "未排序" #. defaults #: ../src/hamster/db.py:937 msgid "Work" msgstr "工作" #: ../src/hamster/db.py:938 msgid "Reading news" msgstr "閱讀新聞" #: ../src/hamster/db.py:939 msgid "Checking stocks" msgstr "查看股票" #: ../src/hamster/db.py:940 msgid "Super secret project X" msgstr "超級祕密專案 X" #: ../src/hamster/db.py:941 msgid "World domination" msgstr "支配世界" #: ../src/hamster/db.py:943 msgid "Day-to-day" msgstr "每日" #: ../src/hamster/db.py:944 msgid "Lunch" msgstr "午餐" #: ../src/hamster/db.py:945 msgid "Watering flowers" msgstr "澆花" #: ../src/hamster/db.py:946 msgid "Doing handstands" msgstr "倒立" #: ../src/hamster/edit_activity.py:75 msgid "Update activity" msgstr "更新活動" #. duration in round hours #: ../src/hamster/lib/stuff.py:57 #, python-format msgid "%dh" msgstr "%d時" #. duration less than hour #: ../src/hamster/lib/stuff.py:60 #, python-format msgid "%dmin" msgstr "%d分" #. x hours, y minutes #: ../src/hamster/lib/stuff.py:63 #, python-format msgid "%dh %dmin" msgstr "%d時 %d分" #. label of date range if looking on single day #. date format for overview label when only single day is visible #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:80 msgid "%B %d, %Y" msgstr "%Y %B %d" #. label of date range if start and end years don't match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:86 #, python-format msgid "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range if start and end month do not match #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:92 #, python-format msgid "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" #. label of date range for interval in same month #. letter after prefixes (start_, end_) is the one of #. standard python date formatting ones- you can use all of them #. see http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/lib/stuff.py:98 #, python-format msgid "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" #: ../src/hamster/overview_activities.py:88 msgctxt "overview list" msgid "%A, %b %d" msgstr "%b %d %A" #: ../src/hamster/overview_totals.py:161 #, python-format msgid "%s hours tracked total" msgstr "總計已追蹤 %s 小時" #. Translators: 'None' refers here to the Todo list choice in Hamster preferences (Tracking tab) #: ../src/hamster/preferences.py:113 msgid "None" msgstr "無" #: ../src/hamster/preferences.py:130 ../src/hamster/preferences.py:208 msgid "Name" msgstr "名稱" #: ../src/hamster/preferences.py:664 msgid "New category" msgstr "新增分類" #: ../src/hamster/preferences.py:677 msgid "New activity" msgstr "新增活動" #. notify interval slider value label #: ../src/hamster/preferences.py:738 #, python-format msgid "%(interval_minutes)d minute" msgid_plural "%(interval_minutes)d minutes" msgstr[0] "%(interval_minutes)d 分鐘" #. notify interval slider value label #: ../src/hamster/preferences.py:743 msgid "Never" msgstr "永不" #. column title in the TSV export format #: ../src/hamster/reports.py:148 msgid "activity" msgstr "活動" #. column title in the TSV export format #: ../src/hamster/reports.py:150 msgid "start time" msgstr "開始時刻" #. column title in the TSV export format #: ../src/hamster/reports.py:152 msgid "end time" msgstr "結束時刻" #. column title in the TSV export format #: ../src/hamster/reports.py:154 msgid "duration minutes" msgstr "持續分鐘" #. column title in the TSV export format #: ../src/hamster/reports.py:156 msgid "category" msgstr "分類" #. column title in the TSV export format #: ../src/hamster/reports.py:158 msgid "description" msgstr "描述" #. column title in the TSV export format #: ../src/hamster/reports.py:160 ../src/hamster/reports.py:312 msgid "tags" msgstr "標籤" #: ../src/hamster/reports.py:207 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s " "%(end_d)s, %(end_Y)s" msgstr "" "%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s 的活動" "日誌" #: ../src/hamster/reports.py:209 #, python-format msgid "" "Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s 的活動日誌" #: ../src/hamster/reports.py:211 #, python-format msgid "Activity report for %(start_B)s %(start_d)s, %(start_Y)s" msgstr "%(start_B)s %(start_d)s, %(start_Y)s 的活動日誌" #: ../src/hamster/reports.py:213 #, python-format msgid "Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s" msgstr "%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s 的活動日誌" #. date column format for each row in HTML report #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/reports.py:265 ../src/hamster/reports.py:297 msgctxt "html report" msgid "%b %d, %Y" msgstr "%b %d, %Y" #. grand_total = _("%s hours") % ("%.1f" % (total_duration.seconds / 60.0 / 60 + total_duration.days * 24)), #: ../src/hamster/reports.py:306 msgid "Totals by Day" msgstr "依日總計" #: ../src/hamster/reports.py:307 msgid "Activity Log" msgstr "活動日誌" #: ../src/hamster/reports.py:310 msgid "activities" msgstr "活動" #: ../src/hamster/reports.py:311 msgid "categories" msgstr "分類" #: ../src/hamster/reports.py:314 msgid "Distinguish:" msgstr "區別:" #: ../src/hamster/reports.py:316 msgid "Date" msgstr "日期" #: ../src/hamster/reports.py:326 msgid "Show template" msgstr "顯示模板" #: ../src/hamster/reports.py:327 #, python-format msgid "You can override it by storing your version in %(home_folder)s" msgstr "您可以藉由於 %(home_folder)s 儲存您自己的版本來凌駕它" #: ../src/hamster/stats.py:147 msgctxt "years" msgid "All" msgstr "全部" #: ../src/hamster/stats.py:177 msgid "" "There is no data to generate statistics yet.\n" "A week of usage would be nice!" msgstr "" "還沒有足夠的資料來產生統計表。\n" "建議最好有一個星期的使用資料!" #: ../src/hamster/stats.py:180 msgid "Collecting data — check back after a week has passed!" msgstr "還在收集資料中 — 請過一星期後再檢查!" #. date format for the first record if the year has not been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:331 msgctxt "first record" msgid "%b %d, %Y" msgstr "%Y %b %d" #. date of first record when year has been selected #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:336 msgctxt "first record" msgid "%b %d" msgstr "%b %d" #: ../src/hamster/stats.py:338 #, python-format msgid "First activity was recorded on %s." msgstr "第一個活動被記錄於 %s。" #: ../src/hamster/stats.py:347 ../src/hamster/stats.py:351 #, python-format msgid "%(num)s year" msgid_plural "%(num)s years" msgstr[0] "%(num)s 年" #. FIXME: difficult string to properly pluralize #: ../src/hamster/stats.py:356 #, python-format msgid "" "Time tracked so far is %(human_days)s human days (%(human_years)s) or " "%(working_days)s working days (%(working_years)s)." msgstr "" "到目前為止追蹤的時間有 %(human_days)s 天(%(human_years)s 年)或 " "%(working_days)s 工作天(%(working_years)s 年)。" #. How the date of the longest activity should be displayed in statistics #. Using python datetime formatting syntax. See: #. http://docs.python.org/library/time.html#time.strftime #: ../src/hamster/stats.py:374 msgctxt "date of the longest activity" msgid "%b %d, %Y" msgstr "%Y %b %d" #: ../src/hamster/stats.py:379 #, python-format msgid "Longest continuous work happened on %(date)s and was %(hours)s hour." msgid_plural "" "Longest continuous work happened on %(date)s and was %(hours)s hours." msgstr[0] "最長的連續工作發生於 %(date)s ,有 %(hours)s 小時。" #. total records (in selected scope) #: ../src/hamster/stats.py:387 #, python-format msgid "There is %s record." msgid_plural "There are %s records." msgstr[0] "總共有 %s 個紀錄。" #: ../src/hamster/stats.py:407 msgid "Hamster would like to observe you some more!" msgstr "Hamster 會更仔細的觀察您!" #: ../src/hamster/stats.py:409 #, python-format msgid "" "With %s percent of all activities starting before 9am, you seem to be an " "early bird." msgstr "在所有活動中有 %s % 在早上 9 點前開始,看起來您是早起的鳥兒。" #: ../src/hamster/stats.py:412 #, python-format msgid "" "With %s percent of all activities starting after 11pm, you seem to be a " "night owl." msgstr "在所有活動中有 %s % 在晚上 11 點後開始,看起來您是個夜貓子。" #: ../src/hamster/stats.py:415 #, python-format msgid "" "With %s percent of all activities being shorter than 15 minutes, you seem to " "be a busy bee." msgstr "在所有工作中有 %s % 短於 15 分鐘,看起來您是忙碌的蜜蜂。" #: ../src/hamster/today.py:243 msgid "No records today" msgstr "今天沒有紀錄" #: ../src/hamster/today.py:250 #, python-format msgid "%(category)s: %(duration)s" msgstr "%(category)s:%(duration)s" #. duration in main drop-down per category in hours #: ../src/hamster/today.py:253 #, python-format msgid "%sh" msgstr "%s時" #: ../src/hamster/today.py:280 msgid "Just started" msgstr "剛剛開始" #: ../src/hamster/widgets/reportchooserdialog.py:39 msgid "Save Report — Time Tracker" msgstr "儲存報告 - 時間追蹤程式" #: ../src/hamster/widgets/reportchooserdialog.py:57 msgid "HTML Report" msgstr "HTML 報告" #: ../src/hamster/widgets/reportchooserdialog.py:65 msgid "Tab-Separated Values (TSV)" msgstr "以 Tab 分隔的數值 (TSV)" #: ../src/hamster/widgets/reportchooserdialog.py:73 msgid "XML" msgstr "XML" #: ../src/hamster/widgets/reportchooserdialog.py:80 msgid "iCal" msgstr "iCal" #. title in the report file name #: ../src/hamster/widgets/reportchooserdialog.py:97 msgid "Time track" msgstr "時間追蹤" #~ msgid "Show activities window" #~ msgstr "顯示活動視窗" #~ msgid "Show _Overview" #~ msgstr "顯示概覽(_O)" #~ msgid "Sto_p Tracking" #~ msgstr "停止追蹤(_P)" #~ msgid "To_day" #~ msgstr "今日(_D)" #~ msgid "_Add earlier activity" #~ msgstr "加入較早的活動(_A)" #~ msgid "_About" #~ msgstr "關於(_A)" #~ msgid "_Preferences" #~ msgstr "偏好設定(_P)" #~ msgid "Starts and ends" #~ msgstr "開始與結束" #~ msgid "Year:" #~ msgstr "年:" #~ msgid "Preferences" #~ msgstr "偏好設定" #~ msgid "Changed activity" #~ msgstr "改變的活動" #~ msgid "Switched to '%s'" #~ msgstr "已切換為「%s」" #~ msgid "Working on %s" #~ msgstr "運作於 %s" #~ msgid "Hamster time tracker. Usage:" #~ msgstr "Hamster 時間追蹤程式。用法:" #~ msgid "Project Hamster (GNOME Time Tracker)" #~ msgstr "Project Hamster (Gnome 時間追蹤程式)" hamster-3.0.3/screenshot.png000066400000000000000000001454261452646177100160740ustar00rootroot00000000000000PNG  IHDR;sBITO IDATxw\IǟM$^TQ˩)vl]PO!b'JPT鐐 1$C ś'm&3ogfw|<$**qH!hF`"V/rjADCj?U/B@ DsA\(K mAder i!!2H*@T`R"B0 À$ @}Rj\gyR@4GN1$EW #˿VqW i%!35@ fu8UjԠ- ADjC|@4T#5V44T$8Fem!.5 EQHv Ѽ*K@?D"$IryeMoCZjP"EtW @ ~ dz30 #4M$8h4AH )  .Uj@@ tFebb\ewAKէh҂!.53O@ qjTt`2%2HF@U ĥI8QTXrJGqP @ Ds t:MYYYSKSCSCK[F^9HQ ʌ,8SR&xdL&RC R qcmUTt:It*&jM:4pA%񋊪S/+ @ &4F+xZXkh4Ni4Nh4 kQr p㥥/qKK{@40 SeUT<.,"&B]C0+nc!DE1ѓEq*>|E-q"0`*()@U;q&Y](m܌C$|&8aF#h4LWoCW2P(0G$.ʸfz4@ۗmݻԻq d :R7 f](m܌Y@8/q0h4 ˟E *i R4BB#*,O9r#I qrJa0 я`*+)+S.\MDF.h`$ٜo9<140if-ZqazFǧJK999v6EBnn^^~}VV6kU+g'׶17_5YABBHШH 獒 7=u A<.5Gn(nO .ndj53$zjì&#cB40lzWա][-:k+Kv`h` ZuutD eeeBOJNjѸzG45(Հ8F!z`TѱAA**[zD4Pe!屒ZWj"~܅ 1!*٩♆2YVfܱCceWM; R:519!Jbػ٪6]c" ~D(!HR@EEEUTTlHhČѸzG4v%+U'F-*^XGުx\C&gAbBW] Djq;rrtt$6`h|դi"RCbCLKRjMvƢRj~ +;^nwDE$2@LaeH)IU 3GSU>hFʩZqW1wDr $I}!fo4vQrs\g(8 =c\[P*TD.EU{i [eϠlA}_LLLzv7We%%EG[ zG;tXH<¢TQ{fVξ|_ѩ1 {& AfC=_0mЇײWwjkkկe=y˗_D~ڲaNׂ޽ãO=[JĸSi4#E_:lm&׾l;(.)?zTgOO'PWo:;:N41;tkӦXz#"-gɱF8\>|(*imS ŪqXj5[o׃C=x~M@Bb@j6Qc!_0{-Lм~uElr(ZB̹dWRRz}N;JC>?zȸy6l=Q}IJ:zLRrx7oү}?,;g}X|etlaTt֬ܰǚZZ/^uFF2bOJN1|etLc5q .J);y Y?5%UEC)TZp8/-^!*j;6oRWW/{ʢFΝMdeaz'ϞXshRw jkW@nB_PdTPFAAE?beih7{NBkn 3+@.]p+tlfر_0^r%()ii&F~#ڢ6;sBTLys:k /^'%'ħ_PZv׬:}BrJò ;ϹE*/BA _OΞhMptht, (*)ټ}غ{'++ u|N/*M&^(+KwUl(#UUvX'Z[nn"VFd2` .].ąSoXӝs;d־]۬|=G7&~pيII$n}7^Ϊ?2JKK_ ;e9NIIG>#^s톍iE~ٙ9rsB0g֌ ׷|(g6eNe\ؤi_3kkee&[ٱ| |-INNl.ԧgOxRC>->%$J~ڻϟI{BH{5;PQ.Z1:ls]vl751?rE+ȗao`x^'pHy<ElZ; dīP{ocbi֖1VTTXT\TnXK $U%A/T괩ǎ9 '~Nؿ{:[UHdss݋8JsfNh؉ [|e諗8._o߼qszQ_ 2v;7;;9 s/_1~#Xh! Xq?$x'뷃9:sΜ g|/>dDͤcxy<}bʀwدOoBF!1qq`miKb`dd߼K$hܲ6{HTx 4M 6K{k={*(056(716 ^ ^Lf'"ą%%LfiQ!CCΩU#>#Cz.'F䩦)l`-t+^m]$K=TU8j#QVQissu1b톍%$I@ ʸŠ 嬌L+ss8THi$J/$n3+32Ds!9XbKIgifѡ}[}#GG ^_[^ҕc?}jۦ͟WikS :C5 *V$I#=۶4 #ɍ\uHI=M $SR454dԉx*Zn%QRZ"k֮2djׁ}J훚FFj}B_Z|qc--̓S'+>?eKY[ oNWvbm-M9ڐ$UUEcr ZPRC6-LM?DE$y?cF;@VJJ̴xc#u[" bݪZZ螻r][7$/\]+e1@(9wjvmqp ֻ Դ]޻f &!B$5vm \ԛҩc âcbRӾ05s!xj,ի ۃaؕkk _ VVR{{ ?mD&yN-ݻ ݹ0n u/]]--\eaE4:wn٤5M=Q]!Wk2zb`صu3cQRr򟛷m \öQ[N!'I**Jv^!8vl([p騠`ޢ"VU&HUrMezҜ?cO:s"͢楪M@>jĈgy-c %ԱqKdaQKUuH#uǍ-}B!pf'gr^223p`̨$|"q5O ӧ~CogM͓Ghkrb 2$QavmutuSRaXYYcOa0~}ոWC|B4$S}M{έu;#Ύ--^6!޽odtQ=QUQڷs&~<}'֯͞acmNUB{5(H4~KSRSKJ,ڴ0NGKzD&kkk߸}ɓ(~[zՉg?kp\mm$`AKrs֭CTL;6PnjA*.3ILƉCjlYwDsD}}˵x<ٳ.QFdszH/?`T6PtHGR>%=sȚ B2hNtXTNMMtFCf IwDEFFr㧣HAy&N)PwN)H-7 ;g֎Z?KT4wQSH,w q |%BNh?"O_AS&Bq}J(۵q-;s =N^jNku;:֦K*JJ..NjFiɍ17_5EfHkIA⸐$f7c @iKm$NWaTTo=31IRekb4`4FtSh5Q1۸yGO}h4 hfqbU 0a 6j"92v!Dlf h?5f$.b]0h؅ L1wtTlBU4Kޣ WkePj"5BFlf ]fA7LCD@ rҸ,@T ,@ X!@ RԥgCƁ@ %Bjxeeez}S@ ͚j+**nP~44 @ DY@  R@  R@  R@  R P(\f˲e ~}#~ijҤٲm1ܩSYXZ99,XP ߶!)+k`b}A T3SRRXl5Qz?5(4O L% +] 0---}vm+++EZ;vc&Uaܹ,ZBB"ܹ!!!zN{TQ'?ffffffCyݲD CvΌk`hءc'QQSΝ?onaihh4f؜&-_difjC.koooooq?~/ 7mԥK/ѦM̙37l@ ~/_ۿrUsFc?|ٳv@QQ3gn׮_U.((8q5k}a ?%sWX}ӧKݩa߾7o9r'g.;߿wqܹI纺FRo~K.Ν׽{w&Wx񢚚a@@ iӦikk/\~РA{ҥKпfGv(1~6nm=<@CC?yvFFK۷˶Ygff6qʕ+.]Fө($8Ə.xGt31V0a?}-ܸCjQKKG*xѢ2tܾ};-5+p'Ut[+%K޽'$u#( SSS377|X\\\PPлwo55mhhHdvvs8C#ûw~mVJ_ŋ7oN0A6>>۷o?ի3++*mׯofF:fW_ llTI-,,iÐDSSZpw} qq>>\\2h={ tĄ*' Ja! ʘb,ݶ 铧^^;{%%%DFF>|TUUoxWZu:>~ 1̚9ԴEZXXXmbbb233323?l֢:*:][b02ddnN155URRoell$ ( #Mڝij~J纺6dPmSD-16ggg}}R_?z֮m[ B!_>- ^y7zP(xׯVjsd<]_vMGG)Sk׎Sʡ*8;DF~ͥ}VGekXX &V$x{?y^^[edd|[n.ׯ(?>:ug`?)""Ν;l V Gaa;Q;wr%___!a6ڵ;&6ʕD}t 乻ŋtÇl6kʔɝ:ujѢqmNNN}X;{ v*m1$8s9sGjՔ)BѶ!Ia؍Hۧƍ`ƍb f(?p[!!s6|xQQш5*edd2oܘ5{N~lܧO_MV$hhht!##'ڥÇ}_ue}^mhh8j|#S\\W(FܫWaSUUUc _z󕔔,-,vܹnU 8;gyn8::K=A]]Ӿ>B\t=*cOIsN J~/ |P @9aĢ;ԳDѦM?K4..nڴi-Z2eʞ={gEGG 2`޽[ndɓ0X%MQYHϗrSzz۷'L@g<}l)5JUV211rqqǯ]#tvvjvvvÇ/_] 3{Vu3QQQ׮ n'%%1L}(+W} ] k5///h:+Sd2 _d2t:lF](++kݺD@ RLyzzjkk?y$Ej9gNos~dǓO#ϫn:B$eXh~6~y***RLfR'N#Fh:?G(/ܼb8tVZm߾R,8z֡C{E0L0DS'Q;ݻ֫W/Stџ"?|8G]ߥ@  RUpP8Z0Ea E (t:)HB @ B4iQVVvСiӦCƍ}v{suuݼy$66vnnnsΥ @ v4yK,ua\.ׯ_^n݈#>ƍş^TT4eʔ:$''ߺu+!!!((ݜҐdff^xSA l477֭[L&Ν;!!!=^ّܹ~nnnƍ/srrO>}Z\p)K ˻rjcG@ ̓۷ Cw???555QߵkݻwsrrfϞM=x hhhL>cǎfy<^^58"Hh 4]aeeedd/wٹ^/\-[|IΟ?"0c  wM2͛!QAOIIWmڴʵk׮^;w\--Zm@ ~:H'|}}Lg϶m6ydww'O@||۷MMM]w%K¿[̙3/]t-==ϟ?(ÇzNIw `O8S;w^xw`SSSxCKKݻw8ةSO>ׯ_DcbběSIw~.]?~={+۵kWOhBxzz>t(//Off F>j tO}tXXRF4xKqqD;;:zQ#n߆}>}nݺ5|p;;;@g֭3FwǏKJJ+na۶m!!!)))nnnݻݻºv󋊊|}}9(,,|9I"":uhmm\.5{߿O޽lrcvbpPEU24~„pqU0LIII__?)))p_oyhj6ovմ4ptt߿1c-[l۶ӧO{M61dȐ+WTOOԩS6md2={\`hD Hsrs M--GGG UTT151)0 M033{ev E.tt(Uko޼yqunA lPRR0a„ UUUu˗/y.]:gΜ9s戗lȑ#5 4551 @?J޹t:Ԕ<|@ 444* }=qȅW>ŽyZGGg]t~î:@$4yNoݺD_?FEus344d2>=zee㸚ZǎӇ0y*LM]Ckpj%&jT^i[ؾcxԒ3b}.kTHm4;vW\/5 m߾h1G߹}&&&}}M4}fΚqz7;d wwݽӌWZW…;x ŪΞݶm@ Xl3l IDATrѣD%K._b/Y K]xum|||Dʕrsӫq!;vsAƍ%gXիOq&&&p>ׯo>0pzK׃Μ>ݧO8s;wFUfeݻ練7x{{;vo(9qysΘ1ڥK/??qbm55dĉkpu@@HH??w6??…f𨍠k+_Bᗤ$@d2 %%q&HuiWێ%ݽx6^  0 )iPFC׫W/k/_⒒ׯ(nnn8xw8rTnXl$J6SS۴iI}eX,+''G4+\A66':IS\Riݻvx񒝻vORo޼aDW^ko`أgpNFFƸ-,lZN:@T?1s_/\H"wO]=}G'={ʰ999Ə73[d@ 6^eA\zmΝޫ[i~G[;8Ι; >";888((h%::jgAɈkbB5II[ 5f,>vŋMNN*--^?%V;wјcsrr&wp~=FRϟ[hhju.@MAj!HMK0ؘb232MLLDfqqq8S҉&P!SQWppo߼<%($G{vc"00pС╷lү__ Z8:eʅ wcH$[ٹٳ׬Y}#(ܼW><W4ǏKMM5{)Sz;fcx{߽s{ڴ/ A())tŸ={ܦM%WC ;gΫ/Y w>%%Ο߻g'M0ReϞ;w9@__MM-9\m'$899YZX*)))"-[TTt̙۸iy<>T ݷFpk?uxD!;ϛ?Ŋ711>}m HNNٿoC#cfڵ}o8r͛!N.]:wﮣ㜹sÛ;oӧ>y~ʢ ';fhߵZAAA&N_rEQqҥt:OgΜ!q$9`iӦo^!+PeHnjy⥎Ύ˓:vVyx_ty}˖-=o劕jjl WX1fhر[۶GG?g-,cbc,L?_HBb@ j׮1u9119){:u.TF2nXqW^z&9rثs;;[Z-&۷M6:taeX[[Q}'##F ߽/q<==í8~!m- 7ϝ??a8 [:9:fee>r_uh ƩceݺvYf:Lζ4 `Æ; ZjժU+/OO=ydy<ŋu?oސ6--RA"QRRbn/^x޼f[)Sb7׮]]q[رGOOq&[ڧwoQ-cǎ9r$66[uڅZhݺ- ҴutEuHLHzJJީSwӳGQ~4Տ;^hV.T'Oe ؘ*VRl\l+V777+6s]e2$񇫫ktt'&N lCn""!!QMMА [n++K).*9cՕ2r䯻`Cvsrslm@4Kmۖgl6 -&&&yDgieuΝ]9U%J:Uo۶myS kIi I6(*.p8F`cc}̌w"[XX(Û7o<<< ##KK ׯofF:g$BN^|E-^@ӧ<\Kj<9Td|ر;l{Kt-+N q M wNETѩZUU7BC;;9;~]Bj.2.;yE,ISh4 Z]6 ,XxIjj?F-Ynfaem333lmlȈf'$&X,661ژ*))G6O:EDn oB i\UUmEX-Dgù0Y__ÇǏk6;;w>T mmm@7z̄ΝJ0L z~G BkII 헷n=zθqPЍX,+(,޽{'^ٳAOOD~(*.ѩR-NBB⪀K[pO'IRFGGhƒC6hckbmmEAiEa@~%rq׮]Ə'#0 Oi˗m.77ZTT*@61uʔի׼y&""b'lRgُ?|K-]J] d|aFF{'G>(^`ƌ޽{*l;w=xcǎ5ti&Nܰq>z寿VX9<:nhh)>֭[[V'u.kj~BFVHPq2X܂8:uuG*ں*BUl8@`E (4jJ1hO{ɽyn'D]믿֭5kV;99=zٲ=JLL\vrӆr?^rɓ 3w uO<|: %%U׏|>댍nق>qDʝ;BF</^+ de1 ln!d2yqqEEKD55߾?\UUfsI&O7q„ظ8A) H&0׾N +WNNNOcjj,c 6HPPR9sȈT*ݻ޽z*=矯\vBaQQggr_9s? ;AJWySwgSSN:E:oリXoo7o =kBHFF&<,,3Մ~cǎۜҤ״p8\\lO~ag>}ڴ>OvAAKmW"x5>1w]K%iiK<={Xmu-##35kٝn7^NT66k֬ *//d adhTYYF&G3̦&##ČN/\XYYYRZzRNWz>d818x_*(($߾M$W\ﯫ3s8.p\.fg{hmm>J Ý'͛7|>_PTTTf%Ź4uXΛ?uꔠMlp =fm=uyc[ZZv,8_^^N$i4tSSӡکV) B׮mۺE$`?{|X4H$JK  H x<|&|>xԿVSSSii#-#oYeZ|wkTVVoU !p&| H-ǢK-\ppqhii<,hlF 0'J $ HT,JD555/:܉ JpHz# m(*G]j  FJz# T`$jkc($zP3TAɂj|L/-mM_t+-P(WUW`46w/=]]0}gRHgee5QH47n#L.++fX&&&vvvRxVMMM.gDG+)+{̝&&&SLxG~mի/^@rr2e HҲӓ"/rժ$GG^g@ B)..z `? A0F4MMMwW9rDIQD"!444=<.GE>tdΛ?xIJrw.Zo9}zҤIݾyܔF+,(8x@^^,''ԩSϜ>}V(f[ፍ؎}3z :o޼/=rD"|D#Eӧeee')) k~\.ƍ4 Ժ26]^^b ?:)''b*R[[z( ,w)[NZZol`0zO~{z X_W5666666ʊXPmUpD"IKK#FYYYiii&6^¸\F vd2 X(gR?nx===wqx<ťӋL7 eʔ)<^wE>0??J]]]NN3WW!G6VSSSQQ!TS]#''W^^}Uܛv/]tΝuuuwRR\htzaAAaaᚵkcu5`uUkזɕII!H=8.p\.fg{hm{!p00 w #((P, gK&Dii"/@  <3),6 YPmJw D&u]Au F6H쬮>YJ.Ykg_0gRH4zÝ $ Ds,6 YPm@dAɂj$ HT,6 YPm@dA1\%^:+WڛFz+%7Ҟ7gz6<o߾ -|R4y{UTTë1#Ճ) a\1Wl6D@>v|?gIW;gryQQ.gmk֮ZaógaagD_nX'~J7l>?1Jec~:{D"aMJ#r4Xmm-,#-mggknn.~7op8YYGr`yfff'L&z͚oD{lެߣTCdH! ? k'SD"[RRb$D"ah)MEE%={6>ť|ѯmj133DuLM}}h;wr\蹳)S.N_0Ӭ7޾}+NL1S*!!͛;fsLx钞Whi11˙!ߟBEi?+.. Yp!6[ͷ޽͛+F_4ZڽTj|||CCmzݦU%5j֮D"jkLI[n8s׮us=UΝ)~~۶}_^~ӧYݝ;ws&OTVVxZMM @044\0P(.|6|ٲA~B%%E4ftϮcbg8 5f#F 7QBpɓ^|ƍl[`+]W9X6nmg2gϋ7mڈWll&OZPP7 tvv]fҤImz2uB477bV}ٱ}3mZZ!tڵznԩ>|u}ûhOfiiiee UYxΝSWS[zښ! gϞuvv"x<^~~qYb/6uttt,-w/J_\tgg޼i][oX,4cG6.^hc{XZZΘ1cժUfff6mc"WG͛*+V8rb0mmӦO_pAyًʊV6}FCCC]cHd Տw/^9r @HHѣ"nbwXd*w)%g„ ؂J| K yylXh2<虐䶶62w\===fan]kF}%B!THg Zۖ-10711,((oe6FF4mؿ`c*"25r_c޻ ejtqUp&e+..ihh.ER{9qdj=xﱺxo._OHX/w*lL533c㥋EFCCNSS!ޮ1C? G -'''b/yy? 'H&XTԼxBWG(Y챖AH/uuF .֖Km]Qb==] `3TEϟ Ztt|/?s洐1*bF̌drr--<`/E<<H\R*".Ce>>;))hnix>8UCN,N:MUzyzvqپ}dž ?|9x萁=ǣR}_w渹orrruuT;wcLL) f{cbV}NlHHH```iIa\\z/KK_8x{<Ex)) sɤիWay? IDATm̢cbo߾-''gdh( u{iolYPUU趋ݻ$ !+8b1SjcԨQKhT*5))Y2GPmP?lll驪}JPpdoo_KL *xώׯ}0pEE}}6=rdݺlr};::.\)@;aa_}ee5AVV"xڵ-[{̕\$`ikk{5zwϙ#''G![JJKTU>|p)~Zz}_38̌~=|EYl'66NNpqvubcbv1H`}ϮYL<\rnvV׊ֶM# ('QA_޼y6e2q/Qi---;[; sPGGGtLl^^H477`eu>"rŋB<&[ncbUT[_^^N$i4k-++cƍe0fΘnjj*N gK&Dii"/@  <jcA_Om2;;;߼yO466 ɓ'I">Ԑt \ͽt)JWWFR{@kiiUL CǏ HT,nD555/:1TD{h=G6HuyЋqUI"{T`$jkȝ庅P/qrA$ 0o߱CEe P(ҠW"b>vp(lmmΞe0Ý t",`(@F%y;3ёL&DGX,иqz6ZYYtt&323EhرN<>33s̙{v+`tooo5)⢠P^^~ʕ?y0R0]jgΞ%:b2͟٨qʕ#G()*rBUUᅦjpVR .?<1w<) O_~roܸAx|Oq8$Q[]]]pRRRG5nܸׯy<ލ7t>bp&|7op8yy,|0b}]<= ?.E%%:nbb755 qhkkSTR–eeeLfX#D)"0= ?.f[_u#) !㵵|`z|Ǎ]\x<^QN$M)W^~++ "8 F Do99WlILHX驨XVV JII+VutܻwP=~]lLrʀ3)#YYO=k'O?⒒## u_lS3Pm !!Fƣ箍,+&&v]]]Lqd^OJq^ceee{}yqqVV?`kk3c={$''lz웯͛7l6_YaeDFF2cGLnjWaD BB5J;;; җȨ[-+/xewH!C##qzE޻ɓ##l.\(b2(U_"A,fzڽǏVI$DGM|k %>`lņL!DPEE%={6>ť|nT]]wSR̙ckcsm%##cڴwUUU>>z4-[Lz?XZb_n5W/=i?FH_/]7\|y}}-mS=&&u6NKKWPT2X3fiz-E͛cǬmlp ɤjiIQggg˗XKEeLVWSX|pB}PQsgu S3/).VUUV:::߿?XՀA14ZڽTU|||CC-Bhyso#!6n:s4UYk{הNKOhBW8NP+))H&`7668:Μ4!.i+u҉z/`JAUWϞ|2A uuskjb\xoou6:yTB|\xxXBB7t-[zݖ[#"Χ޽u!6h"1cٳ!}u[6o~~ d3Q(/U%%fffϋ A7W8}4ЦM31c_}ֶkW  +q{qSpWBBmStt L~},).E͛*+V8rb0JJ,V{ KL?'HD0́b%`떖jjj))***4 !TXTh9{EYYYHBlں[؂‚c-oN"###6 ej>a»OPTlAEEe2ݻ,XSB >0FF^R 1Ĥ =+hkm[@˳݌If7JIIٵk'Brt}6uppNlA@J  wFx_]YOrrݯ-,*rvvXpys'Mx/kqg3x_#"#M7hkkw}Ȑ66FijjvV;D~Fi\M---]__M祤)U rrr566-\J_]a!`%N\.g ~頻eDx(ڹǙou=nU&fdn''cwRR)&pbyy}0vƣGE!)-7' [f2Yt3zsrrǏyFmWDGGS W8qb;]ƃ Nۻg7.d2ˊR!7ĤyqEea_wWwMs-(((**o3}kNN1zh ?Pm j)w~^~:u(H¨QaWhd ..\.wÆYYY>_a`oooO ֬^w'OX!J7eff11Zf9:UTT`m <>x Z=gΜ3gZ455͕ͱ"x5 Y/MDE{x7~\ϋmڦ}ߌ99 [nCy.Yӳkˤ+#CJ5UU%%%dh&ddd +++KJK/^jBo gLTI Aa?20(`nhW\9r䈒"DBihh{x\:|ɜ7>h]x~;sI})VXPpYNN!S9}666QQ̶g@TUU=<.{hhۅbhhhl<|н{}|zMF 6fnaiYYIJJ-,,>}5˽qF26]^^b lטMMM999|>?/7WVV!T[[z( <\oπY]]]pRRRD쥥%--f=yP_odd$b0L epB 7op8yyyl糘Lr^;;<쬭p dg@f{inn|ˋ6 ;6*8B"BmmmJJX4TSSp/vJaaa\.VCCd߶6EEElYAAA^q8Vp(++折6 ;8FqǍ..EEE<O^ded߼P(SL!+;(uuu"8mΈՋ 7nʋR!is`DILHX驨XVVЀNLLĮ,//*͹ӗ.]cκ;))nn4:pڵ?:XTWHJZb޽{R##s8^Ixr8\.prV=BAA^8C;(X7|ɓǘFFD M g5(M$D_@$x<s j++-[xVf`j7YЁDHDR;A@"AuT`$rvvVWW,BR,^ܵeg0,L F6=xdA(`n$ HT,6 YPm@dAɂj$ HT,6c0=z!E^ׇ^|K[GWpUuuuX;۷kC#c3s >?d) %)EJj`͛7Ts Z^~M"SÅijjjmmS6M"Srssm7ii42USs^̊ "Ҳ~]QZ/x왐WC!x3k;l(m5kD_E;ٳ'O  6nBBΛ6nxa?i'RlvZz۷oeeeB!{!A6nڤ/zx<~ͪJN7XшȘX1 jkkeiimmm;;[sss#ya|?OE1s g:r'=R9X#a"CB۷5?/.ƾ|Ϟ=}}l6 =͛:xŦ/-###BeeS6r81SBˈ> !2c߿?!(㑚1 p8*JD,V)G 0 VV66!&YX<"www[[1^zUYIu0rט)ʾ,+&&62"!q^zRE<H+82DY{=JHHqÇ6Nc۷ t]=}E)SU[[[K[6*r>sy!$2em*o]=}S}-L& !4w6bl޲D"$3G%&&ZتDntuuuuutf%ݸ[qb"|,*z⢮1yT@ǏVI$D+&6toȀ IDAT\tIO@CCs+uLitl.Vpf6n:s4UYk 2h'~ե YpLJ7j(l{%%%TS]3)/+N:9J[GwIXq0X)98?z!ؘ8sӬ[o#\ӧ!6h"1cٳ!}u[6o~>͞gRRRq/TVV.}_0!V^={e˺%eֈw(++|vns߾}{ʟAAA=Ӿ~sPP`;y~lcF]t X!䔚z!-= !.-- b敕>˖;;9Hv;v`Oݠyy'O}{Ͼ|D[[By`˗_޻wֈȯ11l6׮}_ =#hp@̭۶߾uKKKkhiRg=lms ж[,\~ʔ !V{{@JQ%>>^j"B(<<ޡyΝ^/**ZhQzZ {iivv$RT(ܹr 'NHdedʌF;w/0OLp|/^-ʀIYe%e?__.%?nttt ]pY,BH4AӧMCmڴqE} ׮]3iҤBbMy~36SXX4j^z^8;xl_i03fr\oe+/^]PjSNF}F3fN:})* !4Ņnذ1++G~+ šիݗɓ+D3%ggƀn''155uvvĔ9Lcbrt.@z:9%իWΝ khllooGIIIUd0NNNG^lG׮]1;sV>y$))w!D)<ZNIAA!;w\@ 8;9?;X)aq1sESSܼJp)??dH$>[n;s%_l޲[q1[m[rsu=x!qq6u"ێׯ]~9B999WWWs0el`CXX[p8Q2>mwTRVp8 @_?-=޾YnfFDp,G6GzJNSGD8:x&f@3 :;;"G[v_D8.p\.fg{hmm>J ͝@__U-YBZZzS49B#:&6//H$M:9dEnbS_ggcbUT[_^^N$i4+vg71eeel6{ܸ FMMMI 9g5(M$D_@$x<j`0LimkVnd0֭fjzkD_Omb| D4jèTQ 4… ---=2I ɓ'I">Ԑtud`rrs/]յT>4B@:*_@8 <?^GH!dAɂj$ HT,6 YPm@dAɂjcHq\]=Rz}hh(L((*a<o߾ -|Ww;()!o8ƔFUQ;n\pWmm RWW7l+N455wA9^)~KKttFiiϛٳgBbBc |+ЩvHZfM_Λ6nxa=v짳gO8A$6l܄ /~J}u'ʾ⧄*++>cV஝ﳲbcc_x͛UUU%|Mzx6$ jkmۊr}_cdhrerM:UMMMHP$4q6dgg錊JȁnsܟJ8D@6Czt}=ZVVnm=ɩk# =͛:xŦ/-###fJv'ʾ⧄ ӻy#INN!4ct{{;k۔1c+Tn|>>FF99$ !TV^˹\.HDUTT" 9Q>E}bbbb##"\]]B '%-^hD@82DY{=JHHqÇ6N'PYDl3--]WO_AQiTkA/^Kuml.:똘hmcF73"ϛcǬmlBUUU>>z4-[LVSʈ lȨKL& ,>@cfVV?[%H$ذv%=} e˗ׯ1cbbhcA17ltirXe_8u괆(m݉'=|!TÍ5 ^IID"T׈O_uM/ӧO;::Y[ߺm[pp[֯_bٳ?LJJ?.ʥKÙd7__pСÂsm6b֭SQVVZ:,o^gpP``PP/OBeϲNN7]f=`-7?|p~lcF]t XKgBy]Q\Rbfff_k06~77k𪪪={ 1 =4ZڽTY;[[1O<hfn`o :y˖gR /^41++kFJJQ\.70(hOd"BSUU%AIVFFFIKSBAӧMCmڴqE!p<H=}/oݺ /?uT.,Hqqr__˿{e3g@mۺuEׯLIbWIi) 0228q"Fcjkj復***"K?/=":##Clnzhc^/+r訪oYe%e?__.%?_,ȥ(S1ft lmmmX3fLXb|򄏙=^uvvk׮4iRTe!18`iiiiiigkK"WZfE9YR\ۯlhl:yzRUL&S$1>˖ai>R_-G%%Al6[Q[[+c0݁IdlիWT|>$3 K w`WO//<L&L-PTl!7/r%Vj kd CQAPAŅ ܊Dq[WYgZ[N\sᢢ@%$81@Dʏ_r=rM>}&M6URRJM-y a; $fֹsg==&jTڦOs?~F]ZpØoB^"3!NشOKKcfgg' V:::\,5PSk_E@3PNm)R}Ybe^^daDDDXXS:2t܇v-##ɓ۽GO8OO;Nc;lb,4KKeK[=]]UUՄĸ8SBiif2&Qhll|$ I(/ح[ױQQQN|fDn<=IP6YQ4ibYgaan`BSii^v-4nNNN|>ϲe}ySUMA=tIV'$$8vqС۷C;tN:ruh޽{ &N9hF8皵kv"U+?|HHa..κ:^^/_^a!D&q85klɓ1ݡ\.WF>pر7 0YJY*?(ѣtobeLLbبd^rRXTXXTQǕmmlΞ;'ٷA5̼vZrr]'].}CJۿSuuk#Ǐl޼go8??_ѣ=zqsZr$Gdan~'v6mVX9h;vqw?sLߔ sm푮&OjkkoB@ t"EQ.-\uşHÆ |!BΝD]oذazBdñ[ ڽQ̞Mq9БLIC0aZjER=FBPG[[2W4777##؈Ybeez1Pwxܫ777͛. W4MpvvBBפMVq%D"X$**D"Q(Qq9u]7I]FDB$%%]tӓ_7o9bPTץȻw6u2xda`ЖKKP233Ϟ WVVb.h!3yVZw޻pٳ:Y-[liӮ@I |'|Cڨ}H߫ts ˟3'-=}Ҥ;wXi#):q" Æ kժ͛(oPoݼQU|cзBv!m6]% _'ήZZZ4k֬vA|OT;jB+)|1H5ɩj `|t2Fu!PM% _;{{{u!PMHU֠8/;VV'4ndȑ[l133رH,655S^zU%,WDpp~^={]ET5k>}ګw/\(imE=}^zu]i=rP4]'@6   66kLCC;88u9P8' Bӧ3g͢iu]( ivk׮e믓eBHLLLLL $%9y-uR!ȇ` iFZZZ5lAEUV*Cڀn79bD-5Y5255155*vo؅Bv!m6]H. ` i؅Bv!m6(HԬAzzd@U5M]ۊWXYGQT9eF SSSn5uf 7 IDAT&7'DpC?~x Bڵ3~TYY&%D/vP^!W <$;;[]]]N^^ޙ3gBa K/>%1?0{֬iӦ2vիm޴Jg7v\…9?=~hFFy~>sBqd|&ůE"@ $& !FƵB/cb=zajjBQXXVK/(p8K}_o~^n[2⍌222w8rMLۗyطOԼ$$` \LIBa۶m******5/#$hK׸qLcXXdSMZÇ:c025k9aLqq7L.\lH[z۶r!zl…"ln;xSNu~^KfF57049kVnnӂHeWT!~5$$ٳ ,l￴o#qq&4M'$aN@QIIVUSe7#:S>zz;ݹsUj`>@?n`BO1㼼63>':v iY֭+3/_vY׏牃K3!dO߾}ƸK7" 8K'N`+j(gy^rѣ֭[/xE۞9}j!fμw"EYHԯܜǷoz-/o1*-)S&O2cwW^oGEtutJFLlU CØ%311QXjϜ),,"C'iiw<"xRRoVUUUE@QSSZWjΦ!D]]?eKiz߾}s͟8qBOJIK;wϿoרQ#7K/QSSŋ!;ڶٷoiaa}x<!ȑ? [DxB%Hl\H$266j߾E&MﹲKzz:uDL;ƏE^fO:.ݭ7544!u5&&TH5ʖc;۶mkkk[1}ɦ&bGIIڶ#޳GXܹcǏ{`9lnRw߽c.5Krsws箖VOS|}u#aÆ+ؔkִjժUV*Ǐg8pPޝ2g Pm%}}֮mڴ;DK/+mÆyyғsss5559}lG)lvNN7GaÆƿ~%LLͱʮ랽z/^dM@_"%)O>wyǘ1t3ҭurݟG=͛7Z5k4ladLQT\l,ZS):u٣G[Q?޽{AE<}V?7hl9vlP`LkP6UVL kNEE%:t#("4M֭[?CWbcZ$%%D"#ϣrsZ043355***5hоw^{ooc|>|C^FճWoɔOvUJВ&sРd5͆-Z2*)YAKK*QQQiִg=4-Y9;''??_:R"#/Cڦ_~mԨիh9^fΝ;EFFL2Y*>fH$b+W9NJbq]L-?/ŅYGU-~Ν mmeuf-CBB*jG,wJ_"",M2S\NqgUرۡys.\P(_g 27,FFEEE)))1&&ƍ%& UTTtuu !S7o"iڴRjjf`` oS|YLLݻZZZ˖4}f--y(J ammϵk_5Q!K1}镢(J,1bq5H4s籣GoKT&MΞ=wU酅?ܑ鰹uUܼqk'>|إk7 2߸jjK Kܽڣg8RQ;O<+g=z4X}-2+X[<|<ͳl--66nE [͛7W__ʔ4MbR&BUUUMHH315!p8ff1/cF`D*y^nݺSA؃nnby[XXXZfF]rr!-{?׮=ɉsǃl',[<,,,<ZZZc<>x ,,ۛ: ]ҵkג:u۷RI=Ǎ[vmظq%sxzzz xs_~ؕVxI&Lݻ_paIzzzw8N5[lzSllUΠA5~ğk֮ڥLrjr7/ZdV8E[G{X} Lr(jI&&&g"())m߾ׯ۷OnxJI!K?zmBZILLKNJXw *-Рs$_}DiӦ?z޽c=ǵhaإgHPsHuI]]?oc==7o~b'Oc=G89`j+BCC H!C|t颎tI/i"֯[|3gΎ}ʕ@E! ];1c/pKPЖ[ p|颾>9wHQLݷwgwmvﶷwqԨ9gWԎ@ t"EQ.-\u~2 ʩu۷CG-kYyjee!CM02Trٶma;wl tl7a_||)P(nذfF++KU5գG ظcǃ---u^z_y7nެva_S'_ǿh7 ·<Psg bH$D"HT$x9j\vvN]MRWo!u-,`CAAEQ,-,bc^V /<3`TSqqqSZZzzzk^q2K6l8Ct$MMMmevlWK0>ohhLد\ _Kfy<j*@|?*jG _Kzڇ\ jWi؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. `_hkRໄ ` i؅Bv!m6]H. ` i؅Bv!m6msYM)) SPPHSYYY+2l؏nńwv=32o2wq [2@zW5Ƴg3OJNߎDQQcϘ8חذ9α̹ o ;ǞVTY6 2+WgddD䓧=zgeg+~!mxQoUSC/ĮcBȋh̝gQ%K^BlmW ذ!SE^_-,XKQT{I4jԨ?O4 Gm,1p!ذ1㥋_pϞ`5ǯfnnݸhkʄ?x}qmBȲŋ&N9}$EM _D<͚B&_^TT$v>b`BS'O{hdXI"xN^BQp87Y))7{ϣyo&B:g7m[wW/dہI3-˫R#۶+))Uij7}%D9o~lܫү_=xhCذ;B/?d{q͚ceFqqoӣ8R\\Lyߍ[ !+׬۽!$A(绸=9{k2Mfس2˅BaÆL lY\\y8y̞{|*-MӃ]\5g֯__B32^'$:,w㚑A}~,##sUN΃~LfV~oPNc}$xB?bToemE~I662x2i#CCVc%&Sg>SyOfso+ڟB_ r?'Vhf4M[Jp2ܣkb;ǞAw0}cϙs˴VXh%encΆUJfwݿUڶn,W^z_M+icM;vMyջ;v]q!G-!\wBQ  PҼׯPpXGG;++[ӛHQdzc ^^o XAf[#CEp8O<ԫGw%%.1~b.3{ *S[7m_{+6mdԢMe۰9h Po`庵ޭʝ:B^DGS2A(cQ:Tc%/[8?JXn!]zT?|~޽v82&&_ޭ"fæŋh4h 7Y[[Bޠ}zBna6s!O^2MD/~sБ esFf&%)z;6lȬvvhff$||7K6oB.^RVVm-lm.ee吋olmlBڴ::=9oGf6m(*hڻc̳titŪgϣpɊU\.WT$b~3γ}f&&]GIJEK'Ϙ(:{B={&xynްNIYy칹3N131šmVl 4GEEE2-{y0o9foޔ:b/xePXPP`e‚/cb !:tc%Mu? $Yr_~ޜYr'!dI޿3k93~ac^=:u(gMq !hlޠI(c2M|Fʻw!.*++޿̒LdjIr,9wK4}W2ҒY%D.~xCӴM۶MB4iצ M12k6nqMc.xON靮_a͛l[^8m:GƍuZ,ټ^=9ںӃL6#+;/Sxn]Z`b_~~Pf&M; 4fSaan^ffQ/sV愐QQ/b^mvDqIjf̔咊gn~S{u~_Ϟ:eiߟ/] L8W~+++'ݨéz ܺ,**+;Cg5UkKptLrv̆/c(j߮dMx<HUK͒z?ۤflu)͞)YK]bzØbe <'L\n#E#uqS4oa?C>>77I&̯)0Q&IpdoEhjjBM_o}jɫ ^R)Wa$&;'7n|##=]FZZ#'$RQ/D쎭W ؈~xJ;95ܻw?#3?iijjhhL2雥}Q񉉎}97q2!!֬/)VֳQ[U IDATfRx+{!}z"p^)隥e6e֖%3gZRT'<{9~։#Glȗ|Ti̔8zKNNyAaFdh]ᛷ̙ս{r㛷Ie{1ulɟolռy3E*|%/邂HdLUEŋSOsss߽7l޼*w351f,-,=ŶزvTXXeNR(X$3D=?vC*%][LVגW_u2_"juϢ.]ֹSGB߂y׮0Rs&DΗРy3Bȣ)Bnܺ-bGUKͪ~Xp@V-Ԭg >V͝=X?X[=}Ǐg>U'8yZ[KBG>6kN|Bbd:n-"y 444.=%\KScᚍLuǔ >ʊ~iߩck2bؐ"o7iܮMke%]o;'uu=6յl^+{_s*B!EIz,o߹CJ'm;V4P=ʵk׮ !***wuPW_1n9|v/,,uikkkkTXXDi@C]]~oB.]XPȜ\֯{q, 9%bjbܿOBރ8Wt֮jNQ-[<{2S7ZREMTt?ᇴV?0;/࿀s'x7j(qԉ> a~:|hfBDΝZQ%|voOBȿ),kk/]}I> 6ܼ~i,Z⯢R/ׯO>ybOnmyAw@N rmldD4/騰$YXKVch7bPB/A[*򕚚ڶ͛|\_mڬٰjϙ#ëׯӌ G kVfoi[*QxsKtutrrsSS~1]DTs 4M-[칒wثS8"bqQH,D"H(rƄ_E"Qg۵UR޽u]7F$-XimծN] P?{EjKaaal+k+˯$lٳM%@ PR|>_ y<GRD G!2#Q>}aEGs!υD,}+++u[@,@q=noNJJmmھ’jn.pPg Bv!m6]՜%˛[@Ѳہg1u]7Z޿ m6]H. ` i؅Bv!m6]H. ` i؅Bv!m6]H. `$mp8Oj(No-?JREƈjZ˼꺄 Ix(7yȎWp宇 4?pq8"G<PgSBryP e#O} 2Y+!:.+$0J,Q饒 nV2Fke퐎23 ?i\ . 8!3C*pp1K$ eT3"6@Q+(37AǫeH_ċ/=R\.8\T1ES (BEQ4M4M .@JK8 \ܒQ)LFiK4ry"ɐ0I%?y%ix\/-8dm\.M4ͥi1?ɧPG9.hW! m|d҆tħ.GcIrp9<#YQ$4F F13J> 4AI8>urHO}eR(tϳӯAQ#Ґ3nZ2JrE$j "r hqQڵAˤ )NRiDNNIFE^ȫdFq1C($hp(KS L@vL!0r%YQUdNe龍OD$[:UC<Z*qHEvq/Y I',q+YidEQRb1J6Z:]S:O1 ot(o # Copyright (C) 2010-2012 Toms Bauģis # Copyright (C) 2012 Ted Smith # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . '''A script to control the applet from the command line.''' import sys, os import argparse import re import gi gi.require_version('Gdk', '3.0') # noqa: E402 gi.require_version('Gtk', '3.0') # noqa: E402 from gi.repository import GLib as glib from gi.repository import Gdk as gdk from gi.repository import Gtk as gtk from gi.repository import Gio as gio from gi.repository import GLib as glib import hamster from hamster import client, reports from hamster import logger as hamster_logger from hamster.about import About from hamster.edit_activity import CustomFactController from hamster.overview import Overview from hamster.preferences import PreferencesEditor from hamster.lib import default_logger, stuff from hamster.lib import datetime as dt from hamster.lib.fact import Fact logger = default_logger(__file__) def word_wrap(line, max_len): """primitive word wrapper""" lines = [] cur_line, cur_len = "", 0 for word in line.split(): if len("%s %s" % (cur_line, word)) < max_len: cur_line = ("%s %s" % (cur_line, word)).strip() else: if cur_line: lines.append(cur_line) cur_line = word if cur_line: lines.append(cur_line) return lines def fact_dict(fact_data, with_date): fact = {} if with_date: fmt = '%Y-%m-%d %H:%M' else: fmt = '%H:%M' fact['start'] = fact_data.start_time.strftime(fmt) if fact_data.end_time: fact['end'] = fact_data.end_time.strftime(fmt) else: end_date = dt.datetime.now() fact['end'] = '' fact['duration'] = fact_data.delta.format() fact['activity'] = fact_data.activity fact['category'] = fact_data.category if fact_data.tags: fact['tags'] = ' '.join('#%s' % tag for tag in fact_data.tags) else: fact['tags'] = '' fact['description'] = fact_data.description return fact class Hamster(gtk.Application): """Hamster gui. Actions should eventually be accessible via Gio.DBusActionGroup with the 'org.gnome.Hamster.GUI' id. but that is still experimental, the actions API is subject to change. Discussion with "external" developers welcome ! The separate dbus org.gnome.Hamster.WindowServer is still the stable recommended way to show windows for now. """ def __init__(self): # inactivity_timeout: How long (ms) the service should stay alive # after all windows have been closed. gtk.Application.__init__(self, application_id="org.gnome.Hamster.GUI", #inactivity_timeout=10000, register_session=True) self.about_controller = None # 'about' window controller self.fact_controller = None # fact window controller self.overview_controller = None # overview window controller self.preferences_controller = None # settings window controller self.connect("startup", self.on_startup) self.connect("activate", self.on_activate) # we need them before the startup phase # so register/activate_action work before the app is ran. # cf. https://gitlab.gnome.org/GNOME/glib/blob/master/gio/tests/gapplication-example-actions.c self.add_actions() def add_actions(self): # most actions have no parameters # for type "i", use Variant.new_int32() and .get_int32() to pack/unpack for name in ("about", "add", "clone", "edit", "overview", "preferences"): data_type = glib.VariantType("i") if name in ("edit", "clone") else None action = gio.SimpleAction.new(name, data_type) action.connect("activate", self.on_activate_window) self.add_action(action) action = gio.SimpleAction.new("quit", None) action.connect("activate", self.on_activate_quit) self.add_action(action) def on_activate(self, data=None): logger.debug("activate") if not self.get_windows(): self.activate_action("overview") def on_activate_window(self, action=None, data=None): self._open_window(action.get_name(), data) def on_activate_quit(self, data=None): self.on_activate_quit() def on_startup(self, data=None): logger.debug("startup") # Must be the same as application_id. Won't be required with gtk4. glib.set_prgname(self.get_application_id()) # localized name, but let's keep it simple. glib.set_application_name("Hamster") def _open_window(self, name, data=None): logger.debug("opening '{}'".format(name)) if name == "about": if not self.about_controller: # silence warning "GtkDialog mapped without a transient parent" # https://stackoverflow.com/a/38408127/3565696 _dummy = gtk.Window() self.about_controller = About(parent=_dummy) logger.debug("new About") controller = self.about_controller elif name in ("add", "clone", "edit"): if self.fact_controller: # Something is already going on, with other arguments, present it. # Or should we just discard the forgotten one ? logger.warning("Fact controller already active. Please close first.") else: fact_id = data.get_int32() if data else None self.fact_controller = CustomFactController(name, fact_id=fact_id) logger.debug("new CustomFactController") controller = self.fact_controller elif name == "overview": if not self.overview_controller: self.overview_controller = Overview() logger.debug("new Overview") controller = self.overview_controller elif name == "preferences": if not self.preferences_controller: self.preferences_controller = PreferencesEditor() logger.debug("new PreferencesEditor") controller = self.preferences_controller window = controller.window if window not in self.get_windows(): self.add_window(window) logger.debug("window added") # Essential for positioning on wayland. # This should also select the correct window type if unset yet. # https://specifications.freedesktop.org/wm-spec/wm-spec-1.3.html if name != "overview" and self.overview_controller: window.set_transient_for(self.overview_controller.window) # so the dialog appears on top of the transient-for: window.set_type_hint(gdk.WindowTypeHint.DIALOG) else: # toplevel window.set_transient_for(None) controller.present() logger.debug("window presented") def present_fact_controller(self, action, fact_id=0): """Present the fact controller window to add, clone or edit a fact. Args: action (str): "add", "clone" or "edit" """ assert action in ("add", "clone", "edit") if action in ("clone", "edit"): action_data = glib.Variant.new_int32(int(fact_id)) else: action_data = None # always open dialogs through actions, # both for consistency, and to reduce the paths to test. app.activate_action(action, action_data) class HamsterCli(object): """Command line interface.""" def __init__(self): self.storage = client.Storage() def assist(self, *args): assist_command = args[0] if args else "" if assist_command == "start": hamster_client._activities(sys.argv[-1]) elif assist_command == "export": formats = "html tsv xml ical".split() chosen = sys.argv[-1] formats = [f for f in formats if not chosen or f.startswith(chosen)] print("\n".join(formats)) def toggle(self): self.storage.toggle() def start(self, *args): '''Start a new activity.''' if not args: print("Error: please specify activity") return 0 fact = Fact.parse(" ".join(args), range_pos="tail") if fact.start_time is None: fact.start_time = dt.datetime.now() self.storage.check_fact(fact, default_day=dt.hday.today()) id_ = self.storage.add_fact(fact) return id_ def stop(self, *args): '''Stop tracking the current activity.''' self.storage.stop_tracking() def export(self, *args): args = args or [] export_format, start_time, end_time = "html", None, None if args: export_format = args[0] (start_time, end_time), __ = dt.Range.parse(" ".join(args[1:])) start_time = start_time or dt.datetime.combine(dt.date.today(), dt.time()) end_time = end_time or start_time.replace(hour=23, minute=59, second=59) facts = self.storage.get_facts(start_time, end_time) writer = reports.simple(facts, start_time.date(), end_time.date(), export_format) def _activities(self, search=""): '''Print the names of all the activities.''' if "@" in search: activity, category = search.split("@") for cat in self.storage.get_categories(): if not category or cat['name'].lower().startswith(category.lower()): print("{}@{}".format(activity, cat['name'])) else: for activity in self.storage.get_activities(search): print(activity['name']) if activity['category']: print("{}@{}".format(activity['name'], activity['category'])) def activities(self, *args): '''Print the names of all the activities.''' search = args[0] if args else "" for activity in self.storage.get_activities(search): print("{}@{}".format(activity['name'], activity['category'])) def categories(self, *args): '''Print the names of all the categories.''' for category in self.storage.get_categories(): print(category['name']) def list(self, *times): """list facts within a date range""" (start_time, end_time), __ = dt.Range.parse(" ".join(times or [])) start_time = start_time or dt.datetime.combine(dt.date.today(), dt.time()) end_time = end_time or start_time.replace(hour=23, minute=59, second=59) self._list(start_time, end_time) def current(self, *args): """prints current activity. kinda minimal right now""" facts = self.storage.get_todays_facts() if facts and not facts[-1].end_time: print("{} {}".format(str(facts[-1]).strip(), facts[-1].delta.format(fmt="HH:MM"))) else: print((_("No activity"))) def search(self, *args): """search for activities by name and optionally within a date range""" args = args or [] search = "" if args: search = args[0] (start_time, end_time), __ = dt.Range.parse(" ".join(args[1:])) start_time = start_time or dt.datetime.combine(dt.date.today(), dt.time()) end_time = end_time or start_time.replace(hour=23, minute=59, second=59) self._list(start_time, end_time, search) def _list(self, start_time, end_time, search=""): """Print a listing of activities""" facts = self.storage.get_facts(start_time, end_time, search) headers = {'activity': _("Activity"), 'category': _("Category"), 'tags': _("Tags"), 'description': _("Description"), 'start': _("Start"), 'end': _("End"), 'duration': _("Duration")} # print date if it is not the same day print_with_date = start_time.date() != end_time.date() cols = 'start', 'end', 'duration', 'activity', 'category' widths = dict([(col, len(headers[col])) for col in cols]) for fact in facts: fact = fact_dict(fact, print_with_date) for col in cols: widths[col] = max(widths[col], len(fact[col])) cols = ["{{{col}: <{len}}}".format(col=col, len=widths[col]) for col in cols] fact_line = " | ".join(cols) row_width = sum(val + 3 for val in list(widths.values())) print() print(fact_line.format(**headers)) print("-" * min(row_width, 80)) by_cat = {} for fact in facts: cat = fact.category or _("Unsorted") by_cat.setdefault(cat, dt.timedelta(0)) by_cat[cat] += fact.delta pretty_fact = fact_dict(fact, print_with_date) print(fact_line.format(**pretty_fact)) if pretty_fact['description']: for line in word_wrap(pretty_fact['description'], 76): print(" {}".format(line)) if pretty_fact['tags']: for line in word_wrap(pretty_fact['tags'], 76): print(" {}".format(line)) print("-" * min(row_width, 80)) cats = [] total_duration = dt.timedelta() for cat, duration in sorted(by_cat.items(), key=lambda x: x[1], reverse=True): cats.append("{}: {}".format(cat, duration.format())) total_duration += duration for line in word_wrap(", ".join(cats), 80): print(line) print("Total: ", total_duration.format()) print() def version(self): print(hamster.__version__) if __name__ == '__main__': from hamster.lib import i18n i18n.setup_i18n() usage = _( """ Actions: * add [activity [start-time [end-time]]]: Add an activity * stop: Stop tracking current activity. * list [start-date [end-date]]: List activities * search [terms] [start-date [end-date]]: List activities matching a search term * export [html|tsv|ical|xml] [start-date [end-date]]: Export activities with the specified format * current: Print current activity * activities: List all the activities names, one per line. * categories: List all the categories names, one per line. * overview / preferences / add / about: launch specific window * version: Show the Hamster version Time formats: * 'YYYY-MM-DD hh:mm': If start-date is missing, it will default to today. If end-date is missing, it will default to start-date. * '-minutes': Relative time in minutes from the current date and time. Note: * For list/search/export a "hamster day" starts at the time set in the preferences (default 05:00) and ends one minute earlier the next day. Activities are reported for each "hamster day" in the interval. Example usage: hamster start bananas -20 start activity 'bananas' with start time 20 minutes ago hamster search pancakes 2012-08-01 2012-08-30 look for an activity matching terms 'pancakes` between 1st and 30st August 2012. Will check against activity, category, description and tags """) hamster_client = HamsterCli() app = Hamster() logger.debug("app instanciated") import signal signal.signal(signal.SIGINT, signal.SIG_DFL) # gtk3 screws up ctrl+c parser = argparse.ArgumentParser( description="Time tracking utility", epilog=usage, formatter_class=argparse.RawDescriptionHelpFormatter) # cf. https://stackoverflow.com/a/28611921/3565696 parser.add_argument("--log", dest="log_level", choices=('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'), default='WARNING', help="Set the logging level (default: %(default)s)") parser.add_argument("action", nargs="?", default="overview") parser.add_argument('action_args', nargs=argparse.REMAINDER, default=[]) args, unknown_args = parser.parse_known_args() # logger for current script logger.setLevel(args.log_level) # hamster_logger for the rest hamster_logger.setLevel(args.log_level) if not hamster.installed: logger.info("Running in devel mode") if args.action in ("start", "track"): action = "add" # alias elif args.action == "prefs": # for backward compatibility action = "preferences" else: action = args.action if action in ("about", "add", "edit", "overview", "preferences"): if action == "add" and args.action_args: assert not unknown_args, "unknown options: {}".format(unknown_args) # directly add fact from arguments id_ = hamster_client.start(*args.action_args) assert id_ > 0, "failed to add fact" sys.exit(0) else: app.register() if action == "edit": assert len(args.action_args) == 1, ( "edit requires exactly one argument, got {}" .format(args.action_args)) id_ = int(args.action_args[0]) assert id_ > 0, "received non-positive id : {}".format(id_) action_data = glib.Variant.new_int32(id_) else: action_data = None app.activate_action(action, action_data) run_args = [sys.argv[0]] + unknown_args logger.debug("run {}".format(run_args)) status = app.run(run_args) logger.debug("app exited") sys.exit(status) elif hasattr(hamster_client, action): getattr(hamster_client, action)(*args.action_args) else: sys.exit(usage % {'prog': sys.argv[0]}) hamster-3.0.3/src/hamster-service.py000077500000000000000000000374051452646177100174530ustar00rootroot00000000000000#!/usr/bin/env python3 # nicked off gwibber import dbus import dbus.service from gi.repository import GLib as glib from gi.repository import Gio as gio import hamster from hamster import logger as hamster_logger from hamster.lib import i18n i18n.setup_i18n() # noqa: E402 from hamster.storage import db from hamster.lib import datetime as dt from hamster.lib import default_logger from hamster.lib.dbus import ( DBusMainLoop, fact_signature, from_dbus_date, from_dbus_fact, from_dbus_fact_json, from_dbus_range, to_dbus_fact, to_dbus_fact_json ) from hamster.lib.fact import Fact, FactError logger = default_logger(__file__) DBusMainLoop(set_as_default=True) loop = glib.MainLoop() if "org.gnome.Hamster" in dbus.SessionBus().list_names(): print("Found hamster-service already running, exiting") quit() class Storage(db.Storage, dbus.service.Object): __dbus_object_path__ = "/org/gnome/Hamster" def __init__(self, loop): self.bus = dbus.SessionBus() bus_name = dbus.service.BusName("org.gnome.Hamster", bus=self.bus) dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) db.Storage.__init__(self, unsorted_localized="") self.mainloop = loop self.__file = gio.File.new_for_path(__file__) self.__monitor = self.__file.monitor_file(gio.FileMonitorFlags.WATCH_MOUNTS | \ gio.FileMonitorFlags.SEND_MOVED, None) self.__monitor.connect("changed", self._on_us_change) def run_fixtures(self): """we start with an empty database and then populate with default values. This way defaults can be localized!""" super(Storage, self).run_fixtures() # defaults defaults = [ (_("Work"), [_("Reading news"), _("Checking stocks"), _("Super secret project X"), _("World domination")]), (_("Day-to-day"), [_("Lunch"), _("Watering flowers"), _("Doing handstands")]) ] if not self.get_categories(): for category, activities in defaults: cat_id = self.add_category(category) for activity in activities: self.add_activity(activity, cat_id) # stop service when we have been updated (will be brought back in next call) # anyway. should make updating simpler def _on_us_change(self, monitor, gio_file, event_uri, event): if event == gio.FileMonitorEvent.CHANGES_DONE_HINT: print("`{}` has changed. Quitting!".format(__file__)) self.Quit() @dbus.service.signal("org.gnome.Hamster") def TagsChanged(self): pass def tags_changed(self): self.TagsChanged() @dbus.service.signal("org.gnome.Hamster") def FactsChanged(self): pass def facts_changed(self): self.FactsChanged() @dbus.service.signal("org.gnome.Hamster") def ActivitiesChanged(self): pass def activities_changed(self): self.ActivitiesChanged() @dbus.service.signal("org.gnome.Hamster") def ToggleCalled(self): pass def toggle_called(self): self.toggle_called() def dispatch_overwrite(self): self.TagsChanged() self.FactsChanged() self.ActivitiesChanged() @dbus.service.method("org.gnome.Hamster") def Quit(self): """ Shutdown the service example: import dbus obj = dbus.SessionBus().get_object("org.gnome.Hamster", "/org/gnome/Hamster") service = dbus.Interface(obj, "org.gnome.Hamster") service.Quit() """ #log.logger.info("Hamster Service is being shutdown") self.mainloop.quit() @dbus.service.method("org.gnome.Hamster") def Toggle(self): """Toggle visibility of the main application window. If several instances are available, it will toggle them all. """ #log.logger.info("Hamster Service is being shutdown") self.ToggleCalled() # facts @dbus.service.method("org.gnome.Hamster", in_signature='siib', out_signature='i') def AddFact(self, fact_str, start_time, end_time, temporary): """Add fact specified by a string. If the parsed fact has no start, then now is used. To fully use the hamster fact parser, as on the cmdline, just pass 0 for start_time and end_time. Args: fact_str (str): string to be parsed. start_time (int): Start datetime ovveride timestamp (ignored if 0). -1 means None. end_time (int): datetime ovveride timestamp (ignored if 0). -1 means None. #temporary (boolean): historical mystery, ignored, but needed to keep the method signature stable. Do not forget to pass something (e.g. False)! Returns: fact id (int), 0 means failure. Note: see datetime.utcfromtimestamp documentation for the precise meaning of timestamps. """ fact = Fact.parse(fact_str) # default value if none found if not fact.start_time: fact.start_time = dt.datetime.now() if start_time == -1: fact.start_time = None elif start_time != 0: fact.start_time = dt.datetime.utcfromtimestamp(start_time) if end_time == -1: fact.end_time = None elif end_time != 0: fact.end_time = dt.datetime.utcfromtimestamp(end_time) return self.add_fact(fact) @dbus.service.method("org.gnome.Hamster", in_signature='s', out_signature='i') def AddFactJSON(self, dbus_fact): """Add fact given in JSON format. This is the preferred method if the fact fields are known separately, as activity, category, description and tags are passed "verbatim". Only datetimes are interpreted (2020-01-20: JSON does not know datetimes). Args: dbus_fact (str): fact in JSON format (cf. from_dbus_fact_json). Returns: fact id (int), 0 means failure. """ fact = from_dbus_fact_json(dbus_fact) return self.add_fact(fact) @dbus.service.method("org.gnome.Hamster", in_signature="si", out_signature='bs') def CheckFact(self, dbus_fact, dbus_default_day): """Check fact validity. Useful to determine in advance whether the fact can be included in the database. Args: dbus_fact (str): fact in JSON format (cf. AddFactJSON) Returns: success (boolean): True upon success. message (str): what's wrong. """ fact = from_dbus_fact_json(dbus_fact) dd = from_dbus_date(dbus_default_day) try: self.check_fact(fact, default_day=dd) success = True message = "" except FactError as error: success = False message = str(error) return success, message @dbus.service.method("org.gnome.Hamster", in_signature='i', out_signature=fact_signature) def GetFact(self, fact_id): """Get fact by id. For output format see GetFacts""" fact = self.get_fact(fact_id) return to_dbus_fact(fact) @dbus.service.method("org.gnome.Hamster", in_signature='i', out_signature="s") def GetFactJSON(self, fact_id): """Get fact by id. Return fact in JSON format (cf. to_dbus_fact_json) """ fact = self.get_fact(fact_id) return to_dbus_fact_json(fact) @dbus.service.method("org.gnome.Hamster", in_signature='isiib', out_signature='i') def UpdateFact(self, fact_id, fact, start_time, end_time, temporary): start_time = start_time or None if start_time: start_time = dt.datetime.utcfromtimestamp(start_time) end_time = end_time or None if end_time: end_time = dt.datetime.utcfromtimestamp(end_time) return self.update_fact(fact_id, fact, start_time, end_time, temporary) @dbus.service.method("org.gnome.Hamster", in_signature='is', out_signature='i') def UpdateFactJSON(self, fact_id, dbus_fact): """Update fact. Args: fact_id (int): fact id in the database. dbus_fact (str): new fact content, in JSON format. Returns: int: new id (0 means failure) """ fact = from_dbus_fact_json(dbus_fact) return self.update_fact(fact_id, fact) @dbus.service.method("org.gnome.Hamster", in_signature='i') def StopTracking(self, end_time): """Stops tracking the current activity""" end_time = end_time or None if end_time: end_time = dt.datetime.utcfromtimestamp(end_time) return self.stop_tracking(end_time) @dbus.service.method("org.gnome.Hamster") def StopOrRestartTracking(self): """Stops or restarts tracking the last activity""" return self.stop_or_restart_tracking() @dbus.service.method("org.gnome.Hamster", in_signature='i') def RemoveFact(self, fact_id): """Remove fact from storage by it's ID""" return self.remove_fact(fact_id) @dbus.service.method("org.gnome.Hamster", in_signature='uus', out_signature='a{}'.format(fact_signature)) def GetFacts(self, start_date, end_date, search_terms): """Gets facts between the day of start_date and the day of end_date. Parameters: i start_date: Seconds since epoch (timestamp). Use 0 for today i end_date: Seconds since epoch (timestamp). Use 0 for today s search_terms: Bleh. If starts with "not ", the search terms will be reversed Returns an array of D-Bus fact structures. Legacy. To be superceded by GetFactsJSON at some point. """ #TODO: Assert start > end ? start = dt.date.today() if start_date: start = dt.datetime.utcfromtimestamp(start_date).date() end = None if end_date: end = dt.datetime.utcfromtimestamp(end_date).date() return [to_dbus_fact(fact) for fact in self.get_facts(start, end, search_terms)] @dbus.service.method("org.gnome.Hamster", in_signature='ss', out_signature='as') def GetFactsJSON(self, dbus_range, search_terms): """Gets facts between the day of start and the day of end. Args: dbus_range (str): same format as on the command line. (cf. dt.Range.parse) search_terms (str): If starts with "not ", the search terms will be reversed Return: array of D-Bus facts in JSON format. (cf. to_dbus_fact_json) This will be the preferred way to get facts. """ range = from_dbus_range(dbus_range) return [to_dbus_fact_json(fact) for fact in self.get_facts(range, search_terms=search_terms)] @dbus.service.method("org.gnome.Hamster", out_signature='a{}'.format(fact_signature)) def GetTodaysFacts(self): """Gets facts of today, respecting hamster midnight. See GetFacts for return info. Legacy, to be superceded by GetTodaysFactsJSON at some point. """ return [to_dbus_fact(fact) for fact in self.get_todays_facts()] @dbus.service.method("org.gnome.Hamster", out_signature='as') def GetTodaysFactsJSON(self): """Gets facts of the current hamster day. Return an array of facts in JSON format. """ return [to_dbus_fact_json(fact) for fact in self.get_todays_facts()] # categories @dbus.service.method("org.gnome.Hamster", in_signature='s', out_signature = 'i') def AddCategory(self, name): return self.add_category(name) @dbus.service.method("org.gnome.Hamster", in_signature='s', out_signature='i') def GetCategoryId(self, category): return self.get_category_id(category) @dbus.service.method("org.gnome.Hamster", in_signature='is') def UpdateCategory(self, id, name): self.update_category(id, name) @dbus.service.method("org.gnome.Hamster", in_signature='i') def RemoveCategory(self, id): self.remove_category(id) @dbus.service.method("org.gnome.Hamster", out_signature='a(is)') def GetCategories(self): return [(category['id'], category['name']) for category in self.get_categories()] # activities @dbus.service.method("org.gnome.Hamster", in_signature='si', out_signature = 'i') def AddActivity(self, name, category_id): return self.add_activity(name, category_id) @dbus.service.method("org.gnome.Hamster", in_signature='isi') def UpdateActivity(self, id, name, category_id): self.update_activity(id, name, category_id) @dbus.service.method("org.gnome.Hamster", in_signature='i') def RemoveActivity(self, id): return self.remove_activity(id) @dbus.service.method("org.gnome.Hamster", in_signature='i', out_signature='a(isis)') def GetCategoryActivities(self, category_id): return [(row['id'], row['name'], row['category_id'], row['category'] or '') for row in self.get_category_activities(category_id = category_id)] @dbus.service.method("org.gnome.Hamster", in_signature='s', out_signature='a(ss)') def GetActivities(self, search = ""): return [(row['name'], row['category'] or '') for row in self.get_activities(search)] @dbus.service.method("org.gnome.Hamster", in_signature='ii', out_signature = 'b') def ChangeCategory(self, id, category_id): return self.change_category(id, category_id) @dbus.service.method("org.gnome.Hamster", in_signature='sib', out_signature='a{sv}') def GetActivityByName(self, activity, category_id, resurrect = True): category_id = category_id or None if activity: return dict(self.get_activity_by_name(activity, category_id, resurrect) or {}) else: return {} # tags @dbus.service.method("org.gnome.Hamster", in_signature='b', out_signature='a(isb)') def GetTags(self, only_autocomplete): return [(tag['id'], tag['name'], tag['autocomplete']) for tag in self.get_tags(only_autocomplete)] @dbus.service.method("org.gnome.Hamster", in_signature='as', out_signature='a(isb)') def GetTagIds(self, tags): return [(tag['id'], tag['name'], tag['autocomplete']) for tag in self.get_tag_ids(tags)] @dbus.service.method("org.gnome.Hamster", in_signature='s') def SetTagsAutocomplete(self, tags): self.update_autocomplete_tags(tags) @dbus.service.method("org.gnome.Hamster", out_signature='s') def Version(self): return hamster.__version__ if __name__ == '__main__': import argparse parser = argparse.ArgumentParser(description="Hamster time tracker D-Bus service") # cf. https://stackoverflow.com/a/28611921/3565696 parser.add_argument("--log", dest="log_level", choices=('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'), default='WARNING', help="Set the logging level (default: %(default)s)") args = parser.parse_args() # logger for current script logger.setLevel(args.log_level) # hamster_logger for the rest hamster_logger.setLevel(args.log_level) print("hamster-service up") storage = Storage(loop) loop.run() hamster-3.0.3/src/hamster-windows-service.py000077500000000000000000000053311452646177100211340ustar00rootroot00000000000000#!/usr/bin/env python3 # nicked off hamster-service import dbus import dbus.service import os.path import subprocess from dbus.mainloop.glib import DBusGMainLoop from gi.repository import GLib as glib import hamster DBusGMainLoop(set_as_default=True) loop = glib.MainLoop() if "org.gnome.Hamster.WindowServer" in dbus.SessionBus().list_names(): print("Found hamster-window-service already running, exiting") quit() # Legacy server. Still used by the shell-extension. # New code _could_ access the org.gnome.Hamster.GUI actions directly, # although the exact action names/data are subject to change. # http://lazka.github.io/pgi-docs/Gio-2.0/classes/Application.html#Gio.Application # > The actions are also exported on the session bus, # and GIO provides the Gio.DBusActionGroup wrapper # to conveniently access them remotely. class WindowServer(dbus.service.Object): __dbus_object_path__ = "/org/gnome/Hamster/WindowServer" def __init__(self, loop): self.app = True self.mainloop = loop self.bus = dbus.SessionBus() bus_name = dbus.service.BusName("org.gnome.Hamster.WindowServer", bus=self.bus) dbus.service.Object.__init__(self, bus_name, self.__dbus_object_path__) @dbus.service.method("org.gnome.Hamster") def Quit(self): """Shutdown the service""" self.mainloop.quit() def _open_window(self, name): if hamster.installed: base_cmd = "hamster" else: # both scripts are at the same place in the source tree cwd = os.path.dirname(__file__) base_cmd = "python3 {}/hamster-cli.py".format(cwd) cmd = "{} {} &".format(base_cmd, name) subprocess.run(cmd, shell=True) @dbus.service.method("org.gnome.Hamster.WindowServer") def edit(self, id: int = 0): """Edit fact, given its id (int) in the database. For backward compatibility, if id is 0, create a brand new fact. """ if id: # {:d} restrict the string format. Too many safeguards cannot hurt. self._open_window("edit {:d}".format(id)) else: self._open_window("add") @dbus.service.method("org.gnome.Hamster.WindowServer") def overview(self): self._open_window("overview") @dbus.service.method("org.gnome.Hamster.WindowServer") def about(self): self._open_window("about") @dbus.service.method("org.gnome.Hamster.WindowServer") def preferences(self): self._open_window("prefs") if __name__ == '__main__': from hamster.lib import i18n i18n.setup_i18n() glib.set_prgname(str(_("hamster-windows-service"))) window_server = WindowServer(loop) print("hamster-window-service up") loop.run() hamster-3.0.3/src/hamster.bash000066400000000000000000000012561452646177100162720ustar00rootroot00000000000000# bash completion for hamster _hamster_helper() { local IFS=$'\n' COMPREPLY+=( $( hamster "$@" 2>/dev/null ) ) } _hamster() { local cur prev opts base COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" # # The basic options we'll complete. # opts="activities categories current export list search start stop " # # Complete the arguments to some of the basic commands. # case "${prev}" in start|export) _hamster_helper "assist" "$prev" "$cur" return 0 ;; esac COMPREPLY=($(compgen -W "${opts}" -- ${cur})) return 0 } complete -F _hamster hamster hamster-3.0.3/src/hamster/000077500000000000000000000000001452646177100154275ustar00rootroot00000000000000hamster-3.0.3/src/hamster/.gitignore000066400000000000000000000000201452646177100174070ustar00rootroot00000000000000*.pyc defs.py hamster-3.0.3/src/hamster/VERSION000066400000000000000000000000051452646177100164720ustar00rootroot000000000000003.0.3hamster-3.0.3/src/hamster/__init__.py000066400000000000000000000007161452646177100175440ustar00rootroot00000000000000import gi gi.require_version('Gtk', '3.0') # noqa: E402 gi.require_version('PangoCairo', '1.0') # noqa: E402 # for some reason performance is improved by importing Gtk early from gi.repository import Gtk as gtk from hamster.lib import default_logger from hamster.version import get_version logger = default_logger(__name__) (__version__, installed) = get_version() # cleanup namespace del get_version del default_logger del gtk # performance is retained hamster-3.0.3/src/hamster/about.py000066400000000000000000000042501452646177100171140ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2007, 2008 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from os.path import join from hamster.lib.configuration import runtime from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk class About(object): def __init__(self, parent=None): about = gtk.AboutDialog(parent=parent) self.window = about infos = { "program-name" : "Hamster", "version" : runtime.version, "comments" : _("Project Hamster — track your time"), "copyright" : _("Copyright © 2007–2010 Toms Bauģis and others"), "website" : "https://github.com/projecthamster/hamster/wiki/", "website-label" : _("Project Hamster Website"), "title": _("About Time Tracker"), "wrap-license": True } about.set_authors(["Toms Bauģis ", "Patryk Zawadzki ", "Pēteris Caune ", "Juanje Ojeda "]) about.set_artists(["Kalle Persson "]) about.set_translator_credits(_("translator-credits")) for prop, val in infos.items(): about.set_property(prop, val) about.set_logo_icon_name("org.gnome.Hamster.GUI") about.connect("response", lambda self, *args: self.destroy()) about.show_all() def present(self): self.window.present() hamster-3.0.3/src/hamster/client.py000066400000000000000000000264761452646177100172760ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2007 Patryk Zawadzki # Copyright (C) 2007-2009 Toms Baugis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import dbus import logging logger = logging.getLogger(__name__) # noqa: E402 import sys from calendar import timegm from distutils.version import LooseVersion from gi.repository import GObject as gobject from textwrap import dedent import hamster from hamster.lib.dbus import ( DBusMainLoop, from_dbus_fact_json, to_dbus_date, to_dbus_fact, to_dbus_fact_json, to_dbus_range, ) from hamster.lib.fact import Fact, FactError from hamster.lib import datetime as dt # bug fixed in dbus-python 1.2.14 (released on 2019-11-25) assert not ( sys.version_info >= (3, 8) and LooseVersion(dbus.__version__) < LooseVersion("1.2.14") ), """python3.8 changed str(). That broke hamster (https://github.com/projecthamster/hamster/issues/477). Please upgrade to dbus-python >= 1.2.14. """ class Storage(gobject.GObject): """Hamster client class, communicating to hamster storage daemon via d-bus. Subscribe to the `tags-changed`, `facts-changed` and `activities-changed` signals to be notified when an appropriate factoid of interest has been changed. In storage a distinguishment is made between the classificator of activities and the event in tracking log. When talking about the event we use term 'fact'. For the classificator we use term 'activity'. The relationship is - one activity can be used in several facts. The rest is hopefully obvious. But if not, please file bug reports! """ __gsignals__ = { "tags-changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, ()), "facts-changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, ()), "activities-changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, ()), "toggle-called": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self): gobject.GObject.__init__(self) DBusMainLoop(set_as_default=True) self.bus = dbus.SessionBus() self._connection = None # will be initiated on demand self.bus.add_signal_receiver(self._on_tags_changed, 'TagsChanged', 'org.gnome.Hamster') self.bus.add_signal_receiver(self._on_facts_changed, 'FactsChanged', 'org.gnome.Hamster') self.bus.add_signal_receiver(self._on_activities_changed, 'ActivitiesChanged', 'org.gnome.Hamster') self.bus.add_signal_receiver(self._on_toggle_called, 'ToggleCalled', 'org.gnome.Hamster') self.bus.add_signal_receiver(self._on_dbus_connection_change, 'NameOwnerChanged', 'org.freedesktop.DBus', arg0='org.gnome.Hamster') @staticmethod def _to_dict(columns, result_list): return [dict(zip(columns, row)) for row in result_list] @property def conn(self): if not self._connection: self._connection = dbus.Interface(self.bus.get_object('org.gnome.Hamster', '/org/gnome/Hamster'), dbus_interface='org.gnome.Hamster') server_version = self._connection.Version() client_version = hamster.__version__ if server_version != client_version: logger.warning(dedent( """\ Server and client version mismatch: server: {} client: {} This is sometimes used during bisections, but generally calls for trouble. Remember to kill hamster daemons after any version change (this is safe): pkill -f hamster-service pkill -f hamster-windows-service see also: https://github.com/projecthamster/hamster#kill-hamster-daemons """.format(server_version, client_version) ) ) return self._connection def _on_dbus_connection_change(self, name, old, new): self._connection = None def _on_tags_changed(self): self.emit("tags-changed") def _on_facts_changed(self): self.emit("facts-changed") def _on_activities_changed(self): self.emit("activities-changed") def _on_toggle_called(self): self.emit("toggle-called") def toggle(self): """toggle visibility of the main application window if any""" self.conn.Toggle() def get_todays_facts(self): """returns facts of the current date, respecting hamster midnight hamster midnight is stored in gconf, and presented in minutes """ return [from_dbus_fact_json(fact) for fact in self.conn.GetTodaysFactsJSON()] def get_facts(self, start, end=None, search_terms=""): """Returns facts for the time span matching the optional filter criteria. In search terms comma (",") translates to boolean OR and space (" ") to boolean AND. Filter is applied to tags, categories, activity names and description """ range = dt.Range.from_start_end(start, end) dbus_range = to_dbus_range(range) return [from_dbus_fact_json(fact) for fact in self.conn.GetFactsJSON(dbus_range, search_terms)] def get_activities(self, search = ""): """returns list of activities name matching search criteria. results are sorted by most recent usage. search is case insensitive """ return self._to_dict(('name', 'category'), self.conn.GetActivities(search)) def get_categories(self): """returns list of categories""" return self._to_dict(('id', 'name'), self.conn.GetCategories()) def get_tags(self, only_autocomplete = False): """returns list of all tags. by default only those that have been set for autocomplete""" return self._to_dict(('id', 'name', 'autocomplete'), self.conn.GetTags(only_autocomplete)) def get_tag_ids(self, tags): """find tag IDs by name. tags should be a list of labels if a requested tag had been removed from the autocomplete list, it will be ressurrected. if tag with such label does not exist, it will be created. on database changes the `tags-changed` signal is emitted. """ return self._to_dict(('id', 'name', 'autocomplete'), self.conn.GetTagIds(tags)) def update_autocomplete_tags(self, tags): """update list of tags that should autocomplete. this list replaces anything that is currently set""" self.conn.SetTagsAutocomplete(tags) def get_fact(self, id): """returns fact by it's ID""" return from_dbus_fact_json(self.conn.GetFactJSON(id)) def check_fact(self, fact, default_day=None): """Check Fact validity for inclusion in the storage. default_day (date): Default hamster day, used to simplify some hint messages (remove unnecessary dates). None is safe (always show dates). """ if not fact.start_time: # Do not even try to pass fact through D-Bus as # conversions would fail in this case. raise FactError("Missing start time") dbus_fact = to_dbus_fact_json(fact) dbus_day = to_dbus_date(default_day) success, message = self.conn.CheckFact(dbus_fact, dbus_day) if not success: raise FactError(message) return success, message def add_fact(self, fact, temporary_activity = False): """Add fact (Fact).""" assert fact.activity, "missing activity" if not fact.start_time: logger.info("Adding fact without any start_time is deprecated") fact.start_time = dt.datetime.now() dbus_fact = to_dbus_fact_json(fact) new_id = self.conn.AddFactJSON(dbus_fact) return new_id def stop_tracking(self, end_time = None): """Stop tracking current activity. end_time can be passed in if the activity should have other end time than the current moment""" end_time = timegm((end_time or dt.datetime.now()).timetuple()) return self.conn.StopTracking(end_time) def stop_or_restart_tracking(self): """Stop or restart tracking last activity.""" return self.conn.StopOrRestartTracking(0) def remove_fact(self, fact_id): "delete fact from database" self.conn.RemoveFact(fact_id) def update_fact(self, fact_id, fact, temporary_activity = False): """Update fact values. See add_fact for rules. Update is performed via remove/insert, so the fact_id after update should not be used anymore. Instead use the ID from the fact dict that is returned by this function""" dbus_fact = to_dbus_fact_json(fact) new_id = self.conn.UpdateFactJSON(fact_id, dbus_fact) return new_id def get_category_activities(self, category_id = None): """Return activities for category. If category is not specified, will return activities that have no category""" category_id = category_id or -1 return self._to_dict(('id', 'name', 'category_id', 'category'), self.conn.GetCategoryActivities(category_id)) def get_category_id(self, category_name): """returns category id by name""" return self.conn.GetCategoryId(category_name) def get_activity_by_name(self, activity, category_id = None, resurrect = True): """returns activity dict by name and optionally filtering by category. if activity is found but is marked as deleted, it will be resurrected unless told otherwise in the resurrect param """ category_id = category_id or 0 return self.conn.GetActivityByName(activity, category_id, resurrect) # category and activity manipulations (normally just via preferences) def remove_activity(self, id): self.conn.RemoveActivity(id) def remove_category(self, id): self.conn.RemoveCategory(id) def change_category(self, id, category_id): return self.conn.ChangeCategory(id, category_id) def update_activity(self, id, name, category_id): return self.conn.UpdateActivity(id, name, category_id) def add_activity(self, name, category_id = -1): return self.conn.AddActivity(name, category_id) def update_category(self, id, name): return self.conn.UpdateCategory(id, name) def add_category(self, name): return self.conn.AddCategory(name) hamster-3.0.3/src/hamster/defs.py.in000066400000000000000000000001621452646177100173260ustar00rootroot00000000000000DATA_DIR = "@DATADIR@" LIB_DIR = "@LIBDIR@" VERSION = "@VERSION@" PACKAGE = "@PACKAGE@" PYTHONDIR = "@PYTHONDIR@" hamster-3.0.3/src/hamster/edit_activity.py000066400000000000000000000363331452646177100206520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2007-2009, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import GObject as gobject from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk import time """ TODO: hook into notifications and refresh our days if some evil neighbour edit fact window has dared to edit facts """ from hamster import widgets from hamster.lib import datetime as dt from hamster.lib.configuration import Controller, runtime, load_ui_file from hamster.lib.fact import Fact, FactError from hamster.lib.stuff import escape_pango class CustomFactController(Controller): """Controller for a Fact edition window. Args: action (str): "add", "clone", "edit" fact_id (int): used for "clone" and "edit" """ def __init__(self, action, fact_id=None): Controller.__init__(self) self._date = None # for the date property self._gui = load_ui_file("edit_activity.ui") self.window = self.get_widget('custom_fact_window') self.window.set_size_request(600, 200) self.action = action self.fact_id = fact_id self.category_entry = widgets.CategoryEntry(widget=self.get_widget('category')) self.activity_entry = widgets.ActivityEntry(widget=self.get_widget('activity'), category_widget=self.category_entry) self.cmdline = widgets.CmdLineEntry(parent=self.get_widget("cmdline box")) self.cmdline.connect("focus_in_event", self.on_cmdline_focus_in_event) self.cmdline.connect("focus_out_event", self.on_cmdline_focus_out_event) self.dayline = widgets.DayLine() self._gui.get_object("day_preview").add(self.dayline) self.description_box = self.get_widget('description') self.description_buffer = self.description_box.get_buffer() self.end_date = widgets.Calendar(widget=self.get_widget("end date"), expander=self.get_widget("end date expander")) self.end_time = widgets.TimeInput(parent=self.get_widget("end time box")) self.start_date = widgets.Calendar(widget=self.get_widget("start date"), expander=self.get_widget("start date expander")) self.start_time = widgets.TimeInput(parent=self.get_widget("start time box")) self.tags_entry = widgets.TagsEntry(parent=self.get_widget("tags box")) self.save_button = self.get_widget("save_button") # this will set self.master_is_cmdline self.cmdline.grab_focus() title = _("Update activity") if action == "edit" else _("Add activity") self.window.set_title(title) self.get_widget("delete_button").set_sensitive(action == "edit") if action == "edit": self.fact = runtime.storage.get_fact(fact_id) elif action == "clone": base_fact = runtime.storage.get_fact(fact_id) self.fact = base_fact.copy(start_time=dt.datetime.now(), end_time=None) else: self.fact = Fact(start_time=dt.datetime.now()) original_fact = self.fact # TODO: should use hday, not date. self.date = self.fact.date self.update_fields() self.update_cmdline(select=True) self.cmdline.original_fact = original_fact # This signal should be emitted only after a manual modification, # not at init time when cmdline might not always be fully parsable. self.cmdline.connect("changed", self.on_cmdline_changed) self.description_buffer.connect("changed", self.on_description_changed) self.start_time.connect("changed", self.on_start_time_changed) self.start_date.connect("day-selected", self.on_start_date_changed) self.start_date.expander.connect("activate", self.on_start_date_expander_activated) self.end_time.connect("changed", self.on_end_time_changed) self.end_date.connect("day-selected", self.on_end_date_changed) self.end_date.expander.connect("activate", self.on_end_date_expander_activated) self.activity_entry.connect("changed", self.on_activity_changed) self.category_entry.connect("changed", self.on_category_changed) self.tags_entry.connect("changed", self.on_tags_changed) self._gui.connect_signals(self) self.validate_fields() self.window.show_all() @property def date(self): """Default hamster day.""" return self._date @date.setter def date(self, value): self._date = value self.cmdline.default_day = value def on_prev_day_clicked(self, button): self.increment_date(-1) def on_next_day_clicked(self, button): self.increment_date(+1) def draw_preview(self, start_time, end_time=None): day_facts = runtime.storage.get_facts(self.date) self.dayline.plot(self.date, day_facts, start_time, end_time) def get_widget(self, name): """ skip one variable (huh) """ return self._gui.get_object(name) def increment_date(self, days): delta = dt.timedelta(days=days) self.date += delta self.fact.date = self.date self.update_fields() def show(self): self.window.show() def figure_description(self): buf = self.description_buffer description = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) return description.strip() def on_activity_changed(self, widget): if not self.master_is_cmdline: self.fact.activity = self.activity_entry.get_text() self.validate_fields() self.update_cmdline() def on_category_changed(self, widget): if not self.master_is_cmdline: self.fact.category = self.category_entry.get_text() self.validate_fields() self.update_cmdline() def on_cmdline_changed(self, widget): if self.master_is_cmdline: fact = Fact.parse(self.cmdline.get_text(), default_day=self.date) previous_cmdline_fact = self.cmdline_fact # copy the entered fact before any modification self.cmdline_fact = fact.copy() if fact.start_time is None: fact.start_time = dt.datetime.now() if fact.description == previous_cmdline_fact.description: # no change to description here, keep the main one fact.description = self.fact.description self.fact = fact self.update_fields() def on_cmdline_focus_in_event(self, widget, event): self.master_is_cmdline = True def on_cmdline_focus_out_event(self, widget, event): self.master_is_cmdline = False def on_description_changed(self, text): if not self.master_is_cmdline: self.fact.description = self.figure_description() self.validate_fields() self.update_cmdline() def on_end_date_changed(self, widget): if not self.master_is_cmdline: if self.fact.end_time: time = self.fact.end_time.time() self.fact.end_time = dt.datetime.combine(self.end_date.date, time) self.validate_fields() self.update_cmdline() elif self.end_date.date: # No end time means on-going, hence date would be meaningless. # And a default end date may be provided when end time is set, # so there should never be a date without time. self.end_date.date = None def on_end_date_expander_activated(self, widget): # state has not changed yet, toggle also start_date calendar visibility previous_state = self.end_date.expander.get_expanded() self.start_date.expander.set_expanded(not previous_state) def on_end_time_changed(self, widget): if not self.master_is_cmdline: # self.end_time.start_time() was given a datetime, # so self.end_time.time is a datetime too. end = self.end_time.time self.fact.end_time = end self.end_date.date = end.date() if end else None self.validate_fields() self.update_cmdline() def on_start_date_changed(self, widget): if not self.master_is_cmdline: if self.fact.start_time: previous_date = self.fact.start_time.date() new_date = self.start_date.date delta = new_date - previous_date self.fact.start_time += delta if self.fact.end_time: # preserve fact duration self.fact.end_time += delta self.end_date.date = self.fact.end_time self.date = self.fact.date or dt.hday.today() self.validate_fields() self.update_cmdline() def on_start_date_expander_activated(self, widget): # state has not changed yet, toggle also end_date calendar visibility previous_state = self.start_date.expander.get_expanded() self.end_date.expander.set_expanded(not previous_state) def on_start_time_changed(self, widget): if not self.master_is_cmdline: # note: resist the temptation to preserve duration here; # for instance, end time might be at the beginning of next fact. new_time = self.start_time.time if new_time: if self.fact.start_time: new_start_time = dt.datetime.combine(self.fact.start_time.date(), new_time) else: # date not specified; result must fall in current hamster_day new_start_time = dt.datetime.from_day_time(dt.hday.today(), new_time) else: new_start_time = None self.fact.start_time = new_start_time # let start_date extract date or handle None self.start_date.date = new_start_time self.validate_fields() self.update_cmdline() def on_tags_changed(self, widget): if not self.master_is_cmdline: self.fact.tags = self.tags_entry.get_tags() self.update_cmdline() def present(self): self.window.present() def update_cmdline(self, select=None): """Update the cmdline entry content.""" self.cmdline_fact = self.fact.copy(description=None) label = self.cmdline_fact.serialized(default_day=self.date) with self.cmdline.handler_block(self.cmdline.checker): self.cmdline.set_text(label) if select: # select the range string exactly (without separator) __, rest = dt.Range.parse(label, position="head", separator="") self.cmdline.select_region(0, len(label) - len(rest)) def update_fields(self): """Update gui fields content.""" self.start_time.time = self.fact.start_time self.end_time.time = self.fact.end_time self.end_time.set_start_time(self.fact.start_time) self.start_date.date = self.fact.start_time self.end_date.date = self.fact.end_time self.activity_entry.set_text(self.fact.activity) self.category_entry.set_text(self.fact.category) self.description_buffer.set_text(self.fact.description) self.tags_entry.set_tags(self.fact.tags) self.validate_fields() def update_status(self, status, markup): """Set save button sensitivity and tooltip.""" self.save_button.set_tooltip_markup(markup) if status == "looks good": self.save_button.set_label("gtk-save") self.save_button.set_sensitive(True) elif status == "warning": self.save_button.set_label("gtk-dialog-warning") self.save_button.set_sensitive(True) elif status == "wrong": self.save_button.set_label("gtk-save") self.save_button.set_sensitive(False) else: raise ValueError("unknown status: '{}'".format(status)) def validate_fields(self): """Check fields information. Update gui status about entry and description validity. Try to merge date, activity and description informations. Return the consolidated fact if successful, or None. """ fact = self.fact now = dt.datetime.now() self.get_widget("button-next-day").set_sensitive(self.date < now.date()) if self.date == now.date(): default_dt = now else: default_dt = dt.datetime.combine(self.date, now.time()) self.draw_preview(fact.start_time or default_dt, fact.end_time or default_dt) try: runtime.storage.check_fact(fact, default_day=self.date) except FactError as error: self.update_status(status="wrong", markup=str(error)) return None roundtrip_fact = Fact.parse(fact.serialized(), default_day=self.date) if roundtrip_fact != fact: self.update_status(status="wrong", markup="Fact could not be parsed back") return None # nothing unusual self.update_status(status="looks good", markup="") return fact def on_delete_clicked(self, button): runtime.storage.remove_fact(self.fact_id) self.close_window() def on_cancel_clicked(self, button): self.close_window() def on_close(self, widget, event): self.close_window() def on_save_button_clicked(self, button): if self.action == "edit": runtime.storage.update_fact(self.fact_id, self.fact) else: runtime.storage.add_fact(self.fact) self.close_window() def on_window_key_pressed(self, tree, event_key): popups = (self.cmdline.popup.get_property("visible") or self.start_time.popup.get_property("visible") or self.end_time.popup.get_property("visible") or self.tags_entry.popup.get_property("visible")) if (event_key.keyval == gdk.KEY_Escape or \ (event_key.keyval == gdk.KEY_w and event_key.state & gdk.ModifierType.CONTROL_MASK)): if popups: return False self.close_window() elif event_key.keyval in (gdk.KEY_Return, gdk.KEY_KP_Enter): if popups: return False if self.description_box.has_focus(): return False if self.validate_fields(): self.on_save_button_clicked(None) hamster-3.0.3/src/hamster/lib/000077500000000000000000000000001452646177100161755ustar00rootroot00000000000000hamster-3.0.3/src/hamster/lib/__init__.py000066400000000000000000000021731452646177100203110ustar00rootroot00000000000000import logging logger = logging.getLogger(__name__) # noqa: E402 from hamster.lib.fact import Fact # for backward compatibility with v2 def default_logger(name): """Return a toplevel logger. This should be used only in the toplevel file. Files deeper in the hierarchy should use ``logger = logging.getLogger(__name__)``, in order to considered as children of the toplevel logger. Beware that without a setLevel() somewhere, the default value (warning) will be used, so no debug message will be shown. Args: name (str): usually `__name__` in the package toplevel __init__.py, or `__file__` in a script file (because __name__ would be "__main__" in this case). """ # https://docs.python.org/3/howto/logging.html#logging-advanced-tutorial logger = logging.getLogger(name) # this is a basic handler, with output to stderr logger_handler = logging.StreamHandler() formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') logger_handler.setFormatter(formatter) logger.addHandler(logger_handler) return logger hamster-3.0.3/src/hamster/lib/charting.py000066400000000000000000000300471452646177100203520ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2010 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import GObject as gobject from gi.repository import Gtk as gtk from gi.repository import Pango as pango import time from hamster.lib import graphics, stuff from hamster.lib import datetime as dt import locale class Bar(graphics.Sprite): def __init__(self, key, value, normalized, label_color): graphics.Sprite.__init__(self, cache_as_bitmap=True) self.key, self.value, self.normalized = key, value, normalized self.height = 0 self.width = 20 self.interactive = True self.fill = None self.label = graphics.Label(value, size=8, color=label_color) self.label_background = graphics.Rectangle(self.label.width + 4, self.label.height + 4, 4, visible=False) self.add_child(self.label_background) self.add_child(self.label) self.connect("on-render", self.on_render) def on_render(self, sprite): # invisible rectangle for the mouse, covering whole area self.graphics.rectangle(0, 0, self.width, self.height) self.graphics.fill("#000", 0) size = round(self.width * self.normalized) self.graphics.rectangle(0, 0, size, self.height, 3) self.graphics.rectangle(0, 0, min(size, 3), self.height) self.graphics.fill(self.fill) self.label.y = (self.height - self.label.height) / 2 horiz_offset = min(10, self.label.y * 2) if self.label.width < size - horiz_offset * 2: #if it fits in the bar self.label.x = size - self.label.width - horiz_offset else: self.label.x = size + 3 self.label_background.x = self.label.x - 2 self.label_background.y = self.label.y - 2 class Chart(graphics.Scene): __gsignals__ = { "bar-clicked": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), } def __init__(self, max_bar_width = 20, legend_width = 70, value_format = "%.2f", interactive = True): graphics.Scene.__init__(self) self.selected_keys = [] # keys of selected bars self.bars = [] self.labels = [] self.data = None self.max_width = max_bar_width self.legend_width = legend_width self.value_format = value_format self.graph_interactive = interactive self.plot_area = graphics.Sprite(interactive = False) self.add_child(self.plot_area) self.bar_color, self.label_color = None, None self.connect("on-enter-frame", self.on_enter_frame) if self.graph_interactive: self.connect("on-mouse-over", self.on_mouse_over) self.connect("on-mouse-out", self.on_mouse_out) self.connect("on-click", self.on_click) def find_colors(self): bg_color = "#eee" #self.get_style().bg[gtk.StateType.NORMAL].to_string() self.bar_color = self.colors.contrast(bg_color, 30) # now for the text - we want reduced contrast for relaxed visuals fg_color = "#aaa" #self.get_style().fg[gtk.StateType.NORMAL].to_string() self.label_color = self.colors.contrast(fg_color, 80) def on_mouse_over(self, scene, bar): if bar.key not in self.selected_keys: bar.fill = "#999" #self.get_style().base[gtk.StateType.PRELIGHT].to_string() def on_mouse_out(self, scene, bar): if bar.key not in self.selected_keys: bar.fill = self.bar_color def on_click(self, scene, event, clicked_bar): if not clicked_bar: return self.emit("bar-clicked", clicked_bar.key) def plot(self, keys, data): self.data = data bars = dict([(bar.key, bar.normalized) for bar in self.bars]) max_val = float(max(data or [0])) new_bars, new_labels = [], [] for key, value in zip(keys, data): if max_val: normalized = value / max_val else: normalized = 0 bar = Bar(key, locale.format(self.value_format, value), normalized, self.label_color) bar.interactive = self.graph_interactive if key in bars: bar.normalized = bars[key] self.tweener.add_tween(bar, normalized=normalized) new_bars.append(bar) label = graphics.Label(stuff.escape_pango(key), size = 8, alignment = pango.Alignment.RIGHT) new_labels.append(label) self.plot_area.remove_child(*self.bars) self.remove_child(*self.labels) self.bars, self.labels = new_bars, new_labels self.add_child(*self.labels) self.plot_area.add_child(*self.bars) self.show() self.redraw() def on_enter_frame(self, scene, context): # adjust sizes and positions on redraw legend_width = self.legend_width if legend_width < 1: # allow fractions legend_width = int(self.width * legend_width) self.find_colors() self.plot_area.y = 0 self.plot_area.height = self.height - self.plot_area.y self.plot_area.x = legend_width + 8 self.plot_area.width = self.width - self.plot_area.x y = 0 for i, (label, bar) in enumerate(zip(self.labels, self.bars)): bar_width = min(round((self.plot_area.height - y) / (len(self.bars) - i)), self.max_width) bar.y = y bar.height = bar_width bar.width = self.plot_area.width if bar.key in self.selected_keys: bar.fill = "#aaa" #self.get_style().bg[gtk.StateType.SELECTED].to_string() if bar.normalized == 0: bar.label.color = "#666" #self.get_style().fg[gtk.StateType.SELECTED].to_string() bar.label_background.fill = "#aaa" #self.get_style().bg[gtk.StateType.SELECTED].to_string() bar.label_background.visible = True else: bar.label_background.visible = False if bar.label.x < round(bar.width * bar.normalized): bar.label.color = "#666" #self.get_style().fg[gtk.StateType.SELECTED].to_string() else: bar.label.color = self.label_color if not bar.fill: bar.fill = self.bar_color bar.label.color = self.label_color bar.label_background.fill = None label.y = y + (bar_width - label.height) / 2 + self.plot_area.y label.width = legend_width if not label.color: label.color = self.label_color y += bar_width + 1 class HorizontalDayChart(graphics.Scene): """Pretty much a horizontal bar chart, except for values it expects tuple of start and end time, and the whole thing hangs in air""" def __init__(self, max_bar_width, legend_width): graphics.Scene.__init__(self) self.max_bar_width = max_bar_width self.legend_width = legend_width self.start_time, self.end_time = None, None self.connect("on-enter-frame", self.on_enter_frame) def plot_day(self, keys, data, start_time = None, end_time = None): self.keys, self.data = keys, data self.start_time, self.end_time = start_time, end_time self.show() self.redraw() def on_enter_frame(self, scene, context): g = graphics.Graphics(context) rowcount, keys = len(self.keys), self.keys start_hour = 0 if self.start_time: start_hour = self.start_time end_hour = 24 * 60 if self.end_time: end_hour = self.end_time # push graph to the right, so it doesn't overlap legend_width = self.legend_width or self.longest_label(keys) self.graph_x = legend_width self.graph_x += 8 #add another 8 pixes of padding self.graph_width = self.width - self.graph_x # TODO - should handle the layout business in graphics self.layout = context.create_layout() default_font = "Sans Serif" #pango.FontDescription(self.get_style().font_desc.to_string()) default_font.set_size(8 * pango.SCALE) self.layout.set_font_description(default_font) #on the botttom leave some space for label self.layout.set_text("1234567890:") label_w, label_h = self.layout.get_pixel_size() self.graph_y, self.graph_height = 0, self.height - label_h - 4 if not self.data: #if we have nothing, let's go home return positions = {} y = 0 bar_width = min(self.graph_height / float(len(self.keys)), self.max_bar_width) for i, key in enumerate(self.keys): positions[key] = (y + self.graph_y, round(bar_width - 1)) y = y + round(bar_width) bar_width = min(self.max_bar_width, (self.graph_height - y) / float(max(1, len(self.keys) - i - 1))) max_bar_size = self.graph_width - 15 # now for the text - we want reduced contrast for relaxed visuals fg_color = "#666" #self.get_style().fg[gtk.StateType.NORMAL].to_string() label_color = self.colors.contrast(fg_color, 80) self.layout.set_alignment(pango.Alignment.RIGHT) self.layout.set_ellipsize(pango.ELLIPSIZE_END) # bars and labels self.layout.set_width(legend_width * pango.SCALE) factor = max_bar_size / float(end_hour - start_hour) # determine bar color bg_color = "#eee" #self.get_style().bg[gtk.StateType.NORMAL].to_string() base_color = self.colors.contrast(bg_color, 30) for i, label in enumerate(keys): g.set_color(label_color) self.layout.set_text(label) label_w, label_h = self.layout.get_pixel_size() context.move_to(0, positions[label][0] + (positions[label][1] - label_h) / 2) context.show_layout(self.layout) if isinstance(self.data[i], list) == False: self.data[i] = [self.data[i]] for row in self.data[i]: bar_x = round((row[0]- start_hour) * factor) bar_size = round((row[1] - start_hour) * factor - bar_x) g.fill_area(round(self.graph_x + bar_x), positions[label][0], bar_size, positions[label][1], base_color) #white grid and scale values self.layout.set_width(-1) context.set_line_width(1) pace = ((end_hour - start_hour) / 3) / 60 * 60 last_position = positions[keys[-1]] grid_color = "#aaa" # self.get_style().bg[gtk.StateType.NORMAL].to_string() for i in range(start_hour + 60, end_hour, pace): x = round((i - start_hour) * factor) minutes = i % (24 * 60) self.layout.set_markup(dt.time(minutes / 60, minutes % 60).strftime("%H%M")) label_w, label_h = self.layout.get_pixel_size() context.move_to(self.graph_x + x - label_w / 2, last_position[0] + last_position[1] + 4) g.set_color(label_color) context.show_layout(self.layout) g.set_color(grid_color) g.move_to(round(self.graph_x + x) + 0.5, self.graph_y) g.line_to(round(self.graph_x + x) + 0.5, last_position[0] + last_position[1]) context.stroke() hamster-3.0.3/src/hamster/lib/configuration.py000066400000000000000000000130611452646177100214170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2008, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . """ License: GPLv2 """ import logging logger = logging.getLogger(__name__) # noqa: E402 import os from hamster.client import Storage from gi.repository import Gdk as gdk from gi.repository import Gio as gio from gi.repository import GLib as glib from gi.repository import GObject as gobject from gi.repository import Gtk as gtk import hamster from hamster.lib import datetime as dt class Controller(gobject.GObject): """Window creator and handler.""" __gsignals__ = { "on-close": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, ui_file=""): gobject.GObject.__init__(self) if ui_file: self._gui = load_ui_file(ui_file) self.window = self.get_widget('window') else: self._gui = None self.window = gtk.Window() self.window.connect("delete-event", self.window_delete_event) if self._gui: self._gui.connect_signals(self) def get_widget(self, name): """ skip one variable (huh) """ return self._gui.get_object(name) def window_delete_event(self, widget, event): self.close_window() def close_window(self): # Do not try to just hide; # dialogs are populated upon instanciation anyway self.window.destroy() self.window = None self.emit("on-close") def present(self): """Show window and bring it to the foreground.""" # workaround https://gitlab.gnome.org/GNOME/gtk/issues/624 # fixed in gtk-3.24.1 (2018-09-19) # self.overview_controller.window.present() self.window.present_with_time(glib.get_monotonic_time() / 1000) def show(self): """Show window. It might be obscurd by others though. See also: presents """ self.window.show() def __bool__(self): return True if self.window else False def load_ui_file(name): """loads interface from the glade file; sorts out the path business""" ui = gtk.Builder() ui.add_from_file(os.path.join(runtime.data_dir, name)) return ui class Singleton(object): def __new__(cls, *args, **kwargs): if '__instance' not in vars(cls): cls.__instance = object.__new__(cls, *args, **kwargs) return cls.__instance class RuntimeStore(Singleton): """XXX - kill""" data_dir = "" home_data_dir = "" storage = None def __init__(self): self.version = hamster.__version__ if hamster.installed: from hamster import defs # only available when running installed self.data_dir = os.path.join(defs.DATA_DIR, "hamster") else: # running from sources module_dir = os.path.dirname(os.path.realpath(__file__)) self.data_dir = os.path.join(module_dir, '..', '..', '..', 'data') self.data_dir = os.path.realpath(self.data_dir) self.storage = Storage() self.home_data_dir = os.path.realpath(os.path.join(glib.get_user_data_dir(), "hamster")) runtime = RuntimeStore() class GSettingsStore(gobject.GObject, Singleton): """ Settings implementation which stores settings in GSettings Snatched from the conduit project (http://live.gnome.org/Conduit) """ __gsignals__ = { "changed": (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)) } def __init__(self): gobject.GObject.__init__(self) self._settings = gio.Settings(schema_id='org.gnome.Hamster') def _key_changed(self, client, key, data=None): """ Callback when a GSettings key changes """ value = self._settings.get_value(key) self.emit('changed', key, value) def get(self, key, default=None): """ Returns the value of the key or the default value if the key is not yet in GSettings """ value = self._settings.get_value(key) if value is None: logger.warn("Unknown GSettings key: %s" % key) return value.unpack() def set(self, key, value): """ Sets the key value in GSettings and connects adds a signal which is fired if the key changes """ logger.debug("Settings %s -> %s" % (key, value)) default = self._settings.get_default_value(key) assert default is not None self._settings.set_value(key, glib.Variant(default.get_type().dup_string(), value)) return True def bind(self, key, obj, prop): self._settings.bind(key, obj, prop, gio.SettingsBindFlags.DEFAULT) @property def day_start(self): """Start of the hamster day.""" day_start_minutes = self.get("day-start-minutes") hours, minutes = divmod(day_start_minutes, 60) return dt.time(hours, minutes) conf = GSettingsStore() hamster-3.0.3/src/hamster/lib/datetime.py000066400000000000000000000616371452646177100203600ustar00rootroot00000000000000# This file is part of Hamster # Copyright (c) The Hamster time tracker developers # SPDX-License-Identifier: GPL-3.0-or-later """Hamster datetime. Python datetime replacement, tuned for hamster use. """ import logging logger = logging.getLogger(__name__) # noqa: E402 import datetime as pdt # standard datetime import re from collections import namedtuple from textwrap import dedent from functools import lru_cache class datetime: # predeclaration for return type annotations pass class time: # predeclaration for return type annotations pass class date(pdt.date): """Hamster date. Should replace the python datetime.date in any customer code. Same as python date, with the addition of parse methods. """ FMT = "%Y-%m-%d" # ISO format def __new__(cls, year, month, day): return pdt.date.__new__(cls, year, month, day) def __add__(self, other): # python date.__add__ was not type stable prior to 3.8 return self.from_pdt(self.to_pdt() + other) __radd__ = __add__ def __sub__(self, other): # python date.__sub__ was not type stable prior to 3.8 if isinstance(other, pdt.timedelta): return self.from_pdt(self.to_pdt() - other) elif isinstance(other, pdt.date): return timedelta.from_pdt(self.to_pdt() - other) else: return NotImplemented @classmethod def parse(cls, s): """Return date from string.""" m = cls.re.search(s) return cls(year=int(m.group('year')), month=int(m.group('month')), day=int(m.group('day')) ) @classmethod def pattern(cls, detailed=True): if detailed: return dedent(r""" (?P\d{4}) # 4 digits - # dash (?P\d{2}) # 2 digits - # dash (?P\d{2}) # 2 digits """) else: return r"""\d{4}-\d{2}-\d{2}""" @classmethod def from_pdt(cls, d): """Convert python date to hamster date.""" return cls(d.year, d.month, d.day) def to_pdt(self): """Convert to python date.""" return pdt.date(self.year, self.month, self.day) # For datetime that will need to be outside the class. # Same here for consistency date.re = re.compile(date.pattern(), flags=re.VERBOSE) class hday(date): """Hamster day. Same as date, but taking into account day-start. A day starts at conf.day_start and ends when the next day starts. """ def __new__(cls, year, month, day): return date.__new__(cls, year, month, day) @property def end(self) -> datetime: """Day end.""" return datetime.from_day_time(self + timedelta(days=1), self.start_time()) @property def start(self) -> datetime: """Day start.""" return datetime.from_day_time(self, self.start_time()) @classmethod def start_time(cls) -> time: """Day start time.""" # work around cyclic imports from hamster.lib.configuration import conf return conf.day_start @classmethod def today(cls): """Return the current hamster day.""" return datetime.now().hday() class time(pdt.time): """Hamster time. Should replace the python datetime.time in any customer code. Specificities: - rounded to minutes - conversion to and from string facilities """ FMT = "%H:%M" # display format, e.g. 13:30 def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, **kwargs): # round down to zero seconds and microseconds return pdt.time.__new__(cls, hour=hour, minute=minute, second=0, microsecond=0, tzinfo=None, **kwargs) @classmethod def _extract_time(cls, match, h="hour", m="minute"): """Extract time from a time.re match. Custom group names allow to use the same method for two times in the same regexp (e.g. for range parsing) h (str): name of the group containing the hour m (str): name of the group containing the minute seealso: time.parse """ h_str = match.group(h) m_str = match.group(m) if h_str and m_str: hour = int(h_str) minute = int(m_str) return cls(hour, minute) else: return None @classmethod def parse(cls, s): """Parse time from string.""" m = cls.re.search(s) return cls._extract_time(m) if m else None # For datetime that must be a method. # Same here for consistency. @classmethod def pattern(cls): """Return a time pattern with all group names.""" # remove the indentation for easier debugging. return dedent(r""" (?P # hour [0-9](?=[,\.:]) # positive lookahead: # allow a single digit only if # followed by a colon, dot or comma | [0-1][0-9] # 00 to 19 | [2][0-3] # 20 to 23 ) [,\.:]? # Separator can be colon, # dot, comma, or nothing. (?P[0-5][0-9]) # minute (2 digits, between 00 and 59) (?!\d?-\d{2}-\d{2}) # Negative lookahead: # avoid matching date by inadvertance. # For instance 2019-12-05 # might be caught as 2:01. # Requiring space or - would not work: # 2019-2025 is the 20:19-20:25 range. """) # For datetime that will need to be outside the class. # Same here for consistency time.re = re.compile(time.pattern(), flags=re.VERBOSE) class datetime(pdt.datetime): """Hamster datetime. Should replace the python datetime.datetime in any customer code. Specificities: - rounded to minutes - conversion to and from string facilities """ # display format, e.g. 2020-01-20 20:40 FMT = "{} {}".format(date.FMT, time.FMT) def __new__(cls, year, month, day, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, **kwargs): # round down to zero seconds and microseconds return pdt.datetime.__new__(cls, year, month, day, hour=hour, minute=minute, second=0, microsecond=0, tzinfo=None, **kwargs) def __add__(self, other): # python datetime.__add__ was not type stable prior to 3.8 return datetime.from_pdt(self.to_pdt() + other) # similar to https://stackoverflow.com/q/51966126/3565696 # __getnewargs_ex__ did not work, brute force required def __deepcopy__(self, memo): kwargs = {} if (hasattr(self, 'fold')): kwargs['fold'] = self.fold return datetime(self.year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, **kwargs) __radd__ = __add__ def __sub__(self, other): # python datetime.__sub__ was not type stable prior to 3.8 if isinstance(other, timedelta): return datetime.from_pdt(self.to_pdt() - other) elif isinstance(other, datetime): return timedelta.from_pdt(self.to_pdt() - other) else: return NotImplemented def __str__(self): if self.tzinfo: raise NotImplementedError("Stay tuned...") else: return self.strftime(self.FMT) @classmethod def _extract_datetime(cls, match, d="date", h="hour", m="minute", r="relative", default_day=None): """extract datetime from a datetime.pattern match. Custom group names allow to use the same method for two datetimes in the same regexp (e.g. for range parsing) h (str): name of the group containing the hour m (str): name of the group containing the minute r (str): name of the group containing the relative time default_day (dt.date): the datetime will belong to this hamster day if date is missing. """ _time = time._extract_time(match, h, m) if _time: date_str = match.group(d) if date_str: _date = date.parse(date_str) return datetime.combine(_date, _time) else: return datetime.from_day_time(default_day, _time) else: relative_str = match.group(r) if relative_str and relative_str != "--": return timedelta(minutes=int(relative_str)) else: return None # not a property, to match other extractions such as .date() or .time() def hday(self) -> hday: """Return the day belonged to. The hamster day start is taken into account. """ # work around cyclic imports from hamster.lib.configuration import conf _day = hday(self.year, self.month, self.day) if self.time() < conf.day_start: # early morning, between midnight and day_start # => the hamster day is the previous civil day _day -= timedelta(days=1) # return only the date return _day @classmethod def from_day_time(cls, d: hday, t: time): """Return a datetime with time t belonging to day. The hamster day start is taken into account. """ # work around cyclic imports from hamster.lib.configuration import conf if t < conf.day_start: # early morning, between midnight and day_start # => the hamster day is the previous civil day civil_date = d + timedelta(days=1) else: civil_date = d return cls.combine(civil_date, t) # Note: fromisoformat appears in python3.7 @classmethod def from_pdt(cls, t): """Convert python datetime to hamster datetime.""" kwargs = {} if (hasattr(t, 'fold')): kwargs['fold'] = t.fold return cls(t.year, t.month, t.day, t.hour, t.minute, t.second, t.microsecond, t.tzinfo, **kwargs) @classmethod def now(cls): """Current datetime.""" return cls.from_pdt(pdt.datetime.now()) @classmethod def parse(cls, s, default_day=None): """Parse a datetime from text. default_day (dt.date): If start is given without any date (e.g. just hh:mm), put the corresponding datetime in default_day. Defaults to today. """ # datetime.re is added below, after the class definition # it will be found at runtime m = datetime.re.search(s) return cls._extract_datetime(m, default_day=default_day) if m else None @classmethod @lru_cache() def pattern(cls, n=None): """Return a datetime pattern with all group names. If n is given, all groups are suffixed with str(n). """ # remove the indentation => easier debugging. base_pattern = dedent(r""" (?P # note: need to double the brackets # for .format (? -- # double dash: None | # or [-+] # minus or plus: relative to ref \d{{1,3}} # 1, 2 or 3 digits ) | # or (?P{})? # maybe date \s? # maybe one space {} # time ) """).format(date.pattern(), time.pattern()) if n is None: return base_pattern else: to_replace = ("whole", "relative", "year", "month", "day", "date", "tens", "hour", "minute") specifics = ["{}{}".format(s, n) for s in to_replace] res = base_pattern for src, dest in zip(to_replace, specifics): res = res.replace(src, dest) return res def to_pdt(self): """Convert to python datetime.""" kwargs = {} if (hasattr(self, 'fold')): kwargs['fold'] = self.fold return pdt.datetime(self.year, self.month, self.day, self.hour, self.minute, self.second, self.microsecond, self.tzinfo, **kwargs) # outside class; need the class to be defined first datetime.re = re.compile(datetime.pattern(), flags=re.VERBOSE) class Range(): """Time span between two datetimes.""" # slight memory optimization; no further attributes besides start or end. __slots__ = ('start', 'end') def __init__(self, start=None, end=None): self.start = start self.end = end def __bool__(self): return not (self.start is None and self.end is None) def __eq__(self, other): if isinstance(other, Range): return self.start == other.start and self.end == other.end else: return False # allow start, end = range def __iter__(self): return (self.start, self.end).__iter__() def format(self, default_day=None, explicit_none=True): """Return a string representing the time range. Start date is shown only if start does not belong to default_day. End date is shown only if end does not belong to the same hamster day as start (or to default_day if start is None). """ none_str = "--" if explicit_none else "" if self.start: if self.start.hday() != default_day: start_str = self.start.strftime(datetime.FMT) else: start_str = self.start.strftime(time.FMT) default_end_day = self.start.hday() else: start_str = none_str default_end_day = default_day if self.end: if self.end.hday() != default_end_day: end_str = self.end.strftime(datetime.FMT) else: end_str = self.end.strftime(time.FMT) else: end_str = none_str if end_str: return "{} - {}".format(start_str, end_str) else: return start_str @classmethod def parse(cls, text, position="exact", separator="\s+", default_day=None, ref="now"): """Parse a start-end range from text. position (str): "exact" to match exactly the full text "head" to search only at the beginning of text, and "tail" to search only at the end. separator (str): regexp pattern (e.g. '\s+') meant to separate the datetime from the rest. Discarded for "exact" position. default_day (date): If start is given without any date (e.g. just hh:mm), put the corresponding datetime in default_day. Defaults to today. Note: the default end day is always the start day, so "2019-11-27 23:50 - 00:20" lasts 30 minutes. ref (datetime): reference for relative times (e.g. -15: quarter hour before ref). For testing purposes only (note: this will be removed later on, and replaced with datetime.now mocking in pytest). For users, it should be "now". Return: (range, rest) range (Range): Range(None, None) if no match is found. rest (str): remainder of the text. """ if ref == "now": ref = datetime.now() if default_day is None: default_day = hday.today() assert position in ("exact", "head", "tail"), "position unknown: '{}'".format(position) if position == "exact": p = "^{}$".format(cls.pattern()) elif position == "head": # ( )?: require either only the range (no rest), # or separator between range and rest, # to avoid matching 10.00@cat # .*? so rest is as little as possible p = "^{}( {}(?P.*?) )?$".format(cls.pattern(), separator) elif position == "tail": p = "^( (?P.*?){} )? {}$".format(separator, cls.pattern()) # No need to compile, recent patterns are cached by re. # DOTALL, so rest may contain newlines # (important for multiline descriptions) m = re.search(p, text, flags=re.VERBOSE | re.DOTALL) if not m: return Range(None, None), text elif position == "exact": rest = "" else: rest = m.group("rest") or "" if m.group('firstday'): # only day given for start firstday = hday.parse(m.group('firstday')) start = firstday.start else: firstday = None start = datetime._extract_datetime(m, d="date1", h="hour1", m="minute1", r="relative1", default_day=default_day) if isinstance(start, pdt.timedelta): # relative to ref, actually assert ref, "relative start needs ref" start = ref + start if m.group('lastday'): lastday = hday.parse(m.group('lastday')) end = lastday.end elif firstday: end = firstday.end elif m.group('duration'): duration = int(m.group('duration')) end = start + timedelta(minutes=duration) else: end_default_day = start.hday() if start else default_day end = datetime._extract_datetime(m, d="date2", h="hour2", m="minute2", r="relative2", default_day=end_default_day) if isinstance(end, pdt.timedelta): # relative to ref, actually assert ref, "relative end needs ref" end = ref + end return Range(start, end), rest @classmethod @lru_cache() def pattern(cls): return dedent(r""" ( # start {} # datetime: relative1 or (date1, hour1, and minute1) | # or (?P{}) # date without time ) ( (?P # (only needed if end time is given) \s? # maybe one space - # dash \s? # maybe one space | # or \s # one space exactly ) ( # end {} # datetime: relative2 or (date2, hour2, and minute2) | # or (?P{}) # date without time | (?P (? # Copyright (c) 2011-2012 Media Modifications, Ltd. # Dual licensed under the MIT or GPL Version 2 licenses. # See http://github.com/tbaugis/hamster_experiments/blob/master/README.textile from collections import defaultdict import math import datetime as dt # need the original python granularity here from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import GObject as gobject from gi.repository import Pango as pango from gi.repository import PangoCairo as pangocairo import cairo from gi.repository import GdkPixbuf import re try: from hamster.lib import pytweener except: # we can also live without tweener. Scene.animate will not work pytweener = None import colorsys from collections import deque # lemme know if you know a better way how to get default font _test_label = gtk.Label("Hello") _font_desc = _test_label.get_style().font_desc.to_string() class ColorUtils(object): hex_color_normal = re.compile("#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})") hex_color_short = re.compile("#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])") hex_color_long = re.compile("#([a-fA-F0-9]{4})([a-fA-F0-9]{4})([a-fA-F0-9]{4})") # d3 colors category10 = ("#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf") category20 = ("#1f77b4", "#aec7e8", "#ff7f0e", "#ffbb78", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5", "#8c564b", "#c49c94", "#e377c2", "#f7b6d2", "#7f7f7f", "#c7c7c7", "#bcbd22", "#dbdb8d", "#17becf", "#9edae5") category20b = ("#393b79", "#5254a3", "#6b6ecf", "#9c9ede", "#637939", "#8ca252", "#b5cf6b", "#cedb9c", "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94", "#843c39", "#ad494a", "#d6616b", "#e7969c", "#7b4173", "#a55194", "#ce6dbd", "#de9ed6") category20c = ("#3182bd", "#6baed6", "#9ecae1", "#c6dbef", "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2", "#31a354", "#74c476", "#a1d99b", "#c7e9c0", "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb", "#636363", "#969696", "#bdbdbd", "#d9d9d9") def parse(self, color): """parse string or a color tuple into color usable for cairo (all values in the normalized (0..1) range""" assert color is not None #parse color into rgb values if isinstance(color, str): match = self.hex_color_long.match(color) if match: color = [int(color, 16) / 65535.0 for color in match.groups()] else: match = self.hex_color_normal.match(color) if match: color = [int(color, 16) / 255.0 for color in match.groups()] else: match = self.hex_color_short.match(color) color = [int(color + color, 16) / 255.0 for color in match.groups()] elif isinstance(color, gdk.Color): color = [color.red / 65535.0, color.green / 65535.0, color.blue / 65535.0] elif isinstance(color, (list, tuple)): # otherwise we assume we have color components in 0..255 range if color[0] > 1 or color[1] > 1 or color[2] > 1: color = [c / 255.0 for c in color] else: color = [color.red, color.green, color.blue] return color def rgb(self, color): """returns rgb[a] tuple of the color with values in range 0.255""" return [c * 255 for c in self.parse(color)] def gdk(self, color): """returns gdk.Color object of the given color""" c = self.parse(color) return gdk.Color.from_floats(c) def hex(self, color): if isinstance(color, gdk.RGBA): r = int(255 * color.red) g = int(255 * color.green) b = int(255 * color.blue) a = int(255 * color.alpha) return "#{:02x}{:02x}{:02x}{:02x}".format(r, g, b, a) else: c = self.parse(color) return "#" + "".join("{:02x}".format(int(color) * 255) for color in c) def is_light(self, color): """tells you if color is dark or light, so you can up or down the scale for improved contrast""" return colorsys.rgb_to_hls(*self.rgb(color))[1] > 150 def darker(self, color, step): """returns color darker by step (where step is in range 0..255)""" hls = colorsys.rgb_to_hls(*self.rgb(color)) return colorsys.hls_to_rgb(hls[0], hls[1] - step, hls[2]) def contrast(self, color, step): """if color is dark, will return a lighter one, otherwise darker""" hls = colorsys.rgb_to_hls(*self.rgb(color)) if self.is_light(color): return colorsys.hls_to_rgb(hls[0], hls[1] - step, hls[2]) else: return colorsys.hls_to_rgb(hls[0], hls[1] + step, hls[2]) # returns color darker by step (where step is in range 0..255) @classmethod def mix(cls, ca, cb, xb): """Mix colors. Args: ca (gdk.RGBA): first color cb (gdk.RGBA): second color xb (float): between 0.0 and 1.0 Return: gdk.RGBA: linear interpolation between ca and cb, 0 or 1 return the unaltered 1st or 2nd color respectively, as in CSS. """ r = (1 - xb) * ca.red + xb * cb.red g = (1 - xb) * ca.green + xb * cb.green b = (1 - xb) * ca.blue + xb * cb.blue a = (1 - xb) * ca.alpha + xb * cb.alpha return gdk.RGBA(red=r, green=g, blue=b, alpha=a) Colors = ColorUtils() # this is a static class, so an instance will do def get_gdk_rectangle(x, y, w, h): rect = gdk.Rectangle() rect.x, rect.y, rect.width, rect.height = x or 0, y or 0, w or 0, h or 0 return rect def chain(*steps): """chains the given list of functions and object animations into a callback string. Expects an interlaced list of object and params, something like: object, {params}, callable, {params}, object, {}, object, {params} Assumes that all callees accept on_complete named param. The last item in the list can omit that. XXX - figure out where to place these guys as they are quite useful """ if not steps: return def on_done(sprite=None): chain(*steps[2:]) obj, params = steps[:2] if len(steps) > 2: params['on_complete'] = on_done if callable(obj): obj(**params) else: obj.animate(**params) def full_pixels(space, data, gap_pixels=1): """returns the given data distributed in the space ensuring it's full pixels and with the given gap. this will result in minor sub-pixel inaccuracies. XXX - figure out where to place these guys as they are quite useful """ available = space - (len(data) - 1) * gap_pixels # 8 recs 7 gaps res = [] for i, val in enumerate(data): # convert data to 0..1 scale so we deal with fractions data_sum = sum(data[i:]) norm = val * 1.0 / data_sum w = max(int(round(available * norm)), 1) res.append(w) available -= w return res class Graphics(object): """If context is given upon contruction, will perform drawing operations on context instantly. Otherwise queues up the drawing instructions and performs them in passed-in order when _draw is called with context. Most of instructions are mapped to cairo functions by the same name. Where there are differences, documenation is provided. See http://cairographics.org/documentation/pycairo/2/reference/context.html for detailed description of the cairo drawing functions. """ __slots__ = ('context', 'extents', 'paths', '_last_matrix', '__new_instructions', '__instruction_cache', 'cache_surface', '_cache_layout') colors = Colors # pointer to the color utilities instance def __init__(self, context = None): self.context = context self.extents = None # bounds of the object, only if interactive self.paths = None # paths for mouse hit checks self._last_matrix = None self.__new_instructions = [] # instruction set until it is converted into path-based instructions self.__instruction_cache = [] self.cache_surface = None self._cache_layout = None def clear(self): """clear all instructions""" self.__new_instructions = [] self.__instruction_cache = [] self.paths = [] def stroke(self, color=None, alpha=1): if color or alpha < 1: self.set_color(color, alpha) self._add_instruction("stroke") def fill(self, color = None, alpha = 1): if color or alpha < 1: self.set_color(color, alpha) self._add_instruction("fill") def mask(self, pattern): self._add_instruction("mask", pattern) def stroke_preserve(self, color = None, alpha = 1): if color or alpha < 1: self.set_color(color, alpha) self._add_instruction("stroke_preserve") def fill_preserve(self, color = None, alpha = 1): if color or alpha < 1: self.set_color(color, alpha) self._add_instruction("fill_preserve") def new_path(self): self._add_instruction("new_path") def paint(self): self._add_instruction("paint") def set_font_face(self, face): self._add_instruction("set_font_face", face) def set_font_size(self, size): self._add_instruction("set_font_size", size) def set_source(self, image, x = 0, y = 0): self._add_instruction("set_source", image) def set_source_surface(self, surface, x = 0, y = 0): self._add_instruction("set_source_surface", surface, x, y) def set_source_pixbuf(self, pixbuf, x = 0, y = 0): self._add_instruction("set_source_pixbuf", pixbuf, x, y) def save_context(self): self._add_instruction("save") def restore_context(self): self._add_instruction("restore") def clip(self): self._add_instruction("clip") def rotate(self, radians): self._add_instruction("rotate", radians) def translate(self, x, y): self._add_instruction("translate", x, y) def scale(self, x_factor, y_factor): self._add_instruction("scale", x_factor, y_factor) def move_to(self, x, y): self._add_instruction("move_to", x, y) def line_to(self, x, y = None): if y is not None: self._add_instruction("line_to", x, y) elif isinstance(x, list) and y is None: for x2, y2 in x: self._add_instruction("line_to", x2, y2) def rel_line_to(self, x, y = None): if x is not None and y is not None: self._add_instruction("rel_line_to", x, y) elif isinstance(x, list) and y is None: for x2, y2 in x: self._add_instruction("rel_line_to", x2, y2) def curve_to(self, x, y, x2, y2, x3, y3): """draw a curve. (x2, y2) is the middle point of the curve""" self._add_instruction("curve_to", x, y, x2, y2, x3, y3) def close_path(self): self._add_instruction("close_path") def set_line_style(self, width = None, dash = None, dash_offset = 0): """change width and dash of a line""" if width is not None: self._add_instruction("set_line_width", width) if dash is not None: self._add_instruction("set_dash", dash, dash_offset) def _set_color(self, context, r, g, b, a): """the alpha has to changed based on the parent, so that happens at the time of drawing""" if a < 1: context.set_source_rgba(r, g, b, a) else: context.set_source_rgb(r, g, b) def set_color(self, color, alpha = 1): """set active color. You can use hex colors like "#aaa", or you can use normalized RGB tripplets (where every value is in range 0..1), or you can do the same thing in range 0..65535. also consider skipping this operation and specify the color on stroke and fill. """ color = self.colors.parse(color) # parse whatever we have there into a normalized triplet if len(color) == 4 and alpha is None: alpha = color[3] r, g, b = color[:3] self._add_instruction("set_color", r, g, b, alpha) def arc(self, x, y, radius, start_angle, end_angle): """draw arc going counter-clockwise from start_angle to end_angle""" self._add_instruction("arc", x, y, radius, start_angle, end_angle) def circle(self, x, y, radius): """draw circle""" self._add_instruction("arc", x, y, radius, 0, math.pi * 2) def ellipse(self, x, y, width, height, edges = None): """draw 'perfect' ellipse, opposed to squashed circle. works also for equilateral polygons""" # the automatic edge case is somewhat arbitrary steps = edges or max((32, width, height)) / 2 angle = 0 step = math.pi * 2 / steps points = [] while angle < math.pi * 2: points.append((width / 2.0 * math.cos(angle), height / 2.0 * math.sin(angle))) angle += step min_x = min((point[0] for point in points)) min_y = min((point[1] for point in points)) self.move_to(points[0][0] - min_x + x, points[0][1] - min_y + y) for p_x, p_y in points: self.line_to(p_x - min_x + x, p_y - min_y + y) self.line_to(points[0][0] - min_x + x, points[0][1] - min_y + y) def arc_negative(self, x, y, radius, start_angle, end_angle): """draw arc going clockwise from start_angle to end_angle""" self._add_instruction("arc_negative", x, y, radius, start_angle, end_angle) def triangle(self, x, y, width, height): self.move_to(x, y) self.line_to(width/2 + x, height + y) self.line_to(width + x, y) self.line_to(x, y) def rectangle(self, x, y, width, height, corner_radius = 0): """draw a rectangle. if corner_radius is specified, will draw rounded corners. corner_radius can be either a number or a tuple of four items to specify individually each corner, starting from top-left and going clockwise""" if corner_radius <= 0: self._add_instruction("rectangle", x, y, width, height) return # convert into 4 border and make sure that w + h are larger than 2 * corner_radius if isinstance(corner_radius, (int, float)): corner_radius = [corner_radius] * 4 corner_radius = [min(r, min(width, height) / 2) for r in corner_radius] x2, y2 = x + width, y + height self._rounded_rectangle(x, y, x2, y2, corner_radius) def _rounded_rectangle(self, x, y, x2, y2, corner_radius): if isinstance(corner_radius, (int, float)): corner_radius = [corner_radius] * 4 self._add_instruction("move_to", x + corner_radius[0], y) self._add_instruction("line_to", x2 - corner_radius[1], y) self._add_instruction("curve_to", x2 - corner_radius[1] / 2, y, x2, y + corner_radius[1] / 2, x2, y + corner_radius[1]) self._add_instruction("line_to", x2, y2 - corner_radius[2]) self._add_instruction("curve_to", x2, y2 - corner_radius[2] / 2, x2 - corner_radius[2] / 2, y2, x2 - corner_radius[2], y2) self._add_instruction("line_to", x + corner_radius[3], y2) self._add_instruction("curve_to", x + corner_radius[3] / 2, y2, x, y2 - corner_radius[3] / 2, x, y2 - corner_radius[3]) self._add_instruction("line_to", x, y + corner_radius[0]) self._add_instruction("curve_to", x, y + corner_radius[0] / 2, x + corner_radius[0] / 2, y, x + corner_radius[0], y) def hexagon(self, x, y, height): side = height * 0.5 angle_x = side * 0.5 angle_y = side * 0.8660254 self.move_to(x, y) self.line_to(x + side, y) self.line_to(x + side + angle_x, y + angle_y) self.line_to(x + side, y + 2*angle_y) self.line_to(x, y + 2*angle_y) self.line_to(x - angle_x, y + angle_y) self.line_to(x, y) self.close_path() def fill_area(self, x, y, width, height, color, opacity = 1): """fill rectangular area with specified color""" self.save_context() self.rectangle(x, y, width, height) self._add_instruction("clip") self.rectangle(x, y, width, height) self.fill(color, opacity) self.restore_context() def fill_stroke(self, fill = None, stroke = None, opacity = 1, line_width = None): """fill and stroke the drawn area in one go""" if line_width: self.set_line_style(line_width) if fill and stroke: self.fill_preserve(fill, opacity) elif fill: self.fill(fill, opacity) if stroke: self.stroke(stroke) def create_layout(self, size = None): """utility function to create layout with the default font. Size and alignment parameters are shortcuts to according functions of the pango.Layout""" if not self.context: # TODO - this is rather sloppy as far as exception goes # should explain better raise Exception("Can not create layout without existing context!") layout = pangocairo.create_layout(self.context) font_desc = pango.FontDescription(_font_desc) if size: font_desc.set_absolute_size(size * pango.SCALE) layout.set_font_description(font_desc) return layout def show_label(self, text, size = None, color = None, font_desc = None): """display text. unless font_desc is provided, will use system's default font""" font_desc = pango.FontDescription(font_desc or _font_desc) if color: self.set_color(color) if size: font_desc.set_absolute_size(size * pango.SCALE) self.show_layout(text, font_desc) def show_text(self, text): self._add_instruction("show_text", text) def text_path(self, text): """this function is most likely to change""" self._add_instruction("text_path", text) def _show_layout(self, context, layout, text, font_desc, alignment, width, wrap, ellipsize, single_paragraph_mode): layout.set_font_description(font_desc) layout.set_markup(text) layout.set_width(int(width or -1)) layout.set_single_paragraph_mode(single_paragraph_mode) if alignment is not None: layout.set_alignment(alignment) if width > 0: if wrap is not None: layout.set_wrap(wrap) else: layout.set_ellipsize(ellipsize or pango.EllipsizeMode.END) pangocairo.show_layout(context, layout) def show_layout(self, text, font_desc, alignment = pango.Alignment.LEFT, width = -1, wrap = None, ellipsize = None, single_paragraph_mode = False): """display text. font_desc is string of pango font description often handier than calling this function directly, is to create a class:Label object """ layout = self._cache_layout = self._cache_layout or pangocairo.create_layout(cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0))) self._add_instruction("show_layout", layout, text, font_desc, alignment, width, wrap, ellipsize, single_paragraph_mode) def _add_instruction(self, function, *params): if self.context: if function == "set_color": self._set_color(self.context, *params) elif function == "show_layout": self._show_layout(self.context, *params) else: getattr(self.context, function)(*params) else: self.paths = None self.__new_instructions.append((function, params)) def _draw(self, context, opacity): """draw accumulated instructions in context""" # if we have been moved around, we should update bounds fresh_draw = len(self.__new_instructions or []) > 0 if fresh_draw: #new stuff! self.paths = [] self.__instruction_cache = self.__new_instructions self.__new_instructions = [] else: if not self.__instruction_cache: return for instruction, args in self.__instruction_cache: if fresh_draw: if instruction in ("new_path", "stroke", "fill", "clip"): self.paths.append((instruction, "path", context.copy_path())) elif instruction in ("save", "restore", "translate", "scale", "rotate"): self.paths.append((instruction, "transform", args)) if instruction == "set_color": self._set_color(context, args[0], args[1], args[2], args[3] * opacity) elif instruction == "show_layout": self._show_layout(context, *args) elif opacity < 1 and instruction == "paint": context.paint_with_alpha(opacity) else: getattr(context, instruction)(*args) def _draw_as_bitmap(self, context, opacity): """ instead of caching paths, this function caches the whole drawn thing use cache_as_bitmap on sprite to enable this mode """ matrix = context.get_matrix() matrix_changed = matrix != self._last_matrix new_instructions = self.__new_instructions is not None and len(self.__new_instructions) > 0 if not new_instructions and not matrix_changed: context.save() context.identity_matrix() context.translate(self.extents.x, self.extents.y) context.set_source_surface(self.cache_surface) if opacity < 1: context.paint_with_alpha(opacity) else: context.paint() context.restore() return if new_instructions: self.__instruction_cache = list(self.__new_instructions) self.__new_instructions = deque() self.paths = [] self.extents = None if not self.__instruction_cache: # no instructions - nothing to do return # instructions that end path path_end_instructions = ("new_path", "clip", "stroke", "fill", "stroke_preserve", "fill_preserve") # measure the path extents so we know the size of cache surface # also to save some time use the context to paint for the first time extents = gdk.Rectangle() for instruction, args in self.__instruction_cache: if instruction in path_end_instructions: self.paths.append((instruction, "path", context.copy_path())) exts = context.path_extents() exts = get_gdk_rectangle(int(exts[0]), int(exts[1]), int(exts[2]-exts[0]), int(exts[3]-exts[1])) if extents.width and extents.height: extents = gdk.rectangle_union(extents, exts) else: extents = exts elif instruction in ("save", "restore", "translate", "scale", "rotate"): self.paths.append((instruction, "transform", args)) if instruction in ("set_source_pixbuf", "set_source_surface"): # draw a rectangle around the pathless instructions so that the extents are correct pixbuf = args[0] x = args[1] if len(args) > 1 else 0 y = args[2] if len(args) > 2 else 0 context.rectangle(x, y, pixbuf.get_width(), pixbuf.get_height()) context.clip() if instruction == "paint" and opacity < 1: context.paint_with_alpha(opacity) elif instruction == "set_color": self._set_color(context, args[0], args[1], args[2], args[3] * opacity) elif instruction == "show_layout": self._show_layout(context, *args) else: getattr(context, instruction)(*args) # avoid re-caching if we have just moved just_transforms = new_instructions == False and \ matrix and self._last_matrix \ and all([matrix[i] == self._last_matrix[i] for i in range(4)]) # TODO - this does not look awfully safe extents.x += matrix[4] - 5 extents.y += matrix[5] - 5 self.extents = extents if not just_transforms: # now draw the instructions on the caching surface w = int(extents.width) + 10 h = int(extents.height) + 10 self.cache_surface = context.get_target().create_similar(cairo.CONTENT_COLOR_ALPHA, w, h) ctx = cairo.Context(self.cache_surface) ctx.translate(-extents.x, -extents.y) ctx.transform(matrix) for instruction, args in self.__instruction_cache: if instruction == "set_color": self._set_color(ctx, args[0], args[1], args[2], args[3]) elif instruction == "show_layout": self._show_layout(ctx, *args) else: getattr(ctx, instruction)(*args) self._last_matrix = matrix class Parent(object): """shared functions across scene and sprite""" def find(self, id): """breadth-first sprite search by ID""" for sprite in self.sprites: if sprite.id == id: return sprite for sprite in self.sprites: found = sprite.find(id) if found: return found def __getitem__(self, i): return self.sprites[i] def traverse(self, attr_name = None, attr_value = None): """traverse the whole sprite tree and return child sprites which have the attribute and it's set to the specified value. If falue is None, will return all sprites that have the attribute """ for sprite in self.sprites: if (attr_name is None) or \ (attr_value is None and hasattr(sprite, attr_name)) or \ (attr_value is not None and getattr(sprite, attr_name, None) == attr_value): yield sprite for child in sprite.traverse(attr_name, attr_value): yield child def log(self, *lines): """will print out the lines in console if debug is enabled for the specific sprite""" if getattr(self, "debug", False): print(dt.datetime.now().time(), end=' ') for line in lines: print(line, end=' ') print() def _add(self, sprite, index = None): """add one sprite at a time. used by add_child. split them up so that it would be possible specify the index externally""" if sprite == self: raise Exception("trying to add sprite to itself") if sprite.parent: sprite.x, sprite.y = self.from_scene_coords(*sprite.to_scene_coords()) sprite.parent.remove_child(sprite) if index is not None: self.sprites.insert(index, sprite) else: self.sprites.append(sprite) sprite.parent = self def _sort(self): """sort sprites by z_order""" self.__dict__['_z_ordered_sprites'] = sorted(self.sprites, key=lambda sprite:sprite.z_order) def add_child(self, *sprites): """Add child sprite. Child will be nested within parent""" for sprite in sprites: self._add(sprite) self._sort() self.redraw() def remove_child(self, *sprites): """Remove one or several :class:`Sprite` sprites from scene """ # first drop focus scene = self.get_scene() if scene: child_sprites = list(self.all_child_sprites()) if scene._focus_sprite in child_sprites: scene._focus_sprite = None for sprite in sprites: if sprite in self.sprites: self.sprites.remove(sprite) sprite._scene = None sprite.parent = None self.disconnect_child(sprite) self._sort() self.redraw() def clear(self): """Remove all child sprites""" self.remove_child(*self.sprites) def destroy(self): """recursively removes all sprite children so that it is freed from any references and can be garbage collected""" for sprite in self.sprites: sprite.destroy() self.clear() def all_child_sprites(self): """returns all child and grandchild sprites in a flat list""" for sprite in self.sprites: for child_sprite in sprite.all_child_sprites(): yield child_sprite yield sprite def get_mouse_sprites(self): """returns list of child sprites that the mouse can interact with. by default returns all visible sprites, but override to define your own rules""" return (sprite for sprite in self._z_ordered_sprites if sprite.visible) def connect_child(self, sprite, event, *args, **kwargs): """connect to a child event so that will disconnect if the child is removed from this sprite. this is the recommended way to connect to child events. syntax is same as for the .connect itself, just you prepend the child sprite as the first element""" handler = sprite.connect(event, *args, **kwargs) self._child_handlers[sprite].append(handler) return handler def connect_child_after(self, sprite, event, *args, **kwargs): """connect to a child event so that will disconnect if the child is removed from this sprite. this is the recommended way to connect to child events. syntax is same as for the .connect itself, just you prepend the child sprite as the first element""" handler = sprite.connect_after(event, *args, **kwargs) self._child_handlers[sprite].append(handler) return handler def disconnect_child(self, sprite, *handlers): """disconnects from child event. if handler is not specified, will disconnect from all the child sprite events""" handlers = handlers or self._child_handlers.get(sprite, []) for handler in list(handlers): if sprite.handler_is_connected(handler): sprite.disconnect(handler) if handler in self._child_handlers.get(sprite, []): self._child_handlers[sprite].remove(handler) if not self._child_handlers[sprite]: del self._child_handlers[sprite] def __repr__(self): return "<%s %s>" % (self.__class__.__name__, getattr(self, "id", None) or str(id(self))) class Sprite(Parent, gobject.GObject): """The Sprite class is a basic display list building block: a display list node that can display graphics and can also contain children. Once you have created the sprite, use Scene's add_child to add it to scene """ __gsignals__ = { "on-mouse-over": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "on-mouse-move": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-out": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "on-mouse-down": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-double-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-triple-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-up": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-scroll": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-drag-start": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-drag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-drag-finish": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-focus": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "on-blur": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), "on-key-press": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-key-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-render": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } transformation_attrs = set(('x', 'y', 'rotation', 'scale_x', 'scale_y', 'pivot_x', 'pivot_y')) visibility_attrs = set(('opacity', 'visible', 'z_order')) cache_attrs = set(('_stroke_context', '_matrix', '_prev_parent_matrix', '_scene')) graphics_unrelated_attrs = set(('drag_x', 'drag_y', 'sprites', 'mouse_cursor', '_sprite_dirty', 'id')) #: mouse-over cursor of the sprite. Can be either a gdk cursor #: constants, or a pixbuf or a pixmap. If set to False, will be using #: scene's cursor. in order to have the cursor displayed, the sprite has #: to be interactive mouse_cursor = None #: whether the widget can gain focus can_focus = None def __init__(self, x = 0, y = 0, opacity = 1, visible = True, rotation = 0, pivot_x = 0, pivot_y = 0, scale_x = 1, scale_y = 1, interactive = False, draggable = False, z_order = 0, mouse_cursor = None, cache_as_bitmap = False, snap_to_pixel = True, debug = False, id = None, can_focus = False): gobject.GObject.__init__(self) # a place where to store child handlers self.__dict__['_child_handlers'] = defaultdict(list) self._scene = None self.debug = debug self.id = id #: list of children sprites. Use :func:`add_child` to add sprites self.sprites = [] self._z_ordered_sprites = [] #: instance of :ref:`graphics` for this sprite self.graphics = Graphics() #: boolean denoting whether the sprite responds to mouse events self.interactive = interactive #: boolean marking if sprite can be automatically dragged self.draggable = draggable #: relative x coordinate of the sprites' rotation point self.pivot_x = pivot_x #: relative y coordinates of the sprites' rotation point self.pivot_y = pivot_y #: sprite opacity self.opacity = opacity #: boolean visibility flag self.visible = visible #: pointer to parent :class:`Sprite` or :class:`Scene` self.parent = None #: sprite coordinates self.x, self.y = x, y #: rotation of the sprite in radians (use :func:`math.degrees` to convert to degrees if necessary) self.rotation = rotation #: scale X self.scale_x = scale_x #: scale Y self.scale_y = scale_y #: drawing order between siblings. The one with the highest z_order will be on top. self.z_order = z_order #: x position of the cursor within mouse upon drag. change this value #: in on-drag-start to adjust drag point self.drag_x = 0 #: y position of the cursor within mouse upon drag. change this value #: in on-drag-start to adjust drag point self.drag_y = 0 #: Whether the sprite should be cached as a bitmap. Default: true #: Generally good when you have many static sprites self.cache_as_bitmap = cache_as_bitmap #: Should the sprite coordinates always rounded to full pixel. Default: true #: Mostly this is good for performance but in some cases that can lead #: to rounding errors in positioning. self.snap_to_pixel = snap_to_pixel #: focus state self.focused = False if mouse_cursor is not None: self.mouse_cursor = mouse_cursor if can_focus is not None: self.can_focus = can_focus self.__dict__["_sprite_dirty"] = True # flag that indicates that the graphics object of the sprite should be rendered self._matrix = None self._prev_parent_matrix = None self._stroke_context = None self.connect("on-click", self.__on_click) def __setattr__(self, name, val): if isinstance(getattr(type(self), name, None), property) and \ getattr(type(self), name).fset is not None: getattr(type(self), name).fset(self, val) return prev = self.__dict__.get(name, "hamster_graphics_no_value_really") if type(prev) == type(val) and prev == val: return self.__dict__[name] = val # prev parent matrix walks downwards if name == '_prev_parent_matrix' and self.visible: # downwards recursive invalidation of parent matrix for sprite in self.sprites: sprite._prev_parent_matrix = None if name in self.cache_attrs or name in self.graphics_unrelated_attrs: return """all the other changes influence cache vars""" if name == 'visible' and self.visible == False: # when transforms happen while sprite is invisible for sprite in self.sprites: sprite._prev_parent_matrix = None # on moves invalidate our matrix, child extent cache (as that depends on our transforms) # as well as our parent's child extents as we moved # then go into children and invalidate the parent matrix down the tree if name in self.transformation_attrs: self._matrix = None for sprite in self.sprites: sprite._prev_parent_matrix = None elif name not in self.visibility_attrs: # if attribute is not in transformation nor visibility, we conclude # that it must be causing the sprite needs re-rendering self.__dict__["_sprite_dirty"] = True # on parent change invalidate the matrix if name == 'parent': self._prev_parent_matrix = None return if name == 'opacity' and getattr(self, "cache_as_bitmap", None) and hasattr(self, "graphics"): # invalidating cache for the bitmap version as that paints opacity in the image self.graphics._last_matrix = None if name == 'z_order' and getattr(self, "parent", None): self.parent._sort() self.redraw() def _get_mouse_cursor(self): """Determine mouse cursor. By default look for self.mouse_cursor is defined and take that. Otherwise use gdk.CursorType.FLEUR for draggable sprites and gdk.CursorType.HAND2 for interactive sprites. Defaults to scenes cursor. """ if self.mouse_cursor is not None: return self.mouse_cursor elif self.interactive and self.draggable: return gdk.CursorType.FLEUR elif self.interactive: return gdk.CursorType.HAND2 def bring_to_front(self): """adjusts sprite's z-order so that the sprite is on top of it's siblings""" if not self.parent: return self.z_order = self.parent._z_ordered_sprites[-1].z_order + 1 def send_to_back(self): """adjusts sprite's z-order so that the sprite is behind it's siblings""" if not self.parent: return self.z_order = self.parent._z_ordered_sprites[0].z_order - 1 def has_focus(self): """True if the sprite has the global input focus, False otherwise.""" scene = self.get_scene() return scene and scene._focus_sprite == self def grab_focus(self): """grab window's focus. Keyboard and scroll events will be forwarded to the sprite who has the focus. Check the 'focused' property of sprite in the on-render event to decide how to render it (say, add an outline when focused=true)""" scene = self.get_scene() if scene and scene._focus_sprite != self: scene._focus_sprite = self def blur(self): """removes focus from the current element if it has it""" scene = self.get_scene() if scene and scene._focus_sprite == self: scene._focus_sprite = None def __on_click(self, sprite, event): if self.interactive and self.can_focus: self.grab_focus() def get_parents(self): """returns all the parent sprites up until scene""" res = [] parent = self.parent while parent and isinstance(parent, Scene) == False: res.insert(0, parent) parent = parent.parent return res def get_extents(self): """measure the extents of the sprite's graphics.""" if self._sprite_dirty: # redrawing merely because we need fresh extents of the sprite context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)) context.transform(self.get_matrix()) self.emit("on-render") self.__dict__["_sprite_dirty"] = False self.graphics._draw(context, 1) if not self.graphics.paths: self.graphics._draw(cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)), 1) if not self.graphics.paths: return None context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)) # bit of a hack around the problem - looking for clip instructions in parent # so extents would not get out of it clip_extents = None for parent in self.get_parents(): context.transform(parent.get_local_matrix()) if parent.graphics.paths: clip_regions = [] for instruction, type, path in parent.graphics.paths: if instruction == "clip": context.append_path(path) context.save() context.identity_matrix() clip_regions.append(context.fill_extents()) context.restore() context.new_path() elif instruction == "restore" and clip_regions: clip_regions.pop() for ext in clip_regions: ext = get_gdk_rectangle(int(ext[0]), int(ext[1]), int(ext[2] - ext[0]), int(ext[3] - ext[1])) intersect, clip_extents = gdk.rectangle_intersect((clip_extents or ext), ext) context.transform(self.get_local_matrix()) for instruction, type, path in self.graphics.paths: if type == "path": context.append_path(path) else: getattr(context, instruction)(*path) context.identity_matrix() ext = context.path_extents() ext = get_gdk_rectangle(int(ext[0]), int(ext[1]), int(ext[2] - ext[0]), int(ext[3] - ext[1])) if clip_extents: intersect, ext = gdk.rectangle_intersect(clip_extents, ext) if not ext.width and not ext.height: ext = None self.__dict__['_stroke_context'] = context return ext def check_hit(self, x, y): """check if the given coordinates are inside the sprite's fill or stroke path""" extents = self.get_extents() if not extents: return False if extents.x <= x <= extents.x + extents.width and extents.y <= y <= extents.y + extents.height: return self._stroke_context is None or self._stroke_context.in_fill(x, y) else: return False def get_scene(self): """returns class:`Scene` the sprite belongs to""" if self._scene is None: parent = getattr(self, "parent", None) if parent: self._scene = parent.get_scene() return self._scene def redraw(self): """queue redraw of the sprite. this function is called automatically whenever a sprite attribute changes. sprite changes that happen during scene redraw are ignored in order to avoid echoes. Call scene.redraw() explicitly if you need to redraw in these cases. """ scene = self.get_scene() if scene: scene.redraw() def animate(self, duration = None, easing = None, on_complete = None, on_update = None, round = False, **kwargs): """Request parent Scene to Interpolate attributes using the internal tweener. Specify sprite's attributes that need changing. `duration` defaults to 0.4 seconds and `easing` to cubic in-out (for others see pytweener.Easing class). Example:: # tween some_sprite to coordinates (50,100) using default duration and easing self.animate(x = 50, y = 100) """ scene = self.get_scene() if scene: return scene.animate(self, duration, easing, on_complete, on_update, round, **kwargs) else: for key, val in kwargs.items(): setattr(self, key, val) return None def stop_animation(self): """stop animation without firing on_complete""" scene = self.get_scene() if scene: scene.stop_animation(self) def get_local_matrix(self): if self._matrix is None: matrix, x, y, pivot_x, pivot_y = cairo.Matrix(), self.x, self.y, self.pivot_x, self.pivot_y if self.snap_to_pixel: matrix.translate(int(x) + int(pivot_x), int(y) + int(pivot_y)) else: matrix.translate(x + pivot_x, self.y + pivot_y) if self.rotation: matrix.rotate(self.rotation) if self.snap_to_pixel: matrix.translate(int(-pivot_x), int(-pivot_y)) else: matrix.translate(-pivot_x, -pivot_y) if self.scale_x != 1 or self.scale_y != 1: matrix.scale(self.scale_x, self.scale_y) self._matrix = matrix return cairo.Matrix() * self._matrix def get_matrix(self): """return sprite's current transformation matrix""" if self.parent: return self.get_local_matrix() * (self._prev_parent_matrix or self.parent.get_matrix()) else: return self.get_local_matrix() def from_scene_coords(self, x=0, y=0): """Converts x, y given in the scene coordinates to sprite's local ones coordinates""" matrix = self.get_matrix() matrix.invert() return matrix.transform_point(x, y) def to_scene_coords(self, x=0, y=0): """Converts x, y from sprite's local coordinates to scene coordinates""" return self.get_matrix().transform_point(x, y) def _draw(self, context, opacity = 1, parent_matrix = None): if self.visible is False: return if (self._sprite_dirty): # send signal to redo the drawing when sprite is dirty self.emit("on-render") self.__dict__["_sprite_dirty"] = False no_matrix = parent_matrix is None parent_matrix = parent_matrix or cairo.Matrix() # cache parent matrix self._prev_parent_matrix = parent_matrix matrix = self.get_local_matrix() context.save() context.transform(matrix) if self.cache_as_bitmap: self.graphics._draw_as_bitmap(context, self.opacity * opacity) else: self.graphics._draw(context, self.opacity * opacity) context.new_path() #forget about us if self.debug: exts = self.get_extents() if exts: debug_colors = ["#c17d11", "#73d216", "#3465a4", "#75507b", "#cc0000", "#edd400", "#f57900"] depth = len(self.get_parents()) color = debug_colors[depth % len(debug_colors)] context.save() context.identity_matrix() scene = self.get_scene() if scene: # go figure - seems like the context we are given starts # in window coords when calling identity matrix scene_alloc = self.get_scene().get_allocation() context.translate(scene_alloc.x, scene_alloc.y) context.rectangle(exts.x, exts.y, exts.width, exts.height) context.set_source_rgb(*Colors.parse(color)) context.stroke() context.restore() for sprite in self._z_ordered_sprites: sprite._draw(context, self.opacity * opacity, matrix * parent_matrix) context.restore() # having parent and not being given parent matrix means that somebody # is calling draw directly - avoid caching matrix for such a case # because when we will get called properly it won't be respecting # the parent's transformations otherwise if isinstance(self.parent, Sprite) and no_matrix: self._prev_parent_matrix = None # using _do functions so that subclassees can override these def _do_mouse_down(self, event): self.emit("on-mouse-down", event) def _do_double_click(self, event): self.emit("on-double-click", event) def _do_triple_click(self, event): self.emit("on-triple-click", event) def _do_mouse_up(self, event): self.emit("on-mouse-up", event) def _do_click(self, event): self.emit("on-click", event) def _do_mouse_over(self): self.emit("on-mouse-over") def _do_mouse_move(self, event): self.emit("on-mouse-move", event) def _do_mouse_out(self): self.emit("on-mouse-out") def _do_focus(self): self.emit("on-focus") def _do_blur(self): self.emit("on-blur") def _do_key_press(self, event): self.emit("on-key-press", event) return False def _do_key_release(self, event): self.emit("on-key-release", event) return False class BitmapSprite(Sprite): """Caches given image data in a surface similar to targets, which ensures that drawing it will be quick and low on CPU. Image data can be either :class:`cairo.ImageSurface` or :class:`GdkPixbuf.Pixbuf` """ def __init__(self, image_data = None, cache_mode = None, **kwargs): Sprite.__init__(self, **kwargs) self.width, self.height = 0, 0 self.cache_mode = cache_mode or cairo.CONTENT_COLOR_ALPHA #: image data self.image_data = image_data self._surface = None self.connect("on-render", self.on_render) def on_render(self, sprite): if not self._surface: self.graphics.rectangle(0, 0, self.width, self.height) self.graphics.new_path() def update_surface_cache(self): """for efficiency the image data is cached on a surface similar to the target one. so if you do custom drawing after setting the image data, it won't be reflected as the sprite has no idea about what is going on there. call this function to trigger cache refresh.""" self._surface = None def __setattr__(self, name, val): if self.__dict__.get(name, "hamster_graphics_no_value_really") == val: return Sprite.__setattr__(self, name, val) if name == 'image_data': self._surface = None if self.image_data: self.__dict__['width'] = self.image_data.get_width() self.__dict__['height'] = self.image_data.get_height() def _draw(self, context, opacity = 1, parent_matrix = None): if self.image_data is None or self.width is None or self.height is None: return if not self._surface: # caching image on surface similar to the target surface = context.get_target().create_similar(self.cache_mode, self.width, self.height) local_context = cairo.Context(surface) if isinstance(self.image_data, GdkPixbuf.Pixbuf): gdk.cairo_set_source_pixbuf(local_context, self.image_data, 0, 0) else: local_context.set_source_surface(self.image_data) local_context.paint() # add instructions with the resulting surface self.graphics.clear() self.graphics.rectangle(0, 0, self.width, self.height) self.graphics.clip() self.graphics.set_source_surface(surface) self.graphics.paint() self.__dict__['_surface'] = surface Sprite._draw(self, context, opacity, parent_matrix) class Image(BitmapSprite): """Displays image by path. Currently supports only PNG images.""" def __init__(self, path, **kwargs): BitmapSprite.__init__(self, **kwargs) #: path to the image self.path = path def __setattr__(self, name, val): BitmapSprite.__setattr__(self, name, val) if name == 'path': # load when the value is set to avoid penalty on render self.image_data = cairo.ImageSurface.create_from_png(self.path) class Icon(BitmapSprite): """Displays icon by name and size in the theme""" def __init__(self, name, size=24, **kwargs): BitmapSprite.__init__(self, **kwargs) self.theme = gtk.IconTheme.get_default() #: icon name from theme self.name = name #: icon size in pixels self.size = size def __setattr__(self, name, val): BitmapSprite.__setattr__(self, name, val) if name in ('name', 'size'): # no other reason to discard cache than just on path change if self.__dict__.get('name') and self.__dict__.get('size'): self.image_data = self.theme.load_icon(self.name, self.size, 0) else: self.image_data = None class Label(Sprite): __gsignals__ = { "on-change": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } cache_attrs = Sprite.cache_attrs | set(("_letter_sizes", "__surface", "_ascent", "_bounds_width", "_measures")) def __init__(self, text = "", size = None, color = None, alignment = pango.Alignment.LEFT, single_paragraph = False, max_width = None, wrap = None, ellipsize = None, markup = "", font_desc = None, **kwargs): Sprite.__init__(self, **kwargs) self.width, self.height = None, None self._test_context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A8, 0, 0)) self._test_layout = pangocairo.create_layout(self._test_context) #: absolute font size in pixels. this will execute set_absolute_size #: instead of set_size, which is fractional self.size = size #: pango.FontDescription, defaults to system font self.font_desc = pango.FontDescription(font_desc or _font_desc) #: color of label either as hex string or an (r,g,b) tuple self.color = color self._bounds_width = None #: wrapping method. Can be set to pango. [WRAP_WORD, WRAP_CHAR, #: WRAP_WORD_CHAR] self.wrap = wrap #: Ellipsize mode. Can be set to pango.[EllipsizeMode.NONE, #: EllipsizeMode.START, EllipsizeMode.MIDDLE, EllipsizeMode.END] self.ellipsize = ellipsize #: alignment. one of pango.[Alignment.LEFT, Alignment.RIGHT, Alignment.CENTER] self.alignment = alignment #: If setting is True, do not treat newlines and similar characters as #: paragraph separators; instead, keep all text in a single paragraph, #: and display a glyph for paragraph separator characters. Used when you #: want to allow editing of newlines on a single text line. #: Defaults to False self.single_paragraph = single_paragraph #: maximum width of the label in pixels. if specified, the label #: will be wrapped or ellipsized depending on the wrap and ellpisize settings self.max_width = max_width self.__surface = None #: label text. upon setting will replace markup self.text = text #: label contents marked up using pango markup. upon setting will replace text self.markup = markup self._measures = {} self.connect("on-render", self.on_render) self.graphics_unrelated_attrs = self.graphics_unrelated_attrs | set(("__surface", "_bounds_width", "_measures")) def __setattr__(self, name, val): if name == "font_desc": if isinstance(val, str): val = pango.FontDescription(val) elif isinstance(val, pango.FontDescription): val = val.copy() if self.__dict__.get(name, "hamster_graphics_no_value_really") != val: if name == "width" and val and self.__dict__.get('_bounds_width') and val * pango.SCALE == self.__dict__['_bounds_width']: return Sprite.__setattr__(self, name, val) if name == "width": # setting width means consumer wants to contrain the label if val is None or val == -1: self.__dict__['_bounds_width'] = None else: self.__dict__['_bounds_width'] = val * pango.SCALE if name in ("width", "text", "markup", "size", "font_desc", "wrap", "ellipsize", "max_width"): self._measures = {} # avoid chicken and egg if hasattr(self, "size") and (hasattr(self, "text") or hasattr(self, "markup")): if self.size: self.font_desc.set_absolute_size(self.size * pango.SCALE) markup = getattr(self, "markup", "") self.__dict__['width'], self.__dict__['height'] = self.measure(markup or getattr(self, "text", ""), escape = len(markup) == 0) if name == 'text': if val: self.__dict__['markup'] = "" self.emit('on-change') elif name == 'markup': if val: self.__dict__['text'] = "" self.emit('on-change') def measure(self, text, escape = True, max_width = None): """measures given text with label's font and size. returns width, height and ascent. Ascent's null in case if the label does not have font face specified (and is thusly using pango)""" if escape: text = text.replace ("&", "&").replace("<", "<").replace(">", ">") if (max_width, text) in self._measures: return self._measures[(max_width, text)] width, height = None, None context = self._test_context layout = self._test_layout layout.set_font_description(self.font_desc) layout.set_markup(text) layout.set_single_paragraph_mode(self.single_paragraph) if self.alignment: layout.set_alignment(self.alignment) if self.wrap is not None: layout.set_wrap(self.wrap) layout.set_ellipsize(pango.EllipsizeMode.NONE) else: layout.set_ellipsize(self.ellipsize or pango.EllipsizeMode.END) if max_width is not None: layout.set_width(max_width * pango.SCALE) else: if self.max_width: max_width = self.max_width * pango.SCALE layout.set_width(int(self._bounds_width or max_width or -1)) width, height = layout.get_pixel_size() self._measures[(max_width, text)] = width, height return self._measures[(max_width, text)] def on_render(self, sprite): if not self.text and not self.markup: self.graphics.clear() return self.graphics.set_color(self.color) rect_width = self.width max_width = 0 if self.max_width: max_width = self.max_width * pango.SCALE # when max width is specified and we are told to align in center # do that (the pango instruction takes care of aligning within # the lines of the text) if self.alignment == pango.Alignment.CENTER: self.graphics.move_to(-(self.max_width - self.width)/2, 0) bounds_width = max_width or self._bounds_width or -1 text = "" if self.markup: text = self.markup else: # otherwise escape pango text = self.text.replace ("&", "&").replace("<", "<").replace(">", ">") self.graphics.show_layout(text, self.font_desc, self.alignment, bounds_width, self.wrap, self.ellipsize, self.single_paragraph) if self._bounds_width: rect_width = self._bounds_width / pango.SCALE self.graphics.rectangle(0, 0, rect_width, self.height) self.graphics.clip() class Rectangle(Sprite): def __init__(self, w, h, corner_radius = 0, fill = None, stroke = None, line_width = 1, **kwargs): Sprite.__init__(self, **kwargs) #: width self.width = w #: height self.height = h #: fill color self.fill = fill #: stroke color self.stroke = stroke #: stroke line width self.line_width = line_width #: corner radius. Set bigger than 0 for rounded corners self.corner_radius = corner_radius self.connect("on-render", self.on_render) def on_render(self, sprite): self.graphics.set_line_style(width = self.line_width) self.graphics.rectangle(0, 0, self.width, self.height, self.corner_radius) self.graphics.fill_stroke(self.fill, self.stroke, line_width = self.line_width) class Polygon(Sprite): def __init__(self, points, fill = None, stroke = None, line_width = 1, **kwargs): Sprite.__init__(self, **kwargs) #: list of (x,y) tuples that the line should go through. Polygon #: will automatically close path. self.points = points #: fill color self.fill = fill #: stroke color self.stroke = stroke #: stroke line width self.line_width = line_width self.connect("on-render", self.on_render) def on_render(self, sprite): if not self.points: self.graphics.clear() return self.graphics.move_to(*self.points[0]) self.graphics.line_to(self.points) if self.fill: self.graphics.close_path() self.graphics.fill_stroke(self.fill, self.stroke, line_width = self.line_width) class Circle(Sprite): def __init__(self, width, height, fill = None, stroke = None, line_width = 1, **kwargs): Sprite.__init__(self, **kwargs) #: circle width self.width = width #: circle height self.height = height #: fill color self.fill = fill #: stroke color self.stroke = stroke #: stroke line width self.line_width = line_width self.connect("on-render", self.on_render) def on_render(self, sprite): if self.width == self.height: radius = self.width / 2.0 self.graphics.circle(radius, radius, radius) else: self.graphics.ellipse(0, 0, self.width, self.height) self.graphics.fill_stroke(self.fill, self.stroke, line_width = self.line_width) class Scene(Parent, gtk.DrawingArea): """ Drawing area for displaying sprites. Add sprites to the Scene by calling :func:`add_child`. Scene is descendant of `gtk.DrawingArea `_ and thus inherits all it's methods and everything. """ __gsignals__ = { # "draw": "override", # "configure_event": "override", "on-first-frame": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), "on-enter-frame": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), "on-finish-frame": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), "on-resize": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, )), "on-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), "on-drag": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), "on-drag-start": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), "on-drag-finish": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), "on-mouse-move": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-down": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-double-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-triple-click": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-up": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-over": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-out": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-mouse-scroll": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-key-press": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), "on-key-release": (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } def __init__(self, interactive = True, framerate = 60, background_color = None, scale = False, keep_aspect = True, style_class=None): gtk.DrawingArea.__init__(self) self._style = self.get_style_context() #: widget style. One of gtk.STYLE_CLASS_*. By default it's BACKGROUND self.style_class = style_class or gtk.STYLE_CLASS_BACKGROUND self._style.add_class(self.style_class) # so we know our colors #: list of sprites in scene. use :func:`add_child` to add sprites self.sprites = [] self._z_ordered_sprites = [] # a place where to store child handlers self.__dict__['_child_handlers'] = defaultdict(list) #: framerate of animation. This will limit how often call for #: redraw will be performed (that is - not more often than the framerate). It will #: also influence the smoothness of tweeners. self.framerate = framerate #: Scene width. Will be `None` until first expose (that is until first #: on-enter-frame signal below). self.width = None #: Scene height. Will be `None` until first expose (that is until first #: on-enter-frame signal below). self.height = None #: instance of :class:`pytweener.Tweener` that is used by #: :func:`animate` function, but can be also accessed directly for advanced control. self.tweener = False if pytweener: self.tweener = pytweener.Tweener(0.4, pytweener.Easing.Cubic.ease_in_out) #: instance of :class:`ColorUtils` class for color parsing self.colors = Colors #: read only info about current framerate (frames per second) self.fps = None # inner frames per second counter self._window = None # scenes don't really get reparented #: Last known x position of the mouse (set on expose event) self.mouse_x = None #: Last known y position of the mouse (set on expose event) self.mouse_y = None #: Background color of the scene. Use either a string with hex color or an RGB triplet. self.background_color = background_color #: Mouse cursor appearance. #: Replace with your own cursor or set to False to have no cursor. #: None will revert back the default behavior self.mouse_cursor = None #: in contrast to the mouse cursor, this one is merely a suggestion and #: can be overidden by child sprites self.default_mouse_cursor = None self._blank_cursor = gdk.Cursor(gdk.CursorType.BLANK_CURSOR) self.__previous_mouse_signal_time = None #: Miminum distance in pixels for a drag to occur self.drag_distance = 1 self._last_frame_time = None self._mouse_sprite = None self._drag_sprite = None self._mouse_down_sprite = None self.__drag_started = False self.__drag_start_x, self.__drag_start_y = None, None self._mouse_in = False self.__last_cursor = None self.__drawing_queued = False #: When specified, upon window resize the content will be scaled #: relative to original window size. Defaults to False. self.scale = scale #: Should the stage maintain aspect ratio upon scale if #: :attr:`Scene.scale` is enabled. Defaults to true. self.keep_aspect = keep_aspect self._original_width, self._original_height = None, None self._focus_sprite = None # our internal focus management self.__last_mouse_move = None self.connect("realize", self.__on_realize) if interactive: self.set_can_focus(True) self.set_events(gdk.EventMask.POINTER_MOTION_MASK | gdk.EventMask.LEAVE_NOTIFY_MASK | gdk.EventMask.ENTER_NOTIFY_MASK | gdk.EventMask.BUTTON_PRESS_MASK | gdk.EventMask.BUTTON_RELEASE_MASK | gdk.EventMask.SCROLL_MASK | gdk.EventMask.KEY_PRESS_MASK) self.connect("motion-notify-event", self.__on_mouse_move) self.connect("enter-notify-event", self.__on_mouse_enter) self.connect("leave-notify-event", self.__on_mouse_leave) self.connect("button-press-event", self.__on_button_press) self.connect("button-release-event", self.__on_button_release) self.connect("scroll-event", self.__on_scroll) self.connect("key-press-event", self.__on_key_press) self.connect("key-release-event", self.__on_key_release) def __setattr__(self, name, val): if self.__dict__.get(name, "hamster_graphics_no_value_really") is val: return if name == '_focus_sprite': prev_focus = getattr(self, '_focus_sprite', None) if prev_focus: prev_focus.focused = False self.__dict__['_focus_sprite'] = val # drop cache to avoid echoes prev_focus._do_blur() if val: val.focused = True val._do_focus() elif name == "style_class": if hasattr(self, "style_class"): self._style.remove_class(self.style_class) self._style.add_class(val) elif name == "background_color": if val: self.override_background_color(gtk.StateType.NORMAL, gdk.RGBA(*Colors.parse(val))) else: self.override_background_color(gtk.StateType.NORMAL, None) self.__dict__[name] = val # these two mimic sprite functions so parent check can be avoided def from_scene_coords(self, x, y): return x, y def to_scene_coords(self, x, y): return x, y def get_matrix(self): return cairo.Matrix() def get_scene(self): return self def animate(self, sprite, duration = None, easing = None, on_complete = None, on_update = None, round = False, **kwargs): """Interpolate attributes of the given object using the internal tweener and redrawing scene after every tweener update. Specify the sprite and sprite's attributes that need changing. `duration` defaults to 0.4 seconds and `easing` to cubic in-out (for others see pytweener.Easing class). Redraw is requested right after creating the animation. Example:: # tween some_sprite to coordinates (50,100) using default duration and easing scene.animate(some_sprite, x = 50, y = 100) """ if not self.tweener: # here we complain raise Exception("pytweener was not found. Include it to enable animations") tween = self.tweener.add_tween(sprite, duration=duration, easing=easing, on_complete=on_complete, on_update=on_update, round=round, **kwargs) self.redraw() return tween def stop_animation(self, sprites): """stop animation without firing on_complete""" if isinstance(sprites, list) is False: sprites = [sprites] for sprite in sprites: self.tweener.kill_tweens(sprite) def redraw(self): """Queue redraw. The redraw will be performed not more often than the `framerate` allows""" if self.__drawing_queued == False: #if we are moving, then there is a timeout somewhere already self.__drawing_queued = True self._last_frame_time = dt.datetime.now() gobject.timeout_add(1000 / self.framerate, self.__redraw_loop) def __redraw_loop(self): """loop until there is nothing more to tween""" self.queue_draw() # this will trigger do_expose_event when the current events have been flushed self.__drawing_queued = self.tweener and self.tweener.has_tweens() return self.__drawing_queued def do_draw(self, context): if self.scale: aspect_x = self.width / self._original_width aspect_y = self.height / self._original_height if self.keep_aspect: aspect_x = aspect_y = min(aspect_x, aspect_y) context.scale(aspect_x, aspect_y) if self.fps is None: self.emit("on-first-frame", context) cursor, self.mouse_x, self.mouse_y, mods = self._window.get_pointer() # update tweens now = dt.datetime.now() delta = (now - (self._last_frame_time or dt.datetime.now())).total_seconds() self._last_frame_time = now if self.tweener: self.tweener.update(delta) self.fps = 1 / delta # start drawing self.emit("on-enter-frame", context) for sprite in self._z_ordered_sprites: sprite._draw(context) self.__check_mouse(self.mouse_x, self.mouse_y) self.emit("on-finish-frame", context) # reset the mouse signal time as redraw means we are good now self.__previous_mouse_signal_time = None def do_configure_event(self, event): if self._original_width is None: self._original_width = float(event.width) self._original_height = float(event.height) width, height = self.width, self.height self.width, self.height = event.width, event.height if width != event.width or height != event.height: self.emit("on-resize", event) # so that sprites can listen to it def all_mouse_sprites(self): """Returns flat list of the sprite tree for simplified iteration""" def all_recursive(sprites): if not sprites: return for sprite in sprites: if sprite.visible: yield sprite for child in all_recursive(sprite.get_mouse_sprites()): yield child return all_recursive(self.get_mouse_sprites()) def get_sprite_at_position(self, x, y): """Returns the topmost visible interactive sprite for given coordinates""" over = None for sprite in self.all_mouse_sprites(): if sprite.interactive and sprite.check_hit(x, y): over = sprite return over def __check_mouse(self, x, y): if x is None or self._mouse_in == False: return cursor = None over = None if self.mouse_cursor is not None: cursor = self.mouse_cursor if cursor is None and self._drag_sprite: drag_cursor = self._drag_sprite._get_mouse_cursor() if drag_cursor: cursor = drag_cursor #check if we have a mouse over if self._drag_sprite is None: over = self.get_sprite_at_position(x, y) if self._mouse_sprite and self._mouse_sprite != over: self._mouse_sprite._do_mouse_out() self.emit("on-mouse-out", self._mouse_sprite) if over and cursor is None: sprite_cursor = over._get_mouse_cursor() if sprite_cursor: cursor = sprite_cursor if over and over != self._mouse_sprite: over._do_mouse_over() self.emit("on-mouse-over", over) self._mouse_sprite = over if cursor is None: cursor = self.default_mouse_cursor or gdk.CursorType.ARROW # default elif cursor is False: cursor = self._blank_cursor if self.__last_cursor is None or cursor != self.__last_cursor: if isinstance(cursor, gdk.Cursor): self._window.set_cursor(cursor) else: self._window.set_cursor(gdk.Cursor(cursor)) self.__last_cursor = cursor """ mouse events """ def __on_mouse_move(self, scene, event): if self.__last_mouse_move: gobject.source_remove(self.__last_mouse_move) self.__last_mouse_move = None self.mouse_x, self.mouse_y = event.x, event.y # don't emit mouse move signals more often than every 0.05 seconds timeout = dt.timedelta(seconds=0.05) if self.__previous_mouse_signal_time and dt.datetime.now() - self.__previous_mouse_signal_time < timeout: self.__last_mouse_move = gobject.timeout_add((timeout - (dt.datetime.now() - self.__previous_mouse_signal_time)).microseconds / 1000, self.__on_mouse_move, scene, event.copy()) return state = event.state if self._mouse_down_sprite and self._mouse_down_sprite.interactive \ and self._mouse_down_sprite.draggable and gdk.ModifierType.BUTTON1_MASK & event.state: # dragging around if not self.__drag_started: drag_started = (self.__drag_start_x is not None and \ (self.__drag_start_x - event.x) ** 2 + \ (self.__drag_start_y - event.y) ** 2 > self.drag_distance ** 2) if drag_started: self._drag_sprite = self._mouse_down_sprite self._mouse_down_sprite.emit("on-drag-start", event) self.emit("on-drag-start", self._drag_sprite, event) self.start_drag(self._drag_sprite, self.__drag_start_x, self.__drag_start_y) else: # avoid double mouse checks - the redraw will also check for mouse! if not self.__drawing_queued: self.__check_mouse(event.x, event.y) if self._drag_sprite: diff_x, diff_y = event.x - self.__drag_start_x, event.y - self.__drag_start_y if isinstance(self._drag_sprite.parent, Sprite): matrix = self._drag_sprite.parent.get_matrix() matrix.invert() diff_x, diff_y = matrix.transform_distance(diff_x, diff_y) self._drag_sprite.x, self._drag_sprite.y = self._drag_sprite.drag_x + diff_x, self._drag_sprite.drag_y + diff_y self._drag_sprite.emit("on-drag", event) self.emit("on-drag", self._drag_sprite, event) if self._mouse_sprite: sprite_event = event.copy() sprite_event.x, sprite_event.y = self._mouse_sprite.from_scene_coords(event.x, event.y) self._mouse_sprite._do_mouse_move(sprite_event) self.emit("on-mouse-move", event) self.__previous_mouse_signal_time = dt.datetime.now() def start_drag(self, sprite, cursor_x = None, cursor_y = None): """start dragging given sprite""" cursor_x, cursor_y = cursor_x or sprite.x, cursor_y or sprite.y self._mouse_down_sprite = self._drag_sprite = sprite sprite.drag_x, sprite.drag_y = self._drag_sprite.x, self._drag_sprite.y self.__drag_start_x, self.__drag_start_y = cursor_x, cursor_y self.__drag_started = True def __on_mouse_enter(self, scene, event): self._mouse_in = True def __on_mouse_leave(self, scene, event): self._mouse_in = False if self._mouse_sprite: self._mouse_sprite._do_mouse_out() self.emit("on-mouse-out", self._mouse_sprite) self._mouse_sprite = None def __on_button_press(self, scene, event): target = self.get_sprite_at_position(event.x, event.y) if not self.__drag_started: self.__drag_start_x, self.__drag_start_y = event.x, event.y self._mouse_down_sprite = target # differentiate between the click count! if event.type == gdk.EventType.BUTTON_PRESS: self.emit("on-mouse-down", event) if target: target_event = event.copy() target_event.x, target_event.y = target.from_scene_coords(event.x, event.y) target._do_mouse_down(target_event) else: scene._focus_sprite = None # lose focus if mouse ends up nowhere elif event.type == gdk.EventType._2BUTTON_PRESS: self.emit("on-double-click", event) if target: target_event = event.copy() target_event.x, target_event.y = target.from_scene_coords(event.x, event.y) target._do_double_click(target_event) elif event.type == gdk.EventType._3BUTTON_PRESS: self.emit("on-triple-click", event) if target: target_event = event.copy() target_event.x, target_event.y = target.from_scene_coords(event.x, event.y) target._do_triple_click(target_event) self.__check_mouse(event.x, event.y) return True def __on_button_release(self, scene, event): target = self.get_sprite_at_position(event.x, event.y) if target: target._do_mouse_up(event) self.emit("on-mouse-up", event) # trying to not emit click and drag-finish at the same time click = not self.__drag_started or (event.x - self.__drag_start_x) ** 2 + \ (event.y - self.__drag_start_y) ** 2 < self.drag_distance if (click and self.__drag_started == False) or not self._drag_sprite: if target and target == self._mouse_down_sprite: target_event = event.copy() target_event.x, target_event.y = target.from_scene_coords(event.x, event.y) target._do_click(target_event) self.emit("on-click", event, target) self._mouse_down_sprite = None self.__drag_started = False self.__drag_start_x, self__drag_start_y = None, None if self._drag_sprite: self._drag_sprite.drag_x, self._drag_sprite.drag_y = None, None drag_sprite, self._drag_sprite = self._drag_sprite, None drag_sprite.emit("on-drag-finish", event) self.emit("on-drag-finish", drag_sprite, event) self.__check_mouse(event.x, event.y) return True def __on_realize(self, widget): # Store as soon as available. Maybe for performance reasons, # to avoid get_window() calls in __on_mouse_move ? self._window = self.get_window() def __on_scroll(self, scene, event): target = self.get_sprite_at_position(event.x, event.y) if target: target.emit("on-mouse-scroll", event) self.emit("on-mouse-scroll", event) return True def __on_key_press(self, scene, event): handled = False if self._focus_sprite: handled = self._focus_sprite._do_key_press(event) if not handled: self.emit("on-key-press", event) return True def __on_key_release(self, scene, event): handled = False if self._focus_sprite: handled = self._focus_sprite._do_key_release(event) if not handled: self.emit("on-key-release", event) return True hamster-3.0.3/src/hamster/lib/i18n.py000066400000000000000000000022141452646177100173250ustar00rootroot00000000000000# - coding: utf-8 - import os import locale, gettext import hamster def setup_i18n(): #determine location of po files # to avoid confusion, we won't translate unless running installed # reason for that is that bindtextdomain is expecting # localedir/language/LC_MESSAGES/domain.mo format, but we have # localedir/language.mo at it's best (after build) # and there does not seem to be any way to run straight from sources if hamster.installed: from hamster import defs # only available when running installed locale_dir = os.path.realpath(os.path.join(defs.DATA_DIR, "locale")) for module in (locale,gettext): module.bindtextdomain('hamster', locale_dir) module.textdomain('hamster') gettext.install("hamster", locale_dir) else: gettext.install("hamster-uninstalled") def C_(ctx, s): """Provide qualified translatable strings via context. Taken from gnome-games. """ translated = gettext.gettext('%s\x04%s' % (ctx, s)) if '\x04' in translated: # no translation found, return input string return s return translated hamster-3.0.3/src/hamster/lib/layout.py000066400000000000000000001100751452646177100200700ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (c) 2011-2012 Media Modifications, Ltd. # Copyright (c) 2014 Toms Baugis # Dual licensed under the MIT or GPL Version 2 licenses. import math from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import GObject as gobject from gi.repository import Pango as pango from collections import defaultdict from hamster.lib import datetime as dt from hamster.lib import graphics class Widget(graphics.Sprite): """Base class for all widgets. You can use the width and height attributes to request a specific width.""" _sizing_attributes = set(("visible", "min_width", "min_height", "expand", "fill", "spacing", "horizontal_spacing", "vertical_spacing", "x_align", "y_align")) min_width = None #: minimum width of the widget min_height = None #: minimum height of the widget #: Whether the child should receive extra space when the parent grows. expand = True #: Whether extra space given to the child should be allocated to the #: child or used as padding. Edit :attr:`x_align` and #: :attr:`y_align` properties to adjust alignment when fill is set to False. fill = True #: horizontal alignment within the parent. Works when :attr:`fill` is False x_align = 0.5 #: vertical alignment within the parent. Works when :attr:`fill` is False y_align = 0.5 #: child padding - shorthand to manipulate padding in pixels ala CSS. tuple #: of one to four elements. Setting this value overwrites values of #: :attr:`padding_top`, :attr:`padding_right`, :attr:`padding_bottom` #: and :attr:`padding_left` padding = None padding_top = None #: child padding - top padding_right = None #: child padding - right padding_bottom = None #: child padding - bottom padding_left = None #: child padding - left #: widget margins - shorthand to manipulate margin in pixels ala CSS. tuple #: of one to four elements. Setting this value overwrites values of #: :attr:`margin_top`, :attr:`margin_right`, :attr:`margin_bottom` and #: :attr:`margin_left` margin = 0 margin_top = 0 #: top margin margin_right = 0 #: right margin margin_bottom = 0 #: bottom margin margin_left = 0 #: left margin enabled = True #: whether the widget is enabled mouse_cursor = False #: Mouse cursor. see :attr:`graphics.Sprite.mouse_cursor` for values def __init__(self, width = None, height = None, expand = None, fill = None, x_align = None, y_align = None, padding_top = None, padding_right = None, padding_bottom = None, padding_left = None, padding = None, margin_top = None, margin_right = None, margin_bottom = None, margin_left = None, margin = None, enabled = None, **kwargs): graphics.Sprite.__init__(self, **kwargs) def set_if_not_none(name, val): # set values - avoid pitfalls of None vs 0/False if val is not None: setattr(self, name, val) set_if_not_none("min_width", width) set_if_not_none("min_height", height) self._enabled = enabled if enabled is not None else self.__class__.enabled set_if_not_none("fill", fill) set_if_not_none("expand", expand) set_if_not_none("x_align", x_align) set_if_not_none("y_align", y_align) # set padding # (class, subclass, instance, and constructor) if padding is not None or self.padding is not None: self.padding = padding if padding is not None else self.padding self.padding_top = padding_top or self.__class__.padding_top or self.padding_top or 0 self.padding_right = padding_right or self.__class__.padding_right or self.padding_right or 0 self.padding_bottom = padding_bottom or self.__class__.padding_bottom or self.padding_bottom or 0 self.padding_left = padding_left or self.__class__.padding_left or self.padding_left or 0 if margin is not None or self.margin is not None: self.margin = margin if margin is not None else self.margin self.margin_top = margin_top or self.__class__.margin_top or self.margin_top or 0 self.margin_right = margin_right or self.__class__.margin_right or self.margin_right or 0 self.margin_bottom = margin_bottom or self.__class__.margin_bottom or self.margin_bottom or 0 self.margin_left = margin_left or self.__class__.margin_left or self.margin_left or 0 #: width in pixels that have been allocated to the widget by parent self.alloc_w = width if width is not None else self.min_width #: height in pixels that have been allocated to the widget by parent self.alloc_h = height if height is not None else self.min_height self.connect_after("on-render", self.__on_render) self.connect("on-mouse-over", self.__on_mouse_over) self.connect("on-mouse-out", self.__on_mouse_out) self.connect("on-mouse-down", self.__on_mouse_down) self.connect("on-key-press", self.__on_key_press) self._children_resize_queued = True self._scene_resize_handler = None def __setattr__(self, name, val): # forward width and height to min_width and min_height as i've ruined the setters a bit i think if name == "width": name = "min_width" elif name == "height": name = "min_height" elif name == 'enabled': name = '_enabled' elif name == "padding": val = val or 0 if isinstance(val, int): val = (val, ) if len(val) == 1: self.padding_top = self.padding_right = self.padding_bottom = self.padding_left = val[0] elif len(val) == 2: self.padding_top = self.padding_bottom = val[0] self.padding_right = self.padding_left = val[1] elif len(val) == 3: self.padding_top = val[0] self.padding_right = self.padding_left = val[1] self.padding_bottom = val[2] elif len(val) == 4: self.padding_top, self.padding_right, self.padding_bottom, self.padding_left = val return elif name == "margin": val = val or 0 if isinstance(val, int): val = (val, ) if len(val) == 1: self.margin_top = self.margin_right = self.margin_bottom = self.margin_left = val[0] elif len(val) == 2: self.margin_top = self.margin_bottom = val[0] self.margin_right = self.margin_left = val[1] elif len(val) == 3: self.margin_top = val[0] self.margin_right = self.margin_left = val[1] self.margin_bottom = val[2] elif len(val) == 4: self.margin_top, self.margin_right, self.margin_bottom, self.margin_left = val return if self.__dict__.get(name, "hamster_graphics_no_value_really") == val: return graphics.Sprite.__setattr__(self, name, val) # in widget case visibility affects placement and everything so request repositioning from parent if name == 'visible' and getattr(self, "parent", None) and getattr(self.parent, "resize_children", None): self.parent.resize_children() elif name == '_enabled' and getattr(self, "sprites", None): self._propagate_enabledness() if name in self._sizing_attributes: self.queue_resize() def _propagate_enabledness(self): # runs down the tree and marks all child sprites as dirty as # enabledness is inherited self._sprite_dirty = True for sprite in self.sprites: next_call = getattr(sprite, "_propagate_enabledness", None) if next_call: next_call() def _with_rotation(self, w, h): """calculate the actual dimensions after rotation""" res_w = abs(w * math.cos(self.rotation) + h * math.sin(self.rotation)) res_h = abs(h * math.cos(self.rotation) + w * math.sin(self.rotation)) return res_w, res_h @property def horizontal_padding(self): """total calculated horizontal padding. A read-only property.""" return self.padding_left + self.padding_right @property def vertical_padding(self): """total calculated vertical padding. A read-only property.""" return self.padding_top + self.padding_bottom def __on_mouse_over(self, sprite): cursor, mouse_x, mouse_y, mods = sprite.get_scene().get_window().get_pointer() if self.tooltip and not gdk.ModifierType.BUTTON1_MASK & mods: self._set_tooltip(self.tooltip) def __on_mouse_out(self, sprite): if self.tooltip: self._set_tooltip(None) def __on_mouse_down(self, sprite, event): if self.can_focus: self.grab_focus() if self.tooltip: self._set_tooltip(None) def __on_key_press(self, sprite, event): if event.keyval in (gdk.KEY_Tab, gdk.KEY_ISO_Left_Tab): idx = self.parent.sprites.index(self) if event.state & gdk.ModifierType.SHIFT_MASK: # going backwards if idx > 0: idx -= 1 self.parent.sprites[idx].grab_focus() else: if idx < len(self.parent.sprites) - 1: idx += 1 self.parent.sprites[idx].grab_focus() def queue_resize(self): """request the element to re-check it's child sprite sizes""" self._children_resize_queued = True parent = getattr(self, "parent", None) if parent and isinstance(parent, graphics.Sprite) and hasattr(parent, "queue_resize"): parent.queue_resize() def get_min_size(self): """returns size required by the widget""" if self.visible == False: return 0, 0 else: return ((self.min_width or 0) + self.horizontal_padding + self.margin_left + self.margin_right, (self.min_height or 0) + self.vertical_padding + self.margin_top + self.margin_bottom) def insert(self, index = 0, *widgets): """insert widget in the sprites list at the given index. by default will prepend.""" for widget in widgets: self._add(widget, index) index +=1 # as we are moving forwards self._sort() def insert_before(self, target): """insert this widget into the targets parent before the target""" if not target.parent: return target.parent.insert(target.parent.sprites.index(target), self) def insert_after(self, target): """insert this widget into the targets parent container after the target""" if not target.parent: return target.parent.insert(target.parent.sprites.index(target) + 1, self) @property def width(self): """width in pixels""" alloc_w = self.alloc_w if self.parent and isinstance(self.parent, graphics.Scene): alloc_w = self.parent.width def res(scene, event): if self.parent: self.queue_resize() else: scene.disconnect(self._scene_resize_handler) self._scene_resize_handler = None if not self._scene_resize_handler: # TODO - disconnect on reparenting self._scene_resize_handler = self.parent.connect("on-resize", res) min_width = (self.min_width or 0) + self.margin_left + self.margin_right w = alloc_w if alloc_w is not None and self.fill else min_width w = max(w or 0, self.get_min_size()[0]) return w - self.margin_left - self.margin_right @property def height(self): """height in pixels""" alloc_h = self.alloc_h if self.parent and isinstance(self.parent, graphics.Scene): alloc_h = self.parent.height min_height = (self.min_height or 0) + self.margin_top + self.margin_bottom h = alloc_h if alloc_h is not None and self.fill else min_height h = max(h or 0, self.get_min_size()[1]) return h - self.margin_top - self.margin_bottom @property def enabled(self): """whether the user is allowed to interact with the widget. Item is enabled only if all it's parent elements are""" enabled = self._enabled if not enabled: return False if self.parent and isinstance(self.parent, Widget): if self.parent.enabled == False: return False return True def __on_render(self, sprite): self.do_render() if self.debug: self.graphics.save_context() w, h = self.width, self.height if hasattr(self, "get_height_for_width_size"): w2, h2 = self.get_height_for_width_size() w2 = w2 - self.margin_left - self.margin_right h2 = h2 - self.margin_top - self.margin_bottom w, h = max(w, w2), max(h, h2) self.graphics.rectangle(0.5, 0.5, w, h) self.graphics.set_line_style(3) self.graphics.stroke("#666", 0.5) self.graphics.restore_context() if self.pivot_x or self.pivot_y: self.graphics.fill_area(self.pivot_x - 3, self.pivot_y - 3, 6, 6, "#666") def do_render(self): """this function is called in the on-render event. override it to do any drawing. subscribing to the "on-render" event will work too, but overriding this method is preferred for easier subclassing. """ pass def get_min_size(sprite): if hasattr(sprite, "get_min_size"): min_width, min_height = sprite.get_min_size() else: min_width, min_height = getattr(sprite, "width", 0), getattr(sprite, "height", 0) min_width = min_width * sprite.scale_x min_height = min_height * sprite.scale_y return min_width, min_height def get_props(sprite): # gets all the relevant info for containers and puts it in a uniform dict. # this way we can access any object without having to check types and such keys = ("margin_top", "margin_right", "margin_bottom", "margin_left", "padding_top", "padding_right", "padding_bottom", "padding_left") res = dict((key, getattr(sprite, key, 0)) for key in keys) res["expand"] = getattr(sprite, "expand", True) return sprite, res class Container(Widget): """The base container class that all other containers inherit from. You can insert any sprite in the container, just make sure that it either has width and height defined so that the container can do alignment, or for more sophisticated cases, make sure it has get_min_size function that returns how much space is needed. Normally while performing layout the container will update child sprites and set their alloc_h and alloc_w properties. The `alloc` part is short for allocated. So use that when making rendering decisions. """ cache_attrs = Widget.cache_attrs | set(('_cached_w', '_cached_h')) _sizing_attributes = Widget._sizing_attributes | set(('padding_top', 'padding_right', 'padding_bottom', 'padding_left')) def __init__(self, contents = None, **kwargs): Widget.__init__(self, **kwargs) #: contents of the container - either a widget or a list of widgets self.contents = contents self._cached_w, self._cached_h = None, None def __setattr__(self, name, val): if self.__dict__.get(name, "hamster_graphics_no_value_really") == val: return Widget.__setattr__(self, name, val) if name == 'contents': if val: if isinstance(val, graphics.Sprite): val = [val] self.add_child(*val) if self.sprites and self.sprites != val: self.remove_child(*list(set(self.sprites) ^ set(val or []))) if name in ("alloc_w", "alloc_h") and val: self.__dict__['_cached_w'], self.__dict__['_cached_h'] = None, None self._children_resize_queued = True @property def contents(self): return self.sprites def _Widget__on_render(self, sprite): if self._children_resize_queued: self.resize_children() self.__dict__['_children_resize_queued'] = False Widget._Widget__on_render(self, sprite) def _add(self, *sprites): Widget._add(self, *sprites) self.queue_resize() def remove_child(self, *sprites): Widget.remove_child(self, *sprites) self.queue_resize() def queue_resize(self): self.__dict__['_cached_w'], self.__dict__['_cached_h'] = None, None Widget.queue_resize(self) def get_min_size(self): # by default max between our requested size and the biggest child if self.visible == False: return 0, 0 if self._cached_w is None: sprites = [sprite for sprite in self.sprites if sprite.visible] width = max([get_min_size(sprite)[0] for sprite in sprites] or [0]) width += self.horizontal_padding + self.margin_left + self.margin_right height = max([get_min_size(sprite)[1] for sprite in sprites] or [0]) height += self.vertical_padding + self.margin_top + self.margin_bottom self._cached_w, self._cached_h = max(width, self.min_width or 0), max(height, self.min_height or 0) return self._cached_w, self._cached_h def get_height_for_width_size(self): return self.get_min_size() def resize_children(self): """default container alignment is to pile stuff just up, respecting only padding, margin and element's alignment properties""" width = self.width - self.horizontal_padding height = self.height - self.vertical_padding for sprite, props in (get_props(sprite) for sprite in self.sprites if sprite.visible): sprite.alloc_w = width sprite.alloc_h = height w, h = getattr(sprite, "width", 0), getattr(sprite, "height", 0) if hasattr(sprite, "get_height_for_width_size"): w2, h2 = sprite.get_height_for_width_size() w, h = max(w, w2), max(h, h2) w = w * sprite.scale_x + props["margin_left"] + props["margin_right"] h = h * sprite.scale_y + props["margin_top"] + props["margin_bottom"] sprite.x = self.padding_left + props["margin_left"] + (max(sprite.alloc_w * sprite.scale_x, w) - w) * getattr(sprite, "x_align", 0) sprite.y = self.padding_top + props["margin_top"] + (max(sprite.alloc_h * sprite.scale_y, h) - h) * getattr(sprite, "y_align", 0) self.__dict__['_children_resize_queued'] = False class Bin(Container): """A container with only one child. Adding new children will throw the previous ones out""" def __init__(self, contents = None, **kwargs): Container.__init__(self, contents, **kwargs) @property def child(self): """child sprite. shorthand for self.sprites[0]""" return self.sprites[0] if self.sprites else None def get_height_for_width_size(self): if self._children_resize_queued: self.resize_children() sprites = [sprite for sprite in self.sprites if sprite.visible] width, height = 0, 0 for sprite in sprites: if hasattr(sprite, "get_height_for_width_size"): w, h = sprite.get_height_for_width_size() else: w, h = getattr(sprite, "width", 0), getattr(sprite, "height", 0) w, h = w * sprite.scale_x, h * sprite.scale_y width = max(width, w) height = max(height, h) #width = width + self.horizontal_padding + self.margin_left + self.margin_right #height = height + self.vertical_padding + self.margin_top + self.margin_bottom return width, height def add_child(self, *sprites): if not sprites: return sprite = sprites[-1] # there can be just one # performing add then remove to not screw up coordinates in # a strange reparenting case Container.add_child(self, sprite) if self.sprites and self.sprites[0] != sprite: self.remove_child(*list(set(self.sprites) ^ set([sprite]))) class Fixed(Container): """Basic container that does not care about child positions. Handy if you want to place stuff yourself or do animations. """ def __init__(self, contents = None, **kwargs): Container.__init__(self, contents, **kwargs) def resize_children(self): # don't want pass class Box(Container): """Align children either horizontally or vertically. Normally you would use :class:`HBox` or :class:`VBox` to be specific but this one is suited so you can change the packing direction dynamically. """ #: spacing in pixels between children spacing = 5 #: whether the box is packing children horizontally (from left to right) or vertically (from top to bottom) orient_horizontal = True def __init__(self, contents = None, horizontal = None, spacing = None, **kwargs): Container.__init__(self, contents, **kwargs) if horizontal is not None: self.orient_horizontal = horizontal if spacing is not None: self.spacing = spacing def get_total_spacing(self): # now lay them out padding_sprites = 0 for sprite in self.sprites: if sprite.visible: if getattr(sprite, "expand", True): padding_sprites += 1 else: if hasattr(sprite, "get_min_size"): size = sprite.get_min_size()[0] if self.orient_horizontal else sprite.get_min_size()[1] else: size = getattr(sprite, "width", 0) * sprite.scale_x if self.orient_horizontal else getattr(sprite, "height", 0) * sprite.scale_y if size > 0: padding_sprites +=1 return self.spacing * max(padding_sprites - 1, 0) def resize_children(self): if not self.parent: return width = self.width - self.padding_left - self.padding_right height = self.height - self.padding_top - self.padding_bottom sprites = [get_props(sprite) for sprite in self.sprites if sprite.visible] # calculate if we have any spare space sprite_sizes = [] for sprite, props in sprites: if self.orient_horizontal: sprite.alloc_h = height / sprite.scale_y size = get_min_size(sprite)[0] size = size + props["margin_left"] + props["margin_right"] else: sprite.alloc_w = width / sprite.scale_x size = get_min_size(sprite)[1] if hasattr(sprite, "get_height_for_width_size"): size = max(size, sprite.get_height_for_width_size()[1] * sprite.scale_y) size = size + props["margin_top"] + props["margin_bottom"] sprite_sizes.append(size) remaining_space = width if self.orient_horizontal else height if sprite_sizes: remaining_space = remaining_space - sum(sprite_sizes) - self.get_total_spacing() interested_sprites = [sprite for sprite, props in sprites if getattr(sprite, "expand", True)] # in order to stay pixel sharp we will recalculate remaining bonus # each time we give up some of the remaining space remaining_interested = len(interested_sprites) bonus = 0 if remaining_space > 0 and interested_sprites: bonus = int(remaining_space / remaining_interested) actual_h = 0 x_pos, y_pos = 0, 0 for (sprite, props), min_size in zip(sprites, sprite_sizes): sprite_bonus = 0 if sprite in interested_sprites: sprite_bonus = bonus remaining_interested -= 1 remaining_space -= bonus if remaining_interested: bonus = int(float(remaining_space) / remaining_interested) if self.orient_horizontal: sprite.alloc_w = (min_size + sprite_bonus) / sprite.scale_x else: sprite.alloc_h = (min_size + sprite_bonus) / sprite.scale_y w, h = getattr(sprite, "width", 0), getattr(sprite, "height", 0) if hasattr(sprite, "get_height_for_width_size"): w2, h2 = sprite.get_height_for_width_size() w, h = max(w, w2), max(h, h2) w = w * sprite.scale_x + props["margin_left"] + props["margin_right"] h = h * sprite.scale_y + props["margin_top"] + props["margin_bottom"] sprite.x = self.padding_left + x_pos + props["margin_left"] + (max(sprite.alloc_w * sprite.scale_x, w) - w) * getattr(sprite, "x_align", 0.5) sprite.y = self.padding_top + y_pos + props["margin_top"] + (max(sprite.alloc_h * sprite.scale_y, h) - h) * getattr(sprite, "y_align", 0.5) actual_h = max(actual_h, h * sprite.scale_y) if (min_size + sprite_bonus) > 0: if self.orient_horizontal: x_pos += int(max(w, sprite.alloc_w * sprite.scale_x)) + self.spacing else: y_pos += max(h, sprite.alloc_h * sprite.scale_y) + self.spacing if self.orient_horizontal: for sprite, props in sprites: sprite.__dict__['alloc_h'] = actual_h self.__dict__['_children_resize_queued'] = False def get_height_for_width_size(self): if self._children_resize_queued: self.resize_children() sprites = [sprite for sprite in self.sprites if sprite.visible] width, height = 0, 0 for sprite in sprites: if hasattr(sprite, "get_height_for_width_size"): w, h = sprite.get_height_for_width_size() else: w, h = getattr(sprite, "width", 0), getattr(sprite, "height", 0) w, h = w * sprite.scale_x, h * sprite.scale_y if self.orient_horizontal: width += w height = max(height, h) else: width = max(width, w) height = height + h if self.orient_horizontal: width = width + self.get_total_spacing() else: height = height + self.get_total_spacing() width = width + self.horizontal_padding + self.margin_left + self.margin_right height = height + self.vertical_padding + self.margin_top + self.margin_bottom return width, height def get_min_size(self): if self.visible == False: return 0, 0 if self._cached_w is None: sprites = [sprite for sprite in self.sprites if sprite.visible] width, height = 0, 0 for sprite in sprites: if hasattr(sprite, "get_min_size"): w, h = sprite.get_min_size() else: w, h = getattr(sprite, "width", 0), getattr(sprite, "height", 0) w, h = w * sprite.scale_x, h * sprite.scale_y if self.orient_horizontal: width += w height = max(height, h) else: width = max(width, w) height = height + h if self.orient_horizontal: width = width + self.get_total_spacing() else: height = height + self.get_total_spacing() width = width + self.horizontal_padding + self.margin_left + self.margin_right height = height + self.vertical_padding + self.margin_top + self.margin_bottom w, h = max(width, self.min_width or 0), max(height, self.min_height or 0) self._cached_w, self._cached_h = w, h return self._cached_w, self._cached_h class HBox(Box): """A horizontally aligned box. identical to ui.Box(horizontal=True)""" def __init__(self, contents = None, **kwargs): Box.__init__(self, contents, **kwargs) self.orient_horizontal = True class VBox(Box): """A vertically aligned box. identical to ui.Box(horizontal=False)""" def __init__(self, contents = None, **kwargs): Box.__init__(self, contents, **kwargs) self.orient_horizontal = False class _DisplayLabel(graphics.Label): cache_attrs = Box.cache_attrs | set(('_cached_w', '_cached_h')) def __init__(self, text="", **kwargs): graphics.Label.__init__(self, text, **kwargs) self._cached_w, self._cached_h = None, None self._cached_wh_w, self._cached_wh_h = None, None def __setattr__(self, name, val): graphics.Label.__setattr__(self, name, val) if name in ("text", "markup", "size", "wrap", "ellipsize", "max_width"): if name != "max_width": self._cached_w, self._cached_h = None, None self._cached_wh_w, self._cached_wh_h = None, None def get_min_size(self): if self._cached_w: return self._cached_w, self._cached_h text = self.markup or self.text escape = len(self.markup) == 0 if self.wrap is not None or self.ellipsize is not None: self._cached_w = self.measure(text, escape, 1)[0] self._cached_h = self.measure(text, escape, -1)[1] else: self._cached_w, self._cached_h = self.measure(text, escape, -1) return self._cached_w, self._cached_h def get_height_for_width_size(self): if self._cached_wh_w: return self._cached_wh_w, self._cached_wh_h text = self.markup or self.text escape = len(self.markup) == 0 self._cached_wh_w, self._cached_wh_h = self.measure(text, escape, self.max_width) return self._cached_wh_w, self._cached_wh_h class Label(Bin): """a widget that displays a limited amount of read-only text""" #: pango.FontDescription to use for the label font_desc = None #: image attachment. one of top, right, bottom, left image_position = "left" #: font size size = None fill = False padding = 0 x_align = 0.5 def __init__(self, text = "", markup = "", spacing = 5, image = None, image_position = None, size = None, font_desc = None, overflow = False, color = "#000", background_color = None, **kwargs): # TODO - am initiating table with fill = false but that yields suboptimal label placement and the 0,0 points to whatever parent gave us Bin.__init__(self, **kwargs) #: image to put next to the label self.image = image # the actual container that contains the label and/or image self.container = Box(spacing = spacing, fill = False, x_align = self.x_align, y_align = self.y_align) if image_position is not None: self.image_position = image_position self.display_label = _DisplayLabel(text = text, markup = markup, color=color, size = size) self.display_label.x_align = 0 # the default is 0.5 which makes label align incorrectly on wrapping if font_desc or self.font_desc: self.display_label.font_desc = font_desc or self.font_desc self.display_label.size = size or self.size self.background_color = background_color #: either the pango `wrap `_ #: or `ellipsize `_ constant. #: if set to False will refuse to become smaller self.overflow = overflow self.add_child(self.container) self._position_contents() self.connect_after("on-render", self.__on_render) def get_mouse_sprites(self): return None @property def text(self): """label text. This attribute and :attr:`markup` are mutually exclusive.""" return self.display_label.text @property def markup(self): """pango markup to use in the label. This attribute and :attr:`text` are mutually exclusive.""" return self.display_label.markup @property def color(self): """label color""" return self.display_label.color def __setattr__(self, name, val): if name in ("text", "markup", "color", "size"): if self.display_label.__dict__.get(name, "hamster_graphics_no_value_really") is val: return setattr(self.display_label, name, val) elif name in ("spacing"): setattr(self.container, name, val) else: if self.__dict__.get(name, "hamster_graphics_no_value_really") is val: return Bin.__setattr__(self, name, val) if name in ('x_align', 'y_align') and hasattr(self, "container"): setattr(self.container, name, val) elif name == "alloc_w" and hasattr(self, "display_label") and getattr(self, "overflow") is not False: self._update_max_width() elif name == "min_width" and hasattr(self, "display_label"): self.display_label.width = val - self.horizontal_padding elif name == "overflow" and hasattr(self, "display_label"): if val is False: self.display_label.wrap = None self.display_label.ellipsize = None elif isinstance(val, pango.WrapMode) and val in (pango.WrapMode.WORD, pango.WrapMode.WORD_CHAR, pango.WrapMode.CHAR): self.display_label.wrap = val self.display_label.ellipsize = None elif isinstance(val, pango.EllipsizeMode) and val in (pango.EllipsizeMode.START, pango.EllipsizeMode.MIDDLE, pango.EllipsizeMode.END): self.display_label.wrap = None self.display_label.ellipsize = val self._update_max_width() elif name in ("font_desc", "size"): setattr(self.display_label, name, val) if name in ("text", "markup", "image", "image_position", "overflow", "size"): if hasattr(self, "overflow"): self._position_contents() self.container.queue_resize() def _update_max_width(self): # updates labels max width, respecting image and spacing if self.overflow is False: self.display_label.max_width = -1 else: w = (self.alloc_w or 0) - self.horizontal_padding - self.container.spacing if self.image and self.image_position in ("left", "right"): w -= self.image.width - self.container.spacing self.display_label.max_width = w self.container.queue_resize() def _position_contents(self): if self.image and (self.text or self.markup): self.image.expand = False self.container.orient_horizontal = self.image_position in ("left", "right") if self.image_position in ("top", "left"): if self.container.sprites != [self.image, self.display_label]: self.container.clear() self.container.add_child(self.image, self.display_label) else: if self.container.sprites != [self.display_label, self.image]: self.container.clear() self.container.add_child(self.display_label, self.image) elif self.image or (self.text or self.markup): sprite = self.image or self.display_label if self.container.sprites != [sprite]: self.container.clear() self.container.add_child(sprite) def __on_render(self, sprite): w, h = self.width, self.height w2, h2 = self.get_height_for_width_size() w, h = max(w, w2), max(h, h2) self.graphics.rectangle(0, 0, w, h) if self.background_color: self.graphics.fill(self.background_color) else: self.graphics.new_path() hamster-3.0.3/src/hamster/lib/parsing.py000066400000000000000000000053341452646177100202170ustar00rootroot00000000000000import logging logger = logging.getLogger(__name__) # noqa: E402 import re from hamster.lib import datetime as dt # separator between times and activity activity_separator = r"\s+" # match #tag followed by any space or # that will be ignored # tag must not contain '#' or ',' tag_re = re.compile(r""" \# # hash character (?P [^#,]+ # (anything but hash or comma) ) """, flags=re.VERBOSE) tags_in_description = re.compile(r""" \# (?P [a-zA-Z] # Starts with an alphabetic character (digits excluded) [^\s]+ # followed by anything except spaces ) """, flags=re.VERBOSE) tags_separator = re.compile(r""" ,{1,2} # 1 or 2 commas \s* # maybe spaces (?=\#) # hash character (start of first tag, doesn't consume it) """, flags=re.VERBOSE) description_separator = re.compile(r""" ,+ # 1 or more commas \s* # maybe spaces """, flags=re.VERBOSE) def get_tags_from_description(description): return list(re.findall(tags_in_description, description)) def parse_fact(text, range_pos="head", default_day=None, ref="now"): """Extract fact fields from the string. Returns found fields as a dict. Tentative syntax (not accurate): start [- end_time] activity[@category][, description][,]{ #tag} According to the legacy tests, # were allowed in the description """ res = {} text = text.strip() if not text: return res # datetimes # force at least a space to avoid matching 10.00@cat (start, end), remaining_text = dt.Range.parse(text, position=range_pos, separator=activity_separator, default_day=default_day) res["start_time"] = start res["end_time"] = end # tags split = re.split(tags_separator, remaining_text, 1) remaining_text = split[0] tags_part = split[1] if len(split) > 1 else None if tags_part: tags = list(map(lambda x: x.strip(), re.findall(tag_re, tags_part))) else: tags = [] # description # first look for comma (description hard left boundary) split = re.split(description_separator, remaining_text, 1) head = split[0] description = split[1] if len(split) > 1 else "" # Extract tags from description, put them before other tags tags = get_tags_from_description(description) + tags res["description"] = description.strip() remaining_text = head.strip() res["tags"] = tags # activity split = remaining_text.rsplit('@', maxsplit=1) activity = split[0] category = split[1] if len(split) > 1 else "" res["activity"] = activity res["category"] = category return res hamster-3.0.3/src/hamster/lib/pytweener.py000066400000000000000000000313741452646177100206010ustar00rootroot00000000000000# pyTweener # # Tweening functions for python # # Heavily based on caurina Tweener: http://code.google.com/p/tweener/ # # Released under M.I.T License - see above url # Python version by Ben Harling 2009 # All kinds of slashing and dashing by Toms Baugis 2010, 2014 import math import collections import time import re from hamster.lib import datetime as dt class Tweener(object): def __init__(self, default_duration = None, tween = None): """Tweener This class manages all active tweens, and provides a factory for creating and spawning tween motions.""" self.current_tweens = collections.defaultdict(set) self.default_easing = tween or Easing.Cubic.ease_in_out self.default_duration = default_duration or 1.0 def has_tweens(self): return len(self.current_tweens) > 0 def add_tween(self, obj, duration = None, easing = None, on_complete = None, on_update = None, round = False, delay = None, **kwargs): """ Add tween for the object to go from current values to set ones. Example: add_tween(sprite, x = 500, y = 200, duration = 0.4) This will move the sprite to coordinates (500, 200) in 0.4 seconds. For parameter "easing" you can use one of the pytweener.Easing functions, or specify your own. The tweener can handle numbers, dates and color strings in hex ("#ffffff"). This function performs overwrite style conflict solving - in case if a previous tween operates on same attributes, the attributes in question are removed from that tween. """ if duration is None: duration = self.default_duration easing = easing or self.default_easing tw = Tween(obj, duration, delay, easing, on_complete, on_update, round, **kwargs ) if obj in self.current_tweens: for current_tween in tuple(self.current_tweens[obj]): prev_keys = set((key for (key, tweenable) in current_tween.tweenables)) dif = prev_keys & set(kwargs.keys()) for key, tweenable in tuple(current_tween.tweenables): if key in dif: current_tween.tweenables.remove((key, tweenable)) if not current_tween.tweenables: current_tween.finish() self.current_tweens[obj].remove(current_tween) self.current_tweens[obj].add(tw) return tw def get_tweens(self, obj): """Get a list of all tweens acting on the specified object Useful for manipulating tweens on the fly""" return self.current_tweens.get(obj, None) def kill_tweens(self, obj = None): """Stop tweening an object, without completing the motion or firing the on_complete""" if obj is not None: try: del self.current_tweens[obj] except: pass else: self.current_tweens = collections.defaultdict(set) def remove_tween(self, tween): """"remove given tween without completing the motion or firing the on_complete""" if tween.target in self.current_tweens and tween in self.current_tweens[tween.target]: self.current_tweens[tween.target].remove(tween) if not self.current_tweens[tween.target]: del self.current_tweens[tween.target] def finish(self): """jump the the last frame of all tweens""" for obj in self.current_tweens: for tween in self.current_tweens[obj]: tween.finish() self.current_tweens = {} def update(self, delta_seconds): """update tweeners. delta_seconds is time in seconds since last frame""" for obj in tuple(self.current_tweens): for tween in tuple(self.current_tweens[obj]): done = tween.update(delta_seconds) if done: self.current_tweens[obj].remove(tween) if tween.on_complete: tween.on_complete(tween.target) if not self.current_tweens[obj]: del self.current_tweens[obj] return self.current_tweens class Tween(object): __slots__ = ('tweenables', 'target', 'delta', 'duration', 'delay', 'ease', 'delta', 'complete', 'round', 'on_complete', 'on_update') def __init__(self, obj, duration, delay, easing, on_complete, on_update, round, **kwargs): """Tween object use Tweener.add_tween( ... ) to create""" #: should the tween values truncated to integers or not. Default is False. self.round = round #: duration of the tween self.duration = duration #: delay before the animation should be started self.delay = delay or 0 self.target = obj #: easing function self.ease = easing # list of (property, start_value, delta) self.tweenables = set() for key, value in kwargs.items(): self.tweenables.add((key, Tweenable(getattr(self.target, key), value))) self.delta = 0 #: callback to execute on complete self.on_complete = on_complete #: callback to execute on update self.on_update = on_update self.complete = False def finish(self): self.update(self.duration) def update(self, ptime): """Update tween with the time since the last frame""" delta = self.delta + ptime total_duration = self.delay + self.duration if delta > total_duration: delta = total_duration if delta < self.delay: pass elif delta == total_duration: for key, tweenable in self.tweenables: setattr(self.target, key, tweenable.target_value) else: fraction = self.ease((delta - self.delay) / (total_duration - self.delay)) for key, tweenable in self.tweenables: res = tweenable.update(fraction) if isinstance(res, float) and self.round: res = int(res) setattr(self.target, key, res) if delta == total_duration or len(self.tweenables) == 0: self.complete = True self.delta = delta if self.on_update: self.on_update(self.target) return self.complete class Tweenable(object): """a single attribute that has to be tweened from start to target""" __slots__ = ('start_value', 'change', 'decode_func', 'target_value', 'update') hex_color_normal = re.compile("#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})") hex_color_short = re.compile("#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])") def __init__(self, start_value, target_value): self.decode_func = lambda x: x self.target_value = target_value def float_update(fraction): return self.start_value + self.change * fraction def date_update(fraction): return dt.date.fromtimestamp(self.start_value + self.change * fraction) def datetime_update(fraction): return dt.datetime.fromtimestamp(self.start_value + self.change * fraction) def color_update(fraction): val = [max(min(self.start_value[i] + self.change[i] * fraction, 255), 0) for i in range(3)] return "#%02x%02x%02x" % (val[0], val[1], val[2]) if isinstance(start_value, int) or isinstance(start_value, float): self.start_value = start_value self.change = target_value - start_value self.update = float_update else: if isinstance(start_value, dt.datetime) or isinstance(start_value, dt.date): if isinstance(start_value, dt.datetime): self.update = datetime_update else: self.update = date_update self.decode_func = lambda x: time.mktime(x.timetuple()) self.start_value = self.decode_func(start_value) self.change = self.decode_func(target_value) - self.start_value elif isinstance(start_value, str) \ and (self.hex_color_normal.match(start_value) or self.hex_color_short.match(start_value)): self.update = color_update if self.hex_color_normal.match(start_value): self.decode_func = lambda val: [int(match, 16) for match in self.hex_color_normal.match(val).groups()] elif self.hex_color_short.match(start_value): self.decode_func = lambda val: [int(match + match, 16) for match in self.hex_color_short.match(val).groups()] if self.hex_color_normal.match(target_value): target_value = [int(match, 16) for match in self.hex_color_normal.match(target_value).groups()] else: target_value = [int(match + match, 16) for match in self.hex_color_short.match(target_value).groups()] self.start_value = self.decode_func(start_value) self.change = [target - start for start, target in zip(self.start_value, target_value)] """Robert Penner's classes stripped from the repetetive c,b,d mish-mash (discovery of Patryk Zawadzki). This way we do the math once and apply to all the tweenables instead of repeating it for each attribute """ def inverse(method): def real_inverse(t, *args, **kwargs): t = 1 - t return 1 - method(t, *args, **kwargs) return real_inverse def symmetric(ease_in, ease_out): def real_symmetric(t, *args, **kwargs): if t < 0.5: return ease_in(t * 2, *args, **kwargs) / 2 return ease_out((t - 0.5) * 2, *args, **kwargs) / 2 + 0.5 return real_symmetric class Symmetric(object): def __init__(self, ease_in = None, ease_out = None): self.ease_in = ease_in or inverse(ease_out) self.ease_out = ease_out or inverse(ease_in) self.ease_in_out = symmetric(self.ease_in, self.ease_out) class Easing(object): """Class containing easing classes to use together with the tweener. All of the classes have :func:`ease_in`, :func:`ease_out` and :func:`ease_in_out` functions.""" Linear = Symmetric(lambda t: t, lambda t: t) Quad = Symmetric(lambda t: t*t) Cubic = Symmetric(lambda t: t*t*t) Quart = Symmetric(lambda t: t*t*t*t) Quint = Symmetric(lambda t: t*t*t*t*t) Strong = Quint #oh i wonder why but the ported code is the same as in Quint Circ = Symmetric(lambda t: 1 - math.sqrt(1 - t * t)) Sine = Symmetric(lambda t: 1 - math.cos(t * (math.pi / 2))) def _back_in(t, s=1.70158): return t * t * ((s + 1) * t - s) Back = Symmetric(_back_in) def _bounce_out(t): if t < 1 / 2.75: return 7.5625 * t * t elif t < 2 / 2.75: t = t - 1.5 / 2.75 return 7.5625 * t * t + 0.75 elif t < 2.5 / 2.75: t = t - 2.25 / 2.75 return 7.5625 * t * t + .9375 else: t = t - 2.625 / 2.75 return 7.5625 * t * t + 0.984375 Bounce = Symmetric(ease_out = _bounce_out) def _elastic_in(t, springiness = 0, wave_length = 0): if t in (0, 1): return t wave_length = wave_length or (1 - t) * 0.3 if springiness <= 1: springiness = t s = wave_length / 4 else: s = wave_length / (2 * math.pi) * math.asin(t / springiness) t = t - 1 return -(springiness * math.pow(2, 10 * t) * math.sin((t * t - s) * (2 * math.pi) / wave_length)) Elastic = Symmetric(_elastic_in) def _expo_in(t): if t in (0, 1): return t return math.pow(2, 10 * t) * 0.001 Expo = Symmetric(_expo_in) class _Dummy(object): def __init__(self, a, b, c): self.a = a self.b = b self.c = c if __name__ == "__main__": import datetime as dt tweener = Tweener() objects = [] object_count, update_times = 1000, 100 for i in range(object_count): objects.append(_Dummy(i-100, i-100, i-100)) total = dt.datetime.now() t = dt.datetime.now() print("Adding %d tweens..." % object_count) for i, o in enumerate(objects): tweener.add_tween(o, a = i, b = i, c = i, duration = 0.1 * update_times, easing=Easing.Circ.ease_in_out) print(dt.datetime.now() - t) t = dt.datetime.now() print("Updating %d times......" % update_times) for i in range(update_times): #update 1000 times tweener.update(0.1) print(dt.datetime.now() - t) hamster-3.0.3/src/hamster/lib/stuff.py000066400000000000000000000205201452646177100176750ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2010, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . # some widgets that repeat all over the place # cells, columns, trees and other import logging logger = logging.getLogger(__name__) # noqa: E402 from gi.repository import Gtk as gtk from gi.repository import Pango as pango from itertools import groupby import calendar import time import re import locale import os from hamster.lib import datetime as dt # for pre-v3.0 backward compatibility hamster_now = dt.datetime.now hamster_today = dt.hday.today hamsterday_time_to_datetime = dt.datetime.from_day_time def datetime_to_hamsterday(civil_date_time): """Return the hamster day corresponding to a given civil datetime. Deprecated: use civil_date_time.hday() instead The hamster day start is taken into account. """ return civil_date_time.hday() def hamster_round(time): """Round time or datetime. Deprecated: hamster.lib/datetime.time or datetime are already rounded. """ if time is None: return None else: return time.replace(second=0, microsecond=0) def format_duration(minutes, human = True): """formats duration in a human readable format. accepts either minutes or timedelta Deprecated: use timedelta.format() instead. """ minutes = duration_minutes(minutes) if not minutes: if human: return "" else: return "00:00" if minutes < 0: # format_duration did not work for negative values anyway # return a warning return "NEGATIVE" hours = minutes / 60 minutes = minutes % 60 formatted_duration = "" if human: if minutes % 60 == 0: # duration in round hours formatted_duration += ("%dh") % (hours) elif hours == 0: # duration less than hour formatted_duration += ("%dmin") % (minutes % 60.0) else: # x hours, y minutes formatted_duration += ("%dh %dmin") % (hours, minutes % 60) else: formatted_duration += "%02d:%02d" % (hours, minutes) return formatted_duration def format_range(start_date, end_date): dates_dict = dateDict(start_date, "start_") dates_dict.update(dateDict(end_date, "end_")) if start_date == end_date: # label of date range if looking on single day # date format for overview label when only single day is visible # Using python datetime formatting syntax. See: # http://docs.python.org/library/time.html#time.strftime title = start_date.strftime(("%B %d, %Y")) elif start_date.year != end_date.year: # label of date range if start and end years don't match # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime title = ("%(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date.month != end_date.month: # label of date range if start and end month do not match # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime title = ("%(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict else: # label of date range for interval in same month # letter after prefixes (start_, end_) is the one of # standard python date formatting ones- you can use all of them # see http://docs.python.org/library/time.html#time.strftime title = ("%(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict return title def week(view_date): # aligns start and end date to week start_date = view_date - dt.timedelta(view_date.weekday() + 1) start_date = start_date + dt.timedelta(locale_first_weekday()) end_date = start_date + dt.timedelta(6) return start_date, end_date def month(view_date): # aligns start and end date to month start_date = view_date - dt.timedelta(view_date.day - 1) #set to beginning of month first_weekday, days_in_month = calendar.monthrange(view_date.year, view_date.month) end_date = start_date + dt.timedelta(days_in_month - 1) return start_date, end_date def duration_minutes(duration): """Returns minutes from duration, otherwise we keep bashing in same math. Deprecated, use dt.timedelta.total_minutes instead. """ if isinstance(duration, dt.timedelta): return duration.total_seconds() / 60 elif isinstance(duration, (int, float)): return duration elif isinstance(duration, list): res = dt.timedelta() for entry in duration: res += entry return duration_minutes(res) else: raise NotImplementedError("received {}".format(type(duration))) def zero_hour(date): return dt.datetime.combine(date.date(), dt.time(0,0)) # it seems that python or something has bug of sorts, that breaks stuff for # japanese locale, so we have this locale from and to ut8 magic in some places # see bug 562298 def locale_from_utf8(utf8_str): try: retval = str (utf8_str, "utf-8").encode(locale.getpreferredencoding()) except: retval = utf8_str return retval def locale_to_utf8(locale_str): try: retval = str (locale_str, locale.getpreferredencoding()).encode("utf-8") except: retval = locale_str return retval def locale_first_weekday(): """figure if week starts on monday or sunday""" first_weekday = 6 #by default settle on monday try: process = os.popen("locale first_weekday week-1stday") week_offset, week_start = process.read().split('\n')[:2] process.close() week_start = dt.date(*time.strptime(week_start, "%Y%m%d")[:3]) week_offset = dt.timedelta(int(week_offset) - 1) beginning = week_start + week_offset first_weekday = int(beginning.strftime("%w")) except: logger.warn("WARNING - Failed to get first weekday from locale") return first_weekday def totals(iter, keyfunc, sumfunc): """groups items by field described in keyfunc and counts totals using value from sumfunc """ data = sorted(iter, key=keyfunc) res = {} for k, group in groupby(data, keyfunc): res[k] = sum([sumfunc(entry) for entry in group]) return res def dateDict(date, prefix = ""): """converts date into dictionary, having prefix for all the keys""" res = {} res[prefix+"a"] = date.strftime("%a") res[prefix+"A"] = date.strftime("%A") res[prefix+"b"] = date.strftime("%b") res[prefix+"B"] = date.strftime("%B") res[prefix+"c"] = date.strftime("%c") res[prefix+"d"] = date.strftime("%d") res[prefix+"H"] = date.strftime("%H") res[prefix+"I"] = date.strftime("%I") res[prefix+"j"] = date.strftime("%j") res[prefix+"m"] = date.strftime("%m") res[prefix+"M"] = date.strftime("%M") res[prefix+"p"] = date.strftime("%p") res[prefix+"S"] = date.strftime("%S") res[prefix+"U"] = date.strftime("%U") res[prefix+"w"] = date.strftime("%w") res[prefix+"W"] = date.strftime("%W") res[prefix+"x"] = date.strftime("%x") res[prefix+"X"] = date.strftime("%X") res[prefix+"y"] = date.strftime("%y") res[prefix+"Y"] = date.strftime("%Y") res[prefix+"Z"] = date.strftime("%Z") for i, value in res.items(): res[i] = locale_to_utf8(value) return res def escape_pango(text): if not text: return text text = text.replace ("&", "&") text = text.replace("<", "<") text = text.replace(">", ">") return text hamster-3.0.3/src/hamster/overview.py000066400000000000000000000575721452646177100176670ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import sys import bisect import itertools import webbrowser from collections import defaultdict from math import ceil from gi.repository import GLib as glib from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import GObject as gobject from gi.repository import PangoCairo as pangocairo from gi.repository import Pango as pango import cairo import hamster.client from hamster.lib import datetime as dt from hamster.lib import graphics from hamster.lib import layout from hamster import reports from hamster.lib import stuff from hamster import widgets from hamster.lib.configuration import Controller from hamster.lib.pytweener import Easing from hamster.widgets.dates import RangePick from hamster.widgets.facttree import FactTree class HeaderBar(gtk.HeaderBar): def __init__(self): gtk.HeaderBar.__init__(self) self.set_show_close_button(True) box = gtk.Box(False) self.time_back = gtk.Button.new_from_icon_name("go-previous-symbolic", gtk.IconSize.MENU) self.time_forth = gtk.Button.new_from_icon_name("go-next-symbolic", gtk.IconSize.MENU) box.add(self.time_back) box.add(self.time_forth) gtk.StyleContext.add_class(box.get_style_context(), "linked") self.pack_start(box) self.range_pick = RangePick(dt.hday.today()) self.pack_start(self.range_pick) self.system_button = gtk.MenuButton() self.system_button.set_image(gtk.Image.new_from_icon_name( "open-menu-symbolic", gtk.IconSize.MENU)) self.system_button.set_tooltip_markup(_("Menu")) self.pack_end(self.system_button) self.search_button = gtk.ToggleButton() self.search_button.set_image(gtk.Image.new_from_icon_name( "edit-find-symbolic", gtk.IconSize.MENU)) self.search_button.set_tooltip_markup(_("Filter activities")) self.pack_end(self.search_button) self.stop_button = gtk.Button() self.stop_button.set_image(gtk.Image.new_from_icon_name( "process-stop-symbolic", gtk.IconSize.MENU)) self.stop_button.set_tooltip_markup(_("Stop tracking (Ctrl-SPACE)")) self.pack_end(self.stop_button) self.add_activity_button = gtk.Button() self.add_activity_button.set_image(gtk.Image.new_from_icon_name( "list-add-symbolic", gtk.IconSize.MENU)) self.add_activity_button.set_tooltip_markup(_("Add activity (Ctrl-+)")) self.pack_end(self.add_activity_button) self.system_menu = gtk.Menu() self.system_button.set_popup(self.system_menu) self.menu_export = gtk.MenuItem(label=_("Export...")) self.system_menu.append(self.menu_export) self.menu_prefs = gtk.MenuItem(label=_("Tracking Settings")) self.system_menu.append(self.menu_prefs) self.menu_help = gtk.MenuItem(label=_("Help")) self.system_menu.append(self.menu_help) self.system_menu.show_all() self.time_back.connect("clicked", self.on_time_back_click) self.time_forth.connect("clicked", self.on_time_forth_click) self.connect("button-press-event", self.on_button_press) def on_button_press(self, bar, event): """swallow clicks on the interactive parts to avoid triggering switch to full-window""" return True def on_time_back_click(self, button): self.range_pick.prev_range() def on_time_forth_click(self, button): self.range_pick.next_range() class StackedBar(layout.Widget): def __init__(self, width=0, height=0, vertical=None, **kwargs): layout.Widget.__init__(self, **kwargs) #: orientation, horizontal by default self.vertical = vertical or False #: allocated width self.width = width #: allocated height self.height = height self._items = [] self.connect("on-render", self.on_render) #: color scheme to use, graphics.colors.category10 by default self.colors = graphics.Colors.category10 self.colors = ["#95CACF", "#A2CFB6", "#D1DEA1", "#E4C384", "#DE9F7B"] self._seen_keys = [] def set_items(self, items): """expects a list of key, value to work with""" res = [] max_value = max(sum((rec[1] for rec in items)), 1) for key, val in items: res.append((key, val, val * 1.0 / max_value)) self._items = res def _take_color(self, key): if key in self._seen_keys: index = self._seen_keys.index(key) else: self._seen_keys.append(key) index = len(self._seen_keys) - 1 return self.colors[index % len(self.colors)] def on_render(self, sprite): if not self._items: self.graphics.clear() return max_width = self.alloc_w - 1 * len(self._items) for i, (key, val, normalized) in enumerate(self._items): color = self._take_color(key) width = int(normalized * max_width) self.graphics.rectangle(0, 0, width, self.height) self.graphics.fill(color) self.graphics.translate(width + 1, 0) class Label(object): """a much cheaper label that would be suitable for cellrenderer""" def __init__(self, x=0, y=0, color=None, use_markup=False): self.x = x self.y = y self.color = color self.use_markup = use_markup def _set_text(self, text): if self.use_markup: self.layout.set_markup(text) else: self.layout.set_text(text, -1) def _show(self, g): if self.color: g.set_color(self.color) pangocairo.show_layout(g.context, self.layout) def show(self, g, text, x=0, y=0): g.save_context() g.move_to(x or self.x, y or self.y) self._set_text(text) self._show(g) g.restore_context() class HorizontalBarChart(graphics.Sprite): def __init__(self, **kwargs): graphics.Sprite.__init__(self, **kwargs) self.x_align = 0 self.y_align = 0 self.values = [] self._label_context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)) self.layout = pangocairo.create_layout(self._label_context) self.layout.set_font_description(pango.FontDescription(graphics._font_desc)) self.layout.set_markup("Hamster") # dummy # ellipsize the middle because depending on the use case, # the distinctive information can be either at the beginning or the end. self.layout.set_ellipsize(pango.EllipsizeMode.MIDDLE) self.layout.set_justify(True) self.layout.set_alignment(pango.Alignment.RIGHT) self.label_height = self.layout.get_pixel_size()[1] # should be updated by the parent self.label_color = gdk.RGBA() self.bar_color = gdk.RGBA() self._max = dt.timedelta(0) def set_values(self, values): """expects a list of 2-tuples""" self.values = values self.height = len(self.values) * 14 self._max = max(rec[1] for rec in values) if values else dt.timedelta(0) def _draw(self, context, opacity, matrix): g = graphics.Graphics(context) g.save_context() g.translate(self.x, self.y) # arbitrary 3/4 total width for label, 1/4 for histogram hist_width = self.alloc_w // 4; margin = 10 # pixels label_width = self.alloc_w - hist_width - margin self.layout.set_width(label_width * pango.SCALE) label_h = self.label_height bar_start_x = label_width + margin for i, (label, value) in enumerate(self.values): g.set_color(self.label_color) duration_str = value.format(fmt="HH:MM") markup_label = stuff.escape_pango(str(label)) markup_duration = stuff.escape_pango(duration_str) self.layout.set_markup("{}, {}".format(markup_label, markup_duration)) y = int(i * label_h * 1.5) g.move_to(0, y) pangocairo.show_layout(context, self.layout) if self._max > dt.timedelta(0): w = ceil(hist_width * value.total_seconds() / self._max.total_seconds()) else: w = 1 g.rectangle(bar_start_x, y, int(w), int(label_h)) g.fill(self.bar_color) g.restore_context() class Totals(graphics.Scene): def __init__(self): graphics.Scene.__init__(self) self.set_size_request(200, 70) self.category_totals = layout.Label(overflow=pango.EllipsizeMode.END, x_align=0, expand=False) self.stacked_bar = StackedBar(height=25, x_align=0, expand=False) box = layout.VBox(padding=10, spacing=5) self.add_child(box) box.add_child(self.category_totals, self.stacked_bar) self.totals = {} self.mouse_cursor = gdk.CursorType.HAND2 self.instructions_label = layout.Label(_("Click to see stats"), color=self._style.get_color(gtk.StateFlags.NORMAL), padding=10, expand=False) box.add_child(self.instructions_label) self.collapsed = True main = layout.HBox(padding_top=10) box.add_child(main) self.stub_label = layout.Label(markup="Here be stats,\ntune in laters!", color="#bbb", size=60) self.activities_chart = HorizontalBarChart() self.categories_chart = HorizontalBarChart() self.tag_chart = HorizontalBarChart() main.add_child(self.activities_chart, self.categories_chart, self.tag_chart) # for use in animation self.height_proxy = graphics.Sprite(x=0) self.height_proxy.height = 70 self.add_child(self.height_proxy) self.connect("on-click", self.on_click) self.connect("enter-notify-event", self.on_mouse_enter) self.connect("leave-notify-event", self.on_mouse_leave) self.connect("state-flags-changed", self.on_state_flags_changed) self.connect("style-updated", self.on_style_changed) def set_facts(self, facts): totals = defaultdict(lambda: defaultdict(dt.timedelta)) for fact in facts: for key in ('category', 'activity'): totals[key][getattr(fact, key)] += fact.delta for tag in fact.tags: totals["tag"][tag] += fact.delta for key, group in totals.items(): totals[key] = sorted(group.items(), key=lambda x: x[1], reverse=True) self.totals = totals self.activities_chart.set_values(totals['activity']) self.categories_chart.set_values(totals['category']) self.tag_chart.set_values(totals['tag']) self.stacked_bar.set_items([(cat, delta.total_seconds() / 60.0) for cat, delta in totals['category']]) grand_total = sum(delta.total_seconds() / 60 for __, delta in totals['activity']) self.category_totals.markup = "Total: %s; " % stuff.format_duration(grand_total) self.category_totals.markup += ", ".join("%s: %s" % (stuff.escape_pango(cat), stuff.format_duration(hours)) for cat, hours in totals['category']) def on_click(self, scene, sprite, event): self.collapsed = not self.collapsed if self.collapsed: self.change_height(70) self.instructions_label.visible = True self.instructions_label.opacity = 0 self.instructions_label.animate(opacity=1, easing=Easing.Expo.ease_in) else: self.change_height(300) self.instructions_label.visible = False self.mouse_cursor = gdk.CursorType.HAND2 if self.collapsed else None def on_mouse_enter(self, scene, event): if not self.collapsed: return def delayed_leave(sprite): self.change_height(100) self.height_proxy.animate(x=50, delay=0.5, duration=0, on_complete=delayed_leave, on_update=lambda sprite: sprite.redraw()) def on_mouse_leave(self, scene, event): if not self.collapsed: return def delayed_leave(sprite): self.change_height(70) self.height_proxy.animate(x=50, delay=0.5, duration=0, on_complete=delayed_leave, on_update=lambda sprite: sprite.redraw()) def on_state_flags_changed(self, previous_state, _): self.update_colors() def on_style_changed(self, _): self.update_colors() def change_height(self, new_height): self.stop_animation(self.height_proxy) def on_update_dummy(sprite): self.set_size_request(200, sprite.height) self.animate(self.height_proxy, height=new_height, on_update=on_update_dummy, easing=Easing.Expo.ease_out) def update_colors(self): color = self._style.get_color(self.get_state()) self.instructions_label.color = color self.category_totals.color = color self.activities_chart.label_color = color self.categories_chart.label_color = color self.tag_chart.label_color = color bg_color = self._style.get_background_color(self.get_state()) bar_color = self.colors.mix(bg_color, color, 0.6) self.activities_chart.bar_color = bar_color self.categories_chart.bar_color = bar_color self.tag_chart.bar_color = bar_color class Overview(Controller): def __init__(self): Controller.__init__(self) self.prefs_dialog = None # preferences dialog controller self.window.set_position(gtk.WindowPosition.CENTER) self.window.set_default_icon_name("org.gnome.Hamster.GUI") self.window.set_default_size(700, 500) self.storage = hamster.client.Storage() self.storage.connect("facts-changed", self.on_facts_changed) self.storage.connect("activities-changed", self.on_facts_changed) self.header_bar = HeaderBar() self.window.set_titlebar(self.header_bar) main = gtk.Box(orientation=1) self.window.add(main) self.report_chooser = None self.search_box = gtk.Revealer() space = gtk.Box(border_width=5) self.search_box.add(space) self.filter_entry = gtk.Entry() self.filter_entry.set_icon_from_icon_name(gtk.EntryIconPosition.PRIMARY, "edit-find-symbolic") self.filter_entry.connect("changed", self.on_search_changed) self.filter_entry.connect("icon-press", self.on_search_icon_press) space.pack_start(self.filter_entry, True, True, 0) main.pack_start(self.search_box, False, True, 0) window = gtk.ScrolledWindow() window.set_policy(gtk.PolicyType.NEVER, gtk.PolicyType.AUTOMATIC) self.fact_tree = FactTree() self.fact_tree.connect("on-activate-row", self.on_row_activated) self.fact_tree.connect("on-delete-called", self.on_row_delete_called) window.add(self.fact_tree) main.pack_start(window, True, True, 1) self.totals = Totals() main.pack_start(self.totals, False, True, 1) # FIXME: should store and recall date_range from hamster.lib.configuration.conf hamster_day = dt.hday.today() self.header_bar.range_pick.set_range(hamster_day) self.header_bar.range_pick.connect("range-selected", self.on_range_selected) self.header_bar.add_activity_button.connect("clicked", self.on_add_activity_clicked) self.header_bar.stop_button.connect("clicked", self.on_stop_clicked) self.header_bar.search_button.connect("toggled", self.on_search_toggled) self.header_bar.menu_prefs.connect("activate", self.on_prefs_clicked) self.header_bar.menu_export.connect("activate", self.on_export_clicked) self.header_bar.menu_help.connect("activate", self.on_help_clicked) self.window.connect("key-press-event", self.on_key_press) self.facts = [] self.find_facts() # update every minute (necessary if an activity is running) gobject.timeout_add_seconds(60, self.on_timeout) self.window.show_all() def on_key_press(self, window, event): if self.filter_entry.has_focus(): if event.keyval == gdk.KEY_Escape: self.filter_entry.set_text("") self.header_bar.search_button.set_active(False) return True elif event.keyval in (gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Home, gdk.KEY_End, gdk.KEY_Page_Up, gdk.KEY_Page_Down, gdk.KEY_Return, gdk.KEY_Delete): # These keys should work even when fact_tree does not have focus self.fact_tree.on_key_press(self, event) return True # stop event propagation elif event.keyval == gdk.KEY_Left: self.header_bar.time_back.emit("clicked") return True elif event.keyval == gdk.KEY_Right: self.header_bar.time_forth.emit("clicked") return True if self.fact_tree.has_focus() or self.totals.has_focus(): if event.keyval == gdk.KEY_Tab: pass # TODO - deal with tab as our scenes eat up navigation if event.state & gdk.ModifierType.CONTROL_MASK: # the ctrl+things if event.keyval == gdk.KEY_f: self.header_bar.search_button.set_active(True) elif event.keyval == gdk.KEY_n: self.start_new_fact(clone_selected=False) elif event.keyval == gdk.KEY_r: # Resume/run; clear separation between Ctrl-R and Ctrl-N self.start_new_fact(clone_selected=True, fallback=False) elif event.keyval == gdk.KEY_space: self.storage.stop_or_restart_tracking() elif event.keyval in (gdk.KEY_KP_Add, gdk.KEY_plus): # same as pressing the + icon self.start_new_fact(clone_selected=True, fallback=True) if event.keyval == gdk.KEY_Escape: self.close_window() def find_facts(self, scroll_to_top=False): start, end = self.header_bar.range_pick.get_range() search_active = self.header_bar.search_button.get_active() search = "" if not search_active else self.filter_entry.get_text() search = "%s*" % search if search else "" # search anywhere self.facts = self.storage.get_facts(start, end, search_terms=search) self.fact_tree.set_facts(self.facts, scroll_to_top=scroll_to_top) self.totals.set_facts(self.facts) self.header_bar.stop_button.set_sensitive( self.facts and not self.facts[-1].end_time) def on_range_selected(self, button, range_type, start, end): self.find_facts(scroll_to_top=True) def on_search_changed(self, entry): if entry.get_text(): self.filter_entry.set_icon_from_icon_name(gtk.EntryIconPosition.SECONDARY, "edit-clear-symbolic") else: self.filter_entry.set_icon_from_icon_name(gtk.EntryIconPosition.SECONDARY, None) self.find_facts(scroll_to_top=True) def on_search_icon_press(self, entry, position, event): if position == gtk.EntryIconPosition.SECONDARY: self.filter_entry.set_text("") def on_facts_changed(self, event): self.find_facts() def on_add_activity_clicked(self, button): self.start_new_fact(clone_selected=True, fallback=True) def on_stop_clicked(self, button): self.storage.stop_tracking() def on_row_activated(self, tree, day, fact): self.present_fact_controller("edit", fact_id=fact.id) def on_row_delete_called(self, tree, fact): self.storage.remove_fact(fact.id) self.find_facts() def on_search_toggled(self, button): active = button.get_active() self.search_box.set_reveal_child(active) if active: self.filter_entry.grab_focus() def on_timeout(self): # TODO: should update only the running FactTree row (if any), and totals self.find_facts() # The timeout will stop if returning False return True def on_help_clicked(self, menu): uri = "help:hamster" try: gtk.show_uri(None, uri, gdk.CURRENT_TIME) except glib.Error: msg = sys.exc_info()[1].args[0] dialog = gtk.MessageDialog(self.window, 0, gtk.MessageType.ERROR, gtk.ButtonsType.CLOSE, _("Failed to open {}").format(uri)) fmt = _('Error: "{}" - is a help browser installed on this computer?') dialog.format_secondary_text(fmt.format(msg)) dialog.run() dialog.destroy() def on_prefs_clicked(self, menu): app = self.window.get_property("application") app.activate_action("preferences") def on_export_clicked(self, menu): if self.report_chooser: self.report_chooser.present() return start, end = self.header_bar.range_pick.get_range() def on_report_chosen(widget, format, path): self.report_chooser = None reports.simple(self.facts, start, end, format, path) if format == ("html"): webbrowser.open_new("file://%s" % path) else: try: gtk.show_uri(None, "file://%s" % path, gdk.CURRENT_TIME) except: pass # bug 626656 - no use in capturing this one i think def on_report_chooser_closed(widget): self.report_chooser = None self.report_chooser = widgets.ReportChooserDialog() self.report_chooser.connect("report-chosen", on_report_chosen) self.report_chooser.connect("report-chooser-closed", on_report_chooser_closed) self.report_chooser.show(start, end) def present_fact_controller(self, action, fact_id=0): app = self.window.get_property("application") app.present_fact_controller(action, fact_id=fact_id) def start_new_fact(self, clone_selected=True, fallback=True): """Start now a new fact. clone_selected (bool): whether to start a clone of currently selected fact or to create a new fact from scratch. fallback (bool): if True, fall back to creating from scratch in case of no selected fact. """ if not clone_selected: self.present_fact_controller("add") elif self.fact_tree.current_fact: self.present_fact_controller("clone", fact_id=self.fact_tree.current_fact.id) elif fallback: self.present_fact_controller("add") def close_window(self): self.window.destroy() self.window = None self._gui = None self.emit("on-close") hamster-3.0.3/src/hamster/preferences.py000066400000000000000000000454571452646177100203210ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2007, 2008, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import GObject as gobject from hamster import widgets from hamster.lib import datetime as dt from hamster.lib import stuff from hamster.lib.configuration import Controller, runtime, conf def get_prev(selection, model): (model, iter) = selection.get_selected() #previous item path = model.get_path(iter)[0] - 1 if path >= 0: return model.get_iter_from_string(str(path)) else: return None class CategoryStore(gtk.ListStore): def __init__(self): #id, name, color_code, order gtk.ListStore.__init__(self, int, str) def load(self): category_list = runtime.storage.get_categories() for category in category_list: self.append([category['id'], category['name']]) self.unsorted_category = self.append([-1, _("Unsorted")]) # all activities without category class ActivityStore(gtk.ListStore): def __init__(self): #id, name, category_id, order gtk.ListStore.__init__(self, int, str, int) def load(self, category_id): self.clear() if category_id is None: return activity_list = runtime.storage.get_category_activities(category_id) for activity in activity_list: self.append([activity['id'], activity['name'], activity['category_id']]) class PreferencesEditor(Controller): TARGETS = [ ('MY_TREE_MODEL_ROW', gtk.TargetFlags.SAME_WIDGET, 0), ('MY_TREE_MODEL_ROW', gtk.TargetFlags.SAME_APP, 0), ] def __init__(self): Controller.__init__(self, ui_file="preferences.ui") # create and fill activity tree self.activity_tree = self.get_widget('activity_list') self.get_widget("activities_label").set_mnemonic_widget(self.activity_tree) self.activity_store = ActivityStore() self.external_listeners = [] self.activityColumn = gtk.TreeViewColumn(_("Name")) self.activityColumn.set_expand(True) self.activityCell = gtk.CellRendererText() self.external_listeners.extend([ (self.activityCell, self.activityCell.connect('edited', self.activity_name_edited_cb, self.activity_store)) ]) self.activityColumn.pack_start(self.activityCell, True) self.activityColumn.set_attributes(self.activityCell, text=1) self.activityColumn.set_sort_column_id(1) self.activity_tree.append_column(self.activityColumn) self.activity_tree.set_model(self.activity_store) self.selection = self.activity_tree.get_selection() self.external_listeners.extend([ (self.selection, self.selection.connect('changed', self.activity_changed, self.activity_store)) ]) # create and fill category tree self.category_tree = self.get_widget('category_list') self.get_widget("categories_label").set_mnemonic_widget(self.category_tree) self.category_store = CategoryStore() self.categoryColumn = gtk.TreeViewColumn(_("Category")) self.categoryColumn.set_expand(True) self.categoryCell = gtk.CellRendererText() self.external_listeners.extend([ (self.categoryCell, self.categoryCell.connect('edited', self.category_edited_cb, self.category_store)) ]) self.categoryColumn.pack_start(self.categoryCell, True) self.categoryColumn.set_attributes(self.categoryCell, text=1) self.categoryColumn.set_sort_column_id(1) self.categoryColumn.set_cell_data_func(self.categoryCell, self.unsorted_painter) self.category_tree.append_column(self.categoryColumn) self.category_store.load() self.category_tree.set_model(self.category_store) selection = self.category_tree.get_selection() self.external_listeners.extend([ (selection, selection.connect('changed', self.category_changed_cb, self.category_store)) ]) self.day_start = widgets.TimeInput(dt.time(5,30), parent=self.get_widget("day_start_placeholder")) self.load_config() # Allow enable drag and drop of rows including row move self.activity_tree.enable_model_drag_source(gdk.ModifierType.BUTTON1_MASK, self.TARGETS, gdk.DragAction.DEFAULT| gdk.DragAction.MOVE) self.category_tree.enable_model_drag_dest(self.TARGETS, gdk.DragAction.MOVE) self.activity_tree.connect("drag_data_get", self.drag_data_get_data) self.category_tree.connect("drag_data_received", self.on_category_drop) #select first category selection = self.category_tree.get_selection() selection.select_path((0,)) self.prev_selected_activity = None self.prev_selected_category = None self.external_listeners.extend([ (self.day_start, self.day_start.connect("time-entered", self.on_day_start_changed)) ]) self.show() def show(self): self.get_widget("notebook1").set_current_page(0) self.window.show_all() def load_config(self, *args): self.day_start.time = conf.day_start self.tags = [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)] self.get_widget("autocomplete_tags").set_text(", ".join(self.tags)) def on_autocomplete_tags_view_focus_out_event(self, view, event): buf = self.get_widget("autocomplete_tags") updated_tags = buf.get_text(buf.get_start_iter(), buf.get_end_iter(), 0) if updated_tags == self.tags: return self.tags = updated_tags runtime.storage.update_autocomplete_tags(updated_tags) def drag_data_get_data(self, treeview, context, selection, target_id, etime): treeselection = treeview.get_selection() model, iter = treeselection.get_selected() data = model.get_value(iter, 0) #get activity ID selection.set(selection.target, 0, str(data)) def select_activity(self, id): model = self.activity_tree.get_model() i = 0 for row in model: if row[0] == id: self.activity_tree.set_cursor((i, )) i += 1 def select_category(self, id): model = self.category_tree.get_model() i = 0 for row in model: if row[0] == id: self.category_tree.set_cursor((i, )) i += 1 def on_category_list_drag_motion(self, treeview, drag_context, x, y, eventtime): self.prev_selected_category = None try: target_path, drop_position = treeview.get_dest_row_at_pos(x, y) model, source = treeview.get_selection().get_selected() except: return drop_yes = ("drop_yes", gtk.TargetFlags.SAME_APP, 0) drop_no = ("drop_no", gtk.TargetFlags.SAME_APP, 0) if drop_position != gtk.TREE_VIEW_DROP_AFTER and \ drop_position != gtk.TREE_VIEW_DROP_BEFORE: treeview.enable_model_drag_dest(self.TARGETS, gdk.DragAction.MOVE) else: treeview.enable_model_drag_dest([drop_no], gdk.DragAction.MOVE) def on_category_drop(self, treeview, context, x, y, selection, info, etime): model = self.category_tree.get_model() data = selection.data drop_info = treeview.get_dest_row_at_pos(x, y) if drop_info: path, position = drop_info iter = model.get_iter(path) changed = runtime.storage.change_category(int(data), model[iter][0]) context.finish(changed, True, etime) else: context.finish(False, True, etime) return # callbacks def category_edited_cb(self, cell, path, new_text, model): id = model[path][0] if id == -1: return False #ignoring unsorted category #look for dupes categories = runtime.storage.get_categories() for category in categories: if category['name'].lower() == new_text.lower(): if id == -2: # that was a new category self.category_store.remove(model.get_iter(path)) self.select_category(category['id']) return False if id == -2: #new category id = runtime.storage.add_category(new_text) model[path][0] = id else: runtime.storage.update_category(id, new_text) model[path][1] = new_text def activity_name_edited_cb(self, cell, path, new_text, model): id = model[path][0] category_id = model[path][2] activities = runtime.storage.get_category_activities(category_id) prev = None for activity in activities: if id == activity['id']: prev = activity['name'] else: # avoid two activities in same category with same name if activity['name'].lower() == new_text.lower(): if id == -1: # that was a new activity self.activity_store.remove(model.get_iter(path)) self.select_activity(activity['id']) return False if id == -1: #new activity -> add model[path][0] = runtime.storage.add_activity(new_text, category_id) else: #existing activity -> update new = new_text runtime.storage.update_activity(id, new, category_id) model[path][1] = new_text return True def category_changed_cb(self, selection, model): """ enables and disables action buttons depending on selected item """ (model, iter) = selection.get_selected() id = 0 if iter is None: self.activity_store.clear() else: self.prev_selected_activity = None id = model[iter][0] self.activity_store.load(model[iter][0]) #start with nothing self.get_widget('activity_edit').set_sensitive(False) self.get_widget('activity_remove').set_sensitive(False) return True def _get_selected_category(self): selection = self.get_widget('category_list').get_selection() (model, iter) = selection.get_selected() return model[iter][0] if iter else None def activity_changed(self, selection, model): """ enables and disables action buttons depending on selected item """ (model, iter) = selection.get_selected() # treat any selected case unsorted_selected = self._get_selected_category() == -1 self.get_widget('activity_edit').set_sensitive(iter != None) self.get_widget('activity_remove').set_sensitive(iter != None) def _del_selected_row(self, tree): selection = tree.get_selection() (model, iter) = selection.get_selected() next_row = model.iter_next(iter) if next_row: selection.select_iter(next_row) else: path = model.get_path(iter)[0] - 1 if path > 0: selection.select_path(path) removable_id = model[iter][0] model.remove(iter) return removable_id def unsorted_painter(self, column, cell, model, iter, data): cell_id = model.get_value(iter, 0) cell_text = model.get_value(iter, 1) if cell_id == -1: text = '%s' % cell_text # TODO - should get color from theme cell.set_property('markup', text) else: cell.set_property('text', cell_text) return def on_activity_list_button_pressed(self, tree, event): self.activityCell.set_property("editable", False) def on_activity_list_button_released(self, tree, event): if event.button == 1 and tree.get_path_at_pos(int(event.x), int(event.y)): # Get treeview path. path, column, x, y = tree.get_path_at_pos(int(event.x), int(event.y)) if self.prev_selected_activity == path: self.activityCell.set_property("editable", True) tree.set_cursor_on_cell(path, self.activityColumn, self.activityCell, True) self.prev_selected_activity = path def on_category_list_button_pressed(self, tree, event): self.activityCell.set_property("editable", False) def on_category_list_button_released(self, tree, event): if event.button == 1 and tree.get_path_at_pos(int(event.x), int(event.y)): # Get treeview path. path, column, x, y = tree.get_path_at_pos(int(event.x), int(event.y)) if self.prev_selected_category == path and \ self._get_selected_category() != -1: #do not allow to edit unsorted self.categoryCell.set_property("editable", True) tree.set_cursor_on_cell(path, self.categoryColumn, self.categoryCell, True) else: self.categoryCell.set_property("editable", False) self.prev_selected_category = path def on_activity_remove_clicked(self, button): self.remove_current_activity() def on_activity_edit_clicked(self, button): self.activityCell.set_property("editable", True) selection = self.activity_tree.get_selection() (model, iter) = selection.get_selected() path = model.get_path(iter) self.activity_tree.set_cursor_on_cell(path, self.activityColumn, self.activityCell, True) """keyboard events""" def on_activity_list_key_pressed(self, tree, event_key): key = event_key.keyval selection = tree.get_selection() (model, iter) = selection.get_selected() if (event_key.keyval == gdk.KEY_Delete): self.remove_current_activity() elif key == gdk.KEY_F2 : self.activityCell.set_property("editable", True) path = model.get_path(iter) tree.set_cursor_on_cell(path, self.activityColumn, self.activityCell, True) def remove_current_activity(self): selection = self.activity_tree.get_selection() (model, iter) = selection.get_selected() runtime.storage.remove_activity(model[iter][0]) self._del_selected_row(self.activity_tree) def on_category_remove_clicked(self, button): self.remove_current_category() def on_category_edit_clicked(self, button): self.categoryCell.set_property("editable", True) selection = self.category_tree.get_selection() (model, iter) = selection.get_selected() path = model.get_path(iter) self.category_tree.set_cursor_on_cell(path, self.categoryColumn, self.categoryCell, True) def on_category_list_key_pressed(self, tree, event_key): key = event_key.keyval if self._get_selected_category() == -1: return #ignoring unsorted category selection = tree.get_selection() (model, iter) = selection.get_selected() if key == gdk.KEY_Delete: self.remove_current_category() elif key == gdk.KEY_F2: self.categoryCell.set_property("editable", True) path = model.get_path(iter) tree.set_cursor_on_cell(path, self.categoryColumn, self.categoryCell, True) def remove_current_category(self): selection = self.category_tree.get_selection() (model, iter) = selection.get_selected() id = model[iter][0] if id != -1: runtime.storage.remove_category(id) self._del_selected_row(self.category_tree) def on_preferences_window_key_press(self, widget, event): # ctrl+w means close window if (event.keyval == gdk.KEY_w \ and event.state & gdk.ModifierType.CONTROL_MASK): self.close_window() # escape can mean several things if event.keyval == gdk.KEY_Escape: #check, maybe we are editing stuff if self.activityCell.get_property("editable"): self.activityCell.set_property("editable", False) return if self.categoryCell.get_property("editable"): self.categoryCell.set_property("editable", False) return self.close_window() """button events""" def on_category_add_clicked(self, button): """ appends row, jumps to it and allows user to input name """ new_category = self.category_store.insert_before(self.category_store.unsorted_category, [-2, _("New category")]) model = self.category_tree.get_model() self.categoryCell.set_property("editable", True) self.category_tree.set_cursor_on_cell(model.get_path(new_category), focus_column = self.category_tree.get_column(0), focus_cell = None, start_editing = True) def on_activity_add_clicked(self, button): """ appends row, jumps to it and allows user to input name """ category_id = self._get_selected_category() new_activity = self.activity_store.append([-1, _("New activity"), category_id]) (model, iter) = self.selection.get_selected() self.activityCell.set_property("editable", True) self.activity_tree.set_cursor_on_cell(model.get_path(new_activity), focus_column = self.activity_tree.get_column(0), focus_cell = None, start_editing = True) def on_activity_remove_clicked(self, button): removable_id = self._del_selected_row(self.activity_tree) runtime.storage.remove_activity(removable_id) def on_day_start_changed(self, widget): day_start = self.day_start.time if day_start is None: return day_start = day_start.hour * 60 + day_start.minute conf.set("day-start-minutes", day_start) def on_close_button_clicked(self, button): self.close_window() hamster-3.0.3/src/hamster/reports.py000066400000000000000000000274271452646177100175130ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2012 Toms Bauģis # Copyright (C) 2008 Nathan Samson # Copyright (C) 2008 Giorgos Logiotatidis # Copyright (C) 2012 Ted Smith # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import os, sys from xml.dom.minidom import Document import csv import copy import itertools import re import codecs import html from string import Template from textwrap import dedent from hamster.lib import datetime as dt from hamster.lib.configuration import runtime from hamster.lib import stuff from hamster.lib.i18n import C_ try: import json except ImportError: # fallback for python < 2.6 json_dumps = lambda s: s else: json_dumps = json.dumps from calendar import timegm from io import StringIO, IOBase def simple(facts, start_date, end_date, format, path = None): facts = copy.deepcopy(facts) # dont want to do anything bad to the input report_path = stuff.locale_from_utf8(path) if format == "tsv": writer = TSVWriter(report_path) elif format == "xml": writer = XMLWriter(report_path) elif format == "ical": writer = ICalWriter(report_path) else: #default to HTML writer = HTMLWriter(report_path, start_date, end_date) writer.write_report(facts) return writer class ReportWriter(object): #a tiny bit better than repeating the code all the time def __init__(self, path = None, datetime_format = "%Y-%m-%d %H:%M:%S"): # if path is empty or None, print to stdout self.file = open(path, "w") if path else StringIO() self.path = path self.datetime_format = datetime_format def write_report(self, facts): try: for fact in facts: fact.description = (fact.description or "") fact.category = (fact.category or _("Unsorted")) self._write_fact(fact) self._finish(facts) finally: if not self.path: # print the full report to stdout print(self.file.getvalue()) self.file.close() def _start(self, facts): raise NotImplementedError def _write_fact(self, fact): raise NotImplementedError def _finish(self, facts): raise NotImplementedError class ICalWriter(ReportWriter): """a lame ical writer, could not be bothered with finding a library""" def __init__(self, path): ReportWriter.__init__(self, path, datetime_format = "%Y%m%dT%H%M%S") self.file.write("BEGIN:VCALENDAR\nVERSION:1.0\n") def _write_fact(self, fact): #for now we will skip ongoing facts if not fact.end_time: return if fact.category == _("Unsorted"): fact.category = None event_str = """\ BEGIN:VEVENT CATEGORIES:{fact.category} DTSTART:{fact.start_time} DTEND:{fact.end_time} SUMMARY:{fact.activity} DESCRIPTION:{fact.description} END:VEVENT """.format(fact=fact) self.file.write(dedent(event_str)) def _finish(self, facts): self.file.write("END:VCALENDAR\n") class TSVWriter(ReportWriter): def __init__(self, path): ReportWriter.__init__(self, path) self.csv_writer = csv.writer(self.file, dialect='excel-tab') headers = [# column title in the TSV export format _("activity"), # column title in the TSV export format _("start time"), # column title in the TSV export format _("end time"), # column title in the TSV export format _("duration minutes"), # column title in the TSV export format _("category"), # column title in the TSV export format _("description"), # column title in the TSV export format _("tags")] self.csv_writer.writerow([h for h in headers]) def _write_fact(self, fact): self.csv_writer.writerow([fact.activity, fact.start_time, fact.end_time, str(stuff.duration_minutes(fact.delta)), fact.category, fact.description, ", ".join(fact.tags)]) def _finish(self, facts): pass class XMLWriter(ReportWriter): def __init__(self, path): ReportWriter.__init__(self, path) self.doc = Document() self.activity_list = self.doc.createElement("activities") def _write_fact(self, fact): activity = self.doc.createElement("activity") activity.setAttribute("name", fact.activity) activity.setAttribute("start_time", str(fact.start_time)) activity.setAttribute("end_time", str(fact.end_time)) activity.setAttribute("duration_minutes", str(stuff.duration_minutes(fact.delta))) activity.setAttribute("category", fact.category) activity.setAttribute("description", fact.description) activity.setAttribute("tags", ", ".join(fact.tags)) self.activity_list.appendChild(activity) def _finish(self, facts): self.doc.appendChild(self.activity_list) self.file.write(self.doc.toxml()) class HTMLWriter(ReportWriter): def __init__(self, path, start_date, end_date): ReportWriter.__init__(self, path, datetime_format = None) self.start_date, self.end_date = start_date, end_date dates_dict = stuff.dateDict(start_date, "start_") dates_dict.update(stuff.dateDict(end_date, "end_")) if start_date.year != end_date.year: self.title = _("Activity report for %(start_B)s %(start_d)s, %(start_Y)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date.month != end_date.month: self.title = _("Activity report for %(start_B)s %(start_d)s – %(end_B)s %(end_d)s, %(end_Y)s") % dates_dict elif start_date == end_date: self.title = _("Activity report for %(start_B)s %(start_d)s, %(start_Y)s") % dates_dict else: self.title = _("Activity report for %(start_B)s %(start_d)s – %(end_d)s, %(end_Y)s") % dates_dict # read the template, allow override self.override = os.path.exists(os.path.join(runtime.home_data_dir, "report_template.html")) if self.override: template = os.path.join(runtime.home_data_dir, "report_template.html") else: template = os.path.join(runtime.data_dir, "report_template.html") self.main_template = "" with open(template, 'r') as f: self.main_template =f.read() self.fact_row_template = self._extract_template('all_activities') self.by_date_row_template = self._extract_template('by_date_activity') self.by_date_template = self._extract_template('by_date') self.fact_rows = [] def _extract_template(self, name): pattern = re.compile('<%s>(.*)' % (name, name), re.DOTALL) match = pattern.search(self.main_template) if match: self.main_template = self.main_template.replace(match.group(), "$%s_rows" % name) return match.groups()[0] return "" def _write_fact(self, fact): # no having end time is fine end_time_str, end_time_iso_str = "", "" if fact.end_time: end_time_str = fact.end_time.strftime('%H:%M') end_time_iso_str = fact.end_time.isoformat() category = "" if fact.category != _("Unsorted"): #do not print "unsorted" in list category = fact.category data = dict( date = fact.date.strftime( # date column format for each row in HTML report # Using python datetime formatting syntax. See: # http://docs.python.org/library/time.html#time.strftime C_("html report","%b %d, %Y")), date_iso = fact.date.isoformat(), activity = html.escape(fact.activity), category = html.escape(category), tags = html.escape(", ".join(fact.tags)), start = fact.start_time.strftime('%H:%M'), start_iso = fact.start_time.isoformat(), end = end_time_str, end_iso = end_time_iso_str, duration = fact.delta.format(), duration_minutes = "%d" % (stuff.duration_minutes(fact.delta)), duration_decimal = "%.2f" % (stuff.duration_minutes(fact.delta) / 60.0), # not only escape html characters, but ensure \n is respected in output description = html.escape(fact.description).replace('\n', '
') or "" ) self.fact_rows.append(Template(self.fact_row_template).safe_substitute(data)) def _finish(self, facts): # group by date by_date = [] for date, date_facts in itertools.groupby(facts, lambda fact:fact.date): by_date.append((date, [fact.as_dict() for fact in date_facts])) by_date = dict(by_date) date_facts = [] date = min(by_date.keys()) while date <= self.end_date: str_date = date.strftime( # date column format for each row in HTML report # Using python datetime formatting syntax. See: # http://docs.python.org/library/time.html#time.strftime C_("html report","%b %d, %Y")) date_facts.append([str_date, by_date.get(date, [])]) date += dt.timedelta(days=1) data = dict( title = self.title, totals_by_day_title = _("Totals by Day"), activity_log_title = _("Activity Log"), totals_title = _("Totals"), activity_totals_heading = _("activities"), category_totals_heading = _("categories"), tag_totals_heading = _("tags"), show_prompt = _("Distinguish:"), header_date = _("Date"), header_activity = _("Activity"), header_category = _("Category"), header_tags = _("Tags"), header_start = _("Start"), header_end = _("End"), header_duration = _("Duration"), header_description = _("Description"), data_dir = runtime.data_dir, show_template = _("Show template"), template_instructions = _("You can override it by storing your version in %(home_folder)s") % {'home_folder': runtime.home_data_dir}, start_date = timegm(self.start_date.timetuple()), end_date = timegm(self.end_date.timetuple()), facts = json_dumps([fact.as_dict() for fact in facts]), date_facts = json_dumps(date_facts), all_activities_rows = "\n".join(self.fact_rows) ) for key, val in data.items(): if isinstance(val, str): data[key] = val self.file.write(Template(self.main_template).safe_substitute(data)) return hamster-3.0.3/src/hamster/storage/000077500000000000000000000000001452646177100170735ustar00rootroot00000000000000hamster-3.0.3/src/hamster/storage/__init__.py000066400000000000000000000000001452646177100211720ustar00rootroot00000000000000hamster-3.0.3/src/hamster/storage/db.py000066400000000000000000001200331452646177100200310ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2007-2009, 2012, 2014 Toms Bauģis # Copyright (C) 2007 Patryk Zawadzki # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . """separate file for database operations""" import logging logger = logging.getLogger(__name__) # noqa: E402 import os, time import itertools import sqlite3 as sqlite from shutil import copy as copyfile try: from gi.repository import Gio as gio except ImportError: print("Could not import gio - requires pygobject. File monitoring will be disabled") gio = None import hamster from hamster.lib import datetime as dt from hamster.lib.configuration import conf from hamster.lib.fact import Fact from hamster.storage import storage # note: "zero id means failure" is quite standard, # and that kind of convention will be mandatory for the dbus interface # (None cannot pass through an integer signature). class Storage(storage.Storage): con = None # Connection will be created on demand def __init__(self, unsorted_localized="Unsorted", database_dir=None): """Database storage. Args: unsorted_localized (str): Default Fact.category value for returned facts that were without any category in the db. This is kept mainly for compatibility reasons. The recommended value is an empty string. How to handle empty category is now left to the caller. database_dir (path): Directory holding the database file, or None to use the default location. Note: Zero id means failure. Unsorted category id is hard-coded as -1 """ storage.Storage.__init__(self) self._unsorted_localized = unsorted_localized self.__con = None self.__cur = None self.__last_etag = None self.db_path = self.__init_db_file(database_dir) logger.info("database: '{}'".format(self.db_path)) if gio: # add file monitoring so the app does not have to be restarted # when db file is rewritten def on_db_file_change(monitor, gio_file, event_uri, event): logger.debug(event) if event == gio.FileMonitorEvent.CHANGES_DONE_HINT: if gio_file.query_info(gio.FILE_ATTRIBUTE_ETAG_VALUE, gio.FileQueryInfoFlags.NONE, None).get_etag() == self.__last_etag: # ours logger.info("database updated") return elif event == gio.FileMonitorEvent.DELETED: self.con = None if event == gio.FileMonitorEvent.CHANGES_DONE_HINT: logger.warning("DB file has been modified externally. Calling all stations") self.dispatch_overwrite() self.__database_file = gio.File.new_for_path(self.db_path) self.__db_monitor = self.__database_file.monitor_file(gio.FileMonitorFlags.WATCH_MOUNTS, None) self.__db_monitor.connect("changed", on_db_file_change) self.run_fixtures() def __init_db_file(self, database_dir): from gi.repository import GLib xdg_data_home = GLib.get_user_data_dir() if not database_dir: database_dir = os.path.join(xdg_data_home, 'hamster') if not os.path.exists(database_dir): os.makedirs(database_dir, 0o744) db_path = os.path.join(database_dir, "hamster.db") # check if we have a database at all if not os.path.exists(db_path): # handle pre-existing hamster-applet database # try most recent directories first # change from hamster-applet to hamster-time-tracker: # 9f345e5e (2019-09-19) old_dirs = ['hamster-time-tracker', 'hamster-applet'] for old_dir in old_dirs: old_db_path = os.path.join(xdg_data_home, old_dir, 'hamster.db') if os.path.exists(old_db_path): logger.warning("Linking {} with {}".format(old_db_path, db_path)) os.link(old_db_path, db_path) break if not os.path.exists(db_path): # make a copy of the empty template hamster.db if hamster.installed: from hamster import defs # only available when running installed data_dir = os.path.join(defs.DATA_DIR, "hamster") else: # running from sources module_dir = os.path.dirname(os.path.realpath(__file__)) if os.path.exists(os.path.join(module_dir, "data")): # running as flask app. XXX - detangle data_dir = os.path.join(module_dir, "data") else: # get ./data from ./src/hamster/storage/db.py (3 levels up) data_dir = os.path.join(module_dir, '..', '..', '..', 'data') logger.warning("Database not found in {} - installing default from {}!" .format(db_path, data_dir)) copyfile(os.path.join(data_dir, 'hamster.db'), db_path) #change also permissions - sometimes they are 444 os.chmod(db_path, 0o664) db_path = os.path.realpath(db_path) # needed for file monitoring? return db_path def register_modification(self): if gio: # db.execute calls this so we know that we were the ones # that modified the DB and no extra refesh is not needed self.__last_etag = self.__database_file.query_info(gio.FILE_ATTRIBUTE_ETAG_VALUE, gio.FileQueryInfoFlags.NONE, None).get_etag() #tags, here we come! def __get_tags(self, only_autocomplete = False): if only_autocomplete: return self.fetchall("select * from tags where autocomplete != 'false' order by name") else: return self.fetchall("select * from tags order by name") def __get_tag_ids(self, tags): """look up tags by their name. create if not found""" db_tags = self.fetchall("select * from tags where name in (%s)" % ",".join(["?"] * len(tags)), tags) # bit of magic here - using sqlites bind variables changes = False # check if any of tags needs resurrection set_complete = [str(tag["id"]) for tag in db_tags if tag["autocomplete"] in (0, "false")] if set_complete: changes = True self.execute("update tags set autocomplete='true' where id in (%s)" % ", ".join(set_complete)) found_tags = [tag["name"] for tag in db_tags] add = set(tags) - set(found_tags) if add: statement = "insert into tags(name) values(?)" self.execute([statement] * len(add), [(tag,) for tag in add]) return self.__get_tag_ids(tags)[0], True # all done, recurse else: return db_tags, changes def __update_autocomplete_tags(self, tags): tags = [tag.strip() for tag in tags.split(",") if tag.strip()] # split by comma #first we will create new ones tags, changes = self.__get_tag_ids(tags) tags = [tag["id"] for tag in tags] #now we will find which ones are gone from the list query = """ SELECT b.id as id, b.autocomplete, count(a.fact_id) as occurences FROM tags b LEFT JOIN fact_tags a on a.tag_id = b.id WHERE b.id not in (%s) GROUP BY b.id """ % ",".join(["?"] * len(tags)) # bit of magic here - using sqlites bind variables gone = self.fetchall(query, tags) to_delete = [str(tag["id"]) for tag in gone if tag["occurences"] == 0] to_uncomplete = [str(tag["id"]) for tag in gone if tag["occurences"] > 0 and tag["autocomplete"] in (1, "true")] if to_delete: self.execute("delete from tags where id in (%s)" % ", ".join(to_delete)) if to_uncomplete: self.execute("update tags set autocomplete='false' where id in (%s)" % ", ".join(to_uncomplete)) return changes or len(to_delete + to_uncomplete) > 0 def __get_categories(self): return self.fetchall("SELECT id, name FROM categories ORDER BY lower(name)") def __update_activity(self, id, name, category_id): query = """ UPDATE activities SET name = ?, search_name = ?, category_id = ? WHERE id = ? """ self.execute(query, (name, name.lower(), category_id, id)) affected_ids = [res[0] for res in self.fetchall("select id from facts where activity_id = ?", (id,))] self.__remove_index(affected_ids) def __change_category(self, id, category_id): """Change the category of an activity. If an activity already exists with the same name in the target category, make all relevant facts use this target activity. Args: id (int): id of the source activity category_id (int): id of the target category Returns: boolean: whether the database was changed. """ # first check if we don't have an activity with same name before us activity = self.fetchone("select name from activities where id = ?", (id, )) existing_activity = self.__get_activity_by_name(activity['name'], category_id) if existing_activity and id == existing_activity['id']: # we are already there, go home return False if existing_activity: #ooh, we have something here! # first move all facts that belong to movable activity to the new one update = """ UPDATE facts SET activity_id = ? WHERE activity_id = ? """ self.execute(update, (existing_activity['id'], id)) # and now get rid of our friend self.__remove_activity(id) else: #just moving statement = """ UPDATE activities SET category_id = ? WHERE id = ? """ self.execute(statement, (category_id, id)) affected_ids = [res[0] for res in self.fetchall("select id from facts where activity_id = ?", (id,))] if existing_activity: affected_ids.extend([res[0] for res in self.fetchall("select id from facts where activity_id = ?", (existing_activity['id'],))]) self.__remove_index(affected_ids) return True def __add_category(self, name): query = """ INSERT INTO categories (name, search_name) VALUES (?, ?) """ self.execute(query, (name, name.lower())) return self.__last_insert_rowid() def __update_category(self, id, name): if id > -1: # Update, and ignore unsorted, if that was somehow triggered update = """ UPDATE categories SET name = ?, search_name = ? WHERE id = ? """ self.execute(update, (name, name.lower(), id)) affected_query = """ SELECT id FROM facts WHERE activity_id in (SELECT id FROM activities where category_id=?) """ affected_ids = [res[0] for res in self.fetchall(affected_query, (id,))] self.__remove_index(affected_ids) def __get_activity_by_name(self, name, category_id = None, resurrect = True): """Get most recent, preferably not deleted activity by it's name. If category_id is None or 0, show all activities matching name. Otherwise, filter on the specified category. """ if category_id: query = """ SELECT a.id, a.name, a.deleted, coalesce(b.name, ?) as category FROM activities a LEFT JOIN categories b ON category_id = b.id WHERE lower(a.name) = lower(?) AND category_id = ? ORDER BY a.deleted, a.id desc LIMIT 1 """ res = self.fetchone(query, (self._unsorted_localized, name, category_id)) else: query = """ SELECT a.id, a.name, a.deleted, coalesce(b.name, ?) as category FROM activities a LEFT JOIN categories b ON category_id = b.id WHERE lower(a.name) = lower(?) ORDER BY a.deleted, a.id desc LIMIT 1 """ res = self.fetchone(query, (self._unsorted_localized, name, )) if res: keys = ('id', 'name', 'deleted', 'category') res = dict([(key, res[key]) for key in keys]) res['deleted'] = res['deleted'] or False # if the activity was marked as deleted, resurrect on first call # and put in the unsorted category if res['deleted'] and resurrect: update = """ UPDATE activities SET deleted = null, category_id = -1 WHERE id = ? """ self.execute(update, (res['id'], )) return res return None def __get_category_id(self, name): """Return category id from its name. 0 means none found. """ if not name: # Unsorted return -1 query = """ SELECT id from categories WHERE lower(name) = lower(?) ORDER BY id desc LIMIT 1 """ res = self.fetchone(query, (name, )) if res: return res['id'] return 0 def _dbfact_to_libfact(self, db_fact): """Convert a db fact (coming from __group_facts) to Fact.""" return Fact(activity=db_fact["name"], category=db_fact["category"], description=db_fact["description"], tags=db_fact["tags"], start_time=db_fact["start_time"], end_time=db_fact["end_time"], id=db_fact["id"], activity_id=db_fact["activity_id"]) def __get_fact(self, id): query = """ SELECT a.id AS id, a.start_time AS start_time, a.end_time AS end_time, a.description as description, b.name AS name, b.id as activity_id, coalesce(c.name, ?) as category, coalesce(c.id, -1) as category_id, e.name as tag FROM facts a LEFT JOIN activities b ON a.activity_id = b.id LEFT JOIN categories c ON b.category_id = c.id LEFT JOIN fact_tags d ON d.fact_id = a.id LEFT JOIN tags e ON e.id = d.tag_id WHERE a.id = ? ORDER BY e.name """ fact_rows = self.fetchall(query, (self._unsorted_localized, id)) assert len(fact_rows) > 0, "No fact with id {}".format(id) dbfact = self.__group_tags(fact_rows)[0] fact = self._dbfact_to_libfact(dbfact) logger.info("got fact {}".format(fact)) return fact def __group_tags(self, facts): """put the fact back together and move all the unique tags to an array""" if not facts: return facts #be it None or whatever grouped_facts = [] for fact_id, fact_tags in itertools.groupby(facts, lambda f: f["id"]): fact_tags = list(fact_tags) # first one is as good as the last one grouped_fact = fact_tags[0] # we need dict so we can modify it (sqlite.Row is read only) # in python 2.5, sqlite does not have keys() yet, so we hardcode them (yay!) keys = ["id", "start_time", "end_time", "description", "name", "activity_id", "category", "tag"] grouped_fact = dict([(key, grouped_fact[key]) for key in keys]) grouped_fact["tags"] = [ft["tag"] for ft in fact_tags if ft["tag"]] grouped_facts.append(grouped_fact) return grouped_facts def __touch_fact(self, fact, end_time = None): end_time = end_time or dt.datetime.now() # tasks under one minute do not count if end_time - fact.start_time < dt.timedelta(minutes = 1): self.__remove_fact(fact.id) else: query = """ UPDATE facts SET end_time = ? WHERE id = ? """ self.execute(query, (end_time, fact.id)) def __squeeze_in(self, start_time): """ tries to put task in the given date if there are conflicts, we will only truncate the ongoing task and replace it's end part with our activity """ # we are checking if our start time is in the middle of anything # or maybe there is something after us - so we know to adjust end time # in the latter case go only few hours ahead. everything else is madness, heh query = """ SELECT a.*, b.name FROM facts a LEFT JOIN activities b on b.id = a.activity_id WHERE ((start_time < ? and end_time > ?) OR (start_time > ? and start_time < ? and end_time is null) OR (start_time > ? and start_time < ?)) ORDER BY start_time LIMIT 1 """ fact = self.fetchone(query, (start_time, start_time, start_time - dt.timedelta(hours = 12), start_time, start_time, start_time + dt.timedelta(hours = 12))) end_time = None if fact: if start_time > fact["start_time"]: #we are in middle of a fact - truncate it to our start self.execute("UPDATE facts SET end_time=? WHERE id=?", (start_time, fact["id"])) else: #otherwise we have found a task that is after us end_time = fact["start_time"] return end_time def __solve_overlaps(self, start_time, end_time): """finds facts that happen in given interval and shifts them to make room for new fact """ if end_time is None or start_time is None: return # possible combinations and the OR clauses that catch them # (the side of the number marks if it catches the end or start time) # |----------------- NEW -----------------| # |--- old --- 1| |2 --- old --- 1| |2 --- old ---| # |3 ----------------------- big old ------------------------ 3| query = """ SELECT a.*, b.name, c.name as category FROM facts a LEFT JOIN activities b on b.id = a.activity_id LEFT JOIN categories c on b.category_id = c.id WHERE (end_time > ? and end_time < ?) OR (start_time > ? and start_time < ?) OR (start_time < ? and end_time > ?) ORDER BY start_time """ conflicts = self.fetchall(query, (start_time, end_time, start_time, end_time, start_time, end_time)) for fact in conflicts: # fact is a sqlite.Row, indexable by column name fact_end_time = fact["end_time"] or dt.datetime.now() # won't eliminate as it is better to have overlapping entries than loosing data if start_time < fact["start_time"] and end_time > fact_end_time: continue # split - truncate until beginning of new entry and create new activity for end if fact["start_time"] < start_time < fact_end_time and \ fact["start_time"] < end_time < fact_end_time: logger.info("splitting %s" % fact["name"]) # truncate until beginning of the new entry self.execute("""UPDATE facts SET end_time = ? WHERE id = ?""", (start_time, fact["id"])) fact_name = fact["name"] # create new fact for the end new_fact = Fact(activity=fact["name"], category=fact["category"], description=fact["description"], start_time=end_time, end_time=fact_end_time) storage.Storage.check_fact(new_fact) new_fact_id = self.__add_fact(new_fact) # copy tags tag_update = """INSERT INTO fact_tags(fact_id, tag_id) SELECT ?, tag_id FROM fact_tags WHERE fact_id = ?""" self.execute(tag_update, (new_fact_id, fact["id"])) #clone tags # overlap start elif start_time < fact["start_time"] < end_time: logger.info("Overlapping start of %s" % fact["name"]) self.execute("UPDATE facts SET start_time=? WHERE id=?", (end_time, fact["id"])) # overlap end elif start_time < fact_end_time < end_time: logger.info("Overlapping end of %s" % fact["name"]) self.execute("UPDATE facts SET end_time=? WHERE id=?", (start_time, fact["id"])) def __add_fact(self, fact, temporary=False): """Add fact to database. Args: fact (Fact) Returns: int, the new fact id in the database (> 0) on success, 0 if nothing needed to be done (e.g. if the same fact was already on-going), note: a sanity check on the given fact is performed first, that would raise an AssertionError. Other errors would also be handled through exceptions. """ logger.info("adding fact {}".format(fact)) start_time = fact.start_time end_time = fact.end_time # get tags from database - this will create any missing tags too tags = [(tag['id'], tag['name'], tag['autocomplete']) for tag in self.get_tag_ids(fact.tags)] # now check if maybe there is also a category category_id = self.__get_category_id(fact.category) if not category_id: category_id = self.__add_category(fact.category) # try to find activity, resurrect if not temporary activity_id = self.__get_activity_by_name(fact.activity, category_id, resurrect = not temporary) if not activity_id: activity_id = self.__add_activity(fact.activity, category_id, temporary) else: activity_id = activity_id['id'] # if we are working on +/- current day - check the last_activity if (dt.timedelta(days=-1) <= dt.datetime.now() - start_time <= dt.timedelta(days=1)): # pull in previous facts facts = self.__get_todays_facts() previous = None if facts and facts[-1].end_time is None: previous = facts[-1] if previous and previous.start_time <= start_time: # check if maybe that is the same one, in that case no need to restart if (previous.activity_id == activity_id and set(previous.tags) == set([tag[1] for tag in tags]) and (previous.description or "") == (fact.description or "") ): logger.info("same fact, already on-going, nothing to do") return 0 # if no description is added # see if maybe previous was too short to qualify as an activity if (not previous.description and 60 >= (start_time - previous.start_time).seconds >= 0 ): self.__remove_fact(previous.id) # now that we removed the previous one, see if maybe the one # before that is actually same as the one we want to start # (glueing) if len(facts) > 1 and 60 >= (start_time - facts[-2].end_time).seconds >= 0: before = facts[-2] if (before.activity_id == activity_id and set(before.tags) == set([tag[1] for tag in tags]) ): # resume and return update = """ UPDATE facts SET end_time = null WHERE id = ? """ self.execute(update, (before.id,)) return before.id else: # otherwise stop update = """ UPDATE facts SET end_time = ? WHERE id = ? """ self.execute(update, (start_time, previous.id)) # done with the current activity, now we can solve overlaps if not end_time: end_time = self.__squeeze_in(start_time) else: self.__solve_overlaps(start_time, end_time) # finally add the new entry insert = """ INSERT INTO facts (activity_id, start_time, end_time, description) VALUES (?, ?, ?, ?) """ self.execute(insert, (activity_id, start_time, end_time, fact.description)) fact_id = self.__last_insert_rowid() #now link tags insert = ["insert into fact_tags(fact_id, tag_id) values(?, ?)"] * len(tags) params = [(fact_id, tag[0]) for tag in tags] self.execute(insert, params) self.__remove_index([fact_id]) logger.info("fact successfully added, with id #{}".format(fact_id)) return fact_id def __last_insert_rowid(self): return self.fetchone("SELECT last_insert_rowid();")[0] or 0 def __get_todays_facts(self): return self.__get_facts(dt.Range.today()) def __get_facts(self, range, search_terms=""): datetime_from = range.start datetime_to = range.end logger.info("searching for facts from {} to {}".format(datetime_from, datetime_to)) query = """ SELECT a.id AS id, a.start_time AS start_time, a.end_time AS end_time, a.description as description, b.name AS name, b.id as activity_id, coalesce(c.name, ?) as category, e.name as tag FROM facts a LEFT JOIN activities b ON a.activity_id = b.id LEFT JOIN categories c ON b.category_id = c.id LEFT JOIN fact_tags d ON d.fact_id = a.id LEFT JOIN tags e ON e.id = d.tag_id WHERE (a.end_time >= ? OR a.end_time IS NULL) AND a.start_time <= ? """ if search_terms: # check if we need changes to the index self.__check_index(datetime_from, datetime_to) # flip the query around when it starts with "not " reverse_search_terms = search_terms.lower().startswith("not ") if reverse_search_terms: search_terms = search_terms[4:] search_terms = search_terms.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_').replace("'", "''") query += """ AND a.id %s IN (SELECT id FROM fact_index WHERE fact_index MATCH '%s')""" % ('NOT' if reverse_search_terms else '', search_terms) query += " ORDER BY a.start_time, e.name" fact_rows = self.fetchall(query, (self._unsorted_localized, datetime_from, datetime_to)) #first let's put all tags in an array dbfacts = self.__group_tags(fact_rows) # ignore old on-going facts return [self._dbfact_to_libfact(dbfact) for dbfact in dbfacts if dbfact["start_time"] >= datetime_from - dt.timedelta(days=30)] def __remove_fact(self, fact_id): logger.info("removing fact #{}".format(fact_id)) statements = ["DELETE FROM fact_tags where fact_id = ?", "DELETE FROM facts where id = ?"] self.execute(statements, [(fact_id,)] * 2) self.__remove_index([fact_id]) def __get_category_activities(self, category_id): """returns list of activities, if category is specified, order by name otherwise - by activity_order""" query = """ SELECT a.id, a.name, a.category_id, b.name as category FROM activities a LEFT JOIN categories b on coalesce(b.id, -1) = a.category_id WHERE category_id = ? AND deleted is null ORDER BY lower(a.name) """ return self.fetchall(query, (category_id, )) def __get_activities(self, search): """returns list of activities for autocomplete, activity names converted to lowercase""" query = """ SELECT a.name AS name, b.name AS category FROM activities a LEFT JOIN categories b ON coalesce(b.id, -1) = a.category_id LEFT JOIN facts f ON a.id = f.activity_id WHERE deleted IS NULL AND a.search_name LIKE ? ESCAPE '\\' GROUP BY a.id ORDER BY max(f.start_time) DESC, lower(a.name) LIMIT 50 """ search = search.lower() search = search.replace('\\', '\\\\').replace('%', '\\%').replace('_', '\\_') activities = self.fetchall(query, ('%s%%' % search, )) return activities def __remove_activity(self, id): """ check if we have any facts with this activity and behave accordingly if there are facts - sets activity to deleted = True else, just remove it""" query = "select count(*) as count from facts where activity_id = ?" bound_facts = self.fetchone(query, (id,))['count'] if bound_facts > 0: self.execute("UPDATE activities SET deleted = 1 WHERE id = ?", (id,)) else: self.execute("delete from activities where id = ?", (id,)) def __remove_category(self, id): """move all activities to unsorted and remove category""" affected_query = """ SELECT id FROM facts WHERE activity_id in (SELECT id FROM activities where category_id=?) """ affected_ids = [res[0] for res in self.fetchall(affected_query, (id,))] update = "update activities set category_id = -1 where category_id = ?" self.execute(update, (id, )) self.execute("delete from categories where id = ?", (id, )) self.__remove_index(affected_ids) def __add_activity(self, name, category_id = None, temporary = False): # first check that we don't have anything like that yet activity = self.__get_activity_by_name(name, category_id) if activity: return activity['id'] #now do the create bit category_id = category_id or -1 deleted = None if temporary: deleted = 1 query = """ INSERT INTO activities (name, search_name, category_id, deleted) VALUES (?, ?, ?, ?) """ self.execute(query, (name, name.lower(), category_id, deleted)) return self.__last_insert_rowid() def __remove_index(self, ids): """remove affected ids from the index""" if not ids: return ids = ",".join((str(id) for id in ids)) logger.info("removing fact #{} from index".format(ids)) self.execute("DELETE FROM fact_index where id in (%s)" % ids) def __check_index(self, start_date, end_date): """check if maybe index needs rebuilding in the time span""" index_query = """SELECT id FROM facts WHERE (end_time >= ? OR end_time IS NULL) AND start_time <= ? AND id not in(select id from fact_index)""" rebuild_ids = ",".join([str(res[0]) for res in self.fetchall(index_query, (start_date, end_date))]) if rebuild_ids: query = """ SELECT a.id AS id, a.start_time AS start_time, a.end_time AS end_time, a.description as description, b.name AS name, b.id as activity_id, coalesce(c.name, ?) as category, e.name as tag FROM facts a LEFT JOIN activities b ON a.activity_id = b.id LEFT JOIN categories c ON b.category_id = c.id LEFT JOIN fact_tags d ON d.fact_id = a.id LEFT JOIN tags e ON e.id = d.tag_id WHERE a.id in (%s) ORDER BY a.id """ % rebuild_ids dbfacts = self.__group_tags(self.fetchall(query, (self._unsorted_localized, ))) facts = [self._dbfact_to_libfact(dbfact) for dbfact in dbfacts] insert = """INSERT INTO fact_index (id, name, category, description, tag) VALUES (?, ?, ?, ?, ?)""" params = [(fact.id, fact.activity, fact.category, fact.description, " ".join(fact.tags)) for fact in facts] self.executemany(insert, params) """ Here be dragons (lame connection/cursor wrappers) """ def get_connection(self): if self.con is None: self.con = sqlite.connect(self.db_path, detect_types=sqlite.PARSE_DECLTYPES|sqlite.PARSE_COLNAMES) self.con.row_factory = sqlite.Row return self.con connection = property(get_connection, None) def fetchall(self, query, params = None): """Execute query. Returns: list(sqlite.Row) """ con = self.connection cur = con.cursor() logger.debug("%s %s" % (query, params)) if params: cur.execute(query, params) else: cur.execute(query) res = cur.fetchall() cur.close() return res def fetchone(self, query, params = None): res = self.fetchall(query, params) if res: return res[0] else: return None def execute(self, statement, params = ()): """ execute sql statement. optionally you can give multiple statements to save on cursor creation and closure """ con = self.__con or self.connection cur = self.__cur or con.cursor() if isinstance(statement, list) == False: # we expect to receive instructions in list statement = [statement] params = [params] for state, param in zip(statement, params): logger.debug("%s %s" % (state, param)) cur.execute(state, param) if not self.__con: con.commit() cur.close() self.register_modification() def executemany(self, statement, params = []): con = self.__con or self.connection cur = self.__cur or con.cursor() logger.debug("%s %s" % (statement, params)) cur.executemany(statement, params) if not self.__con: con.commit() cur.close() self.register_modification() def start_transaction(self): # will give some hints to execute not to close or commit anything self.__con = self.connection self.__cur = self.__con.cursor() def end_transaction(self): self.__con.commit() self.__cur.close() self.__con, self.__cur = None, None self.register_modification() def run_fixtures(self): self.start_transaction() """upgrade DB to hamster version""" version = self.fetchone("SELECT version FROM version")["version"] current_version = 9 if version < 8: # working around sqlite's utf-f case sensitivity (bug 624438) # more info: http://www.gsak.net/help/hs23820.htm self.execute("ALTER TABLE activities ADD COLUMN search_name varchar2") activities = self.fetchall("select * from activities") statement = "update activities set search_name = ? where id = ?" for activity in activities: self.execute(statement, (activity['name'].lower(), activity['id'])) # same for categories self.execute("ALTER TABLE categories ADD COLUMN search_name varchar2") categories = self.fetchall("select * from categories") statement = "update categories set search_name = ? where id = ?" for category in categories: self.execute(statement, (category['name'].lower(), category['id'])) if version < 9: # adding full text search self.execute("""CREATE VIRTUAL TABLE fact_index USING fts3(id, name, category, description, tag)""") # at the happy end, update version number if version < current_version: #lock down current version self.execute("UPDATE version SET version = %d" % current_version) print("updated database from version %d to %d" % (version, current_version)) self.end_transaction() # datetime/sql conversions DATETIME_LOCAL_FMT = "%Y-%m-%d %H:%M:%S" def adapt_datetime(t): """Convert datetime t to the suitable sql representation.""" return t.isoformat(" ") def convert_datetime(s): """Convert the sql timestamp to datetime. s is in bytes. """ # convert s from bytes to utf-8, and keep only data up to seconds # 10 chars for YYYY-MM-DD, 1 space, 8 chars for HH:MM:SS # note: let's leave any further rounding to dt.datetime. datetime_string = s.decode('utf-8')[0:19] return dt.datetime.strptime(datetime_string, DATETIME_LOCAL_FMT) sqlite.register_adapter(dt.datetime, adapt_datetime) sqlite.register_converter("timestamp", convert_datetime) hamster-3.0.3/src/hamster/storage/storage.py000066400000000000000000000201521452646177100211110ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2007 Patryk Zawadzki # Copyright (C) 2007-2012 Toms Baugis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import logging logger = logging.getLogger(__name__) # noqa: E402 from hamster.lib import datetime as dt from textwrap import dedent from hamster.lib.fact import Fact, FactError class Storage(object): """Abstract storage. Concrete instances should implement the required private methods, such as __get_facts. """ def run_fixtures(self): pass # signals that are called upon changes def tags_changed(self): pass def facts_changed(self): pass def activities_changed(self): pass def dispatch_overwrite(self): self.tags_changed() self.facts_changed() self.activities_changed() # facts @classmethod def check_fact(cls, fact, default_day=None): """Check Fact validity for inclusion in the storage. Raise FactError(message) on failure. """ if fact.start_time is None: raise FactError("Missing start time") if fact.end_time and (fact.delta < dt.timedelta(0)): fixed_fact = Fact(start_time=fact.start_time, end_time=fact.end_time + dt.timedelta(days=1)) suggested_range_str = fixed_fact.range.format(default_day=default_day) # work around cyclic imports from hamster.lib.configuration import conf raise FactError(dedent( """\ Duration would be negative. Working late ? This happens when the activity crosses the hamster day start time ({:%H:%M} from tracking settings). Suggestion: move the end to the next day; the range would become: {} (in civil local time) """.format(conf.day_start, suggested_range_str) )) if not fact.activity: raise FactError("Missing activity") if ',' in fact.category: raise FactError(dedent( """\ Forbidden comma in category: '{}' Note: The description separator changed from single comma to double comma ',,' (cf. PR #482). """.format(fact.category) )) def add_fact(self, fact, start_time=None, end_time=None, temporary=False): """Add fact. fact: either a Fact instance or a string that can be parsed through Fact.parse. note: start_time and end_time are used only when fact is a string, for backward compatibility. Passing fact as a string is deprecated and will be removed in a future version. Parsing should be done in the caller. """ if isinstance(fact, str): logger.info("Passing fact as a string is deprecated") fact = Fact.parse(fact) fact.start_time = start_time fact.end_time = end_time # better fail before opening the transaction self.check_fact(fact) self.start_transaction() result = self.__add_fact(fact, temporary) self.end_transaction() if result: self.facts_changed() return result def get_fact(self, fact_id): """Get fact by id. For output format see GetFacts""" return self.__get_fact(fact_id) def update_fact(self, fact_id, fact, start_time=None, end_time=None, temporary=False): # to be removed once update facts use Fact directly. if isinstance(fact, str): fact = Fact.parse(fact) fact = fact.copy(start_time=start_time, end_time=end_time) # better fail before opening the transaction self.check_fact(fact) self.start_transaction() self.__remove_fact(fact_id) result = self.__add_fact(fact, temporary) if not result: logger.warning("failed to update fact {} ({})".format(fact_id, fact)) self.end_transaction() if result: self.facts_changed() return result def stop_tracking(self, end_time): """Stops tracking the current activity""" facts = self.__get_todays_facts() if facts and not facts[-1].end_time: self.__touch_fact(facts[-1], end_time) self.facts_changed() def stop_or_restart_tracking(self): """Stops or restarts tracking the last activity""" facts = self.__get_todays_facts() if facts: if facts[-1].end_time: self.add_fact(facts[-1].copy(start_time=dt.datetime.now(), end_time = None)) else: self.__touch_fact(facts[-1], end_time=dt.datetime.now()) self.facts_changed() def remove_fact(self, fact_id): """Remove fact from storage by it's ID""" self.start_transaction() fact = self.__get_fact(fact_id) if fact: self.__remove_fact(fact_id) self.facts_changed() self.end_transaction() def get_facts(self, start, end=None, search_terms=""): range = dt.Range.from_start_end(start, end) return self.__get_facts(range, search_terms) def get_todays_facts(self): """Gets facts of today, respecting hamster midnight. See GetFacts for return info""" return self.__get_todays_facts() # categories def add_category(self, name): res = self.__add_category(name) self.activities_changed() return res def get_category_id(self, category): return self.__get_category_id(category) def update_category(self, id, name): self.__update_category(id, name) self.activities_changed() def remove_category(self, id): self.__remove_category(id) self.activities_changed() def get_categories(self): return self.__get_categories() # activities def add_activity(self, name, category_id = -1): new_id = self.__add_activity(name, category_id) self.activities_changed() return new_id def update_activity(self, id, name, category_id): self.__update_activity(id, name, category_id) self.activities_changed() def remove_activity(self, id): result = self.__remove_activity(id) self.activities_changed() return result def get_category_activities(self, category_id = -1): return self.__get_category_activities(category_id = category_id) def get_activities(self, search = ""): return self.__get_activities(search) def change_category(self, id, category_id): changed = self.__change_category(id, category_id) if changed: self.activities_changed() return changed def get_activity_by_name(self, activity, category_id, resurrect = True): category_id = category_id or None if activity: return dict(self.__get_activity_by_name(activity, category_id, resurrect) or {}) else: return {} # tags def get_tags(self, only_autocomplete): return self.__get_tags(only_autocomplete) def get_tag_ids(self, tags): tags, new_added = self.__get_tag_ids(tags) if new_added: self.tags_changed() return tags def update_autocomplete_tags(self, tags): changes = self.__update_autocomplete_tags(tags) if changes: self.tags_changed() hamster-3.0.3/src/hamster/version.py000066400000000000000000000026401452646177100174700ustar00rootroot00000000000000# Should not normally be used directly, use hamster.__version__ and # hamster.installed instead def get_installed_version(): try: # defs.py is created by waf from defs.py.in from hamster import defs return defs.VERSION except ImportError: # if defs is not there, we are running from sources return None def get_uninstalled_version(): # If available, prefer the git version, otherwise fall back to # the VERSION file (which is meaningful only in released # versions) from subprocess import getstatusoutput rc, output = getstatusoutput("git describe --tags --always --dirty=+") if rc == 0: import re # Strip "v" prefix that is used in git tags return re.sub(r'^v', '', output) else: from pathlib import Path with open(Path(__file__).parent / 'VERSION', 'r') as f: return f.read() def get_version(): """ Figure out the hamster version. Returns a tuple with the version string and wether we are installed or not. """ version = get_installed_version() if version is not None: return (version, True) version = get_uninstalled_version() return ("{} (uninstalled)".format(version), False) if __name__ == '__main__': import sys # Intended to be called by waf when installing, so only return # uninstalled version sys.stdout.write(get_uninstalled_version()) hamster-3.0.3/src/hamster/widgets/000077500000000000000000000000001452646177100170755ustar00rootroot00000000000000hamster-3.0.3/src/hamster/widgets/__init__.py000066400000000000000000000061251452646177100212120ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2007-2009 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import Pango as pango from hamster.lib import datetime as dt # import our children from hamster.widgets.activityentry import ( ActivityEntry, CategoryEntry, CmdLineEntry, ) from hamster.widgets.timeinput import TimeInput from hamster.widgets.dayline import DayLine from hamster.widgets.tags import Tag, TagBox, TagsEntry from hamster.widgets.reportchooserdialog import ReportChooserDialog from hamster.widgets.facttree import FactTree from hamster.widgets.dates import Calendar, RangePick # handy wrappers def add_hint(entry, hint): entry.hint = hint def override_get_text(self): #override get text so it does not return true when hint is in! if self.real_get_text() == self.hint: return "" else: return self.real_get_text() def _set_hint(self, widget, event): if self.get_text(): # do not mess with user entered text return self.modify_text(gtk.StateType.NORMAL, gdk.Color.parse("gray")[1]) hint_font = pango.FontDescription(self.get_style().font_desc.to_string()) hint_font.set_style(pango.Style.ITALIC) self.modify_font(hint_font) self.set_text(self.hint) def _set_normal(self, widget, event): #self.modify_text(gtk.StateType.NORMAL, self.get_style().fg[gtk.StateType.NORMAL]) hint_font = pango.FontDescription(self.get_style().font_desc.to_string()) hint_font.set_style(pango.Style.NORMAL) self.modify_font(hint_font) if self.real_get_text() == self.hint: self.set_text("") def _on_changed(self, widget): if self.real_get_text() == "" and self.is_focus() == False: self._set_hint(widget, None) import types instancemethod = types.MethodType entry._set_hint = instancemethod(_set_hint, entry, gtk.Entry) entry._set_normal = instancemethod(_set_normal, entry, gtk.Entry) entry._on_changed = instancemethod(_on_changed, entry, gtk.Entry) entry.real_get_text = entry.get_text entry.get_text = instancemethod(override_get_text, entry, gtk.Entry) entry.connect('focus-in-event', entry._set_normal) entry.connect('focus-out-event', entry._set_hint) entry.connect('changed', entry._on_changed) entry._set_hint(entry, None) hamster-3.0.3/src/hamster/widgets/activityentry.py000066400000000000000000000552461452646177100224010ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2009 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import logging logger = logging.getLogger(__name__) # noqa: E402 import bisect import cairo import re from gi.repository import Gdk as gdk from gi.repository import Gtk as gtk from gi.repository import GObject as gobject from gi.repository import PangoCairo as pangocairo from gi.repository import Pango as pango from collections import defaultdict from copy import deepcopy from hamster import client from hamster.lib import datetime as dt from hamster.lib import stuff from hamster.lib import graphics from hamster.lib.configuration import runtime from hamster.lib.fact import Fact # note: Still experimenting in this module. # Code redundancy to be removed later. def extract_search(text): fact = Fact.parse(text) search = fact.activity if fact.category: search += "@%s" % fact.category if fact.tags: search += " #%s" % (" #".join(fact.tags)) return search class DataRow(object): """want to split out visible label, description, activity data and activity data with time (full_data)""" def __init__(self, label, data=None, full_data=None, description=None): self.label = label self.data = data or label self.full_data = full_data or data or label self.description = description or "" class Label(object): """a much cheaper label that would be suitable for cellrenderer""" def __init__(self, x=0, y=0): self.x, self.y = x, y self._label_context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)) self.layout = pangocairo.create_layout(self._label_context) self.layout.set_font_description(pango.FontDescription(graphics._font_desc)) self.layout.set_markup("Hamster") # dummy self.height = self.layout.get_pixel_size()[1] def show(self, g, text, color=None): g.move_to(self.x, self.y) self.layout.set_markup(text) g.save_context() if color: g.set_color(color) pangocairo.show_layout(g.context, self.layout) g.restore_context() class CompleteTree(graphics.Scene): """ ASCII Art | Icon | Activity - description | """ __gsignals__ = { # enter or double-click, passes in current day and fact 'on-select-row': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } def __init__(self): graphics.Scene.__init__(self, style_class=gtk.STYLE_CLASS_VIEW) self.set_can_focus(False) self.row_positions = [] self.current_row = None self.rows = [] self.style = self._style self.label = Label(x=5, y=3) self.row_height = self.label.height + 10 self.connect("on-key-press", self.on_key_press) self.connect("on-enter-frame", self.on_enter_frame) self.connect("on-mouse-move", self.on_mouse_move) self.connect("on-mouse-down", self.on_mouse_down) def _get_mouse_row(self, event): hover_row = None for row, y in zip(self.rows, self.row_positions): if y <= event.y <= (y + self.row_height): hover_row = row break return hover_row def on_mouse_move(self, scene, event): row = self._get_mouse_row(event) if row: self.current_row = row self.redraw() def on_mouse_down(self, scene, event): row = self._get_mouse_row(event) if row: self.set_current_row(self.rows.index(row)) def on_key_press(self, scene, event): if event.keyval == gdk.KEY_Up: idx = self.rows.index(self.current_row) if self.current_row else 1 self.set_current_row(idx - 1) elif event.keyval == gdk.KEY_Down: idx = self.rows.index(self.current_row) if self.current_row else -1 self.set_current_row(idx + 1) def set_current_row(self, idx): idx = max(0, min(len(self.rows) - 1, idx)) row = self.rows[idx] self.current_row = row self.redraw() self.emit("on-select-row", row) def set_rows(self, rows): self.current_row = None self.rows = rows self.set_row_positions() def set_row_positions(self): """creates a list of row positions for simpler manipulation""" self.row_positions = [i * self.row_height for i in range(len(self.rows))] self.set_size_request(0, self.row_positions[-1] + self.row_height if self.row_positions else 0) def on_enter_frame(self, scene, context): if not self.height: return colors = { "normal": self.style.get_color(gtk.StateFlags.NORMAL), "normal_bg": self.style.get_background_color(gtk.StateFlags.NORMAL), "selected": self.style.get_color(gtk.StateFlags.SELECTED), "selected_bg": self.style.get_background_color(gtk.StateFlags.SELECTED), } g = graphics.Graphics(context) g.set_line_style(1) g.translate(0.5, 0.5) for row, y in zip(self.rows, self.row_positions): g.save_context() g.translate(0, y) color, bg = colors["normal"], colors["normal_bg"] if row == self.current_row: color, bg = colors["selected"], colors["selected_bg"] g.fill_area(0, 0, self.width, self.row_height, bg) label = row.label if row.description: description_color = graphics.Colors.mix(bg, color, 0.75) description_color_str = graphics.Colors.hex(description_color) label = '{} [{}]'.format(label, description_color_str, row.description) self.label.show(g, label, color=color) g.restore_context() class CmdLineEntry(gtk.Entry): def __init__(self, *, parent, **kwargs): gtk.Entry.__init__(self, parent=parent, **kwargs) # default day for times without date self.default_day = None # to be set by the caller, if editing an existing fact self.original_fact = None self.popup = gtk.Window(type = gtk.WindowType.POPUP) self.popup.set_type_hint(gdk.WindowTypeHint.COMBO) # why not self.popup.set_attached_to(self) # attributes self.popup.set_transient_for(self.get_ancestor(gtk.Window)) # position box = gtk.Frame() box.set_shadow_type(gtk.ShadowType.IN) self.popup.add(box) self.complete_tree = CompleteTree() self.tree_checker = self.complete_tree.connect("on-select-row", self.on_tree_select_row) self.complete_tree.connect("on-click", self.on_tree_click) box.add(self.complete_tree) self.storage = client.Storage() self.load_suggestions() self.ignore_stroke = False self.set_icon_from_icon_name(gtk.EntryIconPosition.SECONDARY, "go-down-symbolic") self.checker = self.connect("changed", self.on_changed) self.connect("key-press-event", self.on_key_press) self.connect("focus-out-event", self.on_focus_out) self.connect("icon-press", self.on_icon_press) def on_changed(self, entry): text = self.get_text() with self.complete_tree.handler_block(self.tree_checker): self.show_suggestions(text) if self.ignore_stroke: self.ignore_stroke = False return def complete(): text, suffix = self.complete_first() if suffix: #self.ignore_stroke = True with self.handler_block(self.checker): self.update_entry("%s%s" % (text, suffix)) self.select_region(len(text), -1) gobject.timeout_add(0, complete) def on_focus_out(self, entry, event): self.popup.hide() def on_icon_press(self, entry, icon, event): if self.popup.get_visible(): self.popup.hide() else: self.grab_focus() self.show_suggestions(self.get_text()) def on_key_press(self, entry, event=None): if event.keyval in (gdk.KEY_BackSpace, gdk.KEY_Delete): self.ignore_stroke = True elif event.keyval in (gdk.KEY_Return, gdk.KEY_KP_Enter, gdk.KEY_Escape): self.popup.hide() self.set_position(-1) elif event.keyval in (gdk.KEY_Up, gdk.KEY_Down): if not self.popup.get_visible(): self.show_suggestions(self.get_text()) self.complete_tree.on_key_press(self, event) return True def on_tree_click(self, entry, tree, event): self.popup.hide() def on_tree_select_row(self, tree, row): with self.handler_block(self.checker): label = row.full_data self.update_entry(label) self.set_position(-1) def load_suggestions(self): self.todays_facts = self.storage.get_todays_facts() # list of facts of last month now = dt.datetime.now() last_month = self.storage.get_facts(now - dt.timedelta(days=30), now) # naive recency and frequency rank # score is as simple as you get 30-days_ago points for each occurence suggestions = defaultdict(int) for fact in last_month: days = 30 - (now - dt.datetime.combine(fact.date, dt.time())).total_seconds() / 60 / 60 / 24 label = fact.activity if fact.category: label += "@%s" % fact.category suggestions[label] += days if fact.tags: label += " #%s" % (" #".join(fact.tags)) suggestions[label] += days for rec in self.storage.get_activities(): label = rec["name"] if rec["category"]: label += "@%s" % rec["category"] suggestions[label] += 0 # list of (label, score), higher scores first self.suggestions = sorted(suggestions.items(), key=lambda x: x[1], reverse=True) def complete_first(self): text = self.get_text() fact = Fact.parse(text) search = extract_search(text) if not self.complete_tree.rows or not fact.activity: return text, None label = self.complete_tree.rows[0].data if label.startswith(search): return text, label[len(search):] return text, None def update_entry(self, text): self.set_text(text or "") def update_suggestions(self, text=""): """ * from previous activity | set time | minutes ago | start now * to ongoing | set time * activity * [@category] * #tags, #tags, #tags * we will leave description for later all our magic is space separated, strictly, start-end can be just dash phases: [start_time] | [-end_time] | activity | [@category] | [#tag] """ res = [] fact = Fact.parse(text) now = dt.datetime.now() # figure out what we are looking for # time -> activity[@category] -> tags -> description # presence of an attribute means that we are not looking for the previous one # we still might be looking for the current one though looking_for = "start_time" fields = ["start_time", "end_time", "activity", "category", "tags", "description", "done"] for field in reversed(fields): if getattr(fact, field, None): looking_for = field if text[-1] == " ": looking_for = fields[fields.index(field)+1] break fragments = [f for f in re.split("[\s|#]", text)] current_fragment = fragments[-1] if fragments else "" search = extract_search(text) matches = [] for match, score in self.suggestions: if search in match: if match.startswith(search): score += 10**8 # boost beginnings matches.append((match, score)) # need to limit these guys, sorry matches = sorted(matches, key=lambda x: x[1], reverse=True)[:7] for match, score in matches: label = (fact.start_time or now).strftime("%H:%M") if fact.end_time: label += fact.end_time.strftime("-%H:%M") markup_label = label + " " + (stuff.escape_pango(match).replace(search, "%s" % search) if search else match) label += " " + match res.append(DataRow(markup_label, match, label)) # list of tuples (description, variant) variants = [] variant_fact = None if fact.end_time is None: description = "stop now" variant_fact = fact.copy() variant_fact.end_time = now elif self.todays_facts and fact == self.todays_facts[-1]: # that one is too dangerous, except for the last entry description = "keep up" # Do not use Fact(..., end_time=None): it would be a no-op variant_fact = fact.copy() variant_fact.end_time = None if variant_fact: variant_fact.description = None variant = variant_fact.serialized(default_day=self.default_day) variants.append((description, variant)) if fact.start_time is None: description = "start now" variant = now.strftime("%H:%M ") variants.append((description, variant)) prev_fact = self.todays_facts[-1] if self.todays_facts else None if prev_fact and prev_fact.end_time: since = (now - prev_fact.end_time).format() description = "from previous activity, %s ago" % since variant = prev_fact.end_time.strftime("%H:%M ") variants.append((description, variant)) description = "start activity -n minutes ago (1 or 3 digits allowed)" variant = "-" variants.append((description, variant)) text = text.strip() if text: description = "clear" variant = "" variants.append((description, variant)) for (description, variant) in variants: res.append(DataRow(variant, description=description)) self.complete_tree.set_rows(res) def show_suggestions(self, text): if not self.get_window(): return entry_alloc = self.get_allocation() entry_x, entry_y = self.get_window().get_origin()[1:] x, y = entry_x + entry_alloc.x, entry_y + entry_alloc.y + entry_alloc.height self.popup.show_all() self.update_suggestions(text) tree_w, tree_h = self.complete_tree.get_size_request() self.popup.move(x, y) self.popup.resize(entry_alloc.width, tree_h) self.popup.show_all() class ActivityEntry(): """Activity entry widget. widget (gtk.Entry): the associated activity entry category_widget (gtk.Entry): the associated category entry """ def __init__(self, widget=None, category_widget=None, **kwds): # widget and completion may be defined already # e.g. in the glade edit_activity.ui file self.widget = widget if not self.widget: self.widget = gtk.Entry(**kwds) self.category_widget = category_widget # internal list of actions added to the suggestions self._action_list = [] self.completion = self.widget.get_completion() if not self.completion: self.completion = gtk.EntryCompletion() self.widget.set_completion(self.completion) # text to display/filter on, activity, category self.text_column = 0 self.activity_column = 1 self.category_column = 2 # whether the category choice limit the activity suggestions self.filter_on_category = True if self.category_widget else False self.model = gtk.ListStore(str, str, str) self.completion.set_model(self.model) self.completion.set_text_column(self.text_column) self.completion.set_match_func(self.match_func, None) # enable selection with up and down arrow self.completion.set_inline_selection(True) # It is not possible to change actions later dynamically; # once actions are removed, # they can not be added back (they are not visible). # => nevermind, showing all actions. self.add_action("show all", "Show all activities") self.add_action("filter on category", "Filter on selected category") self.connect("icon-release", self.on_icon_release) self.connect("focus-in-event", self.on_focus_in_event) self.completion.connect('match-selected', self.on_match_selected) self.completion.connect("action_activated", self.on_action_activated) def add_action(self, name, text): """Add an action to the suggestions. name (str): unique label, use to retrieve the action index. text (str): text used to display the action. """ markup = "{}".format(stuff.escape_pango(text)) idx = len(self._action_list) self.completion.insert_action_markup(idx, markup) self._action_list.append(name) def clear(self, notify=True): self.widget.set_text("") if notify: self.emit("changed") def match_func(self, completion, key, iter, *user_data): if not key.strip(): # show all keys if entry is empty return True else: # return whether the entered string is # anywhere in the first column data stripped_key = key.strip() activities = self.model.get_value(iter, self.activity_column).lower() categories = self.model.get_value(iter, self.category_column).lower() key_in_activity = stripped_key in activities key_in_category = stripped_key in categories return key_in_activity or key_in_category def on_action_activated(self, completion, index): name = self._action_list[index] if name == "clear": self.clear(notify=False) elif name == "show all": self.filter_on_category = False self.populate_completions() elif name == "filter on category": self.filter_on_category = True self.populate_completions() def on_focus_in_event(self, widget, event): self.populate_completions() def on_icon_release(self, entry, icon_pos, event): self.grab_focus() self.set_text("") self.emit("changed") def on_match_selected(self, entry, model, iter): activity_name = model[iter][self.activity_column] category_name = model[iter][self.category_column] combined = model[iter][self.text_column] if self.category_widget: self.set_text(activity_name) if not self.filter_on_category: self.category_widget.set_text(category_name) else: self.set_text(combined) return True # prevent the standard callback from overwriting text def populate_completions(self): self.model.clear() if self.filter_on_category: category_names = [self.category_widget.get_text()] else: category_names = [category['name'] for category in runtime.storage.get_categories()] for category_name in category_names: category_id = runtime.storage.get_category_id(category_name) activities = runtime.storage.get_category_activities(category_id) for activity in activities: activity_name = activity["name"] text = "{}@{}".format(activity_name, category_name) self.model.append([text, activity_name, category_name]) def __getattr__(self, name): return getattr(self.widget, name) class CategoryEntry(): """Category entry widget. widget (gtk.Entry): the associated category entry """ def __init__(self, widget=None, **kwds): # widget and completion are already defined # e.g. in the glade edit_activity.ui file self.widget = widget if not self.widget: self.widget = gtk.Entry(**kwds) self.completion = self.widget.get_completion() if not self.completion: self.completion = gtk.EntryCompletion() self.widget.set_completion(self.completion) self.completion.insert_action_markup(0, "Clear ({})".format(_("Unsorted"))) self.unsorted_action_index = 0 self.model = gtk.ListStore(str) self.completion.set_model(self.model) self.completion.set_text_column(0) self.completion.set_match_func(self.match_func, None) self.widget.connect("icon-release", self.on_icon_release) self.widget.connect("focus-in-event", self.on_focus_in_event) self.completion.connect("action_activated", self.on_action_activated) def clear(self, notify=True): self.widget.set_text("") if notify: self.emit("changed") def match_func(self, completion, key, iter, *user_data): if not key.strip(): # show all keys if entry is empty return True else: # return whether the entered string is # anywhere in the first column data return key.strip() in self.model.get_value(iter, 0).lower() def on_action_activated(self, completion, index): if index == self.unsorted_action_index: self.clear(notify=False) def on_focus_in_event(self, widget, event): self.populate_completions() def on_icon_release(self, entry, icon_pos, event): self.widget.grab_focus() # do not emit changed on the primary (clear) button self.clear() def populate_completions(self): self.model.clear() for category in runtime.storage.get_categories(): self.model.append([category['name']]) def __getattr__(self, name): return getattr(self.widget, name) hamster-3.0.3/src/hamster/widgets/dates.py000066400000000000000000000166071452646177100205610ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2009, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import GObject as gobject from gi.repository import Gtk as gtk from gi.repository import Pango as pango import calendar import re from hamster.lib import datetime as dt from hamster.lib import stuff from hamster.lib.configuration import load_ui_file class Calendar(): """Python date interface to a Gtk.Calendar. widget (Gtk.Calendar): the associated Gtk widget. expander (Gtk.expander): An optional expander which contains the widget. The expander label displays the date. """ def __init__(self, widget, expander=None): self.widget = widget self.expander = expander self.widget.connect("day-selected", self.on_date_changed) @property def date(self): """Selected day, as datetime.date.""" year, month, day = self.widget.get_date() # months start at 0 in Gtk.Calendar and at 1 in python date month += 1 return dt.date(year=year, month=month, day=day) if day else None @date.setter def date(self, value): """Set date. value can be a python date or datetime. """ if value is None: # unselect day self.widget.select_day(0) else: year = value.year # months start at 0 in Gtk.Calendar and at 1 in python date month = value.month - 1 day = value.day self.widget.select_month(month, year) self.widget.select_day(day) def on_date_changed(self, widget): if self.expander: if self.date: self.expander.set_label(self.date.strftime("%A %Y-%m-%d")) else: self.expander.set_label("") def __getattr__(self, name): return getattr(self.widget, name) class RangePick(gtk.MenuButton): """ a text entry widget with calendar popup""" __gsignals__ = { # day|week|month|manual, start, end 'range-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), } def __init__(self, today): gtk.ToggleButton.__init__(self) self._ui = load_ui_file("date_range.ui") popup = self.get_widget("range_popup") popup.connect("show", self.on_show) self.set_popover(popup) self.today = today hbox = gtk.HBox() hbox.set_spacing(3) self.label = gtk.Label() hbox.add(self.label) hbox.add(gtk.Arrow(gtk.ArrowType.DOWN, gtk.ShadowType.ETCHED_IN)) self.add(hbox) self.start_date, self.end_date = None, None self.current_range = None self._ui.connect_signals(self) def set_range(self, start_date, end_date=None): end_date = end_date or start_date self.start_date, self.end_date = start_date, end_date self.label.set_markup('%s' % stuff.format_range(start_date, end_date)) def get_range(self): return self.start_date, self.end_date def emit_range(self, range, start, end): self.set_range(start, end) self.emit("range-selected", range, start, end) self.set_active(False) def prev_range(self): start, end = self.start_date, self.end_date if self.current_range == "day": start, end = start - dt.timedelta(1), end - dt.timedelta(1) elif self.current_range == "week": start, end = start - dt.timedelta(7), end - dt.timedelta(7) elif self.current_range == "month": end = start - dt.timedelta(1) first_weekday, days_in_month = calendar.monthrange(end.year, end.month) start = end - dt.timedelta(days_in_month - 1) else: # manual range - just jump to the next window days = (end - start) + dt.timedelta(days = 1) start = start - days end = end - days self.emit_range(self.current_range, start, end) def next_range(self): start, end = self.start_date, self.end_date if self.current_range == "day": start, end = start + dt.timedelta(1), end + dt.timedelta(1) elif self.current_range == "week": start, end = start + dt.timedelta(7), end + dt.timedelta(7) elif self.current_range == "month": start = end + dt.timedelta(1) first_weekday, days_in_month = calendar.monthrange(start.year, start.month) end = start + dt.timedelta(days_in_month - 1) else: # manual range - just jump to the next window days = (end - start) + dt.timedelta(days = 1) start = start + days end = end + days self.emit_range(self.current_range, start, end) def get_widget(self, name): """ skip one variable (huh) """ return self._ui.get_object(name) def on_show(self, user_data): self.get_widget("day_preview").set_text(stuff.format_range(self.today, self.today)) self.get_widget("week_preview").set_text(stuff.format_range(*stuff.week(self.today))) self.get_widget("month_preview").set_text(stuff.format_range(*stuff.month(self.today))) start_cal = self.get_widget("start_calendar") start_cal.select_month(self.start_date.month - 1, self.start_date.year) start_cal.select_day(self.start_date.day) end_cal = self.get_widget("end_calendar") end_cal.select_month(self.end_date.month - 1, self.end_date.year) end_cal.select_day(self.end_date.day) self.get_widget("day").grab_focus() def on_day_clicked(self, button): self.current_range = "day" self.emit_range("day", self.today, self.today) def on_week_clicked(self, button): self.current_range = "week" self.start_date, self.end_date = stuff.week(self.today) self.emit_range("week", self.start_date, self.end_date) def on_month_clicked(self, button): self.current_range = "month" self.start_date, self.end_date = stuff.month(self.today) self.emit_range("month", self.start_date, self.end_date) def on_manual_range_apply_clicked(self, button): self.current_range = "manual" # GtkCalendar January is 0, hence the + 1 year, month, day = self.get_widget("start_calendar").get_date() self.start_date = dt.date(year, month + 1, day) year, month, day = self.get_widget("end_calendar").get_date() self.end_date = dt.date(year, month + 1, day) # make sure we always have a valid range if self.end_date < self.start_date: self.start_date, self.end_date = self.end_date, self.start_date self.emit_range("manual", self.start_date, self.end_date) hamster-3.0.3/src/hamster/widgets/dayline.py000066400000000000000000000215731452646177100211040ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2007-2010 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import time from gi.repository import Gtk as gtk from gi.repository import GObject as gobject from gi.repository import PangoCairo as pangocairo from hamster.lib import datetime as dt from hamster.lib import graphics, pytweener from hamster.lib.configuration import conf class Selection(graphics.Sprite): def __init__(self, start_time = None, end_time = None): graphics.Sprite.__init__(self, z_order = 100) self.start_time, self.end_time = None, None self.width, self.height = None, None self.fill = None # will be set to proper theme color on render self.fixed = False self.start_label = graphics.Label("", 11, "#333", visible = False) self.end_label = graphics.Label("", 11, "#333", visible = False) self.duration_label = graphics.Label("", 11, "#FFF", visible = False) self.add_child(self.start_label, self.end_label, self.duration_label) self.connect("on-render", self.on_render) def on_render(self, sprite): if not self.fill: # not ready yet return self.graphics.rectangle(0, 0, self.width, self.height) self.graphics.fill_preserve(self.fill, 0.3) self.graphics.stroke(self.fill) # adjust labels self.start_label.visible = self.start_time is not None and self.start_time != self.end_time if self.start_label.visible: self.start_label.text = self.start_time.strftime("%H:%M") if self.x - self.start_label.width - 5 > 0: self.start_label.x = -self.start_label.width - 5 else: self.start_label.x = 5 self.start_label.y = self.height + 2 self.end_label.visible = self.end_time is not None and self.start_time != self.end_time if self.end_label.visible: self.end_label.text = self.end_time.strftime("%H:%M") self.end_label.x = self.width + 5 self.end_label.y = self.height + 2 duration = self.end_time - self.start_time duration = int(duration.seconds / 60) self.duration_label.text = "%02d:%02d" % (duration / 60, duration % 60) self.duration_label.visible = self.duration_label.width < self.width if self.duration_label.visible: self.duration_label.y = (self.height - self.duration_label.height) / 2 self.duration_label.x = (self.width - self.duration_label.width) / 2 else: self.duration_label.visible = False class DayLine(graphics.Scene): def __init__(self, start_time = None): graphics.Scene.__init__(self) self.set_can_focus(False) # no interaction self.day_start = conf.day_start start_time = start_time or dt.datetime.now() self.view_time = start_time or dt.datetime.combine(start_time.date(), self.day_start) self.scope_hours = 24 self.fact_bars = [] self.categories = [] self.connect("on-enter-frame", self.on_enter_frame) self.plot_area = graphics.Sprite(y=15) self.chosen_selection = Selection() self.plot_area.add_child(self.chosen_selection) self.drag_start = None self.current_x = None self.date_label = graphics.Label(color=self._style.get_color(gtk.StateFlags.NORMAL), x=5, y=16) self.add_child(self.plot_area, self.date_label) def plot(self, date, facts, select_start, select_end = None): for bar in self.fact_bars: self.plot_area.sprites.remove(bar) self.fact_bars = [] for fact in facts: fact_bar = graphics.Rectangle(0, 0, fill="#aaa", stroke="#aaa") # dimensions will depend on screen situation fact_bar.fact = fact if fact.category in self.categories: fact_bar.category = self.categories.index(fact.category) else: fact_bar.category = len(self.categories) self.categories.append(fact.category) self.plot_area.add_child(fact_bar) self.fact_bars.append(fact_bar) self.view_time = dt.datetime.combine(date, self.day_start) self.date_label.text = self.view_time.strftime("%b %d") self.chosen_selection.start_time = select_start self.chosen_selection.end_time = select_end self.chosen_selection.width = None self.chosen_selection.fixed = True self.chosen_selection.visible = True self.redraw() def on_enter_frame(self, scene, context): g = graphics.Graphics(context) self.plot_area.height = self.height - 30 vertical = min(self.plot_area.height / 5, 7) minute_pixel = (self.scope_hours * 60.0 - 15) / self.width g.set_line_style(width=1) g.translate(0.5, 0.5) colors = { "normal": self._style.get_color(gtk.StateFlags.NORMAL), "normal_bg": self._style.get_background_color(gtk.StateFlags.NORMAL), "selected": self._style.get_color(gtk.StateFlags.SELECTED), "selected_bg": self._style.get_background_color(gtk.StateFlags.SELECTED), } bottom = self.plot_area.y + self.plot_area.height for bar in self.fact_bars: bar.y = vertical * bar.category + 5 bar.height = vertical bar_start_time = bar.fact.start_time - self.view_time minutes = bar_start_time.seconds / 60 + bar_start_time.days * self.scope_hours * 60 bar.x = round(minutes / minute_pixel) + 0.5 bar.width = round((bar.fact.delta).seconds / 60 / minute_pixel) if self.chosen_selection.start_time and self.chosen_selection.width is None: # we have time but no pixels minutes = round((self.chosen_selection.start_time - self.view_time).seconds / 60 / minute_pixel) + 0.5 self.chosen_selection.x = minutes if self.chosen_selection.end_time: self.chosen_selection.width = round((self.chosen_selection.end_time - self.chosen_selection.start_time).seconds / 60 / minute_pixel) else: self.chosen_selection.width = 0 self.chosen_selection.height = self.chosen_selection.parent.height # use the oportunity to set proper colors too self.chosen_selection.fill = colors['selected_bg'] self.chosen_selection.duration_label.color = colors['selected'] #time scale g.set_color("#000") background = colors["normal_bg"] text = colors["normal"] tick_color = g.colors.contrast(background, 80) layout = g.create_layout(size = 10) for i in range(self.scope_hours * 60): time = (self.view_time + dt.timedelta(minutes=i)) g.set_color(tick_color) if time.minute == 0: g.move_to(round(i / minute_pixel), bottom - 15) g.line_to(round(i / minute_pixel), bottom) g.stroke() elif time.minute % 15 == 0: g.move_to(round(i / minute_pixel), bottom - 5) g.line_to(round(i / minute_pixel), bottom) g.stroke() if time.minute == 0 and time.hour % 4 == 0: if time.hour == 0: g.move_to(round(i / minute_pixel), self.plot_area.y) g.line_to(round(i / minute_pixel), bottom) label_minutes = time.strftime("%b %d") else: label_minutes = time.strftime("%H%M") g.set_color(text) layout.set_markup(label_minutes) g.move_to(round(i / minute_pixel) + 2, 0) pangocairo.show_layout(context, layout) #current time if self.view_time < dt.datetime.now() < self.view_time + dt.timedelta(hours = self.scope_hours): minutes = round((dt.datetime.now() - self.view_time).seconds / 60 / minute_pixel) g.rectangle(minutes, 0, self.width, self.height) g.fill(colors['normal_bg'], 0.7) g.move_to(minutes, self.plot_area.y) g.line_to(minutes, bottom) g.stroke("#f00", 0.4) hamster-3.0.3/src/hamster/widgets/facttree.py000066400000000000000000000540351452646177100212530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # Copyright (C) 2008-2009, 2014 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import bisect import cairo from collections import defaultdict from gi.repository import GObject as gobject from gi.repository import Gtk as gtk from gi.repository import Gdk as gdk from gi.repository import PangoCairo as pangocairo from gi.repository import Pango as pango from hamster.lib import datetime as dt from hamster.lib import graphics from hamster.lib import stuff from hamster.lib.fact import Fact class ActionRow(graphics.Sprite): def __init__(self): graphics.Sprite.__init__(self) self.visible = False self.restart = graphics.Icon("view-refresh-symbolic", size=18, interactive=True, mouse_cursor=gdk.CursorType.HAND1, y=4) self.add_child(self.restart) self.width = 50 # Simon says class TotalFact(Fact): """An extension of Fact that is used for daily totals. Instances of this class are rendered differently than instances of Fact. A TotalFact doesn't have a meaningful start and an end, but a total duration (delta). FIXME: Ideally, we should have a common parent for Fact and Total Fact so we don't need to have nonsensical start and end properties here. """ def __init__(self, activity, duration): super().__init__(activity=activity, start=dt.datetime.now(), end=dt.datetime.now()) self.duration = duration @property def delta(self): return self.duration class Label(object): """a much cheaper label that would be suitable for cellrenderer""" def __init__(self, x=0, y=0, color=None): self.x = x self.y = y self.color = color self._label_context = cairo.Context(cairo.ImageSurface(cairo.FORMAT_A1, 0, 0)) self.layout = pangocairo.create_layout(self._label_context) self.layout.set_font_description(pango.FontDescription(graphics._font_desc)) self.set_text("00:00 - 00:00") # dummy time_label for finding width @property def height(self): """Label height in pixels.""" return self.layout.get_pixel_size()[1] def set_text(self, text): self.text = text self.layout.set_markup(text) def get_text(self): return self.text def show(self, g, text=None, x=None, y=None): """Show the label. If text is given, it overrides any previous set_text(). x and y can be passed to temporary override the position. (self.x and self.y will not be changed) """ g.save_context() # fallback to self.x if x is None: x = self.x if y is None: y = self.y g.move_to(x, y) if text is not None: self.set_text(text) if self.color: g.set_color(self.color) pangocairo.show_layout(g.context, self.layout) g.restore_context() class TagLabel(Label): """Tag label, with small text.""" def set_text(self, text): Label.set_text(self, "{}".format(text)) class FactRow(object): def __init__(self): self.time_label = Label() x = self.time_label.layout.get_pixel_size()[0] + 10 self.activity_label = Label(x=x) self.category_label = Label() self.description_label = Label() self.tag_label = TagLabel() self.duration_label = Label() self.duration_label.layout.set_alignment(pango.Alignment.RIGHT) self.duration_label.layout.set_width(90 * pango.SCALE) self.width = 0 # margins (in pixels) self.tag_row_margin_H = 2.5 self.tag_row_margin_V = 2.5 self.tag_inner_margin_H = 3 self.tag_inner_margin_V = 2 self.inter_tag_margin = 4 self.row_margin_H = 5 self.row_margin_V = 2 self.category_offset_V = self.category_label.height * 0.1 @property def height(self): res = self.activity_label.height + 2 * 3 if self.fact.description: res += self.description_label.height if self.fact.tags: res += (self.tag_label.height + self.tag_inner_margin_V * 2 + self.tag_row_margin_V * 2) res += self.row_margin_V * 2 return res def set_fact(self, fact): """Set current fact.""" self.fact = fact time_label = fact.start_time.strftime("%H:%M -") if fact.end_time: time_label += fact.end_time.strftime(" %H:%M") self.time_label.set_text(time_label) self.activity_label.set_text(stuff.escape_pango(fact.activity)) category_text = " - {}".format(stuff.escape_pango(fact.category)) if fact.category else "" self.category_label.set_text(category_text) text = stuff.escape_pango(fact.description) description_text = "{}".format(text) if fact.description else "" self.description_label.set_text(description_text) if fact.tags: # for now, tags are on a single line. # The first one is enough to determine the height. self.tag_label.set_text(stuff.escape_pango(fact.tags[0])) def _show_tags(self, g, color, bg): label = self.tag_label label.color = bg g.save_context() g.translate(self.tag_row_margin_H, self.tag_row_margin_V) for tag in self.fact.tags: label.set_text(stuff.escape_pango(tag)) w, h = label.layout.get_pixel_size() rw = w + self.tag_inner_margin_H * 2 rh = h + self.tag_inner_margin_V * 2 g.rectangle(0, 0, rw, rh, 2) g.fill(color, 0.5) label.show(g, x=self.tag_inner_margin_H, y=self.tag_inner_margin_V) g.translate(rw + self.inter_tag_margin, 0) g.restore_context() def show(self, g, colors, fact=None, is_selected=False): """Display the fact row. If fact is given, the fact attribute is updated. """ g.save_context() if fact is not None: # before the selection highlight, to get the correct height self.set_fact(fact) color, bg = colors["normal"], colors["normal_bg"] if is_selected: color, bg = colors["selected"], colors["selected_bg"] g.fill_area(0, 0, self.width, self.height, bg) g.translate(self.row_margin_H, self.row_margin_V) g.set_color(color) # Do not show the start/end time for Totals if not isinstance(self.fact, TotalFact): self.time_label.show(g) self.activity_label.show(g, self.activity_label.get_text() if not isinstance(self.fact, TotalFact) else "{}".format(self.activity_label.get_text())) if self.fact.category: g.save_context() category_color = graphics.ColorUtils.mix(bg, color, 0.57) g.set_color(category_color) x = self.activity_label.x + self.activity_label.layout.get_pixel_size()[0] self.category_label.show(g, x=x, y=self.category_offset_V) g.restore_context() if self.fact.description or self.fact.tags: g.save_context() g.translate(self.activity_label.x, self.activity_label.height + 3) if self.fact.tags: self._show_tags(g, color, bg) tag_height = (self.tag_label.height + self.tag_inner_margin_V * 2 + self.tag_row_margin_V * 2) g.translate(0, tag_height) if self.fact.description: self.description_label.show(g) g.restore_context() self.duration_label.show(g, self.fact.delta.format() if not isinstance(self.fact, TotalFact) else "{}".format(self.fact.delta.format()), x=self.width - 105) g.restore_context() class FactTree(graphics.Scene, gtk.Scrollable): """ The fact tree is a painter. It does not change facts by itself, only sends signals. Facts get updated only through `set_facts`. It maintains scroll state and shows what we can see. That means it does not show all the facts there are, but rather only those that you can see. It's also painter as it reuses labels. Caching is futile, we do all the painting every time ASCII Art! | Weekday | Start - End | Activity - category [actions]| Duration | | Month, Day | | tags, description | | | | Start - End | Activity - category | Duration | | | | Total | Total Duration | Inline edit? """ __gsignals__ = { # enter or double-click, passes in current day and fact 'on-activate-row': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_PYOBJECT)), 'on-delete-called': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT,)), } hadjustment = gobject.property(type=gtk.Adjustment, default=None) hscroll_policy = gobject.property(type=gtk.ScrollablePolicy, default=gtk.ScrollablePolicy.MINIMUM) vadjustment = gobject.property(type=gtk.Adjustment, default=None) vscroll_policy = gobject.property(type=gtk.ScrollablePolicy, default=gtk.ScrollablePolicy.MINIMUM) def __init__(self): graphics.Scene.__init__(self, style_class=gtk.STYLE_CLASS_VIEW) self.date_label = Label(10, 3) fontdesc = pango.FontDescription(graphics._font_desc) fontdesc.set_weight(pango.Weight.BOLD) self.date_label.layout.set_alignment(pango.Alignment.RIGHT) self.date_label.layout.set_width(80 * pango.SCALE) self.date_label.layout.set_font_description(fontdesc) self.fact_row = FactRow() self.action_row = ActionRow() # self.add_child(self.action_row) self.row_positions = [] self.row_heights = [] self.y = 0 self.day_padding = 20 self.hover_day = None self.hover_fact = None self.current_fact = None self.style = self._style self.visible_range = None self.set_size_request(500, 400) self.connect("on-mouse-scroll", self.on_scroll) self.connect("on-mouse-move", self.on_mouse_move) self.connect("on-mouse-down", self.on_mouse_down) self.connect("on-resize", self.on_resize) self.connect("on-key-press", self.on_key_press) self.connect("notify::vadjustment", self._on_vadjustment_change) self.connect("on-enter-frame", self.on_enter_frame) self.connect("on-double-click", self.on_double_click) @property def current_fact_index(self): """Current fact index in the self.facts list.""" facts_ids = [fact.id for fact in self.facts] return facts_ids.index(self.current_fact.id) def on_mouse_down(self, scene, event): self.on_mouse_move(None, event) self.grab_focus() if self.hover_fact: # match either content or id if (self.hover_fact == self.current_fact or (self.hover_fact and self.current_fact and self.hover_fact.id == self.current_fact.id) ): self.unset_current_fact() # Totals can't be selected elif not isinstance(self.hover_fact, TotalFact): self.set_current_fact(self.hover_fact) def activate_row(self, day, fact): self.emit("on-activate-row", day, fact) def delete_row(self, fact): self.emit("on-delete-called", fact) def on_double_click(self, scene, event): if self.hover_fact and not isinstance(self.hover_fact, TotalFact): self.activate_row(self.hover_day, self.hover_fact) def on_key_press(self, scene, event): # all keys should appear also in the Overview.on_key_press # to be forwarded here even without focus. if event.keyval == gdk.KEY_Up: if self.facts: if self.current_fact: idx = max(0, self.current_fact_index - 1) else: # enter from below idx = len(self.facts) - 1 self.set_current_fact(self.facts[idx]) elif event.keyval == gdk.KEY_Down: if self.facts: if self.current_fact: idx = min(len(self.facts) - 1, self.current_fact_index + 1) else: # enter from top idx = 0 self.set_current_fact(self.facts[idx]) elif event.keyval == gdk.KEY_Home: if self.facts: self.set_current_fact(self.facts[0]) elif event.keyval == gdk.KEY_End: if self.facts: self.set_current_fact(self.facts[-1]) elif event.keyval == gdk.KEY_Page_Down: self.y += self.height * 0.8 self.on_scroll() elif event.keyval == gdk.KEY_Page_Up: self.y -= self.height * 0.8 self.on_scroll() elif event.keyval == gdk.KEY_Return: if self.current_fact: self.activate_row(self.hover_day, self.current_fact) elif event.keyval == gdk.KEY_Delete: if self.current_fact: self.delete_row(self.current_fact) def set_current_fact(self, fact): self.current_fact = fact if fact.y < self.y: self.y = fact.y if (fact.y + fact.height) > (self.y + self.height): self.y = fact.y + fact.height - self.height self.on_scroll() def unset_current_fact(self): """Deselect fact.""" self.current_fact = None self.on_scroll() def get_visible_range(self): start, end = (bisect.bisect(self.row_positions, self.y) - 1, bisect.bisect(self.row_positions, self.y + self.height)) y = self.y return [{"i": start + i, "y": pos - y, "h": height, "day": day, "facts": facts} for i, (pos, height, (day, facts)) in enumerate(zip(self.row_positions[start:end], self.row_heights[start:end], self.days[start:end]))] def on_mouse_move(self, tree, event): hover_day, hover_fact = None, None for rec in self.visible_range: if rec['y'] <= event.y <= (rec['y'] + rec['h']): hover_day = rec break if hover_day != self.hover_day: # Facts are considered equal if their content is the same, # even if their id is different. # redraw only cares about content, not id. self.redraw() # make sure it is always fully updated, including facts ids. self.hover_day = hover_day if self.hover_day: for fact in self.hover_day.get('facts', []): if (fact.y - self.y) <= event.y <= (fact.y - self.y + fact.height): hover_fact = fact break if (hover_fact and self.hover_fact and hover_fact.id != self.hover_fact.id ): self.move_actions() # idem, always update hover_fact, not just if they appear different self.hover_fact = hover_fact def move_actions(self): if self.hover_fact: self.action_row.visible = True self.action_row.x = self.width - 80 - self.action_row.width self.action_row.y = self.hover_fact.y - self.y else: self.action_row.visible = False def _on_vadjustment_change(self, scene, vadjustment): if not self.vadjustment: return self.vadjustment.connect("value_changed", self.on_scroll_value_changed) self.set_size_request(500, 300) def set_facts(self, facts, scroll_to_top=False): # FactTree adds attributes to its facts. isolate these side effects # copy the id too; most of the checks are based on id here. self.facts = [fact.copy(id=fact.id) for fact in facts] del facts # make sure facts is not used by inadvertance below. # If we get an entirely new set of facts, scroll back to the top if scroll_to_top: self.y = 0 self.hover_fact = None if self.vadjustment: self.vadjustment.set_value(self.y) if self.facts: start = self.facts[0].date end = self.facts[-1].date else: start = end = dt.hday.today() by_date = defaultdict(list) delta_by_date = defaultdict(dt.timedelta) for fact in self.facts: by_date[fact.date].append(fact) delta_by_date[fact.date] += fact.delta # Add a TotalFact at the end of each day if we are # displaying more than one day. if len(by_date) > 1: for key in by_date: total_by_date = TotalFact(_("Total"), delta_by_date[key]) by_date[key].append(total_by_date) days = [] for i in range((end - start).days + 1): current_date = start + dt.timedelta(days=i) if current_date in by_date: days.append((current_date, by_date[current_date])) self.days = days self.set_row_heights() if (self.current_fact and self.current_fact.id in (fact.id for fact in self.facts) ): self.on_scroll() else: # will also trigger an on_scroll self.unset_current_fact() def set_row_heights(self): """ the row height is defined by following factors: * how many facts are there in the day * does the fact have description / tags This func creates a list of row start positions to be able to quickly determine what to display """ if not self.height: return y, pos, heights = 0, [], [] for date, facts in self.days: height = 0 for fact in facts: self.fact_row.set_fact(fact) fact_height = self.fact_row.height fact.y = y + height fact.height = fact_height height += fact.height height += self.day_padding height = max(height, 60) pos.append(y) heights.append(height) y += height self.row_positions, self.row_heights = pos, heights maxy = max(y, 1) if self.vadjustment: self.vadjustment.set_lower(0) self.vadjustment.set_upper(max(maxy, self.height)) self.vadjustment.set_page_size(self.height) def on_resize(self, scene, event): self.set_row_heights() self.fact_row.width = self.width - 105 self.on_scroll() def on_scroll_value_changed(self, scroll): self.y = int(scroll.get_value()) self.on_scroll() def on_scroll(self, scene=None, event=None): if not self.height: return y_pos = self.y direction = 0 if event and event.direction == gdk.ScrollDirection.UP: direction = -1 elif event and event.direction == gdk.ScrollDirection.DOWN: direction = 1 y_pos += 15 * direction if self.vadjustment: y_pos = max(0, min(self.vadjustment.get_upper() - self.height, y_pos)) self.vadjustment.set_value(y_pos) self.y = y_pos self.move_actions() self.redraw() self.visible_range = self.get_visible_range() def on_enter_frame(self, scene, context): has_focus = self.get_toplevel().has_toplevel_focus() if has_focus: colors = { "normal": self.style.get_color(gtk.StateFlags.NORMAL), "normal_bg": self.style.get_background_color(gtk.StateFlags.NORMAL), "selected": self.style.get_color(gtk.StateFlags.SELECTED), "selected_bg": self.style.get_background_color(gtk.StateFlags.SELECTED), } else: colors = { "normal": self.style.get_color(gtk.StateFlags.BACKDROP), "normal_bg": self.style.get_background_color(gtk.StateFlags.BACKDROP), "selected": self.style.get_color(gtk.StateFlags.BACKDROP), "selected_bg": self.style.get_background_color(gtk.StateFlags.BACKDROP), } if not self.height: return g = graphics.Graphics(context) g.set_line_style(1) g.translate(0.5, 0.5) date_bg_color = self.colors.mix(colors["normal_bg"], colors["normal"], 0.15) g.fill_area(0, 0, 105, self.height, date_bg_color) y = int(self.y) for rec in self.visible_range: g.save_context() g.translate(0, rec['y']) g.set_color(colors["normal"]) self.date_label.show(g, rec['day'].strftime("%A\n%b %d")) g.translate(105, 0) for fact in rec['facts']: is_selected = (self.current_fact is not None and fact.id == self.current_fact.id) self.fact_row.set_fact(fact) self.fact_row.show(g, colors, is_selected=is_selected) g.translate(0, self.fact_row.height) g.restore_context() hamster-3.0.3/src/hamster/widgets/reportchooserdialog.py000066400000000000000000000117041452646177100235300ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2009 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import os from gi.repository import GObject as gobject from gi.repository import Gtk as gtk from hamster.lib.configuration import conf class ReportChooserDialog(gtk.Dialog): __gsignals__ = { # format, path, start_date, end_date 'report-chosen': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, gobject.TYPE_STRING)), 'report-chooser-closed': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self): gtk.Dialog.__init__(self) self.dialog = gtk.FileChooserDialog(title = _("Save Report — Time Tracker"), parent = self, action = gtk.FileChooserAction.SAVE, buttons=(gtk.STOCK_CANCEL, gtk.ResponseType.CANCEL, gtk.STOCK_SAVE, gtk.ResponseType.OK)) # try to set path to last known folder or fall back to home report_folder = os.path.expanduser(conf.get("last-report-folder")) if os.path.exists(report_folder): self.dialog.set_current_folder(report_folder) else: self.dialog.set_current_folder(os.path.expanduser("~")) self.filters = {} filter = gtk.FileFilter() filter.set_name(_("HTML Report")) filter.add_mime_type("text/html") filter.add_pattern("*.html") filter.add_pattern("*.htm") self.filters[filter] = "html" self.dialog.add_filter(filter) filter = gtk.FileFilter() filter.set_name(_("Tab-Separated Values (TSV)")) filter.add_mime_type("text/plain") filter.add_pattern("*.tsv") filter.add_pattern("*.txt") self.filters[filter] = "tsv" self.dialog.add_filter(filter) filter = gtk.FileFilter() filter.set_name(_("XML")) filter.add_mime_type("text/xml") filter.add_pattern("*.xml") self.filters[filter] = "xml" self.dialog.add_filter(filter) filter = gtk.FileFilter() filter.set_name(_("iCal")) filter.add_mime_type("text/calendar") filter.add_pattern("*.ics") self.filters[filter] = "ical" self.dialog.add_filter(filter) filter = gtk.FileFilter() filter.set_name("All files") filter.add_pattern("*") self.dialog.add_filter(filter) def show(self, start_date, end_date): """setting suggested name to something readable, replace backslashes with dots so the name is valid in linux""" # title in the report file name vars = {"title": _("Time track"), "start": start_date.strftime("%x").replace("/", "."), "end": end_date.strftime("%x").replace("/", ".")} if start_date != end_date: filename = "%(title)s, %(start)s - %(end)s.html" % vars else: filename = "%(title)s, %(start)s.html" % vars self.dialog.set_current_name(filename) response = self.dialog.run() if response != gtk.ResponseType.OK: self.emit("report-chooser-closed") self.dialog.destroy() self.dialog = None else: self.on_save_button_clicked() def present(self): self.dialog.present() def on_save_button_clicked(self): path, format = None, None format = "html" if self.dialog.get_filter() in self.filters: format = self.filters[self.dialog.get_filter()] path = self.dialog.get_filename() # append correct extension if it is missing # TODO - proper way would be to change extension on filter change # only pointer in web is http://www.mail-archive.com/pygtk@daa.com.au/msg08740.html if path.endswith(".%s" % format) == False: path = "%s.%s" % (path.rstrip("."), format) categories = [] conf.set("last-report-folder", os.path.dirname(path)) # format, path, start_date, end_date self.emit("report-chosen", format, path) self.dialog.destroy() self.dialog = None hamster-3.0.3/src/hamster/widgets/tags.py000066400000000000000000000303511452646177100204070ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2009 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . from gi.repository import GObject as gobject from gi.repository import Gdk as gdk from gi.repository import Gtk as gtk from gi.repository import Pango as pango import cairo from math import pi from hamster.lib import graphics, stuff from hamster.lib.configuration import runtime class TagsEntry(gtk.Entry): __gsignals__ = { 'tags-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, *, parent): gtk.Entry.__init__(self, parent=parent) self.ac_tags = None # "autocomplete" tags self.filter = None # currently applied filter string self.filter_tags = [] #filtered tags self.popup = gtk.Window(type = gtk.WindowType.POPUP) self.popup.set_attached_to(self) self.popup.set_transient_for(self.get_ancestor(gtk.Window)) self.scroll_box = gtk.ScrolledWindow() self.scroll_box.set_shadow_type(gtk.ShadowType.IN) self.scroll_box.set_policy(gtk.PolicyType.NEVER, gtk.PolicyType.AUTOMATIC) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.ShadowType.NONE) self.tag_box = TagBox() self.tag_box.connect("tag-selected", self.on_tag_selected) self.tag_box.connect("tag-unselected", self.on_tag_unselected) viewport.add(self.tag_box) self.scroll_box.add(viewport) self.popup.add(self.scroll_box) self.set_icon_from_icon_name(gtk.EntryIconPosition.SECONDARY, "go-down-symbolic") self.connect("icon-press", self._on_icon_press) self.connect("key-press-event", self._on_key_press_event) self.connect("focus-out-event", self._on_focus_out_event) self._parent_click_watcher = None # bit lame but works self.external_listeners = [ (runtime.storage, runtime.storage.connect('tags-changed', self.refresh_ac_tags)) ] self.show() self.populate_suggestions() self.connect("destroy", self.on_destroy) def on_destroy(self, window): for obj, handler in self.external_listeners: obj.disconnect(handler) self.popup.destroy() self.popup = None def refresh_ac_tags(self, event): self.ac_tags = None def get_tags(self): # splits the string by comma and filters out blanks return [tag.strip() for tag in self.get_text().split(",") if tag.strip()] def on_tag_selected(self, tag_box, tag): cursor_tag = self.get_cursor_tag() if cursor_tag and tag.lower().startswith(cursor_tag.lower()): self.replace_tag(cursor_tag, tag) tags = self.get_tags() else: tags = self.get_tags() tags.append(tag) self.tag_box.selected_tags = tags self.set_tags(tags) self.update_tagsline(add=True) self.populate_suggestions() self.show_popup() def on_tag_unselected(self, tag_box, tag): tags = self.get_tags() while tag in tags: #it could be that dear user is mocking us and entering same tag over and over again tags.remove(tag) self.tag_box.selected_tags = tags self.set_tags(tags) self.update_tagsline(add=True) def hide_popup(self): self.popup.hide() if self._parent_click_watcher and self.get_toplevel().handler_is_connected(self._parent_click_watcher): self.get_toplevel().disconnect(self._parent_click_watcher) self._parent_click_watcher = None def show_popup(self): if not self.filter_tags: self.popup.hide() return if not self._parent_click_watcher: self._parent_click_watcher = self.get_toplevel().connect("button-press-event", self._on_focus_out_event) alloc = self.get_allocation() _, x, y = self.get_parent_window().get_origin() self.popup.move(x + alloc.x,y + alloc.y + alloc.height) w = alloc.width height = self.tag_box.count_height(w) self.scroll_box.set_size_request(w, height) self.popup.resize(w, height) self.popup.show_all() def refresh_activities(self): # scratch activities and categories so that they get repopulated on demand self.activities = None self.categories = None def populate_suggestions(self): self.ac_tags = self.ac_tags or [tag["name"] for tag in runtime.storage.get_tags(only_autocomplete=True)] cursor_tag = self.get_cursor_tag() self.filter = cursor_tag entered_tags = self.get_tags() self.tag_box.selected_tags = entered_tags self.filter_tags = [tag for tag in self.ac_tags if (tag or "").lower().startswith((self.filter or "").lower())] self.tag_box.draw(self.filter_tags) def _on_focus_out_event(self, widget, event): self.hide_popup() def _on_icon_press(self, entry, icon_pos, event): # otherwise Esc could not hide popup self.grab_focus() # toggle popup if self.popup.get_visible(): # remove trailing comma if any self.update_tagsline(add=False) self.hide_popup() else: # add trailing comma self.update_tagsline(add=True) self.populate_suggestions() self.show_popup() def get_cursor_tag(self): #returns the tag on which the cursor is on right now if self.get_selection_bounds(): cursor = self.get_selection_bounds()[0] else: cursor = self.get_position() text = self.get_text() return text[text.rfind(",", 0, cursor)+1:max(text.find(",", cursor+1)+1, len(text))].strip() def replace_tag(self, old_tag, new_tag): tags = self.get_tags() if old_tag in tags: tags[tags.index(old_tag)] = new_tag if self.get_selection_bounds(): cursor = self.get_selection_bounds()[0] else: cursor = self.get_position() self.set_tags(tags) self.set_position(len(self.get_text())) def set_tags(self, tags): self.tags = tags self.update_tagsline() def update_tagsline(self, add=False): """Update tags line text. If add is True, prepare to add tags to the list: a comma is appended and the popup is displayed. """ text = ", ".join(self.tags) if add and text: text = "{}, ".format(text) self.set_text(text) self.set_position(len(self.get_text())) def _on_key_press_event(self, entry, event): if event.keyval == gdk.KEY_Tab: if self.popup.get_property("visible"): #we have to replace if self.get_text() and self.get_cursor_tag() != self.filter_tags[0]: self.replace_tag(self.get_cursor_tag(), self.filter_tags[0]) return True else: return False else: return False elif event.keyval in (gdk.KEY_Return, gdk.KEY_KP_Enter): if self.popup.get_property("visible"): if self.get_text(): self.hide_popup() return True else: if self.get_text(): self.emit("tags-selected") return False elif event.keyval == gdk.KEY_Escape: if self.popup.get_property("visible"): self.hide_popup() return True else: return False else: self.populate_suggestions() self.show_popup() return False class TagBox(graphics.Scene): __gsignals__ = { 'tag-selected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)), 'tag-unselected': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (str,)), } def __init__(self, interactive = True): graphics.Scene.__init__(self) self.interactive = interactive self.hover_tag = None self.tags = [] self.selected_tags = [] self.layout = None if self.interactive: self.connect("on-mouse-over", self.on_mouse_over) self.connect("on-mouse-out", self.on_mouse_out) self.connect("on-click", self.on_tag_click) self.connect("on-enter-frame", self.on_enter_frame) def on_mouse_over(self, area, tag): tag.color = tag.graphics.colors.darker(tag.color, -20) def on_mouse_out(self, area, tag): if tag.text in self.selected_tags: tag.color = (242, 229, 97) else: tag.color = (241, 234, 170) def on_tag_click(self, area, event, tag): if not tag: return if tag.text in self.selected_tags: self.emit("tag-unselected", tag.text) else: self.emit("tag-selected", tag.text) self.on_mouse_out(area, tag) #paint self.redraw() def draw(self, tags): new_tags = [] for label in tags: tag = Tag(label) if label in self.selected_tags: tag.color = (242, 229, 97) new_tags.append(tag) for tag in self.tags: self.sprites.remove(tag) self.add_child(*new_tags) self.tags = new_tags self.show() self.redraw() def count_height(self, width): # reposition tags and see how much space we take up self.width = width w, h = self.on_enter_frame(None, None) return h + 6 def on_enter_frame(self, scene, context): cur_x, cur_y = 4, 4 tag = None for tag in self.tags: if cur_x + tag.width >= self.width - 5: #if we do not fit, we wrap cur_x = 5 cur_y += tag.height + 6 tag.x = cur_x tag.y = cur_y cur_x += tag.width + 6 #some padding too, please if tag: cur_y += tag.height + 2 # the last one return cur_x, cur_y class Tag(graphics.Sprite): def __init__(self, text, interactive = True, color = "#F1EAAA"): graphics.Sprite.__init__(self, interactive = interactive) self.width, self.height = 0,0 font = gtk.Style().font_desc font_size = int(font.get_size() * 0.8 / pango.SCALE) # 80% of default self.label = graphics.Label(text, size = font_size, color = (30, 30, 30), y = 1) self.color = color self.add_child(self.label) self.corner = int((self.label.height + 3) / 3) + 0.5 self.label.x = self.corner + 6 self.text = stuff.escape_pango(text) self.connect("on-render", self.on_render) def __setattr__(self, name, value): graphics.Sprite.__setattr__(self, name, value) if name == 'text' and hasattr(self, 'label'): self.label.text = value self.__dict__['width'], self.__dict__['height'] = int(self.label.x + self.label.width + self.label.height * 0.3), self.label.height + 3 def on_render(self, sprite): self.graphics.set_line_style(width=1) self.graphics.move_to(0.5, self.corner) self.graphics.line_to([(self.corner, 0.5), (self.width + 0.5, 0.5), (self.width + 0.5, self.height - 0.5), (self.corner, self.height - 0.5), (0.5, self.height - self.corner)]) self.graphics.close_path() self.graphics.fill_stroke(self.color, "#b4b4b4") self.graphics.circle(6, self.height / 2, 2) self.graphics.fill_stroke("#fff", "#b4b4b4") hamster-3.0.3/src/hamster/widgets/timeinput.py000066400000000000000000000245461452646177100215000ustar00rootroot00000000000000# - coding: utf-8 - # Copyright (C) 2008-2009 Toms Bauģis # This file is part of Project Hamster. # Project Hamster is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # Project Hamster is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with Project Hamster. If not, see . import calendar import re from gi.repository import Gdk as gdk from gi.repository import Gtk as gtk from gi.repository import GObject as gobject from hamster.lib import datetime as dt from hamster.lib.stuff import hamster_round class TimeInput(gtk.Entry): __gsignals__ = { 'time-entered': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()), } def __init__(self, time=None, start_time=None, *, parent, **kwargs): gtk.Entry.__init__(self, parent=parent, **kwargs) self.news = False self.set_width_chars(7) #7 is like 11:24pm self.time = time self.set_start_time(start_time) self.popup = gtk.Window(type = gtk.WindowType.POPUP) self.popup.set_type_hint(gdk.WindowTypeHint.COMBO) # why not self.popup.set_attached_to(self) # attributes self.popup.set_transient_for(self.get_ancestor(gtk.Window)) # position time_box = gtk.ScrolledWindow() time_box.set_policy(gtk.PolicyType.NEVER, gtk.PolicyType.ALWAYS) time_box.set_shadow_type(gtk.ShadowType.IN) self.time_tree = gtk.TreeView() self.time_tree.set_headers_visible(False) self.time_tree.set_hover_selection(True) self.time_tree.append_column(gtk.TreeViewColumn("Time", gtk.CellRendererText(), text=0)) self.time_tree.connect("button-press-event", self._on_time_tree_button_press_event) time_box.add(self.time_tree) self.popup.add(time_box) self.set_icon_from_icon_name(gtk.EntryIconPosition.PRIMARY, "edit-clear-all-symbolic") self.connect("icon-release", self._on_icon_release) self.connect("button-press-event", self._on_button_press_event) self.connect("key-press-event", self._on_key_press_event) self.connect("focus-in-event", self._on_focus_in_event) self.connect("focus-out-event", self._on_focus_out_event) self._parent_click_watcher = None # bit lame but works self.connect("changed", self._on_text_changed) self.show() self.connect("destroy", self.on_destroy) @property def time(self): """Displayed time. None, or time type, or datetime if start_time() was given a datetime. """ time = self.figure_time(self.get_text()) if self.start_date and time: # recombine (since self.start_time contains only the time part) start = dt.datetime.combine(self.start_date, self.start_time) new = dt.datetime.combine(self.start_date, time) if new < start: # a bit hackish, valid only because # duration can not be negative if start_time was given, # and we accept that it can not exceed 24h. # For longer durations, # date will have to be changed subsequently. return new + dt.timedelta(days=1) else: return new else: return time @time.setter def time(self, value): time = hamster_round(value) self.set_text(self._format_time(time)) return time def on_destroy(self, window): self.popup.destroy() self.popup = None def set_start_time(self, start_time): """ Set the start time. When start time is set, drop down list will start from start time, and duration will be displayed in brackets. self.time will have the same type as start_time. """ start_time = hamster_round(start_time) if isinstance(start_time, dt.datetime): self.start_date = start_time.date() # timeinput works on time only start_time = start_time.time() else: self.start_date = None self.start_time = start_time def _on_text_changed(self, widget): self.news = True def figure_time(self, str_time): if not str_time: return None # strip everything non-numeric and consider hours to be first number # and minutes - second number numbers = re.split("\D", str_time) numbers = [x for x in numbers if x!=""] hours, minutes = None, None if len(numbers) == 1 and len(numbers[0]) == 4: hours, minutes = int(numbers[0][:2]), int(numbers[0][2:]) else: if len(numbers) >= 1: hours = int(numbers[0]) if len(numbers) >= 2: minutes = int(numbers[1]) if (hours is None or minutes is None) or hours > 24 or minutes > 60: return None # no can do return dt.time(hours, minutes) def _select_time(self, time_text): #convert forth and back so we have text formated as we want time = self.figure_time(time_text) time_text = self._format_time(time) self.set_text(time_text) self.set_position(len(time_text)) self.hide_popup() if self.news: self.emit("time-entered") self.news = False def _format_time(self, time): if time is None: return "" return time.strftime("%H:%M").lower() def _on_focus_in_event(self, entry, event): self.show_popup() def _on_button_press_event(self, button, event): self.show_popup() def _on_focus_out_event(self, event, something): self.hide_popup() if self.news: self.emit("time-entered") self.news = False def _on_icon_release(self, entry, icon_pos, event): self.grab_focus() self.set_text("") self.emit("changed") def hide_popup(self): if self._parent_click_watcher and self.get_toplevel().handler_is_connected(self._parent_click_watcher): self.get_toplevel().disconnect(self._parent_click_watcher) self._parent_click_watcher = None self.popup.hide() def show_popup(self): if not self._parent_click_watcher: self._parent_click_watcher = self.get_toplevel().connect("button-press-event", self._on_focus_out_event) # we will be adding things, need datetime i_time_0 = dt.datetime.combine(self.start_date or dt.date.today(), self.start_time or dt.time()) if self.start_time is None: # full 24 hours i_time = i_time_0 interval = dt.timedelta(minutes = 15) end_time = i_time_0 + dt.timedelta(days = 1) else: # from start time to start time + 12 hours interval = dt.timedelta(minutes = 15) i_time = i_time_0 + interval end_time = i_time_0 + dt.timedelta(hours = 12) time = self.figure_time(self.get_text()) focus_time = dt.datetime.combine(dt.date.today(), time) if time else None hours = gtk.ListStore(str) i, focus_row = 0, None while i_time < end_time: row_text = self._format_time(i_time) if self.start_time is not None: delta_text = (i_time - i_time_0).format() row_text += " (%s)" % delta_text hours.append([row_text]) if focus_time and i_time <= focus_time < i_time + interval: focus_row = i i_time += interval i += 1 self.time_tree.set_model(hours) #focus on row if focus_row != None: selection = self.time_tree.get_selection() selection.select_path(focus_row) self.time_tree.scroll_to_cell(focus_row, use_align = True, row_align = 0.4) #move popup under the widget alloc = self.get_allocation() w = alloc.width self.time_tree.set_size_request(w, alloc.height * 5) window = self.get_parent_window() dmmy, x, y= window.get_origin() self.popup.move(x + alloc.x,y + alloc.y + alloc.height) self.popup.resize(*self.time_tree.get_size_request()) self.popup.show_all() def toggle_popup(self): if self.popup.get_property("visible"): self.hide_popup() else: self.show_popup() def _on_time_tree_button_press_event(self, tree, event): model, iter = tree.get_selection().get_selected() time = model.get_value(iter, 0) self._select_time(time) def _on_key_press_event(self, entry, event): if event.keyval not in (gdk.KEY_Up, gdk.KEY_Down, gdk.KEY_Return, gdk.KEY_KP_Enter): #any kind of other input self.hide_popup() return False model, iter = self.time_tree.get_selection().get_selected() if not iter: return i = model.get_path(iter)[0] if event.keyval == gdk.KEY_Up: i-=1 elif event.keyval == gdk.KEY_Down: i+=1 elif (event.keyval == gdk.KEY_Return or event.keyval == gdk.KEY_KP_Enter): if self.popup.get_property("visible"): self._select_time(self.time_tree.get_model()[i][0]) else: self._select_time(entry.get_text()) elif (event.keyval == gdk.KEY_Escape): self.hide_popup() return # keep it in sane limits i = min(max(i, 0), len(self.time_tree.get_model()) - 1) self.time_tree.set_cursor(i) self.time_tree.scroll_to_cell(i, use_align = True, row_align = 0.4) # if popup is not visible, display it on up and down if event.keyval in (gdk.KEY_Up, gdk.KEY_Down) and self.popup.props.visible == False: self.show_popup() return True hamster-3.0.3/tests/000077500000000000000000000000001452646177100143375ustar00rootroot00000000000000hamster-3.0.3/tests/__init__.py000066400000000000000000000000241452646177100164440ustar00rootroot00000000000000# - coding: utf-8 - hamster-3.0.3/tests/test_stuff.py000066400000000000000000000553071452646177100171110ustar00rootroot00000000000000import sys, os.path # a convoluted line to add hamster module to absolute path sys.path.insert(0, os.path.realpath(os.path.join(os.path.dirname(__file__), "../src"))) import datetime as pdt import unittest import re from hamster.lib import datetime as dt from hamster.lib.dbus import ( to_dbus_fact, to_dbus_fact_json, to_dbus_range, from_dbus_fact, from_dbus_fact_json, from_dbus_range, ) from hamster.lib.fact import Fact from hamster.lib.parsing import get_tags_from_description class TestFact(unittest.TestCase): def test_range(self): t1 = dt.datetime(2020, 1, 15, 13, 30) t2 = dt.datetime(2020, 1, 15, 15, 30) range = dt.Range(t1, t2) fact = Fact(range=range) self.assertEqual(fact.range.start, t1) self.assertEqual(fact.range.end, t2) fact = Fact(start=t1, end=t2) self.assertEqual(fact.range.start, t1) self.assertEqual(fact.range.end, t2) # backward compatibility (before v3.0) fact = Fact(start_time=t1, end_time=t2) self.assertEqual(fact.range.start, t1) self.assertEqual(fact.range.end, t2) class TestFactParsing(unittest.TestCase): def test_plain_name(self): # plain activity name activity = Fact.parse("just a simple case with ütf-8") self.assertEqual(activity.activity, "just a simple case with ütf-8") assert activity.start_time is None assert activity.end_time is None assert not activity.category assert not activity.description def test_only_range(self): fact = Fact.parse("-20") assert not fact.activity fact = Fact.parse("-20 -10") assert not fact.activity def test_with_start_time(self): # with time activity = Fact.parse("12:35 with start time") self.assertEqual(activity.activity, "with start time") self.assertEqual(activity.start_time.strftime("%H:%M"), "12:35") #rest must be empty assert not activity.category assert activity.end_time is None assert not activity.description def test_with_start_and_end_time(self): # with time activity = Fact.parse("12:35-14:25 with start-end time") self.assertEqual(activity.activity, "with start-end time") self.assertEqual(activity.start_time.strftime("%H:%M"), "12:35") self.assertEqual(activity.end_time.strftime("%H:%M"), "14:25") #rest must be empty assert not activity.category assert not activity.description def test_category(self): # plain activity name activity = Fact.parse("just a simple case@hämster") self.assertEqual(activity.activity, "just a simple case") self.assertEqual(activity.category, "hämster") assert activity.start_time is None assert activity.end_time is None assert not activity.description def test_description(self): # plain activity name activity = Fact.parse("case, with added descriptiön") self.assertEqual(activity.activity, "case") self.assertEqual(activity.description, "with added descriptiön") assert not activity.category assert activity.start_time is None assert activity.end_time is None assert not activity.category def test_description_with_commas(self): activity = Fact.parse("case, meet with a, b and c, #holiday") self.assertEqual(activity.description, "meet with a, b and c") def test_tags(self): # plain activity name activity = Fact.parse("#case, description with #hash, #and #some #tägs") self.assertEqual(activity.activity, "#case") self.assertEqual(activity.description, "description with #hash") self.assertEqual(set(activity.tags), set(["and", "hash", "some", "tägs"])) assert not activity.category assert activity.start_time is None assert activity.end_time is None def test_multiple_tags_separated_with_commas(self): activity = Fact.parse("devel, fun times, #bugs, #pr, #hamster") self.assertEqual(set(activity.tags), set(["bugs", "pr", "hamster"])) def test_tag_in_description_ignores_tag_starting_with_a_number(self): activity = Fact.parse("case, fix bug #123, #tag1") self.assertEqual(activity.description, "fix bug #123") self.assertEqual(set(activity.tags), set(["tag1"])) def test_serialization_does_not_duplicate_tag_from_description(self): fact = Fact(activity="activity", description="review #pr", tags=["pr", "hamster"]) self.assertEqual(fact.serialized(), "activity, review #pr, #hamster") fact = Fact(activity="activity", description="review #pr in #hamster", tags=["pr", "hamster"]) self.assertEqual(fact.serialized(), "activity, review #pr in #hamster") def test_tags_without_description(self): activity = Fact.parse("case, #tag1 #tag2") self.assertEqual(activity.activity, "case") self.assertEqual(activity.description, "") self.assertEqual(set(activity.tags), set(["tag1", "tag2"])) def test_tags_with_spaces(self): activity = Fact.parse("case, #tag with space #tag2") self.assertEqual(activity.activity, "case") self.assertEqual(activity.description, "") self.assertEqual(set(activity.tags), set(["tag with space", "tag2"])) def test_full(self): # plain activity name activity = Fact.parse( "1225-1325 case@cat, description #hash non-tag, #tag #bäg") self.assertEqual(activity.start_time.strftime("%H:%M"), "12:25") self.assertEqual(activity.end_time.strftime("%H:%M"), "13:25") self.assertEqual(activity.activity, "case") self.assertEqual(activity.category, "cat") self.assertEqual(activity.description, "description #hash non-tag") self.assertEqual(set(activity.tags), set(["hash", "bäg", "tag"])) def test_copy(self): fact1 = Fact.parse("12:25-13:25 case@cat, description #tag #bäg") fact2 = fact1.copy() self.assertEqual(fact1.start_time, fact2.start_time) self.assertEqual(fact1.end_time, fact2.end_time) self.assertEqual(fact1.activity, fact2.activity) self.assertEqual(fact1.category, fact2.category) self.assertEqual(fact1.description, fact2.description) self.assertEqual(fact1.tags, fact2.tags) fact3 = fact1.copy(activity="changed") self.assertEqual(fact3.activity, "changed") fact3 = fact1.copy(category="changed") self.assertEqual(fact3.category, "changed") fact3 = fact1.copy(description="changed") self.assertEqual(fact3.description, "changed") fact3 = fact1.copy(tags=["changed"]) self.assertEqual(fact3.tags, ["changed"]) def test_comparison(self): fact1 = Fact.parse("12:25-13:25 case@cat, description, #tag #bäg") fact2 = fact1.copy() self.assertEqual(fact1, fact2) fact2 = fact1.copy() fact2.activity = "abcd" self.assertNotEqual(fact1, fact2) fact2 = fact1.copy() fact2.category = "abcd" self.assertNotEqual(fact1, fact2) fact2 = fact1.copy() fact2.description = "abcd" self.assertNotEqual(fact1, fact2) fact2 = fact1.copy() fact2.range.start = fact1.range.start + dt.timedelta(minutes=1) self.assertNotEqual(fact1, fact2) fact2 = fact1.copy() fact2.range.end = fact1.range.end + dt.timedelta(minutes=1) self.assertNotEqual(fact1, fact2) # wrong order fact2 = fact1.copy() fact2.tags = ["bäg", "tag"] self.assertNotEqual(fact1, fact2) # correct order fact2 = fact1.copy() fact2.tags = ["tag", "bäg"] self.assertEqual(fact1, fact2) def test_decimal_in_activity(self): # cf. issue #270 fact = Fact.parse("12:25-13:25 10.0@ABC, Two Words #tag #bäg") self.assertEqual(fact.activity, "10.0") self.assertEqual(fact.category, "ABC") # should not pick up a time here fact = Fact.parse("10.00@ABC, Two Words #tag #bäg") self.assertEqual(fact.activity, "10.00") self.assertEqual(fact.category, "ABC") def test_activity_with_spaces(self): fact = Fact.parse("11:00 12:00 BPC-261 - Task title@Project") self.assertEqual(fact.activity, "BPC-261 - Task title") self.assertEqual(fact.category, "Project") self.assertEqual(fact.description, "") self.assertEqual(fact.tags, []) def test_activity_and_category_with_hash_and_space(self): fact = Fact.parse("11:00 12:00 Activity #1@Category #2") self.assertEqual(fact.activity, "Activity #1") self.assertEqual(fact.category, "Category #2") self.assertEqual(fact.description, "") def test_serialization_of_an_empty_fact(self): fact = Fact() self.assertEqual(fact.serialized(), "") def test_commas(self): fact = Fact.parse("11:00 12:00 activity@category, description, with comma") self.assertEqual(fact.activity, "activity") self.assertEqual(fact.category, "category") self.assertEqual(fact.description, "description, with comma") self.assertEqual(fact.tags, []) fact = Fact.parse("11:00 12:00 activity@category, description, with comma, #tag1 #tag2") self.assertEqual(fact.activity, "activity") self.assertEqual(fact.category, "category") self.assertEqual(fact.description, "description, with comma") self.assertEqual(fact.tags, ["tag1", "tag2"]) fact = Fact.parse("11:00 12:00 activity@category, description, with comma and #hash, #tag1 #tag2") self.assertEqual(fact.activity, "activity") self.assertEqual(fact.category, "category") self.assertEqual(fact.description, "description, with comma and #hash") self.assertEqual(fact.tags, ["hash", "tag1", "tag2"]) def test_backwards_compat_double_comma(self): fact = Fact.parse("act@cat,, My description,, #tag1 #tag2") self.assertEqual(fact.description, "My description") self.assertEqual(fact.tags, ["tag1", "tag2"]) fact = Fact.parse("act@cat,, My description, with comma,, #tag1 #tag2") self.assertEqual(fact.description, "My description, with comma") self.assertEqual(fact.tags, ["tag1", "tag2"]) # ugly. Really need pytest def test_roundtrips(self): for start_time in ( None, dt.time(12, 33), ): for end_time in ( None, dt.time(13, 34), ): for activity in ( "activity", "#123 with two #hash", "17.00 tea", ): for category in ( "", "category", ): for description in ( "", "description", "with, comma", "with @at", "multiline\ndescription", ): for tags in ( [], ["single"], ["with space"], ["two", "tags"], ["with @at"], ): start = dt.datetime.from_day_time(dt.hday.today(), start_time ) if start_time else None end = dt.datetime.from_day_time(dt.hday.today(), end_time ) if end_time else None if end and not start: # end without start is not parseable continue fact = Fact(start_time=start, end_time=end, activity=activity, category=category, description=description, tags=tags) for range_pos in ("head", "tail"): fact_str = fact.serialized(range_pos=range_pos) parsed = Fact.parse(fact_str, range_pos=range_pos) self.assertEqual(parsed.range.start, fact.range.start) self.assertEqual(parsed.range.end, fact.range.end) self.assertEqual(parsed.activity, fact.activity) self.assertEqual(parsed.category, fact.category) self.assertEqual(parsed.description, fact.description) self.assertEqual(parsed.tags, fact.tags) self.assertEqual(fact, parsed) class TestDatetime(unittest.TestCase): def test_datetime_from_day_time(self): day = dt.date(2018, 8, 13) time = dt.time(23, 10) expected = dt.datetime(2018, 8, 13, 23, 10) # 2018-08-13 23:10 self.assertEqual(dt.datetime.from_day_time(day, time), expected) day = dt.date(2018, 8, 13) time = dt.time(0, 10) expected = dt.datetime(2018, 8, 14, 0, 10) # 2018-08-14 00:10 self.assertEqual(dt.datetime.from_day_time(day, time), expected) def test_format_timedelta(self): delta = dt.timedelta(minutes=10) self.assertEqual(delta.format("human"), "10min") delta = dt.timedelta(hours=5, minutes=0) self.assertEqual(delta.format("human"), "5h") delta = dt.timedelta(hours=5, minutes=10) self.assertEqual(delta.format("human"), "5h 10min") delta = dt.timedelta(hours=5, minutes=10) self.assertEqual(delta.format("HH:MM"), "05:10") def test_datetime_hday(self): date_time = dt.datetime(2018, 8, 13, 23, 10) # 2018-08-13 23:10 expected = dt.date(2018, 8, 13) self.assertEqual(date_time.hday(), expected) date_time = dt.datetime(2018, 8, 14, 0, 10) # 2018-08-14 0:10 expected = dt.date(2018, 8, 13) self.assertEqual(date_time.hday(), expected) today = dt.hday.today() self.assertEqual(type(today), dt.hday) def test_parse_date(self): date = dt.date.parse("2020-01-05") self.assertEqual(date, pdt.date(2020, 1, 5)) def test_parse_time(self): self.assertEqual(dt.time.parse("9:01"), pdt.time(9, 1)) self.assertEqual(dt.time.parse("9.01"), pdt.time(9, 1)) self.assertEqual(dt.time.parse("12:01"), pdt.time(12, 1)) self.assertEqual(dt.time.parse("12.01"), pdt.time(12, 1)) self.assertEqual(dt.time.parse("1201"), pdt.time(12, 1)) def test_parse_datetime(self): self.assertEqual(dt.datetime.parse("2020-01-05 9:01"), pdt.datetime(2020, 1, 5, 9, 1)) def test_datetime_patterns(self): p = dt.datetime.pattern(1) s = "12:03" m = re.fullmatch(p, s, re.VERBOSE) time = dt.datetime._extract_datetime(m, d="date1", h="hour1", m="minute1", r="relative1", default_day=dt.hday.today()) self.assertEqual(time.strftime("%H:%M"), "12:03") s = "2019-12-01 12:36" m = re.fullmatch(p, s, re.VERBOSE) time = dt.datetime._extract_datetime(m, d="date1", h="hour1", m="minute1", r="relative1") self.assertEqual(time.strftime("%Y-%m-%d %H:%M"), "2019-12-01 12:36") s = "-25" m = re.fullmatch(p, s, re.VERBOSE) relative = dt.datetime._extract_datetime(m, d="date1", h="hour1", m="minute1", r="relative1", default_day=dt.hday.today()) self.assertEqual(relative, dt.timedelta(minutes=-25)) s = "2019-12-05" m = re.search(p, s, re.VERBOSE) self.assertEqual(m, None) def test_parse_datetime_range(self): # only match clean s = "10.00@cat" (start, end), rest = dt.Range.parse(s, position="head") self.assertEqual(start, None) self.assertEqual(end, None) s = "12:02" (start, end), rest = dt.Range.parse(s) self.assertEqual(start.strftime("%H:%M"), "12:02") self.assertEqual(end, None) s = "12:03 13:04" (start, end), rest = dt.Range.parse(s) self.assertEqual(start.strftime("%H:%M"), "12:03") self.assertEqual(end.strftime("%H:%M"), "13:04") s = "12:35 activity" (start, end), rest = dt.Range.parse(s, position="head") self.assertEqual(start.strftime("%H:%M"), "12:35") self.assertEqual(end, None) s = "2019-12-01 12:33 activity" (start, end), rest = dt.Range.parse(s, position="head") self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-12-01 12:33") self.assertEqual(end, None) ref = dt.datetime(2019, 11, 29, 13, 55) # 2019-11-29 13:55 s = "-25 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:30") self.assertEqual(end, None) s = "+25 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 14:20") self.assertEqual(end, None) s = "-55 -25 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:00") self.assertEqual(end.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:30") s = "+25 +55 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 14:20") self.assertEqual(end.strftime("%Y-%m-%d %H:%M"), "2019-11-29 14:50") s = "-55 -120 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:00") self.assertEqual(end.strftime("%Y-%m-%d %H:%M"), "2019-11-29 11:55") s = "-50 20 activity" (start, end), rest = dt.Range.parse(s, position="head", ref=ref) self.assertEqual(start.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:05") self.assertEqual(end.strftime("%Y-%m-%d %H:%M"), "2019-11-29 13:25") s = "2019-12-05" # single hamster day (start, end), rest = dt.Range.parse(s, ref=ref) just_before = start - dt.timedelta(seconds=1) just_after = end + dt.timedelta(seconds=1) self.assertEqual(just_before.hday(), pdt.date(2019, 12, 4)) self.assertEqual(just_after.hday(), pdt.date(2019, 12, 6)) s = "2019-12-05 2019-12-07" # hamster days range (start, end), rest = dt.Range.parse(s, ref=ref) just_before = start - dt.timedelta(seconds=1) just_after = end + dt.timedelta(seconds=1) self.assertEqual(just_before.hday(), dt.date(2019, 12, 4)) self.assertEqual(just_after.hday(), dt.date(2019, 12, 8)) s = "14:30 - --" (start, end), rest = dt.Range.parse(s, ref=ref) self.assertEqual(start.strftime("%H:%M"), "14:30") self.assertEqual(end, None) def test_range(self): day = dt.hday(2020, 2, 2) time = dt.time(21, 20) base = dt.datetime.from_day_time(day, time) range = dt.Range(base, base + dt.timedelta(minutes=30)) range_str = range.format(default_day=day) self.assertEqual(range_str, "21:20 - 21:50") range = dt.Range(None, base) range_str = range.format(default_day=day) self.assertEqual(range_str, "-- - 21:20") # issue #576 start = dt.datetime(2020, 3, 8, 17, 7) end = dt.datetime(2020, 3, 8, 18, 6) range = dt.Range.from_start_end(start, end) self.assertEqual(range.start, start) self.assertEqual(range.end, end) # check passthrough range2 = dt.Range.from_start_end(range) self.assertEqual(range2.start, range.start) self.assertEqual(range2.end, range.end) def test_rounding(self): dt1 = dt.datetime(2019, 12, 31, hour=13, minute=14, second=10, microsecond=11) self.assertEqual(dt1.second, 0) self.assertEqual(dt1.microsecond, 0) self.assertEqual(str(dt1), "2019-12-31 13:14") def test_type_stability(self): dt1 = dt.datetime(2020, 1, 10, hour=13, minute=30) dt2 = dt.datetime(2020, 1, 10, hour=13, minute=40) delta = dt2 - dt1 self.assertEqual(type(delta), dt.timedelta) _sum = dt1 + delta self.assertEqual(_sum, dt.datetime(2020, 1, 10, hour=13, minute=40)) self.assertEqual(type(_sum), dt.datetime) _sub = dt1 - delta self.assertEqual(_sub, dt.datetime(2020, 1, 10, hour=13, minute=20)) self.assertEqual(type(_sub), dt.datetime) opposite = - delta self.assertEqual(opposite, dt.timedelta(minutes=-10)) self.assertEqual(type(opposite), dt.timedelta) _sum = delta + delta self.assertEqual(_sum, dt.timedelta(minutes=20)) self.assertEqual(type(_sum), dt.timedelta) _sub = delta - delta self.assertEqual(_sub, dt.timedelta()) self.assertEqual(type(_sub), dt.timedelta) def test_timedelta(self): delta = dt.timedelta(seconds=90) self.assertEqual(delta.total_minutes(), 1.5) class TestDBus(unittest.TestCase): def test_round_trip(self): fact = Fact.parse("11:00 12:00 activity@category, description, with comma #and #tags") dbus_fact = to_dbus_fact_json(fact) return_fact = from_dbus_fact_json(dbus_fact) self.assertEqual(return_fact, fact) dbus_fact = to_dbus_fact(fact) return_fact = from_dbus_fact(dbus_fact) self.assertEqual(return_fact, fact) fact = Fact.parse("11:00 activity") dbus_fact = to_dbus_fact_json(fact) return_fact = from_dbus_fact_json(dbus_fact) self.assertEqual(return_fact, fact) dbus_fact = to_dbus_fact(fact) return_fact = from_dbus_fact(dbus_fact) self.assertEqual(return_fact, fact) range, __ = dt.Range.parse("2020-01-19 11:00 - 2020-01-19 12:00") dbus_range = to_dbus_range(range) return_range = from_dbus_range(dbus_range) self.assertEqual(return_range, range) if __name__ == '__main__': unittest.main() hamster-3.0.3/waf000077500000000000000000000101231452646177100136750ustar00rootroot00000000000000#!/usr/bin/env python # encoding: latin-1 # Thomas Nagy, 2005-2018 # """ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ import os, sys, inspect VERSION="2.0.26" REVISION="bbbe549153f90c006795714355b81761" GIT="ad7b733fc60852f77eff200b79e8b6f9562494d2" INSTALL='' C1='#-' C2='#*' C3='#%' cwd = os.getcwd() join = os.path.join WAF='waf' def b(x): return x if sys.hexversion>0x300000f: WAF='waf3' def b(x): return x.encode() def err(m): print(('\033[91mError: %s\033[0m' % m)) sys.exit(1) def unpack_wafdir(dir, src): f = open(src,'rb') c = 'corrupt archive (%d)' while 1: line = f.readline() if not line: err('run waf-light from a folder containing waflib') if line == b('#==>\n'): txt = f.readline() if not txt: err(c % 1) if f.readline() != b('#<==\n'): err(c % 2) break if not txt: err(c % 3) txt = txt[1:-1].replace(b(C1), b('\n')).replace(b(C2), b('\r')).replace(b(C3), b('\x00')) import shutil, tarfile try: shutil.rmtree(dir) except OSError: pass try: for x in ('Tools', 'extras'): os.makedirs(join(dir, 'waflib', x)) except OSError: err("Cannot unpack waf lib into %s\nMove waf in a writable directory" % dir) os.chdir(dir) tmp = 't.bz2' t = open(tmp,'wb') try: t.write(txt) finally: t.close() try: t = tarfile.open(tmp) except: try: os.system('bunzip2 t.bz2') t = tarfile.open('t') tmp = 't' except: os.chdir(cwd) try: shutil.rmtree(dir) except OSError: pass err("Waf cannot be unpacked, check that bzip2 support is present") try: for x in t: t.extract(x) finally: t.close() for x in ('Tools', 'extras'): os.chmod(join('waflib',x), 493) if sys.hexversion<0x300000f: sys.path = [join(dir, 'waflib')] + sys.path import fixpy2 fixpy2.fixdir(dir) os.remove(tmp) os.chdir(cwd) try: dir = unicode(dir, 'mbcs') except: pass try: from ctypes import windll windll.kernel32.SetFileAttributesW(dir, 2) except: pass def test(dir): try: os.stat(join(dir, 'waflib')) return os.path.abspath(dir) except OSError: pass def find_lib(): src = os.path.abspath(inspect.getfile(inspect.getmodule(err))) base, name = os.path.split(src) #devs use $WAFDIR w=test(os.environ.get('WAFDIR', '')) if w: return w #waf-light if name.endswith('waf-light'): w = test(base) if w: return w for dir in sys.path: if test(dir): return dir err('waf-light requires waflib -> export WAFDIR=/folder') dirname = '%s-%s-%s' % (WAF, VERSION, REVISION) for i in (INSTALL,'/usr','/usr/local','/opt'): w = test(i + '/lib/' + dirname) if w: return w #waf-local dir = join(base, (sys.platform != 'win32' and '.' or '') + dirname) w = test(dir) if w: return w #unpack unpack_wafdir(dir, src) return dir wafdir = find_lib() sys.path.insert(0, wafdir) if __name__ == '__main__': from waflib import Scripting Scripting.waf_entry_point(cwd, VERSION, wafdir) hamster-3.0.3/waflib/000077500000000000000000000000001452646177100144415ustar00rootroot00000000000000hamster-3.0.3/waflib/Build.py000066400000000000000000001250001452646177100160500ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Classes related to the build phase (build, clean, install, step, etc) The inheritance tree is the following: """ import os, sys, errno, re, shutil, stat try: import cPickle except ImportError: import pickle as cPickle from waflib import Node, Runner, TaskGen, Utils, ConfigSet, Task, Logs, Options, Context, Errors CACHE_DIR = 'c4che' """Name of the cache directory""" CACHE_SUFFIX = '_cache.py' """ConfigSet cache files for variants are written under :py:attr:´waflib.Build.CACHE_DIR´ in the form ´variant_name´_cache.py""" INSTALL = 1337 """Positive value '->' install, see :py:attr:`waflib.Build.BuildContext.is_install`""" UNINSTALL = -1337 """Negative value '<-' uninstall, see :py:attr:`waflib.Build.BuildContext.is_install`""" SAVED_ATTRS = 'root node_sigs task_sigs imp_sigs raw_deps node_deps'.split() """Build class members to save between the runs; these should be all dicts except for `root` which represents a :py:class:`waflib.Node.Node` instance """ CFG_FILES = 'cfg_files' """Files from the build directory to hash before starting the build (``config.h`` written during the configuration)""" POST_AT_ONCE = 0 """Post mode: all task generators are posted before any task executed""" POST_LAZY = 1 """Post mode: post the task generators group after group, the tasks in the next group are created when the tasks in the previous groups are done""" PROTOCOL = -1 if sys.platform == 'cli': PROTOCOL = 0 class BuildContext(Context.Context): '''executes the build''' cmd = 'build' variant = '' def __init__(self, **kw): super(BuildContext, self).__init__(**kw) self.is_install = 0 """Non-zero value when installing or uninstalling file""" self.top_dir = kw.get('top_dir', Context.top_dir) """See :py:attr:`waflib.Context.top_dir`; prefer :py:attr:`waflib.Build.BuildContext.srcnode`""" self.out_dir = kw.get('out_dir', Context.out_dir) """See :py:attr:`waflib.Context.out_dir`; prefer :py:attr:`waflib.Build.BuildContext.bldnode`""" self.run_dir = kw.get('run_dir', Context.run_dir) """See :py:attr:`waflib.Context.run_dir`""" self.launch_dir = Context.launch_dir """See :py:attr:`waflib.Context.out_dir`; prefer :py:meth:`waflib.Build.BuildContext.launch_node`""" self.post_mode = POST_LAZY """Whether to post the task generators at once or group-by-group (default is group-by-group)""" self.cache_dir = kw.get('cache_dir') if not self.cache_dir: self.cache_dir = os.path.join(self.out_dir, CACHE_DIR) self.all_envs = {} """Map names to :py:class:`waflib.ConfigSet.ConfigSet`, the empty string must map to the default environment""" # ======================================= # # cache variables self.node_sigs = {} """Dict mapping build nodes to task identifier (uid), it indicates whether a task created a particular file (persists across builds)""" self.task_sigs = {} """Dict mapping task identifiers (uid) to task signatures (persists across builds)""" self.imp_sigs = {} """Dict mapping task identifiers (uid) to implicit task dependencies used for scanning targets (persists across builds)""" self.node_deps = {} """Dict mapping task identifiers (uid) to node dependencies found by :py:meth:`waflib.Task.Task.scan` (persists across builds)""" self.raw_deps = {} """Dict mapping task identifiers (uid) to custom data returned by :py:meth:`waflib.Task.Task.scan` (persists across builds)""" self.task_gen_cache_names = {} self.jobs = Options.options.jobs """Amount of jobs to run in parallel""" self.targets = Options.options.targets """List of targets to build (default: \\*)""" self.keep = Options.options.keep """Whether the build should continue past errors""" self.progress_bar = Options.options.progress_bar """ Level of progress status: 0. normal output 1. progress bar 2. IDE output 3. No output at all """ # Manual dependencies. self.deps_man = Utils.defaultdict(list) """Manual dependencies set by :py:meth:`waflib.Build.BuildContext.add_manual_dependency`""" # just the structure here self.current_group = 0 """ Current build group """ self.groups = [] """ List containing lists of task generators """ self.group_names = {} """ Map group names to the group lists. See :py:meth:`waflib.Build.BuildContext.add_group` """ for v in SAVED_ATTRS: if not hasattr(self, v): setattr(self, v, {}) def get_variant_dir(self): """Getter for the variant_dir attribute""" if not self.variant: return self.out_dir return os.path.join(self.out_dir, os.path.normpath(self.variant)) variant_dir = property(get_variant_dir, None) def __call__(self, *k, **kw): """ Create a task generator and add it to the current build group. The following forms are equivalent:: def build(bld): tg = bld(a=1, b=2) def build(bld): tg = bld() tg.a = 1 tg.b = 2 def build(bld): tg = TaskGen.task_gen(a=1, b=2) bld.add_to_group(tg, None) :param group: group name to add the task generator to :type group: string """ kw['bld'] = self ret = TaskGen.task_gen(*k, **kw) self.task_gen_cache_names = {} # reset the cache, each time self.add_to_group(ret, group=kw.get('group')) return ret def __copy__(self): """ Build contexts cannot be copied :raises: :py:class:`waflib.Errors.WafError` """ raise Errors.WafError('build contexts cannot be copied') def load_envs(self): """ The configuration command creates files of the form ``build/c4che/NAMEcache.py``. This method creates a :py:class:`waflib.ConfigSet.ConfigSet` instance for each ``NAME`` by reading those files and stores them in :py:attr:`waflib.Build.BuildContext.allenvs`. """ node = self.root.find_node(self.cache_dir) if not node: raise Errors.WafError('The project was not configured: run "waf configure" first!') lst = node.ant_glob('**/*%s' % CACHE_SUFFIX, quiet=True) if not lst: raise Errors.WafError('The cache directory is empty: reconfigure the project') for x in lst: name = x.path_from(node).replace(CACHE_SUFFIX, '').replace('\\', '/') env = ConfigSet.ConfigSet(x.abspath()) self.all_envs[name] = env for f in env[CFG_FILES]: newnode = self.root.find_resource(f) if not newnode or not newnode.exists(): raise Errors.WafError('Missing configuration file %r, reconfigure the project!' % f) def init_dirs(self): """ Initialize the project directory and the build directory by creating the nodes :py:attr:`waflib.Build.BuildContext.srcnode` and :py:attr:`waflib.Build.BuildContext.bldnode` corresponding to ``top_dir`` and ``variant_dir`` respectively. The ``bldnode`` directory is created if necessary. """ if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)): raise Errors.WafError('The project was not configured: run "waf configure" first!') self.path = self.srcnode = self.root.find_dir(self.top_dir) self.bldnode = self.root.make_node(self.variant_dir) self.bldnode.mkdir() def execute(self): """ Restore data from previous builds and call :py:meth:`waflib.Build.BuildContext.execute_build`. Overrides from :py:func:`waflib.Context.Context.execute` """ self.restore() if not self.all_envs: self.load_envs() self.execute_build() def execute_build(self): """ Execute the build by: * reading the scripts (see :py:meth:`waflib.Context.Context.recurse`) * calling :py:meth:`waflib.Build.BuildContext.pre_build` to call user build functions * calling :py:meth:`waflib.Build.BuildContext.compile` to process the tasks * calling :py:meth:`waflib.Build.BuildContext.post_build` to call user build functions """ Logs.info("Waf: Entering directory `%s'", self.variant_dir) self.recurse([self.run_dir]) self.pre_build() # display the time elapsed in the progress bar self.timer = Utils.Timer() try: self.compile() finally: if self.progress_bar == 1 and sys.stderr.isatty(): c = self.producer.processed or 1 m = self.progress_line(c, c, Logs.colors.BLUE, Logs.colors.NORMAL) Logs.info(m, extra={'stream': sys.stderr, 'c1': Logs.colors.cursor_off, 'c2' : Logs.colors.cursor_on}) Logs.info("Waf: Leaving directory `%s'", self.variant_dir) try: self.producer.bld = None del self.producer except AttributeError: pass self.post_build() def restore(self): """ Load data from a previous run, sets the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS` """ try: env = ConfigSet.ConfigSet(os.path.join(self.cache_dir, 'build.config.py')) except EnvironmentError: pass else: if env.version < Context.HEXVERSION: raise Errors.WafError('Project was configured with a different version of Waf, please reconfigure it') for t in env.tools: self.setup(**t) dbfn = os.path.join(self.variant_dir, Context.DBFILE) try: data = Utils.readf(dbfn, 'rb') except (EnvironmentError, EOFError): # handle missing file/empty file Logs.debug('build: Could not load the build cache %s (missing)', dbfn) else: try: Node.pickle_lock.acquire() Node.Nod3 = self.node_class try: data = cPickle.loads(data) except Exception as e: Logs.debug('build: Could not pickle the build cache %s: %r', dbfn, e) else: for x in SAVED_ATTRS: setattr(self, x, data.get(x, {})) finally: Node.pickle_lock.release() self.init_dirs() def store(self): """ Store data for next runs, set the attributes listed in :py:const:`waflib.Build.SAVED_ATTRS`. Uses a temporary file to avoid problems on ctrl+c. """ data = {} for x in SAVED_ATTRS: data[x] = getattr(self, x) db = os.path.join(self.variant_dir, Context.DBFILE) try: Node.pickle_lock.acquire() Node.Nod3 = self.node_class x = cPickle.dumps(data, PROTOCOL) finally: Node.pickle_lock.release() Utils.writef(db + '.tmp', x, m='wb') try: st = os.stat(db) os.remove(db) if not Utils.is_win32: # win32 has no chown but we're paranoid os.chown(db + '.tmp', st.st_uid, st.st_gid) except (AttributeError, OSError): pass # do not use shutil.move (copy is not thread-safe) os.rename(db + '.tmp', db) def compile(self): """ Run the build by creating an instance of :py:class:`waflib.Runner.Parallel` The cache file is written when at least a task was executed. :raises: :py:class:`waflib.Errors.BuildError` in case the build fails """ Logs.debug('build: compile()') # delegate the producer-consumer logic to another object to reduce the complexity self.producer = Runner.Parallel(self, self.jobs) self.producer.biter = self.get_build_iterator() try: self.producer.start() except KeyboardInterrupt: if self.is_dirty(): self.store() raise else: if self.is_dirty(): self.store() if self.producer.error: raise Errors.BuildError(self.producer.error) def is_dirty(self): return self.producer.dirty def setup(self, tool, tooldir=None, funs=None): """ Import waf tools defined during the configuration:: def configure(conf): conf.load('glib2') def build(bld): pass # glib2 is imported implicitly :param tool: tool list :type tool: list :param tooldir: optional tool directory (sys.path) :type tooldir: list of string :param funs: unused variable """ if isinstance(tool, list): for i in tool: self.setup(i, tooldir) return module = Context.load_tool(tool, tooldir) if hasattr(module, "setup"): module.setup(self) def get_env(self): """Getter for the env property""" try: return self.all_envs[self.variant] except KeyError: return self.all_envs[''] def set_env(self, val): """Setter for the env property""" self.all_envs[self.variant] = val env = property(get_env, set_env) def add_manual_dependency(self, path, value): """ Adds a dependency from a node object to a value:: def build(bld): bld.add_manual_dependency( bld.path.find_resource('wscript'), bld.root.find_resource('/etc/fstab')) :param path: file path :type path: string or :py:class:`waflib.Node.Node` :param value: value to depend :type value: :py:class:`waflib.Node.Node`, byte object, or function returning a byte object """ if not path: raise ValueError('Invalid input path %r' % path) if isinstance(path, Node.Node): node = path elif os.path.isabs(path): node = self.root.find_resource(path) else: node = self.path.find_resource(path) if not node: raise ValueError('Could not find the path %r' % path) if isinstance(value, list): self.deps_man[node].extend(value) else: self.deps_man[node].append(value) def launch_node(self): """Returns the launch directory as a :py:class:`waflib.Node.Node` object (cached)""" try: # private cache return self.p_ln except AttributeError: self.p_ln = self.root.find_dir(self.launch_dir) return self.p_ln def hash_env_vars(self, env, vars_lst): """ Hashes configuration set variables:: def build(bld): bld.hash_env_vars(bld.env, ['CXX', 'CC']) This method uses an internal cache. :param env: Configuration Set :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param vars_lst: list of variables :type vars_list: list of string """ if not env.table: env = env.parent if not env: return Utils.SIG_NIL idx = str(id(env)) + str(vars_lst) try: cache = self.cache_env except AttributeError: cache = self.cache_env = {} else: try: return self.cache_env[idx] except KeyError: pass lst = [env[a] for a in vars_lst] cache[idx] = ret = Utils.h_list(lst) Logs.debug('envhash: %s %r', Utils.to_hex(ret), lst) return ret def get_tgen_by_name(self, name): """ Fetches a task generator by its name or its target attribute; the name must be unique in a build:: def build(bld): tg = bld(name='foo') tg == bld.get_tgen_by_name('foo') This method use a private internal cache. :param name: Task generator name :raises: :py:class:`waflib.Errors.WafError` in case there is no task genenerator by that name """ cache = self.task_gen_cache_names if not cache: # create the index lazily for g in self.groups: for tg in g: try: cache[tg.name] = tg except AttributeError: # raised if not a task generator, which should be uncommon pass try: return cache[name] except KeyError: raise Errors.WafError('Could not find a task generator for the name %r' % name) def progress_line(self, idx, total, col1, col2): """ Computes a progress bar line displayed when running ``waf -p`` :returns: progress bar line :rtype: string """ if not sys.stderr.isatty(): return '' n = len(str(total)) Utils.rot_idx += 1 ind = Utils.rot_chr[Utils.rot_idx % 4] pc = (100. * idx)/total fs = "[%%%dd/%%d][%%s%%2d%%%%%%s][%s][" % (n, ind) left = fs % (idx, total, col1, pc, col2) right = '][%s%s%s]' % (col1, self.timer, col2) cols = Logs.get_term_cols() - len(left) - len(right) + 2*len(col1) + 2*len(col2) if cols < 7: cols = 7 ratio = ((cols * idx)//total) - 1 bar = ('='*ratio+'>').ljust(cols) msg = Logs.indicator % (left, bar, right) return msg def declare_chain(self, *k, **kw): """ Wraps :py:func:`waflib.TaskGen.declare_chain` for convenience """ return TaskGen.declare_chain(*k, **kw) def pre_build(self): """Executes user-defined methods before the build starts, see :py:meth:`waflib.Build.BuildContext.add_pre_fun`""" for m in getattr(self, 'pre_funs', []): m(self) def post_build(self): """Executes user-defined methods after the build is successful, see :py:meth:`waflib.Build.BuildContext.add_post_fun`""" for m in getattr(self, 'post_funs', []): m(self) def add_pre_fun(self, meth): """ Binds a callback method to execute after the scripts are read and before the build starts:: def mycallback(bld): print("Hello, world!") def build(bld): bld.add_pre_fun(mycallback) """ try: self.pre_funs.append(meth) except AttributeError: self.pre_funs = [meth] def add_post_fun(self, meth): """ Binds a callback method to execute immediately after the build is successful:: def call_ldconfig(bld): bld.exec_command('/sbin/ldconfig') def build(bld): if bld.cmd == 'install': bld.add_pre_fun(call_ldconfig) """ try: self.post_funs.append(meth) except AttributeError: self.post_funs = [meth] def get_group(self, x): """ Returns the build group named `x`, or the current group if `x` is None :param x: name or number or None :type x: string, int or None """ if not self.groups: self.add_group() if x is None: return self.groups[self.current_group] if x in self.group_names: return self.group_names[x] return self.groups[x] def add_to_group(self, tgen, group=None): """Adds a task or a task generator to the build; there is no attempt to remove it if it was already added.""" assert(isinstance(tgen, TaskGen.task_gen) or isinstance(tgen, Task.Task)) tgen.bld = self self.get_group(group).append(tgen) def get_group_name(self, g): """ Returns the name of the input build group :param g: build group object or build group index :type g: integer or list :return: name :rtype: string """ if not isinstance(g, list): g = self.groups[g] for x in self.group_names: if id(self.group_names[x]) == id(g): return x return '' def get_group_idx(self, tg): """ Returns the index of the group containing the task generator given as argument:: def build(bld): tg = bld(name='nada') 0 == bld.get_group_idx(tg) :param tg: Task generator object :type tg: :py:class:`waflib.TaskGen.task_gen` :rtype: int """ se = id(tg) for i, tmp in enumerate(self.groups): for t in tmp: if id(t) == se: return i return None def add_group(self, name=None, move=True): """ Adds a new group of tasks/task generators. By default the new group becomes the default group for new task generators (make sure to create build groups in order). :param name: name for this group :type name: string :param move: set this new group as default group (True by default) :type move: bool :raises: :py:class:`waflib.Errors.WafError` if a group by the name given already exists """ if name and name in self.group_names: raise Errors.WafError('add_group: name %s already present', name) g = [] self.group_names[name] = g self.groups.append(g) if move: self.current_group = len(self.groups) - 1 def set_group(self, idx): """ Sets the build group at position idx as current so that newly added task generators are added to this one by default:: def build(bld): bld(rule='touch ${TGT}', target='foo.txt') bld.add_group() # now the current group is 1 bld(rule='touch ${TGT}', target='bar.txt') bld.set_group(0) # now the current group is 0 bld(rule='touch ${TGT}', target='truc.txt') # build truc.txt before bar.txt :param idx: group name or group index :type idx: string or int """ if isinstance(idx, str): g = self.group_names[idx] for i, tmp in enumerate(self.groups): if id(g) == id(tmp): self.current_group = i break else: self.current_group = idx def total(self): """ Approximate task count: this value may be inaccurate if task generators are posted lazily (see :py:attr:`waflib.Build.BuildContext.post_mode`). The value :py:attr:`waflib.Runner.Parallel.total` is updated during the task execution. :rtype: int """ total = 0 for group in self.groups: for tg in group: try: total += len(tg.tasks) except AttributeError: total += 1 return total def get_targets(self): """ This method returns a pair containing the index of the last build group to post, and the list of task generator objects corresponding to the target names. This is used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator` to perform partial builds:: $ waf --targets=myprogram,myshlib :return: the minimum build group index, and list of task generators :rtype: tuple """ to_post = [] min_grp = 0 for name in self.targets.split(','): tg = self.get_tgen_by_name(name) m = self.get_group_idx(tg) if m > min_grp: min_grp = m to_post = [tg] elif m == min_grp: to_post.append(tg) return (min_grp, to_post) def get_all_task_gen(self): """ Returns a list of all task generators for troubleshooting purposes. """ lst = [] for g in self.groups: lst.extend(g) return lst def post_group(self): """ Post task generators from the group indexed by self.current_group; used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator` """ def tgpost(tg): try: f = tg.post except AttributeError: pass else: f() if self.targets == '*': for tg in self.groups[self.current_group]: tgpost(tg) elif self.targets: if self.current_group < self._min_grp: for tg in self.groups[self.current_group]: tgpost(tg) else: for tg in self._exact_tg: tg.post() else: ln = self.launch_node() if ln.is_child_of(self.bldnode): if Logs.verbose > 1: Logs.warn('Building from the build directory, forcing --targets=*') ln = self.srcnode elif not ln.is_child_of(self.srcnode): if Logs.verbose > 1: Logs.warn('CWD %s is not under %s, forcing --targets=* (run distclean?)', ln.abspath(), self.srcnode.abspath()) ln = self.srcnode def is_post(tg, ln): try: p = tg.path except AttributeError: pass else: if p.is_child_of(ln): return True def is_post_group(): for i, g in enumerate(self.groups): if i > self.current_group: for tg in g: if is_post(tg, ln): return True if self.post_mode == POST_LAZY and ln != self.srcnode: # partial folder builds require all targets from a previous build group if is_post_group(): ln = self.srcnode for tg in self.groups[self.current_group]: if is_post(tg, ln): tgpost(tg) def get_tasks_group(self, idx): """ Returns all task instances for the build group at position idx, used internally by :py:meth:`waflib.Build.BuildContext.get_build_iterator` :rtype: list of :py:class:`waflib.Task.Task` """ tasks = [] for tg in self.groups[idx]: try: tasks.extend(tg.tasks) except AttributeError: # not a task generator tasks.append(tg) return tasks def get_build_iterator(self): """ Creates a Python generator object that returns lists of tasks that may be processed in parallel. :return: tasks which can be executed immediately :rtype: generator returning lists of :py:class:`waflib.Task.Task` """ if self.targets and self.targets != '*': (self._min_grp, self._exact_tg) = self.get_targets() if self.post_mode != POST_LAZY: for self.current_group, _ in enumerate(self.groups): self.post_group() for self.current_group, _ in enumerate(self.groups): # first post the task generators for the group if self.post_mode != POST_AT_ONCE: self.post_group() # then extract the tasks tasks = self.get_tasks_group(self.current_group) # if the constraints are set properly (ext_in/ext_out, before/after) # the call to set_file_constraints may be removed (can be a 15% penalty on no-op rebuilds) # (but leave set_file_constraints for the installation step) # # if the tasks have only files, set_file_constraints is required but set_precedence_constraints is not necessary # Task.set_file_constraints(tasks) Task.set_precedence_constraints(tasks) self.cur_tasks = tasks if tasks: yield tasks while 1: # the build stops once there are no tasks to process yield [] def install_files(self, dest, files, **kw): """ Creates a task generator to install files on the system:: def build(bld): bld.install_files('${DATADIR}', self.path.find_resource('wscript')) :param dest: path representing the destination directory :type dest: :py:class:`waflib.Node.Node` or string (absolute path) :param files: input files :type files: list of strings or list of :py:class:`waflib.Node.Node` :param env: configuration set to expand *dest* :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param relative_trick: preserve the folder hierarchy when installing whole folders :type relative_trick: bool :param cwd: parent node for searching srcfile, when srcfile is not an instance of :py:class:`waflib.Node.Node` :type cwd: :py:class:`waflib.Node.Node` :param postpone: execute the task immediately to perform the installation (False by default) :type postpone: bool """ assert(dest) tg = self(features='install_task', install_to=dest, install_from=files, **kw) tg.dest = tg.install_to tg.type = 'install_files' if not kw.get('postpone', True): tg.post() return tg def install_as(self, dest, srcfile, **kw): """ Creates a task generator to install a file on the system with a different name:: def build(bld): bld.install_as('${PREFIX}/bin', 'myapp', chmod=Utils.O755) :param dest: destination file :type dest: :py:class:`waflib.Node.Node` or string (absolute path) :param srcfile: input file :type srcfile: string or :py:class:`waflib.Node.Node` :param cwd: parent node for searching srcfile, when srcfile is not an instance of :py:class:`waflib.Node.Node` :type cwd: :py:class:`waflib.Node.Node` :param env: configuration set for performing substitutions in dest :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param postpone: execute the task immediately to perform the installation (False by default) :type postpone: bool """ assert(dest) tg = self(features='install_task', install_to=dest, install_from=srcfile, **kw) tg.dest = tg.install_to tg.type = 'install_as' if not kw.get('postpone', True): tg.post() return tg def symlink_as(self, dest, src, **kw): """ Creates a task generator to install a symlink:: def build(bld): bld.symlink_as('${PREFIX}/lib/libfoo.so', 'libfoo.so.1.2.3') :param dest: absolute path of the symlink :type dest: :py:class:`waflib.Node.Node` or string (absolute path) :param src: link contents, which is a relative or absolute path which may exist or not :type src: string :param env: configuration set for performing substitutions in dest :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param add: add the task created to a build group - set ``False`` only if the installation task is created after the build has started :type add: bool :param postpone: execute the task immediately to perform the installation :type postpone: bool :param relative_trick: make the symlink relative (default: ``False``) :type relative_trick: bool """ assert(dest) tg = self(features='install_task', install_to=dest, install_from=src, **kw) tg.dest = tg.install_to tg.type = 'symlink_as' tg.link = src # TODO if add: self.add_to_group(tsk) if not kw.get('postpone', True): tg.post() return tg @TaskGen.feature('install_task') @TaskGen.before_method('process_rule', 'process_source') def process_install_task(self): """Creates the installation task for the current task generator; uses :py:func:`waflib.Build.add_install_task` internally.""" self.add_install_task(**self.__dict__) @TaskGen.taskgen_method def add_install_task(self, **kw): """ Creates the installation task for the current task generator, and executes it immediately if necessary :returns: An installation task :rtype: :py:class:`waflib.Build.inst` """ if not self.bld.is_install: return if not kw['install_to']: return if kw['type'] == 'symlink_as' and Utils.is_win32: if kw.get('win32_install'): kw['type'] = 'install_as' else: # just exit return tsk = self.install_task = self.create_task('inst') tsk.chmod = kw.get('chmod', Utils.O644) tsk.link = kw.get('link', '') or kw.get('install_from', '') tsk.relative_trick = kw.get('relative_trick', False) tsk.type = kw['type'] tsk.install_to = tsk.dest = kw['install_to'] tsk.install_from = kw['install_from'] tsk.relative_base = kw.get('cwd') or kw.get('relative_base', self.path) tsk.install_user = kw.get('install_user') tsk.install_group = kw.get('install_group') tsk.init_files() if not kw.get('postpone', True): tsk.run_now() return tsk @TaskGen.taskgen_method def add_install_files(self, **kw): """ Creates an installation task for files :returns: An installation task :rtype: :py:class:`waflib.Build.inst` """ kw['type'] = 'install_files' return self.add_install_task(**kw) @TaskGen.taskgen_method def add_install_as(self, **kw): """ Creates an installation task for a single file :returns: An installation task :rtype: :py:class:`waflib.Build.inst` """ kw['type'] = 'install_as' return self.add_install_task(**kw) @TaskGen.taskgen_method def add_symlink_as(self, **kw): """ Creates an installation task for a symbolic link :returns: An installation task :rtype: :py:class:`waflib.Build.inst` """ kw['type'] = 'symlink_as' return self.add_install_task(**kw) class inst(Task.Task): """Task that installs files or symlinks; it is typically executed by :py:class:`waflib.Build.InstallContext` and :py:class:`waflib.Build.UnInstallContext`""" def __str__(self): """Returns an empty string to disable the standard task display""" return '' def uid(self): """Returns a unique identifier for the task""" lst = self.inputs + self.outputs + [self.link, self.generator.path.abspath()] return Utils.h_list(lst) def init_files(self): """ Initializes the task input and output nodes """ if self.type == 'symlink_as': inputs = [] else: inputs = self.generator.to_nodes(self.install_from) if self.type == 'install_as': assert len(inputs) == 1 self.set_inputs(inputs) dest = self.get_install_path() outputs = [] if self.type == 'symlink_as': if self.relative_trick: self.link = os.path.relpath(self.link, os.path.dirname(dest)) outputs.append(self.generator.bld.root.make_node(dest)) elif self.type == 'install_as': outputs.append(self.generator.bld.root.make_node(dest)) else: for y in inputs: if self.relative_trick: destfile = os.path.join(dest, y.path_from(self.relative_base)) else: destfile = os.path.join(dest, y.name) outputs.append(self.generator.bld.root.make_node(destfile)) self.set_outputs(outputs) def runnable_status(self): """ Installation tasks are always executed, so this method returns either :py:const:`waflib.Task.ASK_LATER` or :py:const:`waflib.Task.RUN_ME`. """ ret = super(inst, self).runnable_status() if ret == Task.SKIP_ME and self.generator.bld.is_install: return Task.RUN_ME return ret def post_run(self): """ Disables any post-run operations """ pass def get_install_path(self, destdir=True): """ Returns the destination path where files will be installed, pre-pending `destdir`. Relative paths will be interpreted relative to `PREFIX` if no `destdir` is given. :rtype: string """ if isinstance(self.install_to, Node.Node): dest = self.install_to.abspath() else: dest = os.path.normpath(Utils.subst_vars(self.install_to, self.env)) if not os.path.isabs(dest): dest = os.path.join(self.env.PREFIX, dest) if destdir and Options.options.destdir: dest = Options.options.destdir.rstrip(os.sep) + os.sep + os.path.splitdrive(dest)[1].lstrip(os.sep) return dest def copy_fun(self, src, tgt): """ Copies a file from src to tgt, preserving permissions and trying to work around path limitations on Windows platforms. On Unix-like platforms, the owner/group of the target file may be set through install_user/install_group :param src: absolute path :type src: string :param tgt: absolute path :type tgt: string """ # override this if you want to strip executables # kw['tsk'].source is the task that created the files in the build if Utils.is_win32 and len(tgt) > 259 and not tgt.startswith('\\\\?\\'): tgt = '\\\\?\\' + tgt shutil.copy2(src, tgt) self.fix_perms(tgt) def rm_empty_dirs(self, tgt): """ Removes empty folders recursively when uninstalling. :param tgt: absolute path :type tgt: string """ while tgt: tgt = os.path.dirname(tgt) try: os.rmdir(tgt) except OSError: break def run(self): """ Performs file or symlink installation """ is_install = self.generator.bld.is_install if not is_install: # unnecessary? return for x in self.outputs: if is_install == INSTALL: x.parent.mkdir() if self.type == 'symlink_as': fun = is_install == INSTALL and self.do_link or self.do_unlink fun(self.link, self.outputs[0].abspath()) else: fun = is_install == INSTALL and self.do_install or self.do_uninstall launch_node = self.generator.bld.launch_node() for x, y in zip(self.inputs, self.outputs): fun(x.abspath(), y.abspath(), x.path_from(launch_node)) def run_now(self): """ Try executing the installation task right now :raises: :py:class:`waflib.Errors.TaskNotReady` """ status = self.runnable_status() if status not in (Task.RUN_ME, Task.SKIP_ME): raise Errors.TaskNotReady('Could not process %r: status %r' % (self, status)) self.run() self.hasrun = Task.SUCCESS def do_install(self, src, tgt, lbl, **kw): """ Copies a file from src to tgt with given file permissions. The actual copy is only performed if the source and target file sizes or timestamps differ. When the copy occurs, the file is always first removed and then copied so as to prevent stale inodes. :param src: file name as absolute path :type src: string :param tgt: file destination, as absolute path :type tgt: string :param lbl: file source description :type lbl: string :param chmod: installation mode :type chmod: int :raises: :py:class:`waflib.Errors.WafError` if the file cannot be written """ if not Options.options.force: # check if the file is already there to avoid a copy try: st1 = os.stat(tgt) st2 = os.stat(src) except OSError: pass else: # same size and identical timestamps -> make no copy if st1.st_mtime + 2 >= st2.st_mtime and st1.st_size == st2.st_size: if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s- install %s%s%s (from %s)', c1, c2, tgt, c1, lbl) return False if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s+ install %s%s%s (from %s)', c1, c2, tgt, c1, lbl) # Give best attempt at making destination overwritable, # like the 'install' utility used by 'make install' does. try: os.chmod(tgt, Utils.O644 | stat.S_IMODE(os.stat(tgt).st_mode)) except EnvironmentError: pass # following is for shared libs and stale inodes (-_-) try: os.remove(tgt) except OSError: pass try: self.copy_fun(src, tgt) except EnvironmentError as e: if not os.path.exists(src): Logs.error('File %r does not exist', src) elif not os.path.isfile(src): Logs.error('Input %r is not a file', src) raise Errors.WafError('Could not install the file %r' % tgt, e) def fix_perms(self, tgt): """ Change the ownership of the file/folder/link pointed by the given path This looks up for `install_user` or `install_group` attributes on the task or on the task generator:: def build(bld): bld.install_as('${PREFIX}/wscript', 'wscript', install_user='nobody', install_group='nogroup') bld.symlink_as('${PREFIX}/wscript_link', Utils.subst_vars('${PREFIX}/wscript', bld.env), install_user='nobody', install_group='nogroup') """ if not Utils.is_win32: user = getattr(self, 'install_user', None) or getattr(self.generator, 'install_user', None) group = getattr(self, 'install_group', None) or getattr(self.generator, 'install_group', None) if user or group: Utils.lchown(tgt, user or -1, group or -1) if not os.path.islink(tgt): os.chmod(tgt, self.chmod) def do_link(self, src, tgt, **kw): """ Creates a symlink from tgt to src. :param src: file name as absolute path :type src: string :param tgt: file destination, as absolute path :type tgt: string """ if os.path.islink(tgt) and os.readlink(tgt) == src: if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s- symlink %s%s%s (to %s)', c1, c2, tgt, c1, src) else: try: os.remove(tgt) except OSError: pass if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s+ symlink %s%s%s (to %s)', c1, c2, tgt, c1, src) os.symlink(src, tgt) self.fix_perms(tgt) def do_uninstall(self, src, tgt, lbl, **kw): """ See :py:meth:`waflib.Build.inst.do_install` """ if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s- remove %s%s%s', c1, c2, tgt, c1) #self.uninstall.append(tgt) try: os.remove(tgt) except OSError as e: if e.errno != errno.ENOENT: if not getattr(self, 'uninstall_error', None): self.uninstall_error = True Logs.warn('build: some files could not be uninstalled (retry with -vv to list them)') if Logs.verbose > 1: Logs.warn('Could not remove %s (error code %r)', e.filename, e.errno) self.rm_empty_dirs(tgt) def do_unlink(self, src, tgt, **kw): """ See :py:meth:`waflib.Build.inst.do_link` """ try: if not self.generator.bld.progress_bar: c1 = Logs.colors.NORMAL c2 = Logs.colors.BLUE Logs.info('%s- remove %s%s%s', c1, c2, tgt, c1) os.remove(tgt) except OSError: pass self.rm_empty_dirs(tgt) class InstallContext(BuildContext): '''installs the targets on the system''' cmd = 'install' def __init__(self, **kw): super(InstallContext, self).__init__(**kw) self.is_install = INSTALL class UninstallContext(InstallContext): '''removes the targets installed''' cmd = 'uninstall' def __init__(self, **kw): super(UninstallContext, self).__init__(**kw) self.is_install = UNINSTALL class CleanContext(BuildContext): '''cleans the project''' cmd = 'clean' def execute(self): """ See :py:func:`waflib.Build.BuildContext.execute`. """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) try: self.clean() finally: self.store() def clean(self): """ Remove most files from the build directory, and reset all caches. Custom lists of files to clean can be declared as `bld.clean_files`. For example, exclude `build/program/myprogram` from getting removed:: def build(bld): bld.clean_files = bld.bldnode.ant_glob('**', excl='.lock* config.log c4che/* config.h program/myprogram', quiet=True, generator=True) """ Logs.debug('build: clean called') if hasattr(self, 'clean_files'): for n in self.clean_files: n.delete() elif self.bldnode != self.srcnode: # would lead to a disaster if top == out lst = [] for env in self.all_envs.values(): lst.extend(self.root.find_or_declare(f) for f in env[CFG_FILES]) excluded_dirs = '.lock* *conf_check_*/** config.log %s/*' % CACHE_DIR for n in self.bldnode.ant_glob('**/*', excl=excluded_dirs, quiet=True): if n in lst: continue n.delete() self.root.children = {} for v in SAVED_ATTRS: if v == 'root': continue setattr(self, v, {}) class ListContext(BuildContext): '''lists the targets to execute''' cmd = 'list' def execute(self): """ In addition to printing the name of each build target, a description column will include text for each task generator which has a "description" field set. See :py:func:`waflib.Build.BuildContext.execute`. """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) self.pre_build() # display the time elapsed in the progress bar self.timer = Utils.Timer() for g in self.groups: for tg in g: try: f = tg.post except AttributeError: pass else: f() try: # force the cache initialization self.get_tgen_by_name('') except Errors.WafError: pass targets = sorted(self.task_gen_cache_names) # figure out how much to left-justify, for largest target name line_just = max(len(t) for t in targets) if targets else 0 for target in targets: tgen = self.task_gen_cache_names[target] # Support displaying the description for the target # if it was set on the tgen descript = getattr(tgen, 'description', '') if descript: target = target.ljust(line_just) descript = ': %s' % descript Logs.pprint('GREEN', target, label=descript) class StepContext(BuildContext): '''executes tasks in a step-by-step fashion, for debugging''' cmd = 'step' def __init__(self, **kw): super(StepContext, self).__init__(**kw) self.files = Options.options.files def compile(self): """ Overrides :py:meth:`waflib.Build.BuildContext.compile` to perform a partial build on tasks matching the input/output pattern given (regular expression matching):: $ waf step --files=foo.c,bar.c,in:truc.c,out:bar.o $ waf step --files=in:foo.cpp.1.o # link task only """ if not self.files: Logs.warn('Add a pattern for the debug build, for example "waf step --files=main.c,app"') BuildContext.compile(self) return targets = [] if self.targets and self.targets != '*': targets = self.targets.split(',') for g in self.groups: for tg in g: if targets and tg.name not in targets: continue try: f = tg.post except AttributeError: pass else: f() for pat in self.files.split(','): matcher = self.get_matcher(pat) for tg in g: if isinstance(tg, Task.Task): lst = [tg] else: lst = tg.tasks for tsk in lst: do_exec = False for node in tsk.inputs: if matcher(node, output=False): do_exec = True break for node in tsk.outputs: if matcher(node, output=True): do_exec = True break if do_exec: ret = tsk.run() Logs.info('%s -> exit %r', tsk, ret) def get_matcher(self, pat): """ Converts a step pattern into a function :param: pat: pattern of the form in:truc.c,out:bar.o :returns: Python function that uses Node objects as inputs and returns matches :rtype: function """ # this returns a function inn = True out = True if pat.startswith('in:'): out = False pat = pat.replace('in:', '') elif pat.startswith('out:'): inn = False pat = pat.replace('out:', '') anode = self.root.find_node(pat) pattern = None if not anode: if not pat.startswith('^'): pat = '^.+?%s' % pat if not pat.endswith('$'): pat = '%s$' % pat pattern = re.compile(pat) def match(node, output): if output and not out: return False if not output and not inn: return False if anode: return anode == node else: return pattern.match(node.abspath()) return match class EnvContext(BuildContext): """Subclass EnvContext to create commands that require configuration data in 'env'""" fun = cmd = None def execute(self): """ See :py:func:`waflib.Build.BuildContext.execute`. """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) hamster-3.0.3/waflib/ConfigSet.py000066400000000000000000000201461452646177100166770ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ ConfigSet: a special dict The values put in :py:class:`ConfigSet` must be serializable (dicts, lists, strings) """ import copy, re, os from waflib import Logs, Utils re_imp = re.compile(r'^(#)*?([^#=]*?)\ =\ (.*?)$', re.M) class ConfigSet(object): """ A copy-on-write dict with human-readable serialized format. The serialization format is human-readable (python-like) and performed by using eval() and repr(). For high performance prefer pickle. Do not store functions as they are not serializable. The values can be accessed by attributes or by keys:: from waflib.ConfigSet import ConfigSet env = ConfigSet() env.FOO = 'test' env['FOO'] = 'test' """ __slots__ = ('table', 'parent') def __init__(self, filename=None): self.table = {} """ Internal dict holding the object values """ #self.parent = None if filename: self.load(filename) def __contains__(self, key): """ Enables the *in* syntax:: if 'foo' in env: print(env['foo']) """ if key in self.table: return True try: return self.parent.__contains__(key) except AttributeError: return False # parent may not exist def keys(self): """Dict interface""" keys = set() cur = self while cur: keys.update(cur.table.keys()) cur = getattr(cur, 'parent', None) keys = list(keys) keys.sort() return keys def __iter__(self): return iter(self.keys()) def __str__(self): """Text representation of the ConfigSet (for debugging purposes)""" return "\n".join(["%r %r" % (x, self.__getitem__(x)) for x in self.keys()]) def __getitem__(self, key): """ Dictionary interface: get value from key:: def configure(conf): conf.env['foo'] = {} print(env['foo']) """ try: while 1: x = self.table.get(key) if not x is None: return x self = self.parent except AttributeError: return [] def __setitem__(self, key, value): """ Dictionary interface: set value from key """ self.table[key] = value def __delitem__(self, key): """ Dictionary interface: mark the value as missing """ self[key] = [] def __getattr__(self, name): """ Attribute access provided for convenience. The following forms are equivalent:: def configure(conf): conf.env.value conf.env['value'] """ if name in self.__slots__: return object.__getattribute__(self, name) else: return self[name] def __setattr__(self, name, value): """ Attribute access provided for convenience. The following forms are equivalent:: def configure(conf): conf.env.value = x env['value'] = x """ if name in self.__slots__: object.__setattr__(self, name, value) else: self[name] = value def __delattr__(self, name): """ Attribute access provided for convenience. The following forms are equivalent:: def configure(conf): del env.value del env['value'] """ if name in self.__slots__: object.__delattr__(self, name) else: del self[name] def derive(self): """ Returns a new ConfigSet deriving from self. The copy returned will be a shallow copy:: from waflib.ConfigSet import ConfigSet env = ConfigSet() env.append_value('CFLAGS', ['-O2']) child = env.derive() child.CFLAGS.append('test') # warning! this will modify 'env' child.CFLAGS = ['-O3'] # new list, ok child.append_value('CFLAGS', ['-O3']) # ok Use :py:func:`ConfigSet.detach` to detach the child from the parent. """ newenv = ConfigSet() newenv.parent = self return newenv def detach(self): """ Detaches this instance from its parent (if present) Modifying the parent :py:class:`ConfigSet` will not change the current object Modifying this :py:class:`ConfigSet` will not modify the parent one. """ tbl = self.get_merged_dict() try: delattr(self, 'parent') except AttributeError: pass else: keys = tbl.keys() for x in keys: tbl[x] = copy.deepcopy(tbl[x]) self.table = tbl return self def get_flat(self, key): """ Returns a value as a string. If the input is a list, the value returned is space-separated. :param key: key to use :type key: string """ s = self[key] if isinstance(s, str): return s return ' '.join(s) def _get_list_value_for_modification(self, key): """ Returns a list value for further modification. The list may be modified inplace and there is no need to do this afterwards:: self.table[var] = value """ try: value = self.table[key] except KeyError: try: value = self.parent[key] except AttributeError: value = [] else: if isinstance(value, list): # force a copy value = value[:] else: value = [value] self.table[key] = value else: if not isinstance(value, list): self.table[key] = value = [value] return value def append_value(self, var, val): """ Appends a value to the specified config key:: def build(bld): bld.env.append_value('CFLAGS', ['-O2']) The value must be a list or a tuple """ if isinstance(val, str): # if there were string everywhere we could optimize this val = [val] current_value = self._get_list_value_for_modification(var) current_value.extend(val) def prepend_value(self, var, val): """ Prepends a value to the specified item:: def configure(conf): conf.env.prepend_value('CFLAGS', ['-O2']) The value must be a list or a tuple """ if isinstance(val, str): val = [val] self.table[var] = val + self._get_list_value_for_modification(var) def append_unique(self, var, val): """ Appends a value to the specified item only if it's not already present:: def build(bld): bld.env.append_unique('CFLAGS', ['-O2', '-g']) The value must be a list or a tuple """ if isinstance(val, str): val = [val] current_value = self._get_list_value_for_modification(var) for x in val: if x not in current_value: current_value.append(x) def get_merged_dict(self): """ Computes the merged dictionary from the fusion of self and all its parent :rtype: a ConfigSet object """ table_list = [] env = self while 1: table_list.insert(0, env.table) try: env = env.parent except AttributeError: break merged_table = {} for table in table_list: merged_table.update(table) return merged_table def store(self, filename): """ Serializes the :py:class:`ConfigSet` data to a file. See :py:meth:`ConfigSet.load` for reading such files. :param filename: file to use :type filename: string """ try: os.makedirs(os.path.split(filename)[0]) except OSError: pass buf = [] merged_table = self.get_merged_dict() keys = list(merged_table.keys()) keys.sort() try: fun = ascii except NameError: fun = repr for k in keys: if k != 'undo_stack': buf.append('%s = %s\n' % (k, fun(merged_table[k]))) Utils.writef(filename, ''.join(buf)) def load(self, filename): """ Restores contents from a file (current values are not cleared). Files are written using :py:meth:`ConfigSet.store`. :param filename: file to use :type filename: string """ tbl = self.table code = Utils.readf(filename, m='r') for m in re_imp.finditer(code): g = m.group tbl[g(2)] = eval(g(3)) Logs.debug('env: %s', self.table) def update(self, d): """ Dictionary interface: replace values with the ones from another dict :param d: object to use the value from :type d: dict-like object """ self.table.update(d) def stash(self): """ Stores the object state to provide transactionality semantics:: env = ConfigSet() env.stash() try: env.append_value('CFLAGS', '-O3') call_some_method(env) finally: env.revert() The history is kept in a stack, and is lost during the serialization by :py:meth:`ConfigSet.store` """ orig = self.table tbl = self.table = self.table.copy() for x in tbl.keys(): tbl[x] = copy.deepcopy(tbl[x]) self.undo_stack = self.undo_stack + [orig] def commit(self): """ Commits transactional changes. See :py:meth:`ConfigSet.stash` """ self.undo_stack.pop(-1) def revert(self): """ Reverts the object to a previous state. See :py:meth:`ConfigSet.stash` """ self.table = self.undo_stack.pop(-1) hamster-3.0.3/waflib/Configure.py000066400000000000000000000453751452646177100167520ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Configuration system A :py:class:`waflib.Configure.ConfigurationContext` instance is created when ``waf configure`` is called, it is used to: * create data dictionaries (ConfigSet instances) * store the list of modules to import * hold configuration routines such as ``find_program``, etc """ import os, re, shlex, shutil, sys, time, traceback from waflib import ConfigSet, Utils, Options, Logs, Context, Build, Errors WAF_CONFIG_LOG = 'config.log' """Name of the configuration log file""" autoconfig = False """Execute the configuration automatically""" conf_template = '''# project %(app)s configured on %(now)s by # waf %(wafver)s (abi %(abi)s, python %(pyver)x on %(systype)s) # using %(args)s #''' class ConfigurationContext(Context.Context): '''configures the project''' cmd = 'configure' error_handlers = [] """ Additional functions to handle configuration errors """ def __init__(self, **kw): super(ConfigurationContext, self).__init__(**kw) self.environ = dict(os.environ) self.all_envs = {} self.top_dir = None self.out_dir = None self.tools = [] # tools loaded in the configuration, and that will be loaded when building self.hash = 0 self.files = [] self.tool_cache = [] self.setenv('') def setenv(self, name, env=None): """ Set a new config set for conf.env. If a config set of that name already exists, recall it without modification. The name is the filename prefix to save to ``c4che/NAME_cache.py``, and it is also used as *variants* by the build commands. Though related to variants, whatever kind of data may be stored in the config set:: def configure(cfg): cfg.env.ONE = 1 cfg.setenv('foo') cfg.env.ONE = 2 def build(bld): 2 == bld.env_of_name('foo').ONE :param name: name of the configuration set :type name: string :param env: ConfigSet to copy, or an empty ConfigSet is created :type env: :py:class:`waflib.ConfigSet.ConfigSet` """ if name not in self.all_envs or env: if not env: env = ConfigSet.ConfigSet() self.prepare_env(env) else: env = env.derive() self.all_envs[name] = env self.variant = name def get_env(self): """Getter for the env property""" return self.all_envs[self.variant] def set_env(self, val): """Setter for the env property""" self.all_envs[self.variant] = val env = property(get_env, set_env) def init_dirs(self): """ Initialize the project directory and the build directory """ top = self.top_dir if not top: top = Options.options.top if not top: top = getattr(Context.g_module, Context.TOP, None) if not top: top = self.path.abspath() top = os.path.abspath(top) self.srcnode = (os.path.isabs(top) and self.root or self.path).find_dir(top) assert(self.srcnode) out = self.out_dir if not out: out = Options.options.out if not out: out = getattr(Context.g_module, Context.OUT, None) if not out: out = Options.lockfile.replace('.lock-waf_%s_' % sys.platform, '').replace('.lock-waf', '') # someone can be messing with symlinks out = os.path.realpath(out) self.bldnode = (os.path.isabs(out) and self.root or self.path).make_node(out) self.bldnode.mkdir() if not os.path.isdir(self.bldnode.abspath()): self.fatal('Could not create the build directory %s' % self.bldnode.abspath()) def execute(self): """ See :py:func:`waflib.Context.Context.execute` """ self.init_dirs() self.cachedir = self.bldnode.make_node(Build.CACHE_DIR) self.cachedir.mkdir() path = os.path.join(self.bldnode.abspath(), WAF_CONFIG_LOG) self.logger = Logs.make_logger(path, 'cfg') app = getattr(Context.g_module, 'APPNAME', '') if app: ver = getattr(Context.g_module, 'VERSION', '') if ver: app = "%s (%s)" % (app, ver) params = {'now': time.ctime(), 'pyver': sys.hexversion, 'systype': sys.platform, 'args': " ".join(sys.argv), 'wafver': Context.WAFVERSION, 'abi': Context.ABI, 'app': app} self.to_log(conf_template % params) self.msg('Setting top to', self.srcnode.abspath()) self.msg('Setting out to', self.bldnode.abspath()) if id(self.srcnode) == id(self.bldnode): Logs.warn('Setting top == out') elif id(self.path) != id(self.srcnode): if self.srcnode.is_child_of(self.path): Logs.warn('Are you certain that you do not want to set top="." ?') super(ConfigurationContext, self).execute() self.store() Context.top_dir = self.srcnode.abspath() Context.out_dir = self.bldnode.abspath() # this will write a configure lock so that subsequent builds will # consider the current path as the root directory (see prepare_impl). # to remove: use 'waf distclean' env = ConfigSet.ConfigSet() env.argv = sys.argv env.options = Options.options.__dict__ env.config_cmd = self.cmd env.run_dir = Context.run_dir env.top_dir = Context.top_dir env.out_dir = Context.out_dir # conf.hash & conf.files hold wscript files paths and hash # (used only by Configure.autoconfig) env.hash = self.hash env.files = self.files env.environ = dict(self.environ) env.launch_dir = Context.launch_dir if not (self.env.NO_LOCK_IN_RUN or env.environ.get('NO_LOCK_IN_RUN') or getattr(Options.options, 'no_lock_in_run')): env.store(os.path.join(Context.run_dir, Options.lockfile)) if not (self.env.NO_LOCK_IN_TOP or env.environ.get('NO_LOCK_IN_TOP') or getattr(Options.options, 'no_lock_in_top')): env.store(os.path.join(Context.top_dir, Options.lockfile)) if not (self.env.NO_LOCK_IN_OUT or env.environ.get('NO_LOCK_IN_OUT') or getattr(Options.options, 'no_lock_in_out')): env.store(os.path.join(Context.out_dir, Options.lockfile)) def prepare_env(self, env): """ Insert *PREFIX*, *BINDIR* and *LIBDIR* values into ``env`` :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param env: a ConfigSet, usually ``conf.env`` """ if not env.PREFIX: if Options.options.prefix or Utils.is_win32: env.PREFIX = Options.options.prefix else: env.PREFIX = '/' if not env.BINDIR: if Options.options.bindir: env.BINDIR = Options.options.bindir else: env.BINDIR = Utils.subst_vars('${PREFIX}/bin', env) if not env.LIBDIR: if Options.options.libdir: env.LIBDIR = Options.options.libdir else: env.LIBDIR = Utils.subst_vars('${PREFIX}/lib%s' % Utils.lib64(), env) def store(self): """Save the config results into the cache file""" n = self.cachedir.make_node('build.config.py') n.write('version = 0x%x\ntools = %r\n' % (Context.HEXVERSION, self.tools)) if not self.all_envs: self.fatal('nothing to store in the configuration context!') for key in self.all_envs: tmpenv = self.all_envs[key] tmpenv.store(os.path.join(self.cachedir.abspath(), key + Build.CACHE_SUFFIX)) def load(self, tool_list, tooldir=None, funs=None, with_sys_path=True, cache=False): """ Load Waf tools, which will be imported whenever a build is started. :param tool_list: waf tools to import :type tool_list: list of string :param tooldir: paths for the imports :type tooldir: list of string :param funs: functions to execute from the waf tools :type funs: list of string :param cache: whether to prevent the tool from running twice :type cache: bool """ tools = Utils.to_list(tool_list) if tooldir: tooldir = Utils.to_list(tooldir) for tool in tools: # avoid loading the same tool more than once with the same functions # used by composite projects if cache: mag = (tool, id(self.env), tooldir, funs) if mag in self.tool_cache: self.to_log('(tool %s is already loaded, skipping)' % tool) continue self.tool_cache.append(mag) module = None try: module = Context.load_tool(tool, tooldir, ctx=self, with_sys_path=with_sys_path) except ImportError as e: self.fatal('Could not load the Waf tool %r from %r\n%s' % (tool, getattr(e, 'waf_sys_path', sys.path), e)) except Exception as e: self.to_log('imp %r (%r & %r)' % (tool, tooldir, funs)) self.to_log(traceback.format_exc()) raise if funs is not None: self.eval_rules(funs) else: func = getattr(module, 'configure', None) if func: if type(func) is type(Utils.readf): func(self) else: self.eval_rules(func) self.tools.append({'tool':tool, 'tooldir':tooldir, 'funs':funs}) def post_recurse(self, node): """ Records the path and a hash of the scripts visited, see :py:meth:`waflib.Context.Context.post_recurse` :param node: script :type node: :py:class:`waflib.Node.Node` """ super(ConfigurationContext, self).post_recurse(node) self.hash = Utils.h_list((self.hash, node.read('rb'))) self.files.append(node.abspath()) def eval_rules(self, rules): """ Execute configuration tests provided as list of functions to run :param rules: list of configuration method names :type rules: list of string """ self.rules = Utils.to_list(rules) for x in self.rules: f = getattr(self, x) if not f: self.fatal('No such configuration function %r' % x) f() def conf(f): """ Decorator: attach new configuration functions to :py:class:`waflib.Build.BuildContext` and :py:class:`waflib.Configure.ConfigurationContext`. The methods bound will accept a parameter named 'mandatory' to disable the configuration errors:: def configure(conf): conf.find_program('abc', mandatory=False) :param f: method to bind :type f: function """ def fun(*k, **kw): mandatory = kw.pop('mandatory', True) try: return f(*k, **kw) except Errors.ConfigurationError: if mandatory: raise fun.__name__ = f.__name__ setattr(ConfigurationContext, f.__name__, fun) setattr(Build.BuildContext, f.__name__, fun) return f @conf def add_os_flags(self, var, dest=None, dup=False): """ Import operating system environment values into ``conf.env`` dict:: def configure(conf): conf.add_os_flags('CFLAGS') :param var: variable to use :type var: string :param dest: destination variable, by default the same as var :type dest: string :param dup: add the same set of flags again :type dup: bool """ try: flags = shlex.split(self.environ[var]) except KeyError: return if dup or ''.join(flags) not in ''.join(Utils.to_list(self.env[dest or var])): self.env.append_value(dest or var, flags) @conf def cmd_to_list(self, cmd): """ Detect if a command is written in pseudo shell like ``ccache g++`` and return a list. :param cmd: command :type cmd: a string or a list of string """ if isinstance(cmd, str): if os.path.isfile(cmd): # do not take any risk return [cmd] if os.sep == '/': return shlex.split(cmd) else: try: return shlex.split(cmd, posix=False) except TypeError: # Python 2.5 on windows? return shlex.split(cmd) return cmd @conf def check_waf_version(self, mini='1.9.99', maxi='2.1.0', **kw): """ Raise a Configuration error if the Waf version does not strictly match the given bounds:: conf.check_waf_version(mini='1.9.99', maxi='2.1.0') :type mini: number, tuple or string :param mini: Minimum required version :type maxi: number, tuple or string :param maxi: Maximum allowed version """ self.start_msg('Checking for waf version in %s-%s' % (str(mini), str(maxi)), **kw) ver = Context.HEXVERSION if Utils.num2ver(mini) > ver: self.fatal('waf version should be at least %r (%r found)' % (Utils.num2ver(mini), ver)) if Utils.num2ver(maxi) < ver: self.fatal('waf version should be at most %r (%r found)' % (Utils.num2ver(maxi), ver)) self.end_msg('ok', **kw) @conf def find_file(self, filename, path_list=[]): """ Find a file in a list of paths :param filename: name of the file to search for :param path_list: list of directories to search :return: the first matching filename; else a configuration exception is raised """ for n in Utils.to_list(filename): for d in Utils.to_list(path_list): p = os.path.expanduser(os.path.join(d, n)) if os.path.exists(p): return p self.fatal('Could not find %r' % filename) @conf def find_program(self, filename, **kw): """ Search for a program on the operating system When var is used, you may set os.environ[var] to help find a specific program version, for example:: $ CC='ccache gcc' waf configure :param path_list: paths to use for searching :type param_list: list of string :param var: store the result to conf.env[var] where var defaults to filename.upper() if not provided; the result is stored as a list of strings :type var: string :param value: obtain the program from the value passed exclusively :type value: list or string (list is preferred) :param exts: list of extensions for the binary (do not add an extension for portability) :type exts: list of string :param msg: name to display in the log, by default filename is used :type msg: string :param interpreter: interpreter for the program :type interpreter: ConfigSet variable key :raises: :py:class:`waflib.Errors.ConfigurationError` """ exts = kw.get('exts', Utils.is_win32 and '.exe,.com,.bat,.cmd' or ',.sh,.pl,.py') environ = kw.get('environ', getattr(self, 'environ', os.environ)) ret = '' filename = Utils.to_list(filename) msg = kw.get('msg', ', '.join(filename)) var = kw.get('var', '') if not var: var = re.sub(r'\W', '_', filename[0].upper()) path_list = kw.get('path_list', '') if path_list: path_list = Utils.to_list(path_list) else: path_list = environ.get('PATH', '').split(os.pathsep) if kw.get('value'): # user-provided in command-line options and passed to find_program ret = self.cmd_to_list(kw['value']) elif environ.get(var): # user-provided in the os environment ret = self.cmd_to_list(environ[var]) elif self.env[var]: # a default option in the wscript file ret = self.cmd_to_list(self.env[var]) else: if not ret: ret = self.find_binary(filename, exts.split(','), path_list) if not ret and Utils.winreg: ret = Utils.get_registry_app_path(Utils.winreg.HKEY_CURRENT_USER, filename) if not ret and Utils.winreg: ret = Utils.get_registry_app_path(Utils.winreg.HKEY_LOCAL_MACHINE, filename) ret = self.cmd_to_list(ret) if ret: if len(ret) == 1: retmsg = ret[0] else: retmsg = ret else: retmsg = False self.msg('Checking for program %r' % msg, retmsg, **kw) if not kw.get('quiet'): self.to_log('find program=%r paths=%r var=%r -> %r' % (filename, path_list, var, ret)) if not ret: self.fatal(kw.get('errmsg', '') or 'Could not find the program %r' % filename) interpreter = kw.get('interpreter') if interpreter is None: if not Utils.check_exe(ret[0], env=environ): self.fatal('Program %r is not executable' % ret) self.env[var] = ret else: self.env[var] = self.env[interpreter] + ret return ret @conf def find_binary(self, filenames, exts, paths): for f in filenames: for ext in exts: exe_name = f + ext if os.path.isabs(exe_name): if os.path.isfile(exe_name): return exe_name else: for path in paths: x = os.path.expanduser(os.path.join(path, exe_name)) if os.path.isfile(x): return x return None @conf def run_build(self, *k, **kw): """ Create a temporary build context to execute a build. A temporary reference to that build context is kept on self.test_bld for debugging purposes. The arguments to this function are passed to a single task generator for that build. Only three parameters are mandatory: :param features: features to pass to a task generator created in the build :type features: list of string :param compile_filename: file to create for the compilation (default: *test.c*) :type compile_filename: string :param code: input file contents :type code: string Though this function returns *0* by default, the build may bind attribute named *retval* on the build context object to return a particular value. See :py:func:`waflib.Tools.c_config.test_exec_fun` for example. The temporary builds creates a temporary folder; the name of that folder is calculated by hashing input arguments to this function, with the exception of :py:class:`waflib.ConfigSet.ConfigSet` objects which are used for both reading and writing values. This function also features a cache which is disabled by default; that cache relies on the hash value calculated as indicated above:: def options(opt): opt.add_option('--confcache', dest='confcache', default=0, action='count', help='Use a configuration cache') And execute the configuration with the following command-line:: $ waf configure --confcache """ buf = [] for key in sorted(kw.keys()): v = kw[key] if isinstance(v, ConfigSet.ConfigSet): # values are being written to, so they are excluded from contributing to the hash continue elif hasattr(v, '__call__'): buf.append(Utils.h_fun(v)) else: buf.append(str(v)) h = Utils.h_list(buf) dir = self.bldnode.abspath() + os.sep + (not Utils.is_win32 and '.' or '') + 'conf_check_' + Utils.to_hex(h) cachemode = kw.get('confcache', getattr(Options.options, 'confcache', None)) if not cachemode and os.path.exists(dir): shutil.rmtree(dir) try: os.makedirs(dir) except OSError: pass try: os.stat(dir) except OSError: self.fatal('cannot use the configuration test folder %r' % dir) if cachemode == 1: try: proj = ConfigSet.ConfigSet(os.path.join(dir, 'cache_run_build')) except EnvironmentError: pass else: ret = proj['cache_run_build'] if isinstance(ret, str) and ret.startswith('Test does not build'): self.fatal(ret) return ret bdir = os.path.join(dir, 'testbuild') if not os.path.exists(bdir): os.makedirs(bdir) cls_name = kw.get('run_build_cls') or getattr(self, 'run_build_cls', 'build') self.test_bld = bld = Context.create_context(cls_name, top_dir=dir, out_dir=bdir) bld.init_dirs() bld.progress_bar = 0 bld.targets = '*' bld.logger = self.logger bld.all_envs.update(self.all_envs) # not really necessary bld.env = kw['env'] bld.kw = kw bld.conf = self kw['build_fun'](bld) ret = -1 try: try: bld.compile() except Errors.WafError: ret = 'Test does not build: %s' % traceback.format_exc() self.fatal(ret) else: ret = getattr(bld, 'retval', 0) finally: if cachemode: # cache the results each time proj = ConfigSet.ConfigSet() proj['cache_run_build'] = ret proj.store(os.path.join(dir, 'cache_run_build')) else: shutil.rmtree(dir) return ret @conf def ret_msg(self, msg, args): if isinstance(msg, str): return msg return msg(args) @conf def test(self, *k, **kw): if not 'env' in kw: kw['env'] = self.env.derive() # validate_c for example if kw.get('validate'): kw['validate'](kw) self.start_msg(kw['msg'], **kw) ret = None try: ret = self.run_build(*k, **kw) except self.errors.ConfigurationError: self.end_msg(kw['errmsg'], 'YELLOW', **kw) if Logs.verbose > 1: raise else: self.fatal('The configuration failed') else: kw['success'] = ret if kw.get('post_check'): ret = kw['post_check'](kw) if ret: self.end_msg(kw['errmsg'], 'YELLOW', **kw) self.fatal('The configuration failed %r' % ret) else: self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw) return ret hamster-3.0.3/waflib/Context.py000077500000000000000000000514041452646177100164460ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010-2018 (ita) """ Classes and functions enabling the command system """ import os, re, sys from waflib import Utils, Errors, Logs import waflib.Node if sys.hexversion > 0x3040000: import types class imp(object): new_module = lambda x: types.ModuleType(x) else: import imp # the following 3 constants are updated on each new release (do not touch) HEXVERSION=0x2001a00 """Constant updated on new releases""" WAFVERSION="2.0.26" """Constant updated on new releases""" WAFREVISION="0fb985ce1932c6f3e7533f435e4ee209d673776e" """Git revision when the waf version is updated""" WAFNAME="waf" """Application name displayed on --help""" ABI = 20 """Version of the build data cache file format (used in :py:const:`waflib.Context.DBFILE`)""" DBFILE = '.wafpickle-%s-%d-%d' % (sys.platform, sys.hexversion, ABI) """Name of the pickle file for storing the build data""" APPNAME = 'APPNAME' """Default application name (used by ``waf dist``)""" VERSION = 'VERSION' """Default application version (used by ``waf dist``)""" TOP = 'top' """The variable name for the top-level directory in wscript files""" OUT = 'out' """The variable name for the output directory in wscript files""" WSCRIPT_FILE = 'wscript' """Name of the waf script files""" launch_dir = '' """Directory from which waf has been called""" run_dir = '' """Location of the wscript file to use as the entry point""" top_dir = '' """Location of the project directory (top), if the project was configured""" out_dir = '' """Location of the build directory (out), if the project was configured""" waf_dir = '' """Directory containing the waf modules""" default_encoding = Utils.console_encoding() """Encoding to use when reading outputs from other processes""" g_module = None """ Module representing the top-level wscript file (see :py:const:`waflib.Context.run_dir`) """ STDOUT = 1 STDERR = -1 BOTH = 0 classes = [] """ List of :py:class:`waflib.Context.Context` subclasses that can be used as waf commands. The classes are added automatically by a metaclass. """ def create_context(cmd_name, *k, **kw): """ Returns a new :py:class:`waflib.Context.Context` instance corresponding to the given command. Used in particular by :py:func:`waflib.Scripting.run_command` :param cmd_name: command name :type cmd_name: string :param k: arguments to give to the context class initializer :type k: list :param k: keyword arguments to give to the context class initializer :type k: dict :return: Context object :rtype: :py:class:`waflib.Context.Context` """ for x in classes: if x.cmd == cmd_name: return x(*k, **kw) ctx = Context(*k, **kw) ctx.fun = cmd_name return ctx class store_context(type): """ Metaclass that registers command classes into the list :py:const:`waflib.Context.classes` Context classes must provide an attribute 'cmd' representing the command name, and a function attribute 'fun' representing the function name that the command uses. """ def __init__(cls, name, bases, dct): super(store_context, cls).__init__(name, bases, dct) name = cls.__name__ if name in ('ctx', 'Context'): return try: cls.cmd except AttributeError: raise Errors.WafError('Missing command for the context class %r (cmd)' % name) if not getattr(cls, 'fun', None): cls.fun = cls.cmd classes.insert(0, cls) ctx = store_context('ctx', (object,), {}) """Base class for all :py:class:`waflib.Context.Context` classes""" class Context(ctx): """ Default context for waf commands, and base class for new command contexts. Context objects are passed to top-level functions:: def foo(ctx): print(ctx.__class__.__name__) # waflib.Context.Context Subclasses must define the class attributes 'cmd' and 'fun': :param cmd: command to execute as in ``waf cmd`` :type cmd: string :param fun: function name to execute when the command is called :type fun: string .. inheritance-diagram:: waflib.Context.Context waflib.Build.BuildContext waflib.Build.InstallContext waflib.Build.UninstallContext waflib.Build.StepContext waflib.Build.ListContext waflib.Configure.ConfigurationContext waflib.Scripting.Dist waflib.Scripting.DistCheck waflib.Build.CleanContext :top-classes: waflib.Context.Context """ errors = Errors """ Shortcut to :py:mod:`waflib.Errors` provided for convenience """ tools = {} """ A module cache for wscript files; see :py:meth:`Context.Context.load` """ def __init__(self, **kw): try: rd = kw['run_dir'] except KeyError: rd = run_dir # binds the context to the nodes in use to avoid a context singleton self.node_class = type('Nod3', (waflib.Node.Node,), {}) self.node_class.__module__ = 'waflib.Node' self.node_class.ctx = self self.root = self.node_class('', None) self.cur_script = None self.path = self.root.find_dir(rd) self.stack_path = [] self.exec_dict = {'ctx':self, 'conf':self, 'bld':self, 'opt':self} self.logger = None def finalize(self): """ Called to free resources such as logger files """ try: logger = self.logger except AttributeError: pass else: Logs.free_logger(logger) delattr(self, 'logger') def load(self, tool_list, *k, **kw): """ Loads a Waf tool as a module, and try calling the function named :py:const:`waflib.Context.Context.fun` from it. A ``tooldir`` argument may be provided as a list of module paths. :param tool_list: list of Waf tool names to load :type tool_list: list of string or space-separated string """ tools = Utils.to_list(tool_list) path = Utils.to_list(kw.get('tooldir', '')) with_sys_path = kw.get('with_sys_path', True) for t in tools: module = load_tool(t, path, with_sys_path=with_sys_path) fun = getattr(module, kw.get('name', self.fun), None) if fun: fun(self) def execute(self): """ Here, it calls the function name in the top-level wscript file. Most subclasses redefine this method to provide additional functionality. """ self.recurse([os.path.dirname(g_module.root_path)]) def pre_recurse(self, node): """ Method executed immediately before a folder is read by :py:meth:`waflib.Context.Context.recurse`. The current script is bound as a Node object on ``self.cur_script``, and the current path is bound to ``self.path`` :param node: script :type node: :py:class:`waflib.Node.Node` """ self.stack_path.append(self.cur_script) self.cur_script = node self.path = node.parent def post_recurse(self, node): """ Restores ``self.cur_script`` and ``self.path`` right after :py:meth:`waflib.Context.Context.recurse` terminates. :param node: script :type node: :py:class:`waflib.Node.Node` """ self.cur_script = self.stack_path.pop() if self.cur_script: self.path = self.cur_script.parent def recurse(self, dirs, name=None, mandatory=True, once=True, encoding=None): """ Runs user-provided functions from the supplied list of directories. The directories can be either absolute, or relative to the directory of the wscript file The methods :py:meth:`waflib.Context.Context.pre_recurse` and :py:meth:`waflib.Context.Context.post_recurse` are called immediately before and after a script has been executed. :param dirs: List of directories to visit :type dirs: list of string or space-separated string :param name: Name of function to invoke from the wscript :type name: string :param mandatory: whether sub wscript files are required to exist :type mandatory: bool :param once: read the script file once for a particular context :type once: bool """ try: cache = self.recurse_cache except AttributeError: cache = self.recurse_cache = {} for d in Utils.to_list(dirs): if not os.path.isabs(d): # absolute paths only d = os.path.join(self.path.abspath(), d) WSCRIPT = os.path.join(d, WSCRIPT_FILE) WSCRIPT_FUN = WSCRIPT + '_' + (name or self.fun) node = self.root.find_node(WSCRIPT_FUN) if node and (not once or node not in cache): cache[node] = True self.pre_recurse(node) try: function_code = node.read('r', encoding) exec(compile(function_code, node.abspath(), 'exec'), self.exec_dict) finally: self.post_recurse(node) elif not node: node = self.root.find_node(WSCRIPT) tup = (node, name or self.fun) if node and (not once or tup not in cache): cache[tup] = True self.pre_recurse(node) try: wscript_module = load_module(node.abspath(), encoding=encoding) user_function = getattr(wscript_module, (name or self.fun), None) if not user_function: if not mandatory: continue raise Errors.WafError('No function %r defined in %s' % (name or self.fun, node.abspath())) user_function(self) finally: self.post_recurse(node) elif not node: if not mandatory: continue try: os.listdir(d) except OSError: raise Errors.WafError('Cannot read the folder %r' % d) raise Errors.WafError('No wscript file in directory %s' % d) def log_command(self, cmd, kw): if Logs.verbose: fmt = os.environ.get('WAF_CMD_FORMAT') if fmt == 'string': if not isinstance(cmd, str): cmd = Utils.shell_escape(cmd) Logs.debug('runner: %r', cmd) Logs.debug('runner_env: kw=%s', kw) def exec_command(self, cmd, **kw): """ Runs an external process and returns the exit status:: def run(tsk): ret = tsk.generator.bld.exec_command('touch foo.txt') return ret If the context has the attribute 'log', then captures and logs the process stderr/stdout. Unlike :py:meth:`waflib.Context.Context.cmd_and_log`, this method does not return the stdout/stderr values captured. :param cmd: command argument for subprocess.Popen :type cmd: string or list :param kw: keyword arguments for subprocess.Popen. The parameters input/timeout will be passed to wait/communicate. :type kw: dict :returns: process exit status :rtype: integer :raises: :py:class:`waflib.Errors.WafError` if an invalid executable is specified for a non-shell process :raises: :py:class:`waflib.Errors.WafError` in case of execution failure """ subprocess = Utils.subprocess kw['shell'] = isinstance(cmd, str) self.log_command(cmd, kw) if self.logger: self.logger.info(cmd) if 'stdout' not in kw: kw['stdout'] = subprocess.PIPE if 'stderr' not in kw: kw['stderr'] = subprocess.PIPE if Logs.verbose and not kw['shell'] and not Utils.check_exe(cmd[0]): raise Errors.WafError('Program %s not found!' % cmd[0]) cargs = {} if 'timeout' in kw: if sys.hexversion >= 0x3030000: cargs['timeout'] = kw['timeout'] if not 'start_new_session' in kw: kw['start_new_session'] = True del kw['timeout'] if 'input' in kw: if kw['input']: cargs['input'] = kw['input'] kw['stdin'] = subprocess.PIPE del kw['input'] if 'cwd' in kw: if not isinstance(kw['cwd'], str): kw['cwd'] = kw['cwd'].abspath() encoding = kw.pop('decode_as', default_encoding) try: ret, out, err = Utils.run_process(cmd, kw, cargs) except Exception as e: raise Errors.WafError('Execution failure: %s' % str(e), ex=e) if out: if not isinstance(out, str): out = out.decode(encoding, errors='replace') if self.logger: self.logger.debug('out: %s', out) else: Logs.info(out, extra={'stream':sys.stdout, 'c1': ''}) if err: if not isinstance(err, str): err = err.decode(encoding, errors='replace') if self.logger: self.logger.error('err: %s' % err) else: Logs.info(err, extra={'stream':sys.stderr, 'c1': ''}) return ret def cmd_and_log(self, cmd, **kw): """ Executes a process and returns stdout/stderr if the execution is successful. An exception is thrown when the exit status is non-0. In that case, both stderr and stdout will be bound to the WafError object (configuration tests):: def configure(conf): out = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.STDOUT, quiet=waflib.Context.BOTH) (out, err) = conf.cmd_and_log(['echo', 'hello'], output=waflib.Context.BOTH) (out, err) = conf.cmd_and_log(cmd, input='\\n'.encode(), output=waflib.Context.STDOUT) try: conf.cmd_and_log(['which', 'someapp'], output=waflib.Context.BOTH) except Errors.WafError as e: print(e.stdout, e.stderr) :param cmd: args for subprocess.Popen :type cmd: list or string :param kw: keyword arguments for subprocess.Popen. The parameters input/timeout will be passed to wait/communicate. :type kw: dict :returns: a tuple containing the contents of stdout and stderr :rtype: string :raises: :py:class:`waflib.Errors.WafError` if an invalid executable is specified for a non-shell process :raises: :py:class:`waflib.Errors.WafError` in case of execution failure; stdout/stderr/returncode are bound to the exception object """ subprocess = Utils.subprocess kw['shell'] = isinstance(cmd, str) self.log_command(cmd, kw) quiet = kw.pop('quiet', None) to_ret = kw.pop('output', STDOUT) if Logs.verbose and not kw['shell'] and not Utils.check_exe(cmd[0]): raise Errors.WafError('Program %r not found!' % cmd[0]) kw['stdout'] = kw['stderr'] = subprocess.PIPE if quiet is None: self.to_log(cmd) cargs = {} if 'timeout' in kw: if sys.hexversion >= 0x3030000: cargs['timeout'] = kw['timeout'] if not 'start_new_session' in kw: kw['start_new_session'] = True del kw['timeout'] if 'input' in kw: if kw['input']: cargs['input'] = kw['input'] kw['stdin'] = subprocess.PIPE del kw['input'] if 'cwd' in kw: if not isinstance(kw['cwd'], str): kw['cwd'] = kw['cwd'].abspath() encoding = kw.pop('decode_as', default_encoding) try: ret, out, err = Utils.run_process(cmd, kw, cargs) except Exception as e: raise Errors.WafError('Execution failure: %s' % str(e), ex=e) if not isinstance(out, str): out = out.decode(encoding, errors='replace') if not isinstance(err, str): err = err.decode(encoding, errors='replace') if out and quiet != STDOUT and quiet != BOTH: self.to_log('out: %s' % out) if err and quiet != STDERR and quiet != BOTH: self.to_log('err: %s' % err) if ret: e = Errors.WafError('Command %r returned %r' % (cmd, ret)) e.returncode = ret e.stderr = err e.stdout = out raise e if to_ret == BOTH: return (out, err) elif to_ret == STDERR: return err return out def fatal(self, msg, ex=None): """ Prints an error message in red and stops command execution; this is usually used in the configuration section:: def configure(conf): conf.fatal('a requirement is missing') :param msg: message to display :type msg: string :param ex: optional exception object :type ex: exception :raises: :py:class:`waflib.Errors.ConfigurationError` """ if self.logger: self.logger.info('from %s: %s' % (self.path.abspath(), msg)) try: logfile = self.logger.handlers[0].baseFilename except AttributeError: pass else: if os.environ.get('WAF_PRINT_FAILURE_LOG'): # see #1930 msg = 'Log from (%s):\n%s\n' % (logfile, Utils.readf(logfile)) else: msg = '%s\n(complete log in %s)' % (msg, logfile) raise self.errors.ConfigurationError(msg, ex=ex) def to_log(self, msg): """ Logs information to the logger (if present), or to stderr. Empty messages are not printed:: def build(bld): bld.to_log('starting the build') Provide a logger on the context class or override this method if necessary. :param msg: message :type msg: string """ if not msg: return if self.logger: self.logger.info(msg) else: sys.stderr.write(str(msg)) sys.stderr.flush() def msg(self, *k, **kw): """ Prints a configuration message of the form ``msg: result``. The second part of the message will be in colors. The output can be disabled easily by setting ``in_msg`` to a positive value:: def configure(conf): self.in_msg = 1 conf.msg('Checking for library foo', 'ok') # no output :param msg: message to display to the user :type msg: string :param result: result to display :type result: string or boolean :param color: color to use, see :py:const:`waflib.Logs.colors_lst` :type color: string """ try: msg = kw['msg'] except KeyError: msg = k[0] self.start_msg(msg, **kw) try: result = kw['result'] except KeyError: result = k[1] color = kw.get('color') if not isinstance(color, str): color = result and 'GREEN' or 'YELLOW' self.end_msg(result, color, **kw) def start_msg(self, *k, **kw): """ Prints the beginning of a 'Checking for xxx' message. See :py:meth:`waflib.Context.Context.msg` """ if kw.get('quiet'): return msg = kw.get('msg') or k[0] try: if self.in_msg: self.in_msg += 1 return except AttributeError: self.in_msg = 0 self.in_msg += 1 try: self.line_just = max(self.line_just, len(msg)) except AttributeError: self.line_just = max(40, len(msg)) for x in (self.line_just * '-', msg): self.to_log(x) Logs.pprint('NORMAL', "%s :" % msg.ljust(self.line_just), sep='') def end_msg(self, *k, **kw): """Prints the end of a 'Checking for' message. See :py:meth:`waflib.Context.Context.msg`""" if kw.get('quiet'): return self.in_msg -= 1 if self.in_msg: return result = kw.get('result') or k[0] defcolor = 'GREEN' if result is True: msg = 'ok' elif not result: msg = 'not found' defcolor = 'YELLOW' else: msg = str(result) self.to_log(msg) try: color = kw['color'] except KeyError: if len(k) > 1 and k[1] in Logs.colors_lst: # compatibility waf 1.7 color = k[1] else: color = defcolor Logs.pprint(color, msg) def load_special_tools(self, var, ban=[]): """ Loads third-party extensions modules for certain programming languages by trying to list certain files in the extras/ directory. This method is typically called once for a programming language group, see for example :py:mod:`waflib.Tools.compiler_c` :param var: glob expression, for example 'cxx\\_\\*.py' :type var: string :param ban: list of exact file names to exclude :type ban: list of string """ if os.path.isdir(waf_dir): lst = self.root.find_node(waf_dir).find_node('waflib/extras').ant_glob(var) for x in lst: if not x.name in ban: load_tool(x.name.replace('.py', '')) else: from zipfile import PyZipFile waflibs = PyZipFile(waf_dir) lst = waflibs.namelist() for x in lst: if not re.match('waflib/extras/%s' % var.replace('*', '.*'), var): continue f = os.path.basename(x) doban = False for b in ban: r = b.replace('*', '.*') if re.match(r, f): doban = True if not doban: f = f.replace('.py', '') load_tool(f) cache_modules = {} """ Dictionary holding already loaded modules (wscript), indexed by their absolute path. The modules are added automatically by :py:func:`waflib.Context.load_module` """ def load_module(path, encoding=None): """ Loads a wscript file as a python module. This method caches results in :py:attr:`waflib.Context.cache_modules` :param path: file path :type path: string :return: Loaded Python module :rtype: module """ try: return cache_modules[path] except KeyError: pass module = imp.new_module(WSCRIPT_FILE) try: code = Utils.readf(path, m='r', encoding=encoding) except EnvironmentError: raise Errors.WafError('Could not read the file %r' % path) module_dir = os.path.dirname(path) sys.path.insert(0, module_dir) try: exec(compile(code, path, 'exec'), module.__dict__) finally: sys.path.remove(module_dir) cache_modules[path] = module return module def load_tool(tool, tooldir=None, ctx=None, with_sys_path=True): """ Imports a Waf tool as a python module, and stores it in the dict :py:const:`waflib.Context.Context.tools` :type tool: string :param tool: Name of the tool :type tooldir: list :param tooldir: List of directories to search for the tool module :type with_sys_path: boolean :param with_sys_path: whether or not to search the regular sys.path, besides waf_dir and potentially given tooldirs """ if tool == 'java': tool = 'javaw' # jython else: tool = tool.replace('++', 'xx') if not with_sys_path: back_path = sys.path sys.path = [] try: if tooldir: assert isinstance(tooldir, list) sys.path = tooldir + sys.path try: __import__(tool) except ImportError as e: e.waf_sys_path = list(sys.path) raise finally: for d in tooldir: sys.path.remove(d) ret = sys.modules[tool] Context.tools[tool] = ret return ret else: if not with_sys_path: sys.path.insert(0, waf_dir) try: for x in ('waflib.Tools.%s', 'waflib.extras.%s', 'waflib.%s', '%s'): try: __import__(x % tool) break except ImportError: x = None else: # raise an exception __import__(tool) except ImportError as e: e.waf_sys_path = list(sys.path) raise finally: if not with_sys_path: sys.path.remove(waf_dir) ret = sys.modules[x % tool] Context.tools[tool] = ret return ret finally: if not with_sys_path: sys.path += back_path hamster-3.0.3/waflib/Errors.py000066400000000000000000000032611452646177100162710ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010-2018 (ita) """ Exceptions used in the Waf code """ import traceback, sys class WafError(Exception): """Base class for all Waf errors""" def __init__(self, msg='', ex=None): """ :param msg: error message :type msg: string :param ex: exception causing this error (optional) :type ex: exception """ Exception.__init__(self) self.msg = msg assert not isinstance(msg, Exception) self.stack = [] if ex: if not msg: self.msg = str(ex) if isinstance(ex, WafError): self.stack = ex.stack else: self.stack = traceback.extract_tb(sys.exc_info()[2]) self.stack += traceback.extract_stack()[:-1] self.verbose_msg = ''.join(traceback.format_list(self.stack)) def __str__(self): return str(self.msg) class BuildError(WafError): """Error raised during the build and install phases""" def __init__(self, error_tasks=[]): """ :param error_tasks: tasks that could not complete normally :type error_tasks: list of task objects """ self.tasks = error_tasks WafError.__init__(self, self.format_error()) def format_error(self): """Formats the error messages from the tasks that failed""" lst = ['Build failed'] for tsk in self.tasks: txt = tsk.format_error() if txt: lst.append(txt) return '\n'.join(lst) class ConfigurationError(WafError): """Configuration exception raised in particular by :py:meth:`waflib.Context.Context.fatal`""" pass class TaskRescan(WafError): """Task-specific exception type signalling required signature recalculations""" pass class TaskNotReady(WafError): """Task-specific exception type signalling that task signatures cannot be computed""" pass hamster-3.0.3/waflib/LICENSE000066400000000000000000000024721452646177100154530ustar00rootroot00000000000000Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. hamster-3.0.3/waflib/Logs.py000066400000000000000000000230331452646177100157200ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ logging, colors, terminal width and pretty-print """ import os, re, traceback, sys from waflib import Utils, ansiterm if not os.environ.get('NOSYNC', False): # synchronized output is nearly mandatory to prevent garbled output if sys.stdout.isatty() and id(sys.stdout) == id(sys.__stdout__): sys.stdout = ansiterm.AnsiTerm(sys.stdout) if sys.stderr.isatty() and id(sys.stderr) == id(sys.__stderr__): sys.stderr = ansiterm.AnsiTerm(sys.stderr) # import the logging module after since it holds a reference on sys.stderr # in case someone uses the root logger import logging LOG_FORMAT = os.environ.get('WAF_LOG_FORMAT', '%(asctime)s %(c1)s%(zone)s%(c2)s %(message)s') HOUR_FORMAT = os.environ.get('WAF_HOUR_FORMAT', '%H:%M:%S') zones = [] """ See :py:class:`waflib.Logs.log_filter` """ verbose = 0 """ Global verbosity level, see :py:func:`waflib.Logs.debug` and :py:func:`waflib.Logs.error` """ colors_lst = { 'USE' : True, 'BOLD' :'\x1b[01;1m', 'RED' :'\x1b[01;31m', 'GREEN' :'\x1b[32m', 'YELLOW':'\x1b[33m', 'PINK' :'\x1b[35m', 'BLUE' :'\x1b[01;34m', 'CYAN' :'\x1b[36m', 'GREY' :'\x1b[37m', 'NORMAL':'\x1b[0m', 'cursor_on' :'\x1b[?25h', 'cursor_off' :'\x1b[?25l', } indicator = '\r\x1b[K%s%s%s' try: unicode except NameError: unicode = None def enable_colors(use): """ If *1* is given, then the system will perform a few verifications before enabling colors, such as checking whether the interpreter is running in a terminal. A value of zero will disable colors, and a value above *1* will force colors. :param use: whether to enable colors or not :type use: integer """ if use == 1: if not (sys.stderr.isatty() or sys.stdout.isatty()): use = 0 if Utils.is_win32 and os.name != 'java': term = os.environ.get('TERM', '') # has ansiterm else: term = os.environ.get('TERM', 'dumb') if term in ('dumb', 'emacs'): use = 0 if use >= 1: os.environ['TERM'] = 'vt100' colors_lst['USE'] = use # If console packages are available, replace the dummy function with a real # implementation try: get_term_cols = ansiterm.get_term_cols except AttributeError: def get_term_cols(): return 80 get_term_cols.__doc__ = """ Returns the console width in characters. :return: the number of characters per line :rtype: int """ def get_color(cl): """ Returns the ansi sequence corresponding to the given color name. An empty string is returned when coloring is globally disabled. :param cl: color name in capital letters :type cl: string """ if colors_lst['USE']: return colors_lst.get(cl, '') return '' class color_dict(object): """attribute-based color access, eg: colors.PINK""" def __getattr__(self, a): return get_color(a) def __call__(self, a): return get_color(a) colors = color_dict() re_log = re.compile(r'(\w+): (.*)', re.M) class log_filter(logging.Filter): """ Waf logs are of the form 'name: message', and can be filtered by 'waf --zones=name'. For example, the following:: from waflib import Logs Logs.debug('test: here is a message') Will be displayed only when executing:: $ waf --zones=test """ def __init__(self, name=''): logging.Filter.__init__(self, name) def filter(self, rec): """ Filters log records by zone and by logging level :param rec: log entry """ rec.zone = rec.module if rec.levelno >= logging.INFO: return True m = re_log.match(rec.msg) if m: rec.zone = m.group(1) rec.msg = m.group(2) if zones: return getattr(rec, 'zone', '') in zones or '*' in zones elif not verbose > 2: return False return True class log_handler(logging.StreamHandler): """Dispatches messages to stderr/stdout depending on the severity level""" def emit(self, record): """ Delegates the functionality to :py:meth:`waflib.Log.log_handler.emit_override` """ # default implementation try: try: self.stream = record.stream except AttributeError: if record.levelno >= logging.WARNING: record.stream = self.stream = sys.stderr else: record.stream = self.stream = sys.stdout self.emit_override(record) self.flush() except (KeyboardInterrupt, SystemExit): raise except: # from the python library -_- self.handleError(record) def emit_override(self, record, **kw): """ Writes the log record to the desired stream (stderr/stdout) """ self.terminator = getattr(record, 'terminator', '\n') stream = self.stream if unicode: # python2 msg = self.formatter.format(record) fs = '%s' + self.terminator try: if (isinstance(msg, unicode) and getattr(stream, 'encoding', None)): fs = fs.decode(stream.encoding) try: stream.write(fs % msg) except UnicodeEncodeError: stream.write((fs % msg).encode(stream.encoding)) else: stream.write(fs % msg) except UnicodeError: stream.write((fs % msg).encode('utf-8')) else: logging.StreamHandler.emit(self, record) class formatter(logging.Formatter): """Simple log formatter which handles colors""" def __init__(self): logging.Formatter.__init__(self, LOG_FORMAT, HOUR_FORMAT) def format(self, rec): """ Formats records and adds colors as needed. The records do not get a leading hour format if the logging level is above *INFO*. """ try: msg = rec.msg.decode('utf-8') except Exception: msg = rec.msg use = colors_lst['USE'] if (use == 1 and rec.stream.isatty()) or use == 2: c1 = getattr(rec, 'c1', None) if c1 is None: c1 = '' if rec.levelno >= logging.ERROR: c1 = colors.RED elif rec.levelno >= logging.WARNING: c1 = colors.YELLOW elif rec.levelno >= logging.INFO: c1 = colors.GREEN c2 = getattr(rec, 'c2', colors.NORMAL) msg = '%s%s%s' % (c1, msg, c2) else: # remove single \r that make long lines in text files # and other terminal commands msg = re.sub(r'\r(?!\n)|\x1B\[(K|.*?(m|h|l))', '', msg) if rec.levelno >= logging.INFO: # the goal of this is to format without the leading "Logs, hour" prefix if rec.args: try: return msg % rec.args except UnicodeDecodeError: return msg.encode('utf-8') % rec.args return msg rec.msg = msg rec.c1 = colors.PINK rec.c2 = colors.NORMAL return logging.Formatter.format(self, rec) log = None """global logger for Logs.debug, Logs.error, etc""" def debug(*k, **kw): """ Wraps logging.debug and discards messages if the verbosity level :py:attr:`waflib.Logs.verbose` ≤ 0 """ if verbose: k = list(k) k[0] = k[0].replace('\n', ' ') log.debug(*k, **kw) def error(*k, **kw): """ Wrap logging.errors, adds the stack trace when the verbosity level :py:attr:`waflib.Logs.verbose` ≥ 2 """ log.error(*k, **kw) if verbose > 2: st = traceback.extract_stack() if st: st = st[:-1] buf = [] for filename, lineno, name, line in st: buf.append(' File %r, line %d, in %s' % (filename, lineno, name)) if line: buf.append(' %s' % line.strip()) if buf: log.error('\n'.join(buf)) def warn(*k, **kw): """ Wraps logging.warning """ log.warning(*k, **kw) def info(*k, **kw): """ Wraps logging.info """ log.info(*k, **kw) def init_log(): """ Initializes the logger :py:attr:`waflib.Logs.log` """ global log log = logging.getLogger('waflib') log.handlers = [] log.filters = [] hdlr = log_handler() hdlr.setFormatter(formatter()) log.addHandler(hdlr) log.addFilter(log_filter()) log.setLevel(logging.DEBUG) def make_logger(path, name): """ Creates a simple logger, which is often used to redirect the context command output:: from waflib import Logs bld.logger = Logs.make_logger('test.log', 'build') bld.check(header_name='sadlib.h', features='cxx cprogram', mandatory=False) # have the file closed immediately Logs.free_logger(bld.logger) # stop logging bld.logger = None The method finalize() of the command will try to free the logger, if any :param path: file name to write the log output to :type path: string :param name: logger name (loggers are reused) :type name: string """ logger = logging.getLogger(name) if sys.hexversion > 0x3000000: encoding = sys.stdout.encoding else: encoding = None hdlr = logging.FileHandler(path, 'w', encoding=encoding) formatter = logging.Formatter('%(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.DEBUG) return logger def make_mem_logger(name, to_log, size=8192): """ Creates a memory logger to avoid writing concurrently to the main logger """ from logging.handlers import MemoryHandler logger = logging.getLogger(name) hdlr = MemoryHandler(size, target=to_log) formatter = logging.Formatter('%(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.memhandler = hdlr logger.setLevel(logging.DEBUG) return logger def free_logger(logger): """ Frees the resources held by the loggers created through make_logger or make_mem_logger. This is used for file cleanup and for handler removal (logger objects are re-used). """ try: for x in logger.handlers: x.close() logger.removeHandler(x) except Exception: pass def pprint(col, msg, label='', sep='\n'): """ Prints messages in color immediately on stderr:: from waflib import Logs Logs.pprint('RED', 'Something bad just happened') :param col: color name to use in :py:const:`Logs.colors_lst` :type col: string :param msg: message to display :type msg: string or a value that can be printed by %s :param label: a message to add after the colored output :type label: string :param sep: a string to append at the end (line separator) :type sep: string """ info('%s%s%s %s', colors(col), msg, colors.NORMAL, label, extra={'terminator':sep}) hamster-3.0.3/waflib/Node.py000066400000000000000000000616251452646177100157120ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Node: filesystem structure #. Each file/folder is represented by exactly one node. #. Some potential class properties are stored on :py:class:`waflib.Build.BuildContext` : nodes to depend on, etc. Unused class members can increase the `.wafpickle` file size sensibly. #. Node objects should never be created directly, use the methods :py:func:`Node.make_node` or :py:func:`Node.find_node` for the low-level operations #. The methods :py:func:`Node.find_resource`, :py:func:`Node.find_dir` :py:func:`Node.find_or_declare` must be used when a build context is present #. Each instance of :py:class:`waflib.Context.Context` has a unique :py:class:`Node` subclass required for serialization. (:py:class:`waflib.Node.Nod3`, see the :py:class:`waflib.Context.Context` initializer). A reference to the context owning a node is held as *self.ctx* """ import os, re, sys, shutil from waflib import Utils, Errors exclude_regs = ''' **/*~ **/#*# **/.#* **/%*% **/._* **/*.swp **/CVS **/CVS/** **/.cvsignore **/SCCS **/SCCS/** **/vssver.scc **/.svn **/.svn/** **/BitKeeper **/.git **/.git/** **/.gitignore **/.bzr **/.bzrignore **/.bzr/** **/.hg **/.hg/** **/_MTN **/_MTN/** **/.arch-ids **/{arch} **/_darcs **/_darcs/** **/.intlcache **/.DS_Store''' """ Ant patterns for files and folders to exclude while doing the recursive traversal in :py:meth:`waflib.Node.Node.ant_glob` """ def ant_matcher(s, ignorecase): reflags = re.I if ignorecase else 0 ret = [] for x in Utils.to_list(s): x = x.replace('\\', '/').replace('//', '/') if x.endswith('/'): x += '**' accu = [] for k in x.split('/'): if k == '**': accu.append(k) else: k = k.replace('.', '[.]').replace('*', '.*').replace('?', '.').replace('+', '\\+') k = '^%s$' % k try: exp = re.compile(k, flags=reflags) except Exception as e: raise Errors.WafError('Invalid pattern: %s' % k, e) else: accu.append(exp) ret.append(accu) return ret def ant_sub_filter(name, nn): ret = [] for lst in nn: if not lst: pass elif lst[0] == '**': ret.append(lst) if len(lst) > 1: if lst[1].match(name): ret.append(lst[2:]) else: ret.append([]) elif lst[0].match(name): ret.append(lst[1:]) return ret def ant_sub_matcher(name, pats): nacc = ant_sub_filter(name, pats[0]) nrej = ant_sub_filter(name, pats[1]) if [] in nrej: nacc = [] return [nacc, nrej] class Node(object): """ This class is organized in two parts: * The basic methods meant for filesystem access (compute paths, create folders, etc) * The methods bound to a :py:class:`waflib.Build.BuildContext` (require ``bld.srcnode`` and ``bld.bldnode``) """ dict_class = dict """ Subclasses can provide a dict class to enable case insensitivity for example. """ __slots__ = ('name', 'parent', 'children', 'cache_abspath', 'cache_isdir') def __init__(self, name, parent): """ .. note:: Use :py:func:`Node.make_node` or :py:func:`Node.find_node` instead of calling this constructor """ self.name = name self.parent = parent if parent: if name in parent.children: raise Errors.WafError('node %s exists in the parent files %r already' % (name, parent)) parent.children[name] = self def __setstate__(self, data): "Deserializes node information, used for persistence" self.name = data[0] self.parent = data[1] if data[2] is not None: # Issue 1480 self.children = self.dict_class(data[2]) def __getstate__(self): "Serializes node information, used for persistence" return (self.name, self.parent, getattr(self, 'children', None)) def __str__(self): """ String representation (abspath), for debugging purposes :rtype: string """ return self.abspath() def __repr__(self): """ String representation (abspath), for debugging purposes :rtype: string """ return self.abspath() def __copy__(self): """ Provided to prevent nodes from being copied :raises: :py:class:`waflib.Errors.WafError` """ raise Errors.WafError('nodes are not supposed to be copied') def read(self, flags='r', encoding='latin-1'): """ Reads and returns the contents of the file represented by this node, see :py:func:`waflib.Utils.readf`:: def build(bld): bld.path.find_node('wscript').read() :param flags: Open mode :type flags: string :param encoding: encoding value for Python3 :type encoding: string :rtype: string or bytes :return: File contents """ return Utils.readf(self.abspath(), flags, encoding) def write(self, data, flags='w', encoding='latin-1'): """ Writes data to the file represented by this node, see :py:func:`waflib.Utils.writef`:: def build(bld): bld.path.make_node('foo.txt').write('Hello, world!') :param data: data to write :type data: string :param flags: Write mode :type flags: string :param encoding: encoding value for Python3 :type encoding: string """ Utils.writef(self.abspath(), data, flags, encoding) def read_json(self, convert=True, encoding='utf-8'): """ Reads and parses the contents of this node as JSON (Python ≥ 2.6):: def build(bld): bld.path.find_node('abc.json').read_json() Note that this by default automatically decodes unicode strings on Python2, unlike what the Python JSON module does. :type convert: boolean :param convert: Prevents decoding of unicode strings on Python2 :type encoding: string :param encoding: The encoding of the file to read. This default to UTF8 as per the JSON standard :rtype: object :return: Parsed file contents """ import json # Python 2.6 and up object_pairs_hook = None if convert and sys.hexversion < 0x3000000: try: _type = unicode except NameError: _type = str def convert(value): if isinstance(value, list): return [convert(element) for element in value] elif isinstance(value, _type): return str(value) else: return value def object_pairs(pairs): return dict((str(pair[0]), convert(pair[1])) for pair in pairs) object_pairs_hook = object_pairs return json.loads(self.read(encoding=encoding), object_pairs_hook=object_pairs_hook) def write_json(self, data, pretty=True): """ Writes a python object as JSON to disk (Python ≥ 2.6) as UTF-8 data (JSON standard):: def build(bld): bld.path.find_node('xyz.json').write_json(199) :type data: object :param data: The data to write to disk :type pretty: boolean :param pretty: Determines if the JSON will be nicely space separated """ import json # Python 2.6 and up indent = 2 separators = (',', ': ') sort_keys = pretty newline = os.linesep if not pretty: indent = None separators = (',', ':') newline = '' output = json.dumps(data, indent=indent, separators=separators, sort_keys=sort_keys) + newline self.write(output, encoding='utf-8') def exists(self): """ Returns whether the Node is present on the filesystem :rtype: bool """ return os.path.exists(self.abspath()) def isdir(self): """ Returns whether the Node represents a folder :rtype: bool """ return os.path.isdir(self.abspath()) def chmod(self, val): """ Changes the file/dir permissions:: def build(bld): bld.path.chmod(493) # 0755 """ os.chmod(self.abspath(), val) def delete(self, evict=True): """ Removes the file/folder from the filesystem (equivalent to `rm -rf`), and remove this object from the Node tree. Do not use this object after calling this method. """ try: try: if os.path.isdir(self.abspath()): shutil.rmtree(self.abspath()) else: os.remove(self.abspath()) except OSError: if os.path.exists(self.abspath()): raise finally: if evict: self.evict() def evict(self): """ Removes this node from the Node tree """ del self.parent.children[self.name] def suffix(self): """ Returns the file rightmost extension, for example `a.b.c.d → .d` :rtype: string """ k = max(0, self.name.rfind('.')) return self.name[k:] def height(self): """ Returns the depth in the folder hierarchy from the filesystem root or from all the file drives :returns: filesystem depth :rtype: integer """ d = self val = -1 while d: d = d.parent val += 1 return val def listdir(self): """ Lists the folder contents :returns: list of file/folder names ordered alphabetically :rtype: list of string """ lst = Utils.listdir(self.abspath()) lst.sort() return lst def mkdir(self): """ Creates a folder represented by this node. Intermediate folders are created as needed. :raises: :py:class:`waflib.Errors.WafError` when the folder is missing """ if self.isdir(): return try: self.parent.mkdir() except OSError: pass if self.name: try: os.makedirs(self.abspath()) except OSError: pass if not self.isdir(): raise Errors.WafError('Could not create the directory %r' % self) try: self.children except AttributeError: self.children = self.dict_class() def find_node(self, lst): """ Finds a node on the file system (files or folders), and creates the corresponding Node objects if it exists :param lst: relative path :type lst: string or list of string :returns: The corresponding Node object or None if no entry was found on the filesystem :rtype: :py:class:´waflib.Node.Node´ """ if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] if lst and lst[0].startswith('\\\\') and not self.parent: node = self.ctx.root.make_node(lst[0]) node.cache_isdir = True return node.find_node(lst[1:]) cur = self for x in lst: if x == '..': cur = cur.parent or cur continue try: ch = cur.children except AttributeError: cur.children = self.dict_class() else: try: cur = ch[x] continue except KeyError: pass # optimistic: create the node first then look if it was correct to do so cur = self.__class__(x, cur) if not cur.exists(): cur.evict() return None if not cur.exists(): cur.evict() return None return cur def make_node(self, lst): """ Returns or creates a Node object corresponding to the input path without considering the filesystem. :param lst: relative path :type lst: string or list of string :rtype: :py:class:´waflib.Node.Node´ """ if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] cur = self for x in lst: if x == '..': cur = cur.parent or cur continue try: cur = cur.children[x] except AttributeError: cur.children = self.dict_class() except KeyError: pass else: continue cur = self.__class__(x, cur) return cur def search_node(self, lst): """ Returns a Node previously defined in the data structure. The filesystem is not considered. :param lst: relative path :type lst: string or list of string :rtype: :py:class:´waflib.Node.Node´ or None if there is no entry in the Node datastructure """ if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] cur = self for x in lst: if x == '..': cur = cur.parent or cur else: try: cur = cur.children[x] except (AttributeError, KeyError): return None return cur def path_from(self, node): """ Path of this node seen from the other:: def build(bld): n1 = bld.path.find_node('foo/bar/xyz.txt') n2 = bld.path.find_node('foo/stuff/') n1.path_from(n2) # '../bar/xyz.txt' :param node: path to use as a reference :type node: :py:class:`waflib.Node.Node` :returns: a relative path or an absolute one if that is better :rtype: string """ c1 = self c2 = node c1h = c1.height() c2h = c2.height() lst = [] up = 0 while c1h > c2h: lst.append(c1.name) c1 = c1.parent c1h -= 1 while c2h > c1h: up += 1 c2 = c2.parent c2h -= 1 while not c1 is c2: lst.append(c1.name) up += 1 c1 = c1.parent c2 = c2.parent if c1.parent: lst.extend(['..'] * up) lst.reverse() return os.sep.join(lst) or '.' else: return self.abspath() def abspath(self): """ Returns the absolute path. A cache is kept in the context as ``cache_node_abspath`` :rtype: string """ try: return self.cache_abspath except AttributeError: pass # think twice before touching this (performance + complexity + correctness) if not self.parent: val = os.sep elif not self.parent.name: val = os.sep + self.name else: val = self.parent.abspath() + os.sep + self.name self.cache_abspath = val return val if Utils.is_win32: def abspath(self): try: return self.cache_abspath except AttributeError: pass if not self.parent: val = '' elif not self.parent.name: val = self.name + os.sep else: val = self.parent.abspath().rstrip(os.sep) + os.sep + self.name self.cache_abspath = val return val def is_child_of(self, node): """ Returns whether the object belongs to a subtree of the input node:: def build(bld): node = bld.path.find_node('wscript') node.is_child_of(bld.path) # True :param node: path to use as a reference :type node: :py:class:`waflib.Node.Node` :rtype: bool """ p = self diff = self.height() - node.height() while diff > 0: diff -= 1 p = p.parent return p is node def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True, quiet=False): """ Recursive method used by :py:meth:`waflib.Node.ant_glob`. :param accept: function used for accepting/rejecting a node, returns the patterns that can be still accepted in recursion :type accept: function :param maxdepth: maximum depth in the filesystem (25) :type maxdepth: int :param pats: list of patterns to accept and list of patterns to exclude :type pats: tuple :param dir: return folders too (False by default) :type dir: bool :param src: return files (True by default) :type src: bool :param remove: remove files/folders that do not exist (True by default) :type remove: bool :param quiet: disable build directory traversal warnings (verbose mode) :type quiet: bool :returns: A generator object to iterate from :rtype: iterator """ dircont = self.listdir() try: lst = set(self.children.keys()) except AttributeError: self.children = self.dict_class() else: if remove: for x in lst - set(dircont): self.children[x].evict() for name in dircont: npats = accept(name, pats) if npats and npats[0]: accepted = [] in npats[0] node = self.make_node([name]) isdir = node.isdir() if accepted: if isdir: if dir: yield node elif src: yield node if isdir: node.cache_isdir = True if maxdepth: for k in node.ant_iter(accept=accept, maxdepth=maxdepth - 1, pats=npats, dir=dir, src=src, remove=remove, quiet=quiet): yield k def ant_glob(self, *k, **kw): """ Finds files across folders and returns Node objects: * ``**/*`` find all files recursively * ``**/*.class`` find all files ending by .class * ``..`` find files having two dot characters For example:: def configure(cfg): # find all .cpp files cfg.path.ant_glob('**/*.cpp') # find particular files from the root filesystem (can be slow) cfg.root.ant_glob('etc/*.txt') # simple exclusion rule example cfg.path.ant_glob('*.c*', excl=['*.c'], src=True, dir=False) For more information about the patterns, consult http://ant.apache.org/manual/dirtasks.html Please remember that the '..' sequence does not represent the parent directory:: def configure(cfg): cfg.path.ant_glob('../*.h') # incorrect cfg.path.parent.ant_glob('*.h') # correct The Node structure is itself a filesystem cache, so certain precautions must be taken while matching files in the build or installation phases. Nodes objects that do have a corresponding file or folder are garbage-collected by default. This garbage collection is usually required to prevent returning files that do not exist anymore. Yet, this may also remove Node objects of files that are yet-to-be built. This typically happens when trying to match files in the build directory, but there are also cases when files are created in the source directory. Run ``waf -v`` to display any warnings, and try consider passing ``remove=False`` when matching files in the build directory. Since ant_glob can traverse both source and build folders, it is a best practice to call this method only from the most specific build node:: def build(bld): # traverses the build directory, may need ``remove=False``: bld.path.ant_glob('project/dir/**/*.h') # better, no accidental build directory traversal: bld.path.find_node('project/dir').ant_glob('**/*.h') # best In addition, files and folders are listed immediately. When matching files in the build folders, consider passing ``generator=True`` so that the generator object returned can defer computation to a later stage. For example:: def build(bld): bld(rule='tar xvf ${SRC}', source='arch.tar') bld.add_group() gen = bld.bldnode.ant_glob("*.h", generator=True, remove=True) # files will be listed only after the arch.tar is unpacked bld(rule='ls ${SRC}', source=gen, name='XYZ') :param incl: ant patterns or list of patterns to include :type incl: string or list of strings :param excl: ant patterns or list of patterns to exclude :type excl: string or list of strings :param dir: return folders too (False by default) :type dir: bool :param src: return files (True by default) :type src: bool :param maxdepth: maximum depth of recursion :type maxdepth: int :param ignorecase: ignore case while matching (False by default) :type ignorecase: bool :param generator: Whether to evaluate the Nodes lazily :type generator: bool :param remove: remove files/folders that do not exist (True by default) :type remove: bool :param quiet: disable build directory traversal warnings (verbose mode) :type quiet: bool :returns: The corresponding Node objects as a list or as a generator object (generator=True) :rtype: by default, list of :py:class:`waflib.Node.Node` instances """ src = kw.get('src', True) dir = kw.get('dir') excl = kw.get('excl', exclude_regs) incl = k and k[0] or kw.get('incl', '**') remove = kw.get('remove', True) maxdepth = kw.get('maxdepth', 25) ignorecase = kw.get('ignorecase', False) quiet = kw.get('quiet', False) pats = (ant_matcher(incl, ignorecase), ant_matcher(excl, ignorecase)) if kw.get('generator'): return Utils.lazy_generator(self.ant_iter, (ant_sub_matcher, maxdepth, pats, dir, src, remove, quiet)) it = self.ant_iter(ant_sub_matcher, maxdepth, pats, dir, src, remove, quiet) if kw.get('flat'): # returns relative paths as a space-delimited string # prefer Node objects whenever possible return ' '.join(x.path_from(self) for x in it) return list(it) # ---------------------------------------------------------------------------- # the methods below require the source/build folders (bld.srcnode/bld.bldnode) def is_src(self): """ Returns True if the node is below the source directory. Note that ``!is_src() ≠ is_bld()`` :rtype: bool """ cur = self x = self.ctx.srcnode y = self.ctx.bldnode while cur.parent: if cur is y: return False if cur is x: return True cur = cur.parent return False def is_bld(self): """ Returns True if the node is below the build directory. Note that ``!is_bld() ≠ is_src()`` :rtype: bool """ cur = self y = self.ctx.bldnode while cur.parent: if cur is y: return True cur = cur.parent return False def get_src(self): """ Returns the corresponding Node object in the source directory (or self if already under the source directory). Use this method only if the purpose is to create a Node object (this is common with folders but not with files, see ticket 1937) :rtype: :py:class:`waflib.Node.Node` """ cur = self x = self.ctx.srcnode y = self.ctx.bldnode lst = [] while cur.parent: if cur is y: lst.reverse() return x.make_node(lst) if cur is x: return self lst.append(cur.name) cur = cur.parent return self def get_bld(self): """ Return the corresponding Node object in the build directory (or self if already under the build directory). Use this method only if the purpose is to create a Node object (this is common with folders but not with files, see ticket 1937) :rtype: :py:class:`waflib.Node.Node` """ cur = self x = self.ctx.srcnode y = self.ctx.bldnode lst = [] while cur.parent: if cur is y: return self if cur is x: lst.reverse() return self.ctx.bldnode.make_node(lst) lst.append(cur.name) cur = cur.parent # the file is external to the current project, make a fake root in the current build directory lst.reverse() if lst and Utils.is_win32 and len(lst[0]) == 2 and lst[0].endswith(':'): lst[0] = lst[0][0] return self.ctx.bldnode.make_node(['__root__'] + lst) def find_resource(self, lst): """ Use this method in the build phase to find source files corresponding to the relative path given. First it looks up the Node data structure to find any declared Node object in the build directory. If None is found, it then considers the filesystem in the source directory. :param lst: relative path :type lst: string or list of string :returns: the corresponding Node object or None :rtype: :py:class:`waflib.Node.Node` """ if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] node = self.get_bld().search_node(lst) if not node: node = self.get_src().find_node(lst) if node and node.isdir(): return None return node def find_or_declare(self, lst): """ Use this method in the build phase to declare output files which are meant to be written in the build directory. This method creates the Node object and its parent folder as needed. :param lst: relative path :type lst: string or list of string """ if isinstance(lst, str) and os.path.isabs(lst): node = self.ctx.root.make_node(lst) else: node = self.get_bld().make_node(lst) node.parent.mkdir() return node def find_dir(self, lst): """ Searches for a folder on the filesystem (see :py:meth:`waflib.Node.Node.find_node`) :param lst: relative path :type lst: string or list of string :returns: The corresponding Node object or None if there is no such folder :rtype: :py:class:`waflib.Node.Node` """ if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] node = self.find_node(lst) if node and not node.isdir(): return None return node # helpers for building things def change_ext(self, ext, ext_in=None): """ Declares a build node with a distinct extension; this is uses :py:meth:`waflib.Node.Node.find_or_declare` :return: A build node of the same path, but with a different extension :rtype: :py:class:`waflib.Node.Node` """ name = self.name if ext_in is None: k = name.rfind('.') if k >= 0: name = name[:k] + ext else: name = name + ext else: name = name[:- len(ext_in)] + ext return self.parent.find_or_declare([name]) def bldpath(self): """ Returns the relative path seen from the build directory ``src/foo.cpp`` :rtype: string """ return self.path_from(self.ctx.bldnode) def srcpath(self): """ Returns the relative path seen from the source directory ``../src/foo.cpp`` :rtype: string """ return self.path_from(self.ctx.srcnode) def relpath(self): """ If a file in the build directory, returns :py:meth:`waflib.Node.Node.bldpath`, else returns :py:meth:`waflib.Node.Node.srcpath` :rtype: string """ cur = self x = self.ctx.bldnode while cur.parent: if cur is x: return self.bldpath() cur = cur.parent return self.srcpath() def bld_dir(self): """ Equivalent to self.parent.bldpath() :rtype: string """ return self.parent.bldpath() def h_file(self): """ See :py:func:`waflib.Utils.h_file` :return: a hash representing the file contents :rtype: string or bytes """ return Utils.h_file(self.abspath()) def get_bld_sig(self): """ Returns a signature (see :py:meth:`waflib.Node.Node.h_file`) for the purpose of build dependency calculation. This method uses a per-context cache. :return: a hash representing the object contents :rtype: string or bytes """ # previous behaviour can be set by returning self.ctx.node_sigs[self] when a build node try: cache = self.ctx.cache_sig except AttributeError: cache = self.ctx.cache_sig = {} try: ret = cache[self] except KeyError: p = self.abspath() try: ret = cache[self] = self.h_file() except EnvironmentError: if self.isdir(): # allow folders as build nodes, do not use the creation time st = os.stat(p) ret = cache[self] = Utils.h_list([p, st.st_ino, st.st_mode]) return ret raise return ret pickle_lock = Utils.threading.Lock() """Lock mandatory for thread-safe node serialization""" class Nod3(Node): """Mandatory subclass for thread-safe node serialization""" pass # do not remove hamster-3.0.3/waflib/Options.py000066400000000000000000000272661452646177100164630ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Scott Newton, 2005 (scottn) # Thomas Nagy, 2006-2018 (ita) """ Support for waf command-line options Provides default and command-line options, as well the command that reads the ``options`` wscript function. """ import os, tempfile, optparse, sys, re from waflib import Logs, Utils, Context, Errors options = optparse.Values() """ A global dictionary representing user-provided command-line options:: $ waf --foo=bar """ commands = [] """ List of commands to execute extracted from the command-line. This list is consumed during the execution by :py:func:`waflib.Scripting.run_commands`. """ envvars = [] """ List of environment variable declarations placed after the Waf executable name. These are detected by searching for "=" in the remaining arguments. You probably do not want to use this. """ lockfile = os.environ.get('WAFLOCK', '.lock-waf_%s_build' % sys.platform) """ Name of the lock file that marks a project as configured """ class opt_parser(optparse.OptionParser): """ Command-line options parser. """ def __init__(self, ctx, allow_unknown=False): optparse.OptionParser.__init__(self, conflict_handler='resolve', add_help_option=False, version='%s %s (%s)' % (Context.WAFNAME, Context.WAFVERSION, Context.WAFREVISION)) self.formatter.width = Logs.get_term_cols() self.ctx = ctx self.allow_unknown = allow_unknown def _process_args(self, largs, rargs, values): """ Custom _process_args to allow unknown options according to the allow_unknown status """ while rargs: try: optparse.OptionParser._process_args(self,largs,rargs,values) except (optparse.BadOptionError, optparse.AmbiguousOptionError) as e: if self.allow_unknown: largs.append(e.opt_str) else: self.error(str(e)) def _process_long_opt(self, rargs, values): # --custom-option=-ftxyz is interpreted as -f -t... see #2280 if self.allow_unknown: back = [] + rargs try: optparse.OptionParser._process_long_opt(self, rargs, values) except optparse.BadOptionError: while rargs: rargs.pop() rargs.extend(back) rargs.pop(0) raise else: optparse.OptionParser._process_long_opt(self, rargs, values) def print_usage(self, file=None): return self.print_help(file) def get_usage(self): """ Builds the message to print on ``waf --help`` :rtype: string """ cmds_str = {} for cls in Context.classes: if not cls.cmd or cls.cmd == 'options' or cls.cmd.startswith( '_' ): continue s = cls.__doc__ or '' cmds_str[cls.cmd] = s if Context.g_module: for (k, v) in Context.g_module.__dict__.items(): if k in ('options', 'init', 'shutdown'): continue if type(v) is type(Context.create_context): if v.__doc__ and not k.startswith('_'): cmds_str[k] = v.__doc__ just = 0 for k in cmds_str: just = max(just, len(k)) lst = [' %s: %s' % (k.ljust(just), v) for (k, v) in cmds_str.items()] lst.sort() ret = '\n'.join(lst) return '''%s [commands] [options] Main commands (example: ./%s build -j4) %s ''' % (Context.WAFNAME, Context.WAFNAME, ret) class OptionsContext(Context.Context): """ Collects custom options from wscript files and parses the command line. Sets the global :py:const:`waflib.Options.commands` and :py:const:`waflib.Options.options` values. """ cmd = 'options' fun = 'options' def __init__(self, **kw): super(OptionsContext, self).__init__(**kw) self.parser = opt_parser(self) """Instance of :py:class:`waflib.Options.opt_parser`""" self.option_groups = {} jobs = self.jobs() p = self.add_option color = os.environ.get('NOCOLOR', '') and 'no' or 'auto' if os.environ.get('CLICOLOR', '') == '0': color = 'no' elif os.environ.get('CLICOLOR_FORCE', '') == '1': color = 'yes' p('-c', '--color', dest='colors', default=color, action='store', help='whether to use colors (yes/no/auto) [default: auto]', choices=('yes', 'no', 'auto')) p('-j', '--jobs', dest='jobs', default=jobs, type='int', help='amount of parallel jobs (%r)' % jobs) p('-k', '--keep', dest='keep', default=0, action='count', help='continue despite errors (-kk to try harder)') p('-v', '--verbose', dest='verbose', default=0, action='count', help='verbosity level -v -vv or -vvv [default: 0]') p('--zones', dest='zones', default='', action='store', help='debugging zones (task_gen, deps, tasks, etc)') p('--profile', dest='profile', default=0, action='store_true', help=optparse.SUPPRESS_HELP) p('--pdb', dest='pdb', default=0, action='store_true', help=optparse.SUPPRESS_HELP) p('-h', '--help', dest='whelp', default=0, action='store_true', help="show this help message and exit") gr = self.add_option_group('Configuration options') self.option_groups['configure options'] = gr gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out') gr.add_option('-t', '--top', action='store', default='', help='src dir for the project', dest='top') gr.add_option('--no-lock-in-run', action='store_true', default=os.environ.get('NO_LOCK_IN_RUN', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_run') gr.add_option('--no-lock-in-out', action='store_true', default=os.environ.get('NO_LOCK_IN_OUT', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_out') gr.add_option('--no-lock-in-top', action='store_true', default=os.environ.get('NO_LOCK_IN_TOP', ''), help=optparse.SUPPRESS_HELP, dest='no_lock_in_top') default_prefix = getattr(Context.g_module, 'default_prefix', os.environ.get('PREFIX')) if not default_prefix: if Utils.unversioned_sys_platform() == 'win32': d = tempfile.gettempdir() default_prefix = d[0].upper() + d[1:] # win32 preserves the case, but gettempdir does not else: default_prefix = '/usr/local/' gr.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: %r]' % default_prefix) gr.add_option('--bindir', dest='bindir', help='bindir') gr.add_option('--libdir', dest='libdir', help='libdir') gr = self.add_option_group('Build and installation options') self.option_groups['build and install options'] = gr gr.add_option('-p', '--progress', dest='progress_bar', default=0, action='count', help= '-p: progress bar; -pp: ide output') gr.add_option('--targets', dest='targets', default='', action='store', help='task generators, e.g. "target1,target2"') gr = self.add_option_group('Step options') self.option_groups['step options'] = gr gr.add_option('--files', dest='files', default='', action='store', help='files to process, by regexp, e.g. "*/main.c,*/test/main.o"') default_destdir = os.environ.get('DESTDIR', '') gr = self.add_option_group('Installation and uninstallation options') self.option_groups['install/uninstall options'] = gr gr.add_option('--destdir', help='installation root [default: %r]' % default_destdir, default=default_destdir, dest='destdir') gr.add_option('-f', '--force', dest='force', default=False, action='store_true', help='force file installation') gr.add_option('--distcheck-args', metavar='ARGS', help='arguments to pass to distcheck', default=None, action='store') def jobs(self): """ Finds the optimal amount of cpu cores to use for parallel jobs. At runtime the options can be obtained from :py:const:`waflib.Options.options` :: from waflib.Options import options njobs = options.jobs :return: the amount of cpu cores :rtype: int """ count = int(os.environ.get('JOBS', 0)) if count < 1: if 'NUMBER_OF_PROCESSORS' in os.environ: # on Windows, use the NUMBER_OF_PROCESSORS environment variable count = int(os.environ.get('NUMBER_OF_PROCESSORS', 1)) else: # on everything else, first try the POSIX sysconf values if hasattr(os, 'sysconf_names'): if 'SC_NPROCESSORS_ONLN' in os.sysconf_names: count = int(os.sysconf('SC_NPROCESSORS_ONLN')) elif 'SC_NPROCESSORS_CONF' in os.sysconf_names: count = int(os.sysconf('SC_NPROCESSORS_CONF')) if not count and os.name not in ('nt', 'java'): try: tmp = self.cmd_and_log(['sysctl', '-n', 'hw.ncpu'], quiet=0) except Errors.WafError: pass else: if re.match('^[0-9]+$', tmp): count = int(tmp) if count < 1: count = 1 elif count > 1024: count = 1024 return count def add_option(self, *k, **kw): """ Wraps ``optparse.add_option``:: def options(ctx): ctx.add_option('-u', '--use', dest='use', default=False, action='store_true', help='a boolean option') :rtype: optparse option object """ return self.parser.add_option(*k, **kw) def add_option_group(self, *k, **kw): """ Wraps ``optparse.add_option_group``:: def options(ctx): gr = ctx.add_option_group('some options') gr.add_option('-u', '--use', dest='use', default=False, action='store_true') :rtype: optparse option group object """ try: gr = self.option_groups[k[0]] except KeyError: gr = self.parser.add_option_group(*k, **kw) self.option_groups[k[0]] = gr return gr def get_option_group(self, opt_str): """ Wraps ``optparse.get_option_group``:: def options(ctx): gr = ctx.get_option_group('configure options') gr.add_option('-o', '--out', action='store', default='', help='build dir for the project', dest='out') :rtype: optparse option group object """ try: return self.option_groups[opt_str] except KeyError: for group in self.parser.option_groups: if group.title == opt_str: return group return None def sanitize_path(self, path, cwd=None): if not cwd: cwd = Context.launch_dir p = os.path.expanduser(path) p = os.path.join(cwd, p) p = os.path.normpath(p) p = os.path.abspath(p) return p def parse_cmd_args(self, _args=None, cwd=None, allow_unknown=False): """ Just parse the arguments """ self.parser.allow_unknown = allow_unknown (options, leftover_args) = self.parser.parse_args(args=_args) envvars = [] commands = [] for arg in leftover_args: if '=' in arg: envvars.append(arg) elif arg != 'options': commands.append(arg) if options.jobs < 1: options.jobs = 1 for name in 'top out destdir prefix bindir libdir'.split(): # those paths are usually expanded from Context.launch_dir if getattr(options, name, None): path = self.sanitize_path(getattr(options, name), cwd) setattr(options, name, path) return options, commands, envvars def init_module_vars(self, arg_options, arg_commands, arg_envvars): options.__dict__.clear() del commands[:] del envvars[:] options.__dict__.update(arg_options.__dict__) commands.extend(arg_commands) envvars.extend(arg_envvars) for var in envvars: (name, value) = var.split('=', 1) os.environ[name.strip()] = value def init_logs(self, options, commands, envvars): Logs.verbose = options.verbose if options.verbose >= 1: self.load('errcheck') colors = {'yes' : 2, 'auto' : 1, 'no' : 0}[options.colors] Logs.enable_colors(colors) if options.zones: Logs.zones = options.zones.split(',') if not Logs.verbose: Logs.verbose = 1 elif Logs.verbose > 0: Logs.zones = ['runner'] if Logs.verbose > 2: Logs.zones = ['*'] def parse_args(self, _args=None): """ Parses arguments from a list which is not necessarily the command-line. Initializes the module variables options, commands and envvars If help is requested, prints it and exit the application :param _args: arguments :type _args: list of strings """ options, commands, envvars = self.parse_cmd_args() self.init_logs(options, commands, envvars) self.init_module_vars(options, commands, envvars) def execute(self): """ See :py:func:`waflib.Context.Context.execute` """ super(OptionsContext, self).execute() self.parse_args() Utils.alloc_process_pool(options.jobs) hamster-3.0.3/waflib/Runner.py000066400000000000000000000400121452646177100162610ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Runner.py: Task scheduling and execution """ import heapq, traceback try: from queue import Queue, PriorityQueue except ImportError: from Queue import Queue try: from Queue import PriorityQueue except ImportError: class PriorityQueue(Queue): def _init(self, maxsize): self.maxsize = maxsize self.queue = [] def _put(self, item): heapq.heappush(self.queue, item) def _get(self): return heapq.heappop(self.queue) from waflib import Utils, Task, Errors, Logs GAP = 5 """ Wait for at least ``GAP * njobs`` before trying to enqueue more tasks to run """ class PriorityTasks(object): def __init__(self): self.lst = [] def __len__(self): return len(self.lst) def __iter__(self): return iter(self.lst) def __str__(self): return 'PriorityTasks: [%s]' % '\n '.join(str(x) for x in self.lst) def clear(self): self.lst = [] def append(self, task): heapq.heappush(self.lst, task) def appendleft(self, task): "Deprecated, do not use" heapq.heappush(self.lst, task) def pop(self): return heapq.heappop(self.lst) def extend(self, lst): if self.lst: for x in lst: self.append(x) else: if isinstance(lst, list): self.lst = lst heapq.heapify(lst) else: self.lst = lst.lst class Consumer(Utils.threading.Thread): """ Daemon thread object that executes a task. It shares a semaphore with the coordinator :py:class:`waflib.Runner.Spawner`. There is one instance per task to consume. """ def __init__(self, spawner, task): Utils.threading.Thread.__init__(self) self.task = task """Task to execute""" self.spawner = spawner """Coordinator object""" self.daemon = True self.start() def run(self): """ Processes a single task """ try: if not self.spawner.master.stop: self.spawner.master.process_task(self.task) finally: self.spawner.sem.release() self.spawner.master.out.put(self.task) self.task = None self.spawner = None class Spawner(Utils.threading.Thread): """ Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each :py:class:`waflib.Task.Task` instance. """ def __init__(self, master): Utils.threading.Thread.__init__(self) self.master = master """:py:class:`waflib.Runner.Parallel` producer instance""" self.sem = Utils.threading.Semaphore(master.numjobs) """Bounded semaphore that prevents spawning more than *n* concurrent consumers""" self.daemon = True self.start() def run(self): """ Spawns new consumers to execute tasks by delegating to :py:meth:`waflib.Runner.Spawner.loop` """ try: self.loop() except Exception: # Python 2 prints unnecessary messages when shutting down # we also want to stop the thread properly pass def loop(self): """ Consumes task objects from the producer; ends when the producer has no more task to provide. """ master = self.master while 1: task = master.ready.get() self.sem.acquire() if not master.stop: task.log_display(task.generator.bld) Consumer(self, task) class Parallel(object): """ Schedule the tasks obtained from the build context for execution. """ def __init__(self, bld, j=2): """ The initialization requires a build context reference for computing the total number of jobs. """ self.numjobs = j """ Amount of parallel consumers to use """ self.bld = bld """ Instance of :py:class:`waflib.Build.BuildContext` """ self.outstanding = PriorityTasks() """Heap of :py:class:`waflib.Task.Task` that may be ready to be executed""" self.postponed = PriorityTasks() """Heap of :py:class:`waflib.Task.Task` which are not ready to run for non-DAG reasons""" self.incomplete = set() """List of :py:class:`waflib.Task.Task` waiting for dependent tasks to complete (DAG)""" self.ready = PriorityQueue(0) """List of :py:class:`waflib.Task.Task` ready to be executed by consumers""" self.out = Queue(0) """List of :py:class:`waflib.Task.Task` returned by the task consumers""" self.count = 0 """Amount of tasks that may be processed by :py:class:`waflib.Runner.TaskConsumer`""" self.processed = 0 """Amount of tasks processed""" self.stop = False """Error flag to stop the build""" self.error = [] """Tasks that could not be executed""" self.biter = None """Task iterator which must give groups of parallelizable tasks when calling ``next()``""" self.dirty = False """ Flag that indicates that the build cache must be saved when a task was executed (calls :py:meth:`waflib.Build.BuildContext.store`)""" self.revdeps = Utils.defaultdict(set) """ The reverse dependency graph of dependencies obtained from Task.run_after """ self.spawner = None """ Coordinating daemon thread that spawns thread consumers """ if self.numjobs > 1: self.spawner = Spawner(self) def get_next_task(self): """ Obtains the next Task instance to run :rtype: :py:class:`waflib.Task.Task` """ if not self.outstanding: return None return self.outstanding.pop() def postpone(self, tsk): """ Adds the task to the list :py:attr:`waflib.Runner.Parallel.postponed`. The order is scrambled so as to consume as many tasks in parallel as possible. :param tsk: task instance :type tsk: :py:class:`waflib.Task.Task` """ self.postponed.append(tsk) def refill_task_list(self): """ Pulls a next group of tasks to execute in :py:attr:`waflib.Runner.Parallel.outstanding`. Ensures that all tasks in the current build group are complete before processing the next one. """ while self.count > self.numjobs * GAP: self.get_out() while not self.outstanding: if self.count: self.get_out() if self.outstanding: break elif self.postponed: try: cond = self.deadlock == self.processed except AttributeError: pass else: if cond: # The most common reason is conflicting build order declaration # for example: "X run_after Y" and "Y run_after X" # Another can be changing "run_after" dependencies while the build is running # for example: updating "tsk.run_after" in the "runnable_status" method lst = [] for tsk in self.postponed: deps = [id(x) for x in tsk.run_after if not x.hasrun] lst.append('%s\t-> %r' % (repr(tsk), deps)) if not deps: lst.append('\n task %r dependencies are done, check its *runnable_status*?' % id(tsk)) raise Errors.WafError('Deadlock detected: check the task build order%s' % ''.join(lst)) self.deadlock = self.processed if self.postponed: self.outstanding.extend(self.postponed) self.postponed.clear() elif not self.count: if self.incomplete: for x in self.incomplete: for k in x.run_after: if not k.hasrun: break else: # dependency added after the build started without updating revdeps self.incomplete.remove(x) self.outstanding.append(x) break else: if self.stop or self.error: break raise Errors.WafError('Broken revdeps detected on %r' % self.incomplete) else: tasks = next(self.biter) ready, waiting = self.prio_and_split(tasks) self.outstanding.extend(ready) self.incomplete.update(waiting) self.total = self.bld.total() break def add_more_tasks(self, tsk): """ If a task provides :py:attr:`waflib.Task.Task.more_tasks`, then the tasks contained in that list are added to the current build and will be processed before the next build group. The priorities for dependent tasks are not re-calculated globally :param tsk: task instance :type tsk: :py:attr:`waflib.Task.Task` """ if getattr(tsk, 'more_tasks', None): more = set(tsk.more_tasks) groups_done = set() def iteri(a, b): for x in a: yield x for x in b: yield x # Update the dependency tree # this assumes that task.run_after values were updated for x in iteri(self.outstanding, self.incomplete): for k in x.run_after: if isinstance(k, Task.TaskGroup): if k not in groups_done: groups_done.add(k) for j in k.prev & more: self.revdeps[j].add(k) elif k in more: self.revdeps[k].add(x) ready, waiting = self.prio_and_split(tsk.more_tasks) self.outstanding.extend(ready) self.incomplete.update(waiting) self.total += len(tsk.more_tasks) def mark_finished(self, tsk): def try_unfreeze(x): # DAG ancestors are likely to be in the incomplete set # This assumes that the run_after contents have not changed # after the build starts, else a deadlock may occur if x in self.incomplete: # TODO remove dependencies to free some memory? # x.run_after.remove(tsk) for k in x.run_after: if not k.hasrun: break else: self.incomplete.remove(x) self.outstanding.append(x) if tsk in self.revdeps: for x in self.revdeps[tsk]: if isinstance(x, Task.TaskGroup): x.prev.remove(tsk) if not x.prev: for k in x.next: # TODO necessary optimization? k.run_after.remove(x) try_unfreeze(k) # TODO necessary optimization? x.next = [] else: try_unfreeze(x) del self.revdeps[tsk] if hasattr(tsk, 'semaphore'): sem = tsk.semaphore try: sem.release(tsk) except KeyError: # TODO pass else: while sem.waiting and not sem.is_locked(): # take a frozen task, make it ready to run x = sem.waiting.pop() self._add_task(x) def get_out(self): """ Waits for a Task that task consumers add to :py:attr:`waflib.Runner.Parallel.out` after execution. Adds more Tasks if necessary through :py:attr:`waflib.Runner.Parallel.add_more_tasks`. :rtype: :py:attr:`waflib.Task.Task` """ tsk = self.out.get() if not self.stop: self.add_more_tasks(tsk) self.mark_finished(tsk) self.count -= 1 self.dirty = True return tsk def add_task(self, tsk): """ Enqueue a Task to :py:attr:`waflib.Runner.Parallel.ready` so that consumers can run them. :param tsk: task instance :type tsk: :py:attr:`waflib.Task.Task` """ # TODO change in waf 2.1 self.ready.put(tsk) def _add_task(self, tsk): if hasattr(tsk, 'semaphore'): sem = tsk.semaphore try: sem.acquire(tsk) except IndexError: sem.waiting.add(tsk) return self.count += 1 self.processed += 1 if self.numjobs == 1: tsk.log_display(tsk.generator.bld) try: self.process_task(tsk) finally: self.out.put(tsk) else: self.add_task(tsk) def process_task(self, tsk): """ Processes a task and attempts to stop the build in case of errors """ tsk.process() if tsk.hasrun != Task.SUCCESS: self.error_handler(tsk) def skip(self, tsk): """ Mark a task as skipped/up-to-date """ tsk.hasrun = Task.SKIPPED self.mark_finished(tsk) def cancel(self, tsk): """ Mark a task as failed because of unsatisfiable dependencies """ tsk.hasrun = Task.CANCELED self.mark_finished(tsk) def error_handler(self, tsk): """ Called when a task cannot be executed. The flag :py:attr:`waflib.Runner.Parallel.stop` is set, unless the build is executed with:: $ waf build -k :param tsk: task instance :type tsk: :py:attr:`waflib.Task.Task` """ if not self.bld.keep: self.stop = True self.error.append(tsk) def task_status(self, tsk): """ Obtains the task status to decide whether to run it immediately or not. :return: the exit status, for example :py:attr:`waflib.Task.ASK_LATER` :rtype: integer """ try: return tsk.runnable_status() except Exception: self.processed += 1 tsk.err_msg = traceback.format_exc() if not self.stop and self.bld.keep: self.skip(tsk) if self.bld.keep == 1: # if -k stop on the first exception, if -kk try to go as far as possible if Logs.verbose > 1 or not self.error: self.error.append(tsk) self.stop = True else: if Logs.verbose > 1: self.error.append(tsk) return Task.EXCEPTION tsk.hasrun = Task.EXCEPTION self.error_handler(tsk) return Task.EXCEPTION def start(self): """ Obtains Task instances from the BuildContext instance and adds the ones that need to be executed to :py:class:`waflib.Runner.Parallel.ready` so that the :py:class:`waflib.Runner.Spawner` consumer thread has them executed. Obtains the executed Tasks back from :py:class:`waflib.Runner.Parallel.out` and marks the build as failed by setting the ``stop`` flag. If only one job is used, then executes the tasks one by one, without consumers. """ self.total = self.bld.total() while not self.stop: self.refill_task_list() # consider the next task tsk = self.get_next_task() if not tsk: if self.count: # tasks may add new ones after they are run continue else: # no tasks to run, no tasks running, time to exit break if tsk.hasrun: # if the task is marked as "run", just skip it self.processed += 1 continue if self.stop: # stop immediately after a failure is detected break st = self.task_status(tsk) if st == Task.RUN_ME: self._add_task(tsk) elif st == Task.ASK_LATER: self.postpone(tsk) elif st == Task.SKIP_ME: self.processed += 1 self.skip(tsk) self.add_more_tasks(tsk) elif st == Task.CANCEL_ME: # A dependency problem has occurred, and the # build is most likely run with `waf -k` if Logs.verbose > 1: self.error.append(tsk) self.processed += 1 self.cancel(tsk) # self.count represents the tasks that have been made available to the consumer threads # collect all the tasks after an error else the message may be incomplete while self.error and self.count: self.get_out() self.ready.put(None) if not self.stop: assert not self.count assert not self.postponed assert not self.incomplete def prio_and_split(self, tasks): """ Label input tasks with priority values, and return a pair containing the tasks that are ready to run and the tasks that are necessarily waiting for other tasks to complete. The priority system is really meant as an optional layer for optimization: dependency cycles are found quickly, and builds should be more efficient. A high priority number means that a task is processed first. This method can be overridden to disable the priority system:: def prio_and_split(self, tasks): return tasks, [] :return: A pair of task lists :rtype: tuple """ # to disable: #return tasks, [] for x in tasks: x.visited = 0 reverse = self.revdeps groups_done = set() for x in tasks: for k in x.run_after: if isinstance(k, Task.TaskGroup): if k not in groups_done: groups_done.add(k) for j in k.prev: reverse[j].add(k) else: reverse[k].add(x) # the priority number is not the tree depth def visit(n): if isinstance(n, Task.TaskGroup): return sum(visit(k) for k in n.next) if n.visited == 0: n.visited = 1 if n in reverse: rev = reverse[n] n.prio_order = n.tree_weight + len(rev) + sum(visit(k) for k in rev) else: n.prio_order = n.tree_weight n.visited = 2 elif n.visited == 1: raise Errors.WafError('Dependency cycle found!') return n.prio_order for x in tasks: if x.visited != 0: # must visit all to detect cycles continue try: visit(x) except Errors.WafError: self.debug_cycles(tasks, reverse) ready = [] waiting = [] for x in tasks: for k in x.run_after: if not k.hasrun: waiting.append(x) break else: ready.append(x) return (ready, waiting) def debug_cycles(self, tasks, reverse): tmp = {} for x in tasks: tmp[x] = 0 def visit(n, acc): if isinstance(n, Task.TaskGroup): for k in n.next: visit(k, acc) return if tmp[n] == 0: tmp[n] = 1 for k in reverse.get(n, []): visit(k, [n] + acc) tmp[n] = 2 elif tmp[n] == 1: lst = [] for tsk in acc: lst.append(repr(tsk)) if tsk is n: # exclude prior nodes, we want the minimum cycle break raise Errors.WafError('Task dependency cycle in "run_after" constraints: %s' % ''.join(lst)) for x in tasks: visit(x, []) hamster-3.0.3/waflib/Scripting.py000066400000000000000000000410121452646177100167530ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) "Module called for configuring, compiling and installing targets" from __future__ import with_statement import os, shlex, shutil, traceback, errno, sys, stat from waflib import Utils, Configure, Logs, Options, ConfigSet, Context, Errors, Build, Node build_dir_override = None no_climb_commands = ['configure'] default_cmd = "build" def waf_entry_point(current_directory, version, wafdir): """ This is the main entry point, all Waf execution starts here. :param current_directory: absolute path representing the current directory :type current_directory: string :param version: version number :type version: string :param wafdir: absolute path representing the directory of the waf library :type wafdir: string """ Logs.init_log() if Context.WAFVERSION != version: Logs.error('Waf script %r and library %r do not match (directory %r)', version, Context.WAFVERSION, wafdir) sys.exit(1) # Store current directory before any chdir Context.waf_dir = wafdir Context.run_dir = Context.launch_dir = current_directory start_dir = current_directory no_climb = os.environ.get('NOCLIMB') if len(sys.argv) > 1: # os.path.join handles absolute paths # if sys.argv[1] is not an absolute path, then it is relative to the current working directory potential_wscript = os.path.join(current_directory, sys.argv[1]) if os.path.basename(potential_wscript) == Context.WSCRIPT_FILE and os.path.isfile(potential_wscript): # need to explicitly normalize the path, as it may contain extra '/.' path = os.path.normpath(os.path.dirname(potential_wscript)) start_dir = os.path.abspath(path) no_climb = True sys.argv.pop(1) ctx = Context.create_context('options') (options, commands, env) = ctx.parse_cmd_args(allow_unknown=True) if options.top: start_dir = Context.run_dir = Context.top_dir = options.top no_climb = True if options.out: Context.out_dir = options.out # if 'configure' is in the commands, do not search any further if not no_climb: for k in no_climb_commands: for y in commands: if y.startswith(k): no_climb = True break # try to find a lock file (if the project was configured) # at the same time, store the first wscript file seen cur = start_dir while cur: try: lst = os.listdir(cur) except OSError: lst = [] Logs.error('Directory %r is unreadable!', cur) if Options.lockfile in lst: env = ConfigSet.ConfigSet() try: env.load(os.path.join(cur, Options.lockfile)) ino = os.stat(cur)[stat.ST_INO] except EnvironmentError: pass else: # check if the folder was not moved for x in (env.run_dir, env.top_dir, env.out_dir): if not x: continue if Utils.is_win32: if cur == x: load = True break else: # if the filesystem features symlinks, compare the inode numbers try: ino2 = os.stat(x)[stat.ST_INO] except OSError: pass else: if ino == ino2: load = True break else: Logs.warn('invalid lock file in %s', cur) load = False if load: Context.run_dir = env.run_dir Context.top_dir = env.top_dir Context.out_dir = env.out_dir break if not Context.run_dir: if Context.WSCRIPT_FILE in lst: Context.run_dir = cur next = os.path.dirname(cur) if next == cur: break cur = next if no_climb: break wscript = os.path.normpath(os.path.join(Context.run_dir, Context.WSCRIPT_FILE)) if not os.path.exists(wscript): if options.whelp: Logs.warn('These are the generic options (no wscript/project found)') ctx.parser.print_help() sys.exit(0) Logs.error('Waf: Run from a folder containing a %r file (or try -h for the generic options)', Context.WSCRIPT_FILE) sys.exit(1) try: os.chdir(Context.run_dir) except OSError: Logs.error('Waf: The folder %r is unreadable', Context.run_dir) sys.exit(1) try: set_main_module(wscript) except Errors.WafError as e: Logs.pprint('RED', e.verbose_msg) Logs.error(str(e)) sys.exit(1) except Exception as e: Logs.error('Waf: The wscript in %r is unreadable', Context.run_dir) traceback.print_exc(file=sys.stdout) sys.exit(2) if options.profile: import cProfile, pstats cProfile.runctx('from waflib import Scripting; Scripting.run_commands()', {}, {}, 'profi.txt') p = pstats.Stats('profi.txt') p.sort_stats('time').print_stats(75) # or 'cumulative' else: try: try: run_commands() except: if options.pdb: import pdb type, value, tb = sys.exc_info() traceback.print_exc() pdb.post_mortem(tb) else: raise except Errors.WafError as e: if Logs.verbose > 1: Logs.pprint('RED', e.verbose_msg) Logs.error(e.msg) sys.exit(1) except SystemExit: raise except Exception as e: traceback.print_exc(file=sys.stdout) sys.exit(2) except KeyboardInterrupt: Logs.pprint('RED', 'Interrupted') sys.exit(68) def set_main_module(file_path): """ Read the main wscript file into :py:const:`waflib.Context.Context.g_module` and bind default functions such as ``init``, ``dist``, ``distclean`` if not defined. Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization. :param file_path: absolute path representing the top-level wscript file :type file_path: string """ Context.g_module = Context.load_module(file_path) Context.g_module.root_path = file_path # note: to register the module globally, use the following: # sys.modules['wscript_main'] = g_module def set_def(obj): name = obj.__name__ if not name in Context.g_module.__dict__: setattr(Context.g_module, name, obj) for k in (dist, distclean, distcheck): set_def(k) # add dummy init and shutdown functions if they're not defined if not 'init' in Context.g_module.__dict__: Context.g_module.init = Utils.nada if not 'shutdown' in Context.g_module.__dict__: Context.g_module.shutdown = Utils.nada if not 'options' in Context.g_module.__dict__: Context.g_module.options = Utils.nada def parse_options(): """ Parses the command-line options and initialize the logging system. Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization. """ ctx = Context.create_context('options') ctx.execute() if not Options.commands: if isinstance(default_cmd, list): Options.commands.extend(default_cmd) else: Options.commands.append(default_cmd) if Options.options.whelp: ctx.parser.print_help() sys.exit(0) def run_command(cmd_name): """ Executes a single Waf command. Called by :py:func:`waflib.Scripting.run_commands`. :param cmd_name: command to execute, like ``build`` :type cmd_name: string """ ctx = Context.create_context(cmd_name) ctx.log_timer = Utils.Timer() ctx.options = Options.options # provided for convenience ctx.cmd = cmd_name try: ctx.execute() finally: # Issue 1374 ctx.finalize() return ctx def run_commands(): """ Execute the Waf commands that were given on the command-line, and the other options Called by :py:func:`waflib.Scripting.waf_entry_point` during the initialization, and executed after :py:func:`waflib.Scripting.parse_options`. """ parse_options() run_command('init') while Options.commands: cmd_name = Options.commands.pop(0) ctx = run_command(cmd_name) Logs.info('%r finished successfully (%s)', cmd_name, ctx.log_timer) run_command('shutdown') ########################################################################################### def distclean_dir(dirname): """ Distclean function called in the particular case when:: top == out :param dirname: absolute path of the folder to clean :type dirname: string """ for (root, dirs, files) in os.walk(dirname): for f in files: if f.endswith(('.o', '.moc', '.exe')): fname = os.path.join(root, f) try: os.remove(fname) except OSError: Logs.warn('Could not remove %r', fname) for x in (Context.DBFILE, 'config.log'): try: os.remove(x) except OSError: pass try: shutil.rmtree(Build.CACHE_DIR) except OSError: pass def distclean(ctx): '''removes build folders and data''' def remove_and_log(k, fun): try: fun(k) except EnvironmentError as e: if e.errno != errno.ENOENT: Logs.warn('Could not remove %r', k) # remove waf cache folders on the top-level if not Options.commands: for k in os.listdir('.'): for x in '.waf-2 waf-2 .waf3-2 waf3-2'.split(): if k.startswith(x): remove_and_log(k, shutil.rmtree) # remove a build folder, if any cur = '.' if os.environ.get('NO_LOCK_IN_TOP') or ctx.options.no_lock_in_top: cur = ctx.options.out try: lst = os.listdir(cur) except OSError: Logs.warn('Could not read %r', cur) return if Options.lockfile in lst: f = os.path.join(cur, Options.lockfile) try: env = ConfigSet.ConfigSet(f) except EnvironmentError: Logs.warn('Could not read %r', f) return if not env.out_dir or not env.top_dir: Logs.warn('Invalid lock file %r', f) return if env.out_dir == env.top_dir: distclean_dir(env.out_dir) else: remove_and_log(env.out_dir, shutil.rmtree) env_dirs = [env.out_dir] if not (os.environ.get('NO_LOCK_IN_TOP') or ctx.options.no_lock_in_top): env_dirs.append(env.top_dir) if not (os.environ.get('NO_LOCK_IN_RUN') or ctx.options.no_lock_in_run): env_dirs.append(env.run_dir) for k in env_dirs: p = os.path.join(k, Options.lockfile) remove_and_log(p, os.remove) class Dist(Context.Context): '''creates an archive containing the project source code''' cmd = 'dist' fun = 'dist' algo = 'tar.bz2' ext_algo = {} def execute(self): """ See :py:func:`waflib.Context.Context.execute` """ self.recurse([os.path.dirname(Context.g_module.root_path)]) self.archive() def archive(self): """ Creates the source archive. """ import tarfile arch_name = self.get_arch_name() try: self.base_path except AttributeError: self.base_path = self.path node = self.base_path.make_node(arch_name) try: node.delete() except OSError: pass files = self.get_files() if self.algo.startswith('tar.'): tar = tarfile.open(node.abspath(), 'w:' + self.algo.replace('tar.', '')) for x in files: self.add_tar_file(x, tar) tar.close() elif self.algo == 'zip': import zipfile zip = zipfile.ZipFile(node.abspath(), 'w', compression=zipfile.ZIP_DEFLATED) for x in files: archive_name = self.get_base_name() + '/' + x.path_from(self.base_path) if os.environ.get('SOURCE_DATE_EPOCH'): # TODO: parse that timestamp zip.writestr(zipfile.ZipInfo(archive_name), x.read(), zipfile.ZIP_DEFLATED) else: zip.write(x.abspath(), archive_name, zipfile.ZIP_DEFLATED) zip.close() else: self.fatal('Valid algo types are tar.bz2, tar.gz, tar.xz or zip') try: from hashlib import sha256 except ImportError: digest = '' else: digest = ' (sha256=%r)' % sha256(node.read(flags='rb')).hexdigest() Logs.info('New archive created: %s%s', self.arch_name, digest) def get_tar_path(self, node): """ Return the path to use for a node in the tar archive, the purpose of this is to let subclases resolve symbolic links or to change file names :return: absolute path :rtype: string """ return node.abspath() def add_tar_file(self, x, tar): """ Adds a file to the tar archive. Symlinks are not verified. :param x: file path :param tar: tar file object """ p = self.get_tar_path(x) tinfo = tar.gettarinfo(name=p, arcname=self.get_tar_prefix() + '/' + x.path_from(self.base_path)) tinfo.uid = 0 tinfo.gid = 0 tinfo.uname = 'root' tinfo.gname = 'root' if os.environ.get('SOURCE_DATE_EPOCH'): tinfo.mtime = int(os.environ.get('SOURCE_DATE_EPOCH')) if os.path.isfile(p): with open(p, 'rb') as f: tar.addfile(tinfo, fileobj=f) else: tar.addfile(tinfo) def get_tar_prefix(self): """ Returns the base path for files added into the archive tar file :rtype: string """ try: return self.tar_prefix except AttributeError: return self.get_base_name() def get_arch_name(self): """ Returns the archive file name. Set the attribute *arch_name* to change the default value:: def dist(ctx): ctx.arch_name = 'ctx.tar.bz2' :rtype: string """ try: self.arch_name except AttributeError: self.arch_name = self.get_base_name() + '.' + self.ext_algo.get(self.algo, self.algo) return self.arch_name def get_base_name(self): """ Returns the default name of the main directory in the archive, which is set to *appname-version*. Set the attribute *base_name* to change the default value:: def dist(ctx): ctx.base_name = 'files' :rtype: string """ try: self.base_name except AttributeError: appname = getattr(Context.g_module, Context.APPNAME, 'noname') version = getattr(Context.g_module, Context.VERSION, '1.0') self.base_name = appname + '-' + version return self.base_name def get_excl(self): """ Returns the patterns to exclude for finding the files in the top-level directory. Set the attribute *excl* to change the default value:: def dist(ctx): ctx.excl = 'build **/*.o **/*.class' :rtype: string """ try: return self.excl except AttributeError: self.excl = Node.exclude_regs + ' **/waf-2.* **/.waf-2.* **/waf3-2.* **/.waf3-2.* **/*~ **/*.rej **/*.orig **/*.pyc **/*.pyo **/*.bak **/*.swp **/.lock-w*' if Context.out_dir: nd = self.root.find_node(Context.out_dir) if nd: self.excl += ' ' + nd.path_from(self.base_path) return self.excl def get_files(self): """ Files to package are searched automatically by :py:func:`waflib.Node.Node.ant_glob`. Set *files* to prevent this behaviour:: def dist(ctx): ctx.files = ctx.path.find_node('wscript') Files are also searched from the directory 'base_path', to change it, set:: def dist(ctx): ctx.base_path = path :rtype: list of :py:class:`waflib.Node.Node` """ try: files = self.files except AttributeError: files = self.base_path.ant_glob('**/*', excl=self.get_excl()) return files def dist(ctx): '''makes a tarball for redistributing the sources''' pass class DistCheck(Dist): """creates an archive with dist, then tries to build it""" fun = 'distcheck' cmd = 'distcheck' def execute(self): """ See :py:func:`waflib.Context.Context.execute` """ self.recurse([os.path.dirname(Context.g_module.root_path)]) self.archive() self.check() def make_distcheck_cmd(self, tmpdir): cfg = [] if Options.options.distcheck_args: cfg = shlex.split(Options.options.distcheck_args) else: cfg = [x for x in sys.argv if x.startswith('-')] cmd = [sys.executable, sys.argv[0], 'configure', 'build', 'install', 'uninstall', '--destdir=' + tmpdir] + cfg return cmd def check(self): """ Creates the archive, uncompresses it and tries to build the project """ import tempfile, tarfile with tarfile.open(self.get_arch_name()) as t: for x in t: t.extract(x) instdir = tempfile.mkdtemp('.inst', self.get_base_name()) cmd = self.make_distcheck_cmd(instdir) ret = Utils.subprocess.Popen(cmd, cwd=self.get_base_name()).wait() if ret: raise Errors.WafError('distcheck failed with code %r' % ret) if os.path.exists(instdir): raise Errors.WafError('distcheck succeeded, but files were left in %s' % instdir) shutil.rmtree(self.get_base_name()) def distcheck(ctx): '''checks if the project compiles (tarball from 'dist')''' pass def autoconfigure(execute_method): """ Decorator that enables context commands to run *configure* as needed. """ def execute(self): """ Wraps :py:func:`waflib.Context.Context.execute` on the context class """ if not Configure.autoconfig: return execute_method(self) env = ConfigSet.ConfigSet() do_config = False try: env.load(os.path.join(Context.top_dir, Options.lockfile)) except EnvironmentError: Logs.warn('Configuring the project') do_config = True else: if env.run_dir != Context.run_dir: do_config = True else: h = 0 for f in env.files: try: h = Utils.h_list((h, Utils.readf(f, 'rb'))) except EnvironmentError: do_config = True break else: do_config = h != env.hash if do_config: cmd = env.config_cmd or 'configure' if Configure.autoconfig == 'clobber': tmp = Options.options.__dict__ launch_dir_tmp = Context.launch_dir if env.options: Options.options.__dict__ = env.options Context.launch_dir = env.launch_dir try: run_command(cmd) finally: Options.options.__dict__ = tmp Context.launch_dir = launch_dir_tmp else: run_command(cmd) run_command(self.cmd) else: return execute_method(self) return execute Build.BuildContext.execute = autoconfigure(Build.BuildContext.execute) hamster-3.0.3/waflib/Task.py000066400000000000000000001150761452646177100157270ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Tasks represent atomic operations such as processes. """ import os, re, sys, tempfile, traceback from waflib import Utils, Logs, Errors # task states NOT_RUN = 0 """The task was not executed yet""" MISSING = 1 """The task has been executed but the files have not been created""" CRASHED = 2 """The task execution returned a non-zero exit status""" EXCEPTION = 3 """An exception occurred in the task execution""" CANCELED = 4 """A dependency for the task is missing so it was cancelled""" SKIPPED = 8 """The task did not have to be executed""" SUCCESS = 9 """The task was successfully executed""" ASK_LATER = -1 """The task is not ready to be executed""" SKIP_ME = -2 """The task does not need to be executed""" RUN_ME = -3 """The task must be executed""" CANCEL_ME = -4 """The task cannot be executed because of a dependency problem""" COMPILE_TEMPLATE_SHELL = ''' def f(tsk): env = tsk.env gen = tsk.generator bld = gen.bld cwdx = tsk.get_cwd() p = env.get_flat def to_list(xx): if isinstance(xx, str): return [xx] return xx tsk.last_cmd = cmd = \'\'\' %s \'\'\' % s return tsk.exec_command(cmd, cwd=cwdx, env=env.env or None) ''' COMPILE_TEMPLATE_NOSHELL = ''' def f(tsk): env = tsk.env gen = tsk.generator bld = gen.bld cwdx = tsk.get_cwd() def to_list(xx): if isinstance(xx, str): return [xx] return xx def merge(lst1, lst2): if lst1 and lst2: return lst1[:-1] + [lst1[-1] + lst2[0]] + lst2[1:] return lst1 + lst2 lst = [] %s if '' in lst: lst = [x for x in lst if x] tsk.last_cmd = lst return tsk.exec_command(lst, cwd=cwdx, env=env.env or None) ''' COMPILE_TEMPLATE_SIG_VARS = ''' def f(tsk): sig = tsk.generator.bld.hash_env_vars(tsk.env, tsk.vars) tsk.m.update(sig) env = tsk.env gen = tsk.generator bld = gen.bld cwdx = tsk.get_cwd() p = env.get_flat buf = [] %s tsk.m.update(repr(buf).encode()) ''' classes = {} """ The metaclass :py:class:`waflib.Task.store_task_type` stores all class tasks created by user scripts or Waf tools to this dict. It maps class names to class objects. """ class store_task_type(type): """ Metaclass: store the task classes into the dict pointed by the class attribute 'register' which defaults to :py:const:`waflib.Task.classes`, The attribute 'run_str' is compiled into a method 'run' bound to the task class. """ def __init__(cls, name, bases, dict): super(store_task_type, cls).__init__(name, bases, dict) name = cls.__name__ if name != 'evil' and name != 'Task': if getattr(cls, 'run_str', None): # if a string is provided, convert it to a method (f, dvars) = compile_fun(cls.run_str, cls.shell) cls.hcode = Utils.h_cmd(cls.run_str) cls.orig_run_str = cls.run_str # change the name of run_str or it is impossible to subclass with a function cls.run_str = None cls.run = f # process variables cls.vars = list(set(cls.vars + dvars)) cls.vars.sort() if cls.vars: fun = compile_sig_vars(cls.vars) if fun: cls.sig_vars = fun elif getattr(cls, 'run', None) and not 'hcode' in cls.__dict__: # getattr(cls, 'hcode') would look in the upper classes cls.hcode = Utils.h_cmd(cls.run) # be creative getattr(cls, 'register', classes)[name] = cls evil = store_task_type('evil', (object,), {}) "Base class provided to avoid writing a metaclass, so the code can run in python 2.6 and 3.x unmodified" class Task(evil): """ Task objects represents actions to perform such as commands to execute by calling the `run` method. Detecting when to execute a task occurs in the method :py:meth:`waflib.Task.Task.runnable_status`. Detecting which tasks to execute is performed through a hash value returned by :py:meth:`waflib.Task.Task.signature`. The task signature is persistent from build to build. """ vars = [] """ConfigSet variables that should trigger a rebuild (class attribute used for :py:meth:`waflib.Task.Task.sig_vars`)""" always_run = False """Specify whether task instances must always be executed or not (class attribute)""" shell = False """Execute the command with the shell (class attribute)""" color = 'GREEN' """Color for the console display, see :py:const:`waflib.Logs.colors_lst`""" ext_in = [] """File extensions that objects of this task class may use""" ext_out = [] """File extensions that objects of this task class may create""" before = [] """The instances of this class are executed before the instances of classes whose names are in this list""" after = [] """The instances of this class are executed after the instances of classes whose names are in this list""" hcode = Utils.SIG_NIL """String representing an additional hash for the class representation""" keep_last_cmd = False """Whether to keep the last command executed on the instance after execution. This may be useful for certain extensions but it can a lot of memory. """ weight = 0 """Optional weight to tune the priority for task instances. The higher, the earlier. The weight only applies to single task objects.""" tree_weight = 0 """Optional weight to tune the priority of task instances and whole subtrees. The higher, the earlier.""" prio_order = 0 """Priority order set by the scheduler on instances during the build phase. You most likely do not need to set it. """ __slots__ = ('hasrun', 'generator', 'env', 'inputs', 'outputs', 'dep_nodes', 'run_after') def __init__(self, *k, **kw): self.hasrun = NOT_RUN try: self.generator = kw['generator'] except KeyError: self.generator = self self.env = kw['env'] """:py:class:`waflib.ConfigSet.ConfigSet` object (make sure to provide one)""" self.inputs = [] """List of input nodes, which represent the files used by the task instance""" self.outputs = [] """List of output nodes, which represent the files created by the task instance""" self.dep_nodes = [] """List of additional nodes to depend on""" self.run_after = set() """Set of tasks that must be executed before this one""" def __lt__(self, other): return self.priority() > other.priority() def __le__(self, other): return self.priority() >= other.priority() def __gt__(self, other): return self.priority() < other.priority() def __ge__(self, other): return self.priority() <= other.priority() def get_cwd(self): """ :return: current working directory :rtype: :py:class:`waflib.Node.Node` """ bld = self.generator.bld ret = getattr(self, 'cwd', None) or getattr(bld, 'cwd', bld.bldnode) if isinstance(ret, str): if os.path.isabs(ret): ret = bld.root.make_node(ret) else: ret = self.generator.path.make_node(ret) return ret def quote_flag(self, x): """ Surround a process argument by quotes so that a list of arguments can be written to a file :param x: flag :type x: string :return: quoted flag :rtype: string """ old = x if '\\' in x: x = x.replace('\\', '\\\\') if '"' in x: x = x.replace('"', '\\"') if old != x or ' ' in x or '\t' in x or "'" in x: x = '"%s"' % x return x def priority(self): """ Priority of execution; the higher, the earlier :return: the priority value :rtype: a tuple of numeric values """ return (self.weight + self.prio_order, - getattr(self.generator, 'tg_idx_count', 0)) def split_argfile(self, cmd): """ Splits a list of process commands into the executable part and its list of arguments :return: a tuple containing the executable first and then the rest of arguments :rtype: tuple """ return ([cmd[0]], [self.quote_flag(x) for x in cmd[1:]]) def exec_command(self, cmd, **kw): """ Wrapper for :py:meth:`waflib.Context.Context.exec_command`. This version set the current working directory (``build.variant_dir``), applies PATH settings (if self.env.PATH is provided), and can run long commands through a temporary ``@argfile``. :param cmd: process command to execute :type cmd: list of string (best) or string (process will use a shell) :return: the return code :rtype: int Optional parameters: #. cwd: current working directory (Node or string) #. stdout: set to None to prevent waf from capturing the process standard output #. stderr: set to None to prevent waf from capturing the process standard error #. timeout: timeout value (Python 3) """ if not 'cwd' in kw: kw['cwd'] = self.get_cwd() if hasattr(self, 'timeout'): kw['timeout'] = self.timeout if self.env.PATH: env = kw['env'] = dict(kw.get('env') or self.env.env or os.environ) env['PATH'] = self.env.PATH if isinstance(self.env.PATH, str) else os.pathsep.join(self.env.PATH) if hasattr(self, 'stdout'): kw['stdout'] = self.stdout if hasattr(self, 'stderr'): kw['stderr'] = self.stderr if not isinstance(cmd, str): if Utils.is_win32: # win32 compares the resulting length http://support.microsoft.com/kb/830473 too_long = sum([len(arg) for arg in cmd]) + len(cmd) > 8192 else: # non-win32 counts the amount of arguments (200k) too_long = len(cmd) > 200000 if too_long and getattr(self, 'allow_argsfile', True): # Shunt arguments to a temporary file if the command is too long. cmd, args = self.split_argfile(cmd) try: (fd, tmp) = tempfile.mkstemp() os.write(fd, '\r\n'.join(args).encode()) os.close(fd) if Logs.verbose: Logs.debug('argfile: @%r -> %r', tmp, args) return self.generator.bld.exec_command(cmd + ['@' + tmp], **kw) finally: try: os.remove(tmp) except OSError: # anti-virus and indexers can keep files open -_- pass return self.generator.bld.exec_command(cmd, **kw) def process(self): """ Runs the task and handles errors :return: 0 or None if everything is fine :rtype: integer """ # remove the task signature immediately before it is executed # so that the task will be executed again in case of failure try: del self.generator.bld.task_sigs[self.uid()] except KeyError: pass try: ret = self.run() except Exception: self.err_msg = traceback.format_exc() self.hasrun = EXCEPTION else: if ret: self.err_code = ret self.hasrun = CRASHED else: try: self.post_run() except Errors.WafError: pass except Exception: self.err_msg = traceback.format_exc() self.hasrun = EXCEPTION else: self.hasrun = SUCCESS if self.hasrun != SUCCESS and self.scan: # rescan dependencies on next run try: del self.generator.bld.imp_sigs[self.uid()] except KeyError: pass def log_display(self, bld): "Writes the execution status on the context logger" if self.generator.bld.progress_bar == 3: return s = self.display() if s: if bld.logger: logger = bld.logger else: logger = Logs if self.generator.bld.progress_bar == 1: c1 = Logs.colors.cursor_off c2 = Logs.colors.cursor_on logger.info(s, extra={'stream': sys.stderr, 'terminator':'', 'c1': c1, 'c2' : c2}) else: logger.info(s, extra={'terminator':'', 'c1': '', 'c2' : ''}) def display(self): """ Returns an execution status for the console, the progress bar, or the IDE output. :rtype: string """ col1 = Logs.colors(self.color) col2 = Logs.colors.NORMAL master = self.generator.bld.producer def cur(): # the current task position, computed as late as possible return master.processed - master.ready.qsize() if self.generator.bld.progress_bar == 1: return self.generator.bld.progress_line(cur(), master.total, col1, col2) if self.generator.bld.progress_bar == 2: ela = str(self.generator.bld.timer) try: ins = ','.join([n.name for n in self.inputs]) except AttributeError: ins = '' try: outs = ','.join([n.name for n in self.outputs]) except AttributeError: outs = '' return '|Total %s|Current %s|Inputs %s|Outputs %s|Time %s|\n' % (master.total, cur(), ins, outs, ela) s = str(self) if not s: return None total = master.total n = len(str(total)) fs = '[%%%dd/%%%dd] %%s%%s%%s%%s\n' % (n, n) kw = self.keyword() if kw: kw += ' ' return fs % (cur(), total, kw, col1, s, col2) def hash_constraints(self): """ Identifies a task type for all the constraints relevant for the scheduler: precedence, file production :return: a hash value :rtype: string """ return (tuple(self.before), tuple(self.after), tuple(self.ext_in), tuple(self.ext_out), self.__class__.__name__, self.hcode) def format_error(self): """ Returns an error message to display the build failure reasons :rtype: string """ if Logs.verbose: msg = ': %r\n%r' % (self, getattr(self, 'last_cmd', '')) else: msg = ' (run with -v to display more information)' name = getattr(self.generator, 'name', '') if getattr(self, "err_msg", None): return self.err_msg elif not self.hasrun: return 'task in %r was not executed for some reason: %r' % (name, self) elif self.hasrun == CRASHED: try: return ' -> task in %r failed with exit status %r%s' % (name, self.err_code, msg) except AttributeError: return ' -> task in %r failed%s' % (name, msg) elif self.hasrun == MISSING: return ' -> missing files in %r%s' % (name, msg) elif self.hasrun == CANCELED: return ' -> %r canceled because of missing dependencies' % name else: return 'invalid status for task in %r: %r' % (name, self.hasrun) def colon(self, var1, var2): """ Enable scriptlet expressions of the form ${FOO_ST:FOO} If the first variable (FOO_ST) is empty, then an empty list is returned The results will be slightly different if FOO_ST is a list, for example:: env.FOO = ['p1', 'p2'] env.FOO_ST = '-I%s' # ${FOO_ST:FOO} returns ['-Ip1', '-Ip2'] env.FOO_ST = ['-a', '-b'] # ${FOO_ST:FOO} returns ['-a', '-b', 'p1', '-a', '-b', 'p2'] """ tmp = self.env[var1] if not tmp: return [] if isinstance(var2, str): it = self.env[var2] else: it = var2 if isinstance(tmp, str): return [tmp % x for x in it] else: lst = [] for y in it: lst.extend(tmp) lst.append(y) return lst def __str__(self): "string to display to the user" name = self.__class__.__name__ if self.outputs: if name.endswith(('lib', 'program')) or not self.inputs: node = self.outputs[0] return node.path_from(node.ctx.launch_node()) if not (self.inputs or self.outputs): return self.__class__.__name__ if len(self.inputs) == 1: node = self.inputs[0] return node.path_from(node.ctx.launch_node()) src_str = ' '.join([a.path_from(a.ctx.launch_node()) for a in self.inputs]) tgt_str = ' '.join([a.path_from(a.ctx.launch_node()) for a in self.outputs]) if self.outputs: sep = ' -> ' else: sep = '' return '%s: %s%s%s' % (self.__class__.__name__, src_str, sep, tgt_str) def keyword(self): "Display keyword used to prettify the console outputs" name = self.__class__.__name__ if name.endswith(('lib', 'program')): return 'Linking' if len(self.inputs) == 1 and len(self.outputs) == 1: return 'Compiling' if not self.inputs: if self.outputs: return 'Creating' else: return 'Running' return 'Processing' def __repr__(self): "for debugging purposes" try: ins = ",".join([x.name for x in self.inputs]) outs = ",".join([x.name for x in self.outputs]) except AttributeError: ins = ",".join([str(x) for x in self.inputs]) outs = ",".join([str(x) for x in self.outputs]) return "".join(['\n\t{task %r: ' % id(self), self.__class__.__name__, " ", ins, " -> ", outs, '}']) def uid(self): """ Returns an identifier used to determine if tasks are up-to-date. Since the identifier will be stored between executions, it must be: - unique for a task: no two tasks return the same value (for a given build context) - the same for a given task instance By default, the node paths, the class name, and the function are used as inputs to compute a hash. The pointer to the object (python built-in 'id') will change between build executions, and must be avoided in such hashes. :return: hash value :rtype: string """ try: return self.uid_ except AttributeError: m = Utils.md5(self.__class__.__name__) up = m.update for x in self.inputs + self.outputs: up(x.abspath()) self.uid_ = m.digest() return self.uid_ def set_inputs(self, inp): """ Appends the nodes to the *inputs* list :param inp: input nodes :type inp: node or list of nodes """ if isinstance(inp, list): self.inputs += inp else: self.inputs.append(inp) def set_outputs(self, out): """ Appends the nodes to the *outputs* list :param out: output nodes :type out: node or list of nodes """ if isinstance(out, list): self.outputs += out else: self.outputs.append(out) def set_run_after(self, task): """ Run this task only after the given *task*. Calling this method from :py:meth:`waflib.Task.Task.runnable_status` may cause build deadlocks; see :py:meth:`waflib.Tools.fc.fc.runnable_status` for details. :param task: task :type task: :py:class:`waflib.Task.Task` """ assert isinstance(task, Task) self.run_after.add(task) def signature(self): """ Task signatures are stored between build executions, they are use to track the changes made to the input nodes (not to the outputs!). The signature hashes data from various sources: * explicit dependencies: files listed in the inputs (list of node objects) :py:meth:`waflib.Task.Task.sig_explicit_deps` * implicit dependencies: list of nodes returned by scanner methods (when present) :py:meth:`waflib.Task.Task.sig_implicit_deps` * hashed data: variables/values read from task.vars/task.env :py:meth:`waflib.Task.Task.sig_vars` If the signature is expected to give a different result, clear the cache kept in ``self.cache_sig``:: from waflib import Task class cls(Task.Task): def signature(self): sig = super(Task.Task, self).signature() delattr(self, 'cache_sig') return super(Task.Task, self).signature() :return: the signature value :rtype: string or bytes """ try: return self.cache_sig except AttributeError: pass self.m = Utils.md5(self.hcode) # explicit deps self.sig_explicit_deps() # env vars self.sig_vars() # implicit deps / scanner results if self.scan: try: self.sig_implicit_deps() except Errors.TaskRescan: return self.signature() ret = self.cache_sig = self.m.digest() return ret def runnable_status(self): """ Returns the Task status :return: a task state in :py:const:`waflib.Task.RUN_ME`, :py:const:`waflib.Task.SKIP_ME`, :py:const:`waflib.Task.CANCEL_ME` or :py:const:`waflib.Task.ASK_LATER`. :rtype: int """ bld = self.generator.bld if bld.is_install < 0: return SKIP_ME for t in self.run_after: if not t.hasrun: return ASK_LATER elif t.hasrun < SKIPPED: # a dependency has an error return CANCEL_ME # first compute the signature try: new_sig = self.signature() except Errors.TaskNotReady: return ASK_LATER # compare the signature to a signature computed previously key = self.uid() try: prev_sig = bld.task_sigs[key] except KeyError: Logs.debug('task: task %r must run: it was never run before or the task code changed', self) return RUN_ME if new_sig != prev_sig: Logs.debug('task: task %r must run: the task signature changed', self) return RUN_ME # compare the signatures of the outputs for node in self.outputs: sig = bld.node_sigs.get(node) if not sig: Logs.debug('task: task %r must run: an output node has no signature', self) return RUN_ME if sig != key: Logs.debug('task: task %r must run: an output node was produced by another task', self) return RUN_ME if not node.exists(): Logs.debug('task: task %r must run: an output node does not exist', self) return RUN_ME return (self.always_run and RUN_ME) or SKIP_ME def post_run(self): """ Called after successful execution to record that the task has run by updating the entry in :py:attr:`waflib.Build.BuildContext.task_sigs`. """ bld = self.generator.bld for node in self.outputs: if not node.exists(): self.hasrun = MISSING self.err_msg = '-> missing file: %r' % node.abspath() raise Errors.WafError(self.err_msg) bld.node_sigs[node] = self.uid() # make sure this task produced the files in question bld.task_sigs[self.uid()] = self.signature() if not self.keep_last_cmd: try: del self.last_cmd except AttributeError: pass def sig_explicit_deps(self): """ Used by :py:meth:`waflib.Task.Task.signature`; it hashes :py:attr:`waflib.Task.Task.inputs` and :py:attr:`waflib.Task.Task.dep_nodes` signatures. """ bld = self.generator.bld upd = self.m.update # the inputs for x in self.inputs + self.dep_nodes: upd(x.get_bld_sig()) # manual dependencies, they can slow down the builds if bld.deps_man: additional_deps = bld.deps_man for x in self.inputs + self.outputs: try: d = additional_deps[x] except KeyError: continue for v in d: try: v = v.get_bld_sig() except AttributeError: if hasattr(v, '__call__'): v = v() # dependency is a function, call it upd(v) def sig_deep_inputs(self): """ Enable rebuilds on input files task signatures. Not used by default. Example: hashes of output programs can be unchanged after being re-linked, despite the libraries being different. This method can thus prevent stale unit test results (waf_unit_test.py). Hashing input file timestamps is another possibility for the implementation. This may cause unnecessary rebuilds when input tasks are frequently executed. Here is an implementation example:: lst = [] for node in self.inputs + self.dep_nodes: st = os.stat(node.abspath()) lst.append(st.st_mtime) lst.append(st.st_size) self.m.update(Utils.h_list(lst)) The downside of the implementation is that it absolutely requires all build directory files to be declared within the current build. """ bld = self.generator.bld lst = [bld.task_sigs[bld.node_sigs[node]] for node in (self.inputs + self.dep_nodes) if node.is_bld()] self.m.update(Utils.h_list(lst)) def sig_vars(self): """ Used by :py:meth:`waflib.Task.Task.signature`; it hashes :py:attr:`waflib.Task.Task.env` variables/values When overriding this method, and if scriptlet expressions are used, make sure to follow the code in :py:meth:`waflib.Task.Task.compile_sig_vars` to enable dependencies on scriptlet results. This method may be replaced on subclasses by the metaclass to force dependencies on scriptlet code. """ sig = self.generator.bld.hash_env_vars(self.env, self.vars) self.m.update(sig) scan = None """ This method, when provided, returns a tuple containing: * a list of nodes corresponding to real files * a list of names for files not found in path_lst For example:: from waflib.Task import Task class mytask(Task): def scan(self, node): return ([], []) The first and second lists in the tuple are stored in :py:attr:`waflib.Build.BuildContext.node_deps` and :py:attr:`waflib.Build.BuildContext.raw_deps` respectively. """ def sig_implicit_deps(self): """ Used by :py:meth:`waflib.Task.Task.signature`; it hashes node signatures obtained by scanning for dependencies (:py:meth:`waflib.Task.Task.scan`). The exception :py:class:`waflib.Errors.TaskRescan` is thrown when a file has changed. In this case, the method :py:meth:`waflib.Task.Task.signature` is called once again, and return here to call :py:meth:`waflib.Task.Task.scan` and searching for dependencies. """ bld = self.generator.bld # get the task signatures from previous runs key = self.uid() prev = bld.imp_sigs.get(key, []) # for issue #379 if prev: try: if prev == self.compute_sig_implicit_deps(): return prev except Errors.TaskNotReady: raise except EnvironmentError: # when a file was renamed, remove the stale nodes (headers in folders without source files) # this will break the order calculation for headers created during the build in the source directory (should be uncommon) # the behaviour will differ when top != out for x in bld.node_deps.get(self.uid(), []): if not x.is_bld() and not x.exists(): try: del x.parent.children[x.name] except KeyError: pass del bld.imp_sigs[key] raise Errors.TaskRescan('rescan') # no previous run or the signature of the dependencies has changed, rescan the dependencies (bld.node_deps[key], bld.raw_deps[key]) = self.scan() if Logs.verbose: Logs.debug('deps: scanner for %s: %r; unresolved: %r', self, bld.node_deps[key], bld.raw_deps[key]) # recompute the signature and return it try: bld.imp_sigs[key] = self.compute_sig_implicit_deps() except EnvironmentError: for k in bld.node_deps.get(self.uid(), []): if not k.exists(): Logs.warn('Dependency %r for %r is missing: check the task declaration and the build order!', k, self) raise def compute_sig_implicit_deps(self): """ Used by :py:meth:`waflib.Task.Task.sig_implicit_deps` for computing the actual hash of the :py:class:`waflib.Node.Node` returned by the scanner. :return: a hash value for the implicit dependencies :rtype: string or bytes """ upd = self.m.update self.are_implicit_nodes_ready() # scanner returns a node that does not have a signature # just *ignore* the error and let them figure out from the compiler output # waf -k behaviour for k in self.generator.bld.node_deps.get(self.uid(), []): upd(k.get_bld_sig()) return self.m.digest() def are_implicit_nodes_ready(self): """ For each node returned by the scanner, see if there is a task that creates it, and infer the build order This has a low performance impact on null builds (1.86s->1.66s) thanks to caching (28s->1.86s) """ bld = self.generator.bld try: cache = bld.dct_implicit_nodes except AttributeError: bld.dct_implicit_nodes = cache = {} # one cache per build group try: dct = cache[bld.current_group] except KeyError: dct = cache[bld.current_group] = {} for tsk in bld.cur_tasks: for x in tsk.outputs: dct[x] = tsk modified = False for x in bld.node_deps.get(self.uid(), []): if x in dct: self.run_after.add(dct[x]) modified = True if modified: for tsk in self.run_after: if not tsk.hasrun: #print "task is not ready..." raise Errors.TaskNotReady('not ready') if sys.hexversion > 0x3000000: def uid(self): try: return self.uid_ except AttributeError: m = Utils.md5(self.__class__.__name__.encode('latin-1', 'xmlcharrefreplace')) up = m.update for x in self.inputs + self.outputs: up(x.abspath().encode('latin-1', 'xmlcharrefreplace')) self.uid_ = m.digest() return self.uid_ uid.__doc__ = Task.uid.__doc__ Task.uid = uid def is_before(t1, t2): """ Returns a non-zero value if task t1 is to be executed before task t2:: t1.ext_out = '.h' t2.ext_in = '.h' t2.after = ['t1'] t1.before = ['t2'] waflib.Task.is_before(t1, t2) # True :param t1: Task object :type t1: :py:class:`waflib.Task.Task` :param t2: Task object :type t2: :py:class:`waflib.Task.Task` """ to_list = Utils.to_list for k in to_list(t2.ext_in): if k in to_list(t1.ext_out): return 1 if t1.__class__.__name__ in to_list(t2.after): return 1 if t2.__class__.__name__ in to_list(t1.before): return 1 return 0 def set_file_constraints(tasks): """ Updates the ``run_after`` attribute of all tasks based on the task inputs and outputs :param tasks: tasks :type tasks: list of :py:class:`waflib.Task.Task` """ ins = Utils.defaultdict(set) outs = Utils.defaultdict(set) for x in tasks: for a in x.inputs: ins[a].add(x) for a in x.dep_nodes: ins[a].add(x) for a in x.outputs: outs[a].add(x) links = set(ins.keys()).intersection(outs.keys()) for k in links: for a in ins[k]: a.run_after.update(outs[k]) class TaskGroup(object): """ Wrap nxm task order constraints into a single object to prevent the creation of large list/set objects This is an optimization """ def __init__(self, prev, next): self.prev = prev self.next = next self.done = False def get_hasrun(self): for k in self.prev: if not k.hasrun: return NOT_RUN return SUCCESS hasrun = property(get_hasrun, None) def set_precedence_constraints(tasks): """ Updates the ``run_after`` attribute of all tasks based on the after/before/ext_out/ext_in attributes :param tasks: tasks :type tasks: list of :py:class:`waflib.Task.Task` """ cstr_groups = Utils.defaultdict(list) for x in tasks: h = x.hash_constraints() cstr_groups[h].append(x) keys = list(cstr_groups.keys()) maxi = len(keys) # this list should be short for i in range(maxi): t1 = cstr_groups[keys[i]][0] for j in range(i + 1, maxi): t2 = cstr_groups[keys[j]][0] # add the constraints based on the comparisons if is_before(t1, t2): a = i b = j elif is_before(t2, t1): a = j b = i else: continue a = cstr_groups[keys[a]] b = cstr_groups[keys[b]] if len(a) < 2 or len(b) < 2: for x in b: x.run_after.update(a) else: group = TaskGroup(set(a), set(b)) for x in b: x.run_after.add(group) def funex(c): """ Compiles a scriptlet expression into a Python function :param c: function to compile :type c: string :return: the function 'f' declared in the input string :rtype: function """ dc = {} exec(c, dc) return dc['f'] re_cond = re.compile(r'(?P\w+)|(?P\|)|(?P&)') re_novar = re.compile(r'^(SRC|TGT)\W+.*?$') reg_act = re.compile(r'(?P\\)|(?P\$\$)|(?P\$\{(?P\w+)(?P.*?)\})', re.M) def compile_fun_shell(line): """ Creates a compiled function to execute a process through a sub-shell """ extr = [] def repl(match): g = match.group if g('dollar'): return "$" elif g('backslash'): return '\\\\' elif g('subst'): extr.append((g('var'), g('code'))) return "%s" return None line = reg_act.sub(repl, line) or line dvars = [] def add_dvar(x): if x not in dvars: dvars.append(x) def replc(m): # performs substitutions and populates dvars if m.group('and'): return ' and ' elif m.group('or'): return ' or ' else: x = m.group('var') add_dvar(x) return 'env[%r]' % x parm = [] app = parm.append for (var, meth) in extr: if var == 'SRC': if meth: app('tsk.inputs%s' % meth) else: app('" ".join([a.path_from(cwdx) for a in tsk.inputs])') elif var == 'TGT': if meth: app('tsk.outputs%s' % meth) else: app('" ".join([a.path_from(cwdx) for a in tsk.outputs])') elif meth: if meth.startswith(':'): add_dvar(var) m = meth[1:] if m == 'SRC': m = '[a.path_from(cwdx) for a in tsk.inputs]' elif m == 'TGT': m = '[a.path_from(cwdx) for a in tsk.outputs]' elif re_novar.match(m): m = '[tsk.inputs%s]' % m[3:] elif re_novar.match(m): m = '[tsk.outputs%s]' % m[3:] else: add_dvar(m) if m[:3] not in ('tsk', 'gen', 'bld'): m = '%r' % m app('" ".join(tsk.colon(%r, %s))' % (var, m)) elif meth.startswith('?'): # In A?B|C output env.A if one of env.B or env.C is non-empty expr = re_cond.sub(replc, meth[1:]) app('p(%r) if (%s) else ""' % (var, expr)) else: call = '%s%s' % (var, meth) add_dvar(call) app(call) else: add_dvar(var) app("p('%s')" % var) if parm: parm = "%% (%s) " % (',\n\t\t'.join(parm)) else: parm = '' c = COMPILE_TEMPLATE_SHELL % (line, parm) Logs.debug('action: %s', c.strip().splitlines()) return (funex(c), dvars) reg_act_noshell = re.compile(r"(?P\s+)|(?P\$\{(?P\w+)(?P.*?)\})|(?P([^$ \t\n\r\f\v]|\$\$)+)", re.M) def compile_fun_noshell(line): """ Creates a compiled function to execute a process without a sub-shell """ buf = [] dvars = [] merge = False app = buf.append def add_dvar(x): if x not in dvars: dvars.append(x) def replc(m): # performs substitutions and populates dvars if m.group('and'): return ' and ' elif m.group('or'): return ' or ' else: x = m.group('var') add_dvar(x) return 'env[%r]' % x for m in reg_act_noshell.finditer(line): if m.group('space'): merge = False continue elif m.group('text'): app('[%r]' % m.group('text').replace('$$', '$')) elif m.group('subst'): var = m.group('var') code = m.group('code') if var == 'SRC': if code: app('[tsk.inputs%s]' % code) else: app('[a.path_from(cwdx) for a in tsk.inputs]') elif var == 'TGT': if code: app('[tsk.outputs%s]' % code) else: app('[a.path_from(cwdx) for a in tsk.outputs]') elif code: if code.startswith(':'): # a composed variable ${FOO:OUT} add_dvar(var) m = code[1:] if m == 'SRC': m = '[a.path_from(cwdx) for a in tsk.inputs]' elif m == 'TGT': m = '[a.path_from(cwdx) for a in tsk.outputs]' elif re_novar.match(m): m = '[tsk.inputs%s]' % m[3:] elif re_novar.match(m): m = '[tsk.outputs%s]' % m[3:] else: add_dvar(m) if m[:3] not in ('tsk', 'gen', 'bld'): m = '%r' % m app('tsk.colon(%r, %s)' % (var, m)) elif code.startswith('?'): # In A?B|C output env.A if one of env.B or env.C is non-empty expr = re_cond.sub(replc, code[1:]) app('to_list(env[%r] if (%s) else [])' % (var, expr)) else: # plain code such as ${tsk.inputs[0].abspath()} call = '%s%s' % (var, code) add_dvar(call) app('to_list(%s)' % call) else: # a plain variable such as # a plain variable like ${AR} app('to_list(env[%r])' % var) add_dvar(var) if merge: tmp = 'merge(%s, %s)' % (buf[-2], buf[-1]) del buf[-1] buf[-1] = tmp merge = True # next turn buf = ['lst.extend(%s)' % x for x in buf] fun = COMPILE_TEMPLATE_NOSHELL % "\n\t".join(buf) Logs.debug('action: %s', fun.strip().splitlines()) return (funex(fun), dvars) def compile_fun(line, shell=False): """ Parses a string expression such as '${CC} ${SRC} -o ${TGT}' and returns a pair containing: * The function created (compiled) for use as :py:meth:`waflib.Task.Task.run` * The list of variables that must cause rebuilds when *env* data is modified for example:: from waflib.Task import compile_fun compile_fun('cxx', '${CXX} -o ${TGT[0]} ${SRC} -I ${SRC[0].parent.bldpath()}') def build(bld): bld(source='wscript', rule='echo "foo\\${SRC[0].name}\\bar"') The env variables (CXX, ..) on the task must not hold dicts so as to preserve a consistent order. The reserved keywords ``TGT`` and ``SRC`` represent the task input and output nodes """ if isinstance(line, str): if line.find('<') > 0 or line.find('>') > 0 or line.find('&&') > 0: shell = True else: dvars_lst = [] funs_lst = [] for x in line: if isinstance(x, str): fun, dvars = compile_fun(x, shell) dvars_lst += dvars funs_lst.append(fun) else: # assume a function to let through funs_lst.append(x) def composed_fun(task): for x in funs_lst: ret = x(task) if ret: return ret return None return composed_fun, dvars_lst if shell: return compile_fun_shell(line) else: return compile_fun_noshell(line) def compile_sig_vars(vars): """ This method produces a sig_vars method suitable for subclasses that provide scriptlet code in their run_str code. If no such method can be created, this method returns None. The purpose of the sig_vars method returned is to ensures that rebuilds occur whenever the contents of the expression changes. This is the case B below:: import time # case A: regular variables tg = bld(rule='echo ${FOO}') tg.env.FOO = '%s' % time.time() # case B bld(rule='echo ${gen.foo}', foo='%s' % time.time()) :param vars: env variables such as CXXFLAGS or gen.foo :type vars: list of string :return: A sig_vars method relevant for dependencies if adequate, else None :rtype: A function, or None in most cases """ buf = [] for x in sorted(vars): if x[:3] in ('tsk', 'gen', 'bld'): buf.append('buf.append(%s)' % x) if buf: return funex(COMPILE_TEMPLATE_SIG_VARS % '\n\t'.join(buf)) return None def task_factory(name, func=None, vars=None, color='GREEN', ext_in=[], ext_out=[], before=[], after=[], shell=False, scan=None): """ Returns a new task subclass with the function ``run`` compiled from the line given. :param func: method run :type func: string or function :param vars: list of variables to hash :type vars: list of string :param color: color to use :type color: string :param shell: when *func* is a string, enable/disable the use of the shell :type shell: bool :param scan: method scan :type scan: function :rtype: :py:class:`waflib.Task.Task` """ params = { 'vars': vars or [], # function arguments are static, and this one may be modified by the class 'color': color, 'name': name, 'shell': shell, 'scan': scan, } if isinstance(func, str) or isinstance(func, tuple): params['run_str'] = func else: params['run'] = func cls = type(Task)(name, (Task,), params) classes[name] = cls if ext_in: cls.ext_in = Utils.to_list(ext_in) if ext_out: cls.ext_out = Utils.to_list(ext_out) if before: cls.before = Utils.to_list(before) if after: cls.after = Utils.to_list(after) return cls def deep_inputs(cls): """ Task class decorator to enable rebuilds on input files task signatures """ def sig_explicit_deps(self): Task.sig_explicit_deps(self) Task.sig_deep_inputs(self) cls.sig_explicit_deps = sig_explicit_deps return cls TaskBase = Task "Provided for compatibility reasons, TaskBase should not be used" class TaskSemaphore(object): """ Task semaphores provide a simple and efficient way of throttling the amount of a particular task to run concurrently. The throttling value is capped by the amount of maximum jobs, so for example, a `TaskSemaphore(10)` has no effect in a `-j2` build. Task semaphores are typically specified on the task class level:: class compile(waflib.Task.Task): semaphore = waflib.Task.TaskSemaphore(2) run_str = 'touch ${TGT}' Task semaphores are meant to be used by the build scheduler in the main thread, so there are no guarantees of thread safety. """ def __init__(self, num): """ :param num: maximum value of concurrent tasks :type num: int """ self.num = num self.locking = set() self.waiting = set() def is_locked(self): """Returns True if this semaphore cannot be acquired by more tasks""" return len(self.locking) >= self.num def acquire(self, tsk): """ Mark the semaphore as used by the given task (not re-entrant). :param tsk: task object :type tsk: :py:class:`waflib.Task.Task` :raises: :py:class:`IndexError` in case the resource is already acquired """ if self.is_locked(): raise IndexError('Cannot lock more %r' % self.locking) self.locking.add(tsk) def release(self, tsk): """ Mark the semaphore as unused by the given task. :param tsk: task object :type tsk: :py:class:`waflib.Task.Task` :raises: :py:class:`KeyError` in case the resource is not acquired by the task """ self.locking.remove(tsk) hamster-3.0.3/waflib/TaskGen.py000066400000000000000000000636351452646177100163640ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Task generators The class :py:class:`waflib.TaskGen.task_gen` encapsulates the creation of task objects (low-level code) The instances can have various parameters, but the creation of task nodes (Task.py) is deferred. To achieve this, various methods are called from the method "apply" """ import copy, re, os, functools from waflib import Task, Utils, Logs, Errors, ConfigSet, Node feats = Utils.defaultdict(set) """remember the methods declaring features""" HEADER_EXTS = ['.h', '.hpp', '.hxx', '.hh'] class task_gen(object): """ Instances of this class create :py:class:`waflib.Task.Task` when calling the method :py:meth:`waflib.TaskGen.task_gen.post` from the main thread. A few notes: * The methods to call (*self.meths*) can be specified dynamically (removing, adding, ..) * The 'features' are used to add methods to self.meths and then execute them * The attribute 'path' is a node representing the location of the task generator * The tasks created are added to the attribute *tasks* * The attribute 'idx' is a counter of task generators in the same path """ mappings = Utils.ordered_iter_dict() """Mappings are global file extension mappings that are retrieved in the order of definition""" prec = Utils.defaultdict(set) """Dict that holds the precedence execution rules for task generator methods""" def __init__(self, *k, **kw): """ Task generator objects predefine various attributes (source, target) for possible processing by process_rule (make-like rules) or process_source (extensions, misc methods) Tasks are stored on the attribute 'tasks'. They are created by calling methods listed in ``self.meths`` or referenced in the attribute ``features`` A topological sort is performed to execute the methods in correct order. The extra key/value elements passed in ``kw`` are set as attributes """ self.source = [] self.target = '' self.meths = [] """ List of method names to execute (internal) """ self.features = [] """ List of feature names for bringing new methods in """ self.tasks = [] """ Tasks created are added to this list """ if not 'bld' in kw: # task generators without a build context :-/ self.env = ConfigSet.ConfigSet() self.idx = 0 self.path = None else: self.bld = kw['bld'] self.env = self.bld.env.derive() self.path = kw.get('path', self.bld.path) # by default, emulate chdir when reading scripts # Provide a unique index per folder # This is part of a measure to prevent output file name collisions path = self.path.abspath() try: self.idx = self.bld.idx[path] = self.bld.idx.get(path, 0) + 1 except AttributeError: self.bld.idx = {} self.idx = self.bld.idx[path] = 1 # Record the global task generator count try: self.tg_idx_count = self.bld.tg_idx_count = self.bld.tg_idx_count + 1 except AttributeError: self.tg_idx_count = self.bld.tg_idx_count = 1 for key, val in kw.items(): setattr(self, key, val) def __str__(self): """Debugging helper""" return "" % (self.name, self.path.abspath()) def __repr__(self): """Debugging helper""" lst = [] for x in self.__dict__: if x not in ('env', 'bld', 'compiled_tasks', 'tasks'): lst.append("%s=%s" % (x, repr(getattr(self, x)))) return "bld(%s) in %s" % (", ".join(lst), self.path.abspath()) def get_cwd(self): """ Current working directory for the task generator, defaults to the build directory. This is still used in a few places but it should disappear at some point as the classes define their own working directory. :rtype: :py:class:`waflib.Node.Node` """ return self.bld.bldnode def get_name(self): """ If the attribute ``name`` is not set on the instance, the name is computed from the target name:: def build(bld): x = bld(name='foo') x.get_name() # foo y = bld(target='bar') y.get_name() # bar :rtype: string :return: name of this task generator """ try: return self._name except AttributeError: if isinstance(self.target, list): lst = [str(x) for x in self.target] name = self._name = ','.join(lst) else: name = self._name = str(self.target) return name def set_name(self, name): self._name = name name = property(get_name, set_name) def to_list(self, val): """ Ensures that a parameter is a list, see :py:func:`waflib.Utils.to_list` :type val: string or list of string :param val: input to return as a list :rtype: list """ if isinstance(val, str): return val.split() else: return val def post(self): """ Creates tasks for this task generators. The following operations are performed: #. The body of this method is called only once and sets the attribute ``posted`` #. The attribute ``features`` is used to add more methods in ``self.meths`` #. The methods are sorted by the precedence table ``self.prec`` or `:waflib:attr:waflib.TaskGen.task_gen.prec` #. The methods are then executed in order #. The tasks created are added to :py:attr:`waflib.TaskGen.task_gen.tasks` """ if getattr(self, 'posted', None): return False self.posted = True keys = set(self.meths) keys.update(feats['*']) # add the methods listed in the features self.features = Utils.to_list(self.features) for x in self.features: st = feats[x] if st: keys.update(st) elif not x in Task.classes: Logs.warn('feature %r does not exist - bind at least one method to it?', x) # copy the precedence table prec = {} prec_tbl = self.prec for x in prec_tbl: if x in keys: prec[x] = prec_tbl[x] # elements disconnected tmp = [] for a in keys: for x in prec.values(): if a in x: break else: tmp.append(a) tmp.sort(reverse=True) # topological sort out = [] while tmp: e = tmp.pop() if e in keys: out.append(e) try: nlst = prec[e] except KeyError: pass else: del prec[e] for x in nlst: for y in prec: if x in prec[y]: break else: tmp.append(x) tmp.sort(reverse=True) if prec: buf = ['Cycle detected in the method execution:'] for k, v in prec.items(): buf.append('- %s after %s' % (k, [x for x in v if x in prec])) raise Errors.WafError('\n'.join(buf)) self.meths = out # then we run the methods in order Logs.debug('task_gen: posting %s %d', self, id(self)) for x in out: try: v = getattr(self, x) except AttributeError: raise Errors.WafError('%r is not a valid task generator method' % x) Logs.debug('task_gen: -> %s (%d)', x, id(self)) v() Logs.debug('task_gen: posted %s', self.name) return True def get_hook(self, node): """ Returns the ``@extension`` method to call for a Node of a particular extension. :param node: Input file to process :type node: :py:class:`waflib.Tools.Node.Node` :return: A method able to process the input node by looking at the extension :rtype: function """ name = node.name for k in self.mappings: try: if name.endswith(k): return self.mappings[k] except TypeError: # regexps objects if k.match(name): return self.mappings[k] keys = list(self.mappings.keys()) raise Errors.WafError("File %r has no mapping in %r (load a waf tool?)" % (node, keys)) def create_task(self, name, src=None, tgt=None, **kw): """ Creates task instances. :param name: task class name :type name: string :param src: input nodes :type src: list of :py:class:`waflib.Tools.Node.Node` :param tgt: output nodes :type tgt: list of :py:class:`waflib.Tools.Node.Node` :return: A task object :rtype: :py:class:`waflib.Task.Task` """ task = Task.classes[name](env=self.env.derive(), generator=self) if src: task.set_inputs(src) if tgt: task.set_outputs(tgt) task.__dict__.update(kw) self.tasks.append(task) return task def clone(self, env): """ Makes a copy of a task generator. Once the copy is made, it is necessary to ensure that the it does not create the same output files as the original, or the same files may be compiled several times. :param env: A configuration set :type env: :py:class:`waflib.ConfigSet.ConfigSet` :return: A copy :rtype: :py:class:`waflib.TaskGen.task_gen` """ newobj = self.bld() for x in self.__dict__: if x in ('env', 'bld'): continue elif x in ('path', 'features'): setattr(newobj, x, getattr(self, x)) else: setattr(newobj, x, copy.copy(getattr(self, x))) newobj.posted = False if isinstance(env, str): newobj.env = self.bld.all_envs[env].derive() else: newobj.env = env.derive() return newobj def declare_chain(name='', rule=None, reentrant=None, color='BLUE', ext_in=[], ext_out=[], before=[], after=[], decider=None, scan=None, install_path=None, shell=False): """ Creates a new mapping and a task class for processing files by extension. See Tools/flex.py for an example. :param name: name for the task class :type name: string :param rule: function to execute or string to be compiled in a function :type rule: string or function :param reentrant: re-inject the output file in the process (done automatically, set to 0 to disable) :type reentrant: int :param color: color for the task output :type color: string :param ext_in: execute the task only after the files of such extensions are created :type ext_in: list of string :param ext_out: execute the task only before files of such extensions are processed :type ext_out: list of string :param before: execute instances of this task before classes of the given names :type before: list of string :param after: execute instances of this task after classes of the given names :type after: list of string :param decider: if present, function that returns a list of output file extensions (overrides ext_out for output files, but not for the build order) :type decider: function :param scan: scanner function for the task :type scan: function :param install_path: installation path for the output nodes :type install_path: string """ ext_in = Utils.to_list(ext_in) ext_out = Utils.to_list(ext_out) if not name: name = rule cls = Task.task_factory(name, rule, color=color, ext_in=ext_in, ext_out=ext_out, before=before, after=after, scan=scan, shell=shell) def x_file(self, node): if ext_in: _ext_in = ext_in[0] tsk = self.create_task(name, node) cnt = 0 ext = decider(self, node) if decider else cls.ext_out for x in ext: k = node.change_ext(x, ext_in=_ext_in) tsk.outputs.append(k) if reentrant != None: if cnt < int(reentrant): self.source.append(k) else: # reinject downstream files into the build for y in self.mappings: # ~ nfile * nextensions :-/ if k.name.endswith(y): self.source.append(k) break cnt += 1 if install_path: self.install_task = self.add_install_files(install_to=install_path, install_from=tsk.outputs) return tsk for x in cls.ext_in: task_gen.mappings[x] = x_file return x_file def taskgen_method(func): """ Decorator that registers method as a task generator method. The function must accept a task generator as first parameter:: from waflib.TaskGen import taskgen_method @taskgen_method def mymethod(self): pass :param func: task generator method to add :type func: function :rtype: function """ setattr(task_gen, func.__name__, func) return func def feature(*k): """ Decorator that registers a task generator method that will be executed when the object attribute ``feature`` contains the corresponding key(s):: from waflib.TaskGen import feature @feature('myfeature') def myfunction(self): print('that is my feature!') def build(bld): bld(features='myfeature') :param k: feature names :type k: list of string """ def deco(func): setattr(task_gen, func.__name__, func) for name in k: feats[name].update([func.__name__]) return func return deco def before_method(*k): """ Decorator that registera task generator method which will be executed before the functions of given name(s):: from waflib.TaskGen import feature, before @feature('myfeature') @before_method('fun2') def fun1(self): print('feature 1!') @feature('myfeature') def fun2(self): print('feature 2!') def build(bld): bld(features='myfeature') :param k: method names :type k: list of string """ def deco(func): setattr(task_gen, func.__name__, func) for fun_name in k: task_gen.prec[func.__name__].add(fun_name) return func return deco before = before_method def after_method(*k): """ Decorator that registers a task generator method which will be executed after the functions of given name(s):: from waflib.TaskGen import feature, after @feature('myfeature') @after_method('fun2') def fun1(self): print('feature 1!') @feature('myfeature') def fun2(self): print('feature 2!') def build(bld): bld(features='myfeature') :param k: method names :type k: list of string """ def deco(func): setattr(task_gen, func.__name__, func) for fun_name in k: task_gen.prec[fun_name].add(func.__name__) return func return deco after = after_method def extension(*k): """ Decorator that registers a task generator method which will be invoked during the processing of source files for the extension given:: from waflib import Task class mytask(Task): run_str = 'cp ${SRC} ${TGT}' @extension('.moo') def create_maa_file(self, node): self.create_task('mytask', node, node.change_ext('.maa')) def build(bld): bld(source='foo.moo') """ def deco(func): setattr(task_gen, func.__name__, func) for x in k: task_gen.mappings[x] = func return func return deco @taskgen_method def to_nodes(self, lst, path=None): """ Flatten the input list of string/nodes/lists into a list of nodes. It is used by :py:func:`waflib.TaskGen.process_source` and :py:func:`waflib.TaskGen.process_rule`. It is designed for source files, for folders, see :py:func:`waflib.Tools.ccroot.to_incnodes`: :param lst: input list :type lst: list of string and nodes :param path: path from which to search the nodes (by default, :py:attr:`waflib.TaskGen.task_gen.path`) :type path: :py:class:`waflib.Tools.Node.Node` :rtype: list of :py:class:`waflib.Tools.Node.Node` """ tmp = [] path = path or self.path find = path.find_resource if isinstance(lst, Node.Node): lst = [lst] for x in Utils.to_list(lst): if isinstance(x, str): node = find(x) elif hasattr(x, 'name'): node = x else: tmp.extend(self.to_nodes(x)) continue if not node: raise Errors.WafError('source not found: %r in %r' % (x, self)) tmp.append(node) return tmp @feature('*') def process_source(self): """ Processes each element in the attribute ``source`` by extension. #. The *source* list is converted through :py:meth:`waflib.TaskGen.to_nodes` to a list of :py:class:`waflib.Node.Node` first. #. File extensions are mapped to methods having the signature: ``def meth(self, node)`` by :py:meth:`waflib.TaskGen.extension` #. The method is retrieved through :py:meth:`waflib.TaskGen.task_gen.get_hook` #. When called, the methods may modify self.source to append more source to process #. The mappings can map an extension or a filename (see the code below) """ self.source = self.to_nodes(getattr(self, 'source', [])) for node in self.source: self.get_hook(node)(self, node) @feature('*') @before_method('process_source') def process_rule(self): """ Processes the attribute ``rule``. When present, :py:meth:`waflib.TaskGen.process_source` is disabled:: def build(bld): bld(rule='cp ${SRC} ${TGT}', source='wscript', target='bar.txt') Main attributes processed: * rule: command to execute, it can be a tuple of strings for multiple commands * chmod: permissions for the resulting files (integer value such as Utils.O755) * shell: set to False to execute the command directly (default is True to use a shell) * scan: scanner function * vars: list of variables to trigger rebuilds, such as CFLAGS * cls_str: string to display when executing the task * cls_keyword: label to display when executing the task * cache_rule: by default, try to re-use similar classes, set to False to disable * source: list of Node or string objects representing the source files required by this task * target: list of Node or string objects representing the files that this task creates * cwd: current working directory (Node or string) * stdout: standard output, set to None to prevent waf from capturing the text * stderr: standard error, set to None to prevent waf from capturing the text * timeout: timeout for command execution (Python 3) * always: whether to always run the command (False by default) * deep_inputs: whether the task must depend on the input file tasks too (False by default) """ if not getattr(self, 'rule', None): return # create the task class name = str(getattr(self, 'name', None) or self.target or getattr(self.rule, '__name__', self.rule)) # or we can put the class in a cache for performance reasons try: cache = self.bld.cache_rule_attr except AttributeError: cache = self.bld.cache_rule_attr = {} chmod = getattr(self, 'chmod', None) shell = getattr(self, 'shell', True) color = getattr(self, 'color', 'BLUE') scan = getattr(self, 'scan', None) _vars = getattr(self, 'vars', []) cls_str = getattr(self, 'cls_str', None) cls_keyword = getattr(self, 'cls_keyword', None) use_cache = getattr(self, 'cache_rule', 'True') deep_inputs = getattr(self, 'deep_inputs', False) scan_val = has_deps = hasattr(self, 'deps') if scan: scan_val = id(scan) key = Utils.h_list((name, self.rule, chmod, shell, color, cls_str, cls_keyword, scan_val, _vars, deep_inputs)) cls = None if use_cache: try: cls = cache[key] except KeyError: pass if not cls: rule = self.rule if chmod is not None: def chmod_fun(tsk): for x in tsk.outputs: os.chmod(x.abspath(), tsk.generator.chmod) if isinstance(rule, tuple): rule = list(rule) rule.append(chmod_fun) rule = tuple(rule) else: rule = (rule, chmod_fun) cls = Task.task_factory(name, rule, _vars, shell=shell, color=color) if cls_str: setattr(cls, '__str__', self.cls_str) if cls_keyword: setattr(cls, 'keyword', self.cls_keyword) if deep_inputs: Task.deep_inputs(cls) if scan: cls.scan = self.scan elif has_deps: def scan(self): deps = getattr(self.generator, 'deps', None) nodes = self.generator.to_nodes(deps) return [nodes, []] cls.scan = scan if use_cache: cache[key] = cls # now create one instance tsk = self.create_task(name) for x in ('after', 'before', 'ext_in', 'ext_out'): setattr(tsk, x, getattr(self, x, [])) if hasattr(self, 'stdout'): tsk.stdout = self.stdout if hasattr(self, 'stderr'): tsk.stderr = self.stderr if getattr(self, 'timeout', None): tsk.timeout = self.timeout if getattr(self, 'always', None): tsk.always_run = True if getattr(self, 'target', None): if isinstance(self.target, str): self.target = self.target.split() if not isinstance(self.target, list): self.target = [self.target] for x in self.target: if isinstance(x, str): tsk.outputs.append(self.path.find_or_declare(x)) else: x.parent.mkdir() # if a node was given, create the required folders tsk.outputs.append(x) if getattr(self, 'install_path', None): self.install_task = self.add_install_files(install_to=self.install_path, install_from=tsk.outputs, chmod=getattr(self, 'chmod', Utils.O644)) if getattr(self, 'source', None): tsk.inputs = self.to_nodes(self.source) # bypass the execution of process_source by setting the source to an empty list self.source = [] if getattr(self, 'cwd', None): tsk.cwd = self.cwd if isinstance(tsk.run, functools.partial): # Python documentation says: "partial objects defined in classes # behave like static methods and do not transform into bound # methods during instance attribute look-up." tsk.run = functools.partial(tsk.run, tsk) @feature('seq') def sequence_order(self): """ Adds a strict sequential constraint between the tasks generated by task generators. It works because task generators are posted in order. It will not post objects which belong to other folders. Example:: bld(features='javac seq') bld(features='jar seq') To start a new sequence, set the attribute seq_start, for example:: obj = bld(features='seq') obj.seq_start = True Note that the method is executed in last position. This is more an example than a widely-used solution. """ if self.meths and self.meths[-1] != 'sequence_order': self.meths.append('sequence_order') return if getattr(self, 'seq_start', None): return # all the tasks previously declared must be run before these if getattr(self.bld, 'prev', None): self.bld.prev.post() for x in self.bld.prev.tasks: for y in self.tasks: y.set_run_after(x) self.bld.prev = self re_m4 = re.compile(r'@(\w+)@', re.M) class subst_pc(Task.Task): """ Creates *.pc* files from *.pc.in*. The task is executed whenever an input variable used in the substitution changes. """ def force_permissions(self): "Private for the time being, we will probably refactor this into run_str=[run1,chmod]" if getattr(self.generator, 'chmod', None): for x in self.outputs: os.chmod(x.abspath(), self.generator.chmod) def run(self): "Substitutes variables in a .in file" if getattr(self.generator, 'is_copy', None): for i, x in enumerate(self.outputs): x.write(self.inputs[i].read('rb'), 'wb') stat = os.stat(self.inputs[i].abspath()) # Preserve mtime of the copy os.utime(self.outputs[i].abspath(), (stat.st_atime, stat.st_mtime)) self.force_permissions() return None if getattr(self.generator, 'fun', None): ret = self.generator.fun(self) if not ret: self.force_permissions() return ret code = self.inputs[0].read(encoding=getattr(self.generator, 'encoding', 'latin-1')) if getattr(self.generator, 'subst_fun', None): code = self.generator.subst_fun(self, code) if code is not None: self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'latin-1')) self.force_permissions() return None # replace all % by %% to prevent errors by % signs code = code.replace('%', '%%') # extract the vars foo into lst and replace @foo@ by %(foo)s lst = [] def repl(match): g = match.group if g(1): lst.append(g(1)) return "%%(%s)s" % g(1) return '' code = getattr(self.generator, 're_m4', re_m4).sub(repl, code) try: d = self.generator.dct except AttributeError: d = {} for x in lst: tmp = getattr(self.generator, x, '') or self.env[x] or self.env[x.upper()] try: tmp = ''.join(tmp) except TypeError: tmp = str(tmp) d[x] = tmp code = code % d self.outputs[0].write(code, encoding=getattr(self.generator, 'encoding', 'latin-1')) self.generator.bld.raw_deps[self.uid()] = lst # make sure the signature is updated try: delattr(self, 'cache_sig') except AttributeError: pass self.force_permissions() def sig_vars(self): """ Compute a hash (signature) of the variables used in the substitution """ bld = self.generator.bld env = self.env upd = self.m.update if getattr(self.generator, 'fun', None): upd(Utils.h_fun(self.generator.fun).encode()) if getattr(self.generator, 'subst_fun', None): upd(Utils.h_fun(self.generator.subst_fun).encode()) # raw_deps: persistent custom values returned by the scanner vars = self.generator.bld.raw_deps.get(self.uid(), []) # hash both env vars and task generator attributes act_sig = bld.hash_env_vars(env, vars) upd(act_sig) lst = [getattr(self.generator, x, '') for x in vars] upd(Utils.h_list(lst)) return self.m.digest() @extension('.pc.in') def add_pcfile(self, node): """ Processes *.pc.in* files to *.pc*. Installs the results to ``${PREFIX}/lib/pkgconfig/`` by default def build(bld): bld(source='foo.pc.in', install_path='${LIBDIR}/pkgconfig/') """ tsk = self.create_task('subst_pc', node, node.change_ext('.pc', '.pc.in')) self.install_task = self.add_install_files( install_to=getattr(self, 'install_path', '${LIBDIR}/pkgconfig/'), install_from=tsk.outputs) class subst(subst_pc): pass @feature('subst') @before_method('process_source', 'process_rule') def process_subst(self): """ Defines a transformation that substitutes the contents of *source* files to *target* files:: def build(bld): bld( features='subst', source='foo.c.in', target='foo.c', install_path='${LIBDIR}/pkgconfig', VAR = 'val' ) The input files are supposed to contain macros of the form *@VAR@*, where *VAR* is an argument of the task generator object. This method overrides the processing by :py:meth:`waflib.TaskGen.process_source`. """ src = Utils.to_list(getattr(self, 'source', [])) if isinstance(src, Node.Node): src = [src] tgt = Utils.to_list(getattr(self, 'target', [])) if isinstance(tgt, Node.Node): tgt = [tgt] if len(src) != len(tgt): raise Errors.WafError('invalid number of source/target for %r' % self) for x, y in zip(src, tgt): if not x or not y: raise Errors.WafError('null source or target for %r' % self) a, b = None, None if isinstance(x, str) and isinstance(y, str) and x == y: a = self.path.find_node(x) b = self.path.get_bld().make_node(y) if not os.path.isfile(b.abspath()): b.parent.mkdir() else: if isinstance(x, str): a = self.path.find_resource(x) elif isinstance(x, Node.Node): a = x if isinstance(y, str): b = self.path.find_or_declare(y) elif isinstance(y, Node.Node): b = y if not a: raise Errors.WafError('could not find %r for %r' % (x, self)) tsk = self.create_task('subst', a, b) for k in ('after', 'before', 'ext_in', 'ext_out'): val = getattr(self, k, None) if val: setattr(tsk, k, val) # paranoid safety measure for the general case foo.in->foo.h with ambiguous dependencies for xt in HEADER_EXTS: if b.name.endswith(xt): tsk.ext_out = tsk.ext_out + ['.h'] break inst_to = getattr(self, 'install_path', None) if inst_to: self.install_task = self.add_install_files(install_to=inst_to, install_from=b, chmod=getattr(self, 'chmod', Utils.O644)) self.source = [] hamster-3.0.3/waflib/Tools/000077500000000000000000000000001452646177100155415ustar00rootroot00000000000000hamster-3.0.3/waflib/Tools/__init__.py000066400000000000000000000001071452646177100176500ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) hamster-3.0.3/waflib/Tools/ar.py000066400000000000000000000011721452646177100165160ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) """ The **ar** program creates static libraries. This tool is almost always loaded from others (C, C++, D, etc) for static library support. """ from waflib.Configure import conf @conf def find_ar(conf): """Configuration helper used by C/C++ tools to enable the support for static libraries""" conf.load('ar') def configure(conf): """Finds the ar program and sets the default flags in ``conf.env.ARFLAGS``""" conf.find_program('ar', var='AR') conf.add_os_flags('ARFLAGS') if not conf.env.ARFLAGS: conf.env.ARFLAGS = ['rcs'] hamster-3.0.3/waflib/Tools/asm.py000066400000000000000000000052051452646177100166750ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2008-2018 (ita) """ Assembly support, used by tools such as gas and nasm To declare targets using assembly:: def configure(conf): conf.load('gcc gas') def build(bld): bld( features='c cstlib asm', source = 'test.S', target = 'asmtest') bld( features='asm asmprogram', source = 'test.S', target = 'asmtest') Support for pure asm programs and libraries should also work:: def configure(conf): conf.load('nasm') conf.find_program('ld', 'ASLINK') def build(bld): bld( features='asm asmprogram', source = 'test.S', target = 'asmtest') """ import re from waflib import Errors, Logs, Task from waflib.Tools.ccroot import link_task, stlink_task from waflib.TaskGen import extension from waflib.Tools import c_preproc re_lines = re.compile( '^[ \t]*(?:%)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef)[ \t]*(.*)\r*$', re.IGNORECASE | re.MULTILINE) class asm_parser(c_preproc.c_parser): def filter_comments(self, node): code = node.read() code = c_preproc.re_nl.sub('', code) code = c_preproc.re_cpp.sub(c_preproc.repl, code) return re_lines.findall(code) class asm(Task.Task): """ Compiles asm files by gas/nasm/yasm/... """ color = 'BLUE' run_str = '${AS} ${ASFLAGS} ${ASMPATH_ST:INCPATHS} ${ASMDEFINES_ST:DEFINES} ${AS_SRC_F}${SRC} ${AS_TGT_F}${TGT}' def scan(self): if self.env.ASM_NAME == 'gas': return c_preproc.scan(self) elif self.env.ASM_NAME == 'nasm': Logs.warn('The Nasm dependency scanner is incomplete!') try: incn = self.generator.includes_nodes except AttributeError: raise Errors.WafError('%r is missing the "asm" feature' % self.generator) if c_preproc.go_absolute: nodepaths = incn else: nodepaths = [x for x in incn if x.is_child_of(x.ctx.srcnode) or x.is_child_of(x.ctx.bldnode)] tmp = asm_parser(nodepaths) tmp.start(self.inputs[0], self.env) return (tmp.nodes, tmp.names) @extension('.s', '.S', '.asm', '.ASM', '.spp', '.SPP') def asm_hook(self, node): """ Binds the asm extension to the asm task :param node: input file :type node: :py:class:`waflib.Node.Node` """ return self.create_compiled_task('asm', node) class asmprogram(link_task): "Links object files into a c program" run_str = '${ASLINK} ${ASLINKFLAGS} ${ASLNK_TGT_F}${TGT} ${ASLNK_SRC_F}${SRC}' ext_out = ['.bin'] inst_to = '${BINDIR}' class asmshlib(asmprogram): "Links object files into a c shared library" inst_to = '${LIBDIR}' class asmstlib(stlink_task): "Links object files into a c static library" pass # do not remove def configure(conf): conf.env.ASMPATH_ST = '-I%s' conf.env.ASMDEFINES_ST = '-D%s' hamster-3.0.3/waflib/Tools/bison.py000066400000000000000000000022431452646177100172260ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # John O'Meara, 2006 # Thomas Nagy 2009-2018 (ita) """ The **bison** program is a code generator which creates C or C++ files. The generated files are compiled into object files. """ from waflib import Task from waflib.TaskGen import extension class bison(Task.Task): """Compiles bison files""" color = 'BLUE' run_str = '${BISON} ${BISONFLAGS} ${SRC[0].abspath()} -o ${TGT[0].name}' ext_out = ['.h'] # just to make sure @extension('.y', '.yc', '.yy') def big_bison(self, node): """ Creates a bison task, which must be executed from the directory of the output file. """ has_h = '-d' in self.env.BISONFLAGS outs = [] if node.name.endswith('.yc'): outs.append(node.change_ext('.tab.cc')) if has_h: outs.append(node.change_ext('.tab.hh')) else: outs.append(node.change_ext('.tab.c')) if has_h: outs.append(node.change_ext('.tab.h')) tsk = self.create_task('bison', node, outs) tsk.cwd = node.parent.get_bld() # and the c/cxx file must be compiled too self.source.append(outs[0]) def configure(conf): """ Detects the *bison* program """ conf.find_program('bison', var='BISON') conf.env.BISONFLAGS = ['-d'] hamster-3.0.3/waflib/Tools/c.py000066400000000000000000000027711452646177100163440ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) "Base for c programs/libraries" from waflib import TaskGen, Task from waflib.Tools import c_preproc from waflib.Tools.ccroot import link_task, stlink_task @TaskGen.extension('.c') def c_hook(self, node): "Binds the c file extensions create :py:class:`waflib.Tools.c.c` instances" if not self.env.CC and self.env.CXX: return self.create_compiled_task('cxx', node) return self.create_compiled_task('c', node) class c(Task.Task): "Compiles C files into object files" run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CC_SRC_F}${SRC} ${CC_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}' vars = ['CCDEPS'] # unused variable to depend on, just in case ext_in = ['.h'] # set the build order easily by using ext_out=['.h'] scan = c_preproc.scan class cprogram(link_task): "Links object files into c programs" run_str = '${LINK_CC} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LDFLAGS}' ext_out = ['.bin'] vars = ['LINKDEPS'] inst_to = '${BINDIR}' class cshlib(cprogram): "Links object files into c shared libraries" inst_to = '${LIBDIR}' class cstlib(stlink_task): "Links object files into a c static libraries" pass # do not remove hamster-3.0.3/waflib/Tools/c_aliases.py000066400000000000000000000067741452646177100200540ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2015 (ita) "base for all c/c++ programs and libraries" from waflib import Utils, Errors from waflib.Configure import conf def get_extensions(lst): """ Returns the file extensions for the list of files given as input :param lst: files to process :list lst: list of string or :py:class:`waflib.Node.Node` :return: list of file extensions :rtype: list of string """ ret = [] for x in Utils.to_list(lst): if not isinstance(x, str): x = x.name ret.append(x[x.rfind('.') + 1:]) return ret def sniff_features(**kw): """ Computes and returns the features required for a task generator by looking at the file extensions. This aimed for C/C++ mainly:: snif_features(source=['foo.c', 'foo.cxx'], type='shlib') # returns ['cxx', 'c', 'cxxshlib', 'cshlib'] :param source: source files to process :type source: list of string or :py:class:`waflib.Node.Node` :param type: object type in *program*, *shlib* or *stlib* :type type: string :return: the list of features for a task generator processing the source files :rtype: list of string """ exts = get_extensions(kw.get('source', [])) typ = kw['typ'] feats = [] # watch the order, cxx will have the precedence for x in 'cxx cpp c++ cc C'.split(): if x in exts: feats.append('cxx') break if 'c' in exts or 'vala' in exts or 'gs' in exts: feats.append('c') if 's' in exts or 'S' in exts: feats.append('asm') for x in 'f f90 F F90 for FOR'.split(): if x in exts: feats.append('fc') break if 'd' in exts: feats.append('d') if 'java' in exts: feats.append('java') return 'java' if typ in ('program', 'shlib', 'stlib'): will_link = False for x in feats: if x in ('cxx', 'd', 'fc', 'c', 'asm'): feats.append(x + typ) will_link = True if not will_link and not kw.get('features', []): raise Errors.WafError('Unable to determine how to link %r, try adding eg: features="c cshlib"?' % kw) return feats def set_features(kw, typ): """ Inserts data in the input dict *kw* based on existing data and on the type of target required (typ). :param kw: task generator parameters :type kw: dict :param typ: type of target :type typ: string """ kw['typ'] = typ kw['features'] = Utils.to_list(kw.get('features', [])) + Utils.to_list(sniff_features(**kw)) @conf def program(bld, *k, **kw): """ Alias for creating programs by looking at the file extensions:: def build(bld): bld.program(source='foo.c', target='app') # equivalent to: # bld(features='c cprogram', source='foo.c', target='app') """ set_features(kw, 'program') return bld(*k, **kw) @conf def shlib(bld, *k, **kw): """ Alias for creating shared libraries by looking at the file extensions:: def build(bld): bld.shlib(source='foo.c', target='app') # equivalent to: # bld(features='c cshlib', source='foo.c', target='app') """ set_features(kw, 'shlib') return bld(*k, **kw) @conf def stlib(bld, *k, **kw): """ Alias for creating static libraries by looking at the file extensions:: def build(bld): bld.stlib(source='foo.cpp', target='app') # equivalent to: # bld(features='cxx cxxstlib', source='foo.cpp', target='app') """ set_features(kw, 'stlib') return bld(*k, **kw) @conf def objects(bld, *k, **kw): """ Alias for creating object files by looking at the file extensions:: def build(bld): bld.objects(source='foo.c', target='app') # equivalent to: # bld(features='c', source='foo.c', target='app') """ set_features(kw, 'objects') return bld(*k, **kw) hamster-3.0.3/waflib/Tools/c_config.py000066400000000000000000001220121452646177100176600ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ C/C++/D configuration helpers """ from __future__ import with_statement import os, re, shlex from waflib import Build, Utils, Task, Options, Logs, Errors, Runner from waflib.TaskGen import after_method, feature from waflib.Configure import conf WAF_CONFIG_H = 'config.h' """default name for the config.h file""" DEFKEYS = 'define_key' INCKEYS = 'include_key' SNIP_EMPTY_PROGRAM = ''' int main(int argc, char **argv) { (void)argc; (void)argv; return 0; } ''' MACRO_TO_DESTOS = { '__linux__' : 'linux', '__GNU__' : 'gnu', # hurd '__FreeBSD__' : 'freebsd', '__NetBSD__' : 'netbsd', '__OpenBSD__' : 'openbsd', '__sun' : 'sunos', '__hpux' : 'hpux', '__sgi' : 'irix', '_AIX' : 'aix', '__CYGWIN__' : 'cygwin', '__MSYS__' : 'cygwin', '_UWIN' : 'uwin', '_WIN64' : 'win32', '_WIN32' : 'win32', # Note about darwin: this is also tested with 'defined __APPLE__ && defined __MACH__' somewhere below in this file. '__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__' : 'darwin', '__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__' : 'darwin', # iphone '__QNX__' : 'qnx', '__native_client__' : 'nacl' # google native client platform } MACRO_TO_DEST_CPU = { '__x86_64__' : 'x86_64', '__amd64__' : 'x86_64', '__i386__' : 'x86', '__ia64__' : 'ia', '__mips__' : 'mips', '__sparc__' : 'sparc', '__alpha__' : 'alpha', '__aarch64__' : 'aarch64', '__thumb__' : 'thumb', '__arm__' : 'arm', '__hppa__' : 'hppa', '__powerpc__' : 'powerpc', '__ppc__' : 'powerpc', '__convex__' : 'convex', '__m68k__' : 'm68k', '__s390x__' : 's390x', '__s390__' : 's390', '__sh__' : 'sh', '__xtensa__' : 'xtensa', '__e2k__' : 'e2k', '__riscv' : 'riscv', } @conf def parse_flags(self, line, uselib_store, env=None, force_static=False, posix=None): """ Parses flags from the input lines, and adds them to the relevant use variables:: def configure(conf): conf.parse_flags('-O3', 'FOO') # conf.env.CXXFLAGS_FOO = ['-O3'] # conf.env.CFLAGS_FOO = ['-O3'] :param line: flags :type line: string :param uselib_store: where to add the flags :type uselib_store: string :param env: config set or conf.env by default :type env: :py:class:`waflib.ConfigSet.ConfigSet` :param force_static: force usage of static libraries :type force_static: bool default False :param posix: usage of POSIX mode for shlex lexical analiysis library :type posix: bool default True """ assert(isinstance(line, str)) env = env or self.env # Issue 811 and 1371 if posix is None: posix = True if '\\' in line: posix = ('\\ ' in line) or ('\\\\' in line) lex = shlex.shlex(line, posix=posix) lex.whitespace_split = True lex.commenters = '' lst = list(lex) so_re = re.compile(r"\.so(?:\.[0-9]+)*$") # append_unique is not always possible # for example, apple flags may require both -arch i386 and -arch ppc uselib = uselib_store def app(var, val): env.append_value('%s_%s' % (var, uselib), val) def appu(var, val): env.append_unique('%s_%s' % (var, uselib), val) static = False while lst: x = lst.pop(0) st = x[:2] ot = x[2:] if st == '-I' or st == '/I': if not ot: ot = lst.pop(0) appu('INCLUDES', ot) elif st == '-i': tmp = [x, lst.pop(0)] app('CFLAGS', tmp) app('CXXFLAGS', tmp) elif st == '-D' or (env.CXX_NAME == 'msvc' and st == '/D'): # not perfect but.. if not ot: ot = lst.pop(0) app('DEFINES', ot) elif st == '-l': if not ot: ot = lst.pop(0) prefix = 'STLIB' if (force_static or static) else 'LIB' app(prefix, ot) elif st == '-L': if not ot: ot = lst.pop(0) prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH' appu(prefix, ot) elif x.startswith('/LIBPATH:'): prefix = 'STLIBPATH' if (force_static or static) else 'LIBPATH' appu(prefix, x.replace('/LIBPATH:', '')) elif x.startswith('-std='): prefix = 'CXXFLAGS' if '++' in x else 'CFLAGS' app(prefix, x) elif x.startswith('+') or x in ('-pthread', '-fPIC', '-fpic', '-fPIE', '-fpie', '-flto', '-fno-lto'): app('CFLAGS', x) app('CXXFLAGS', x) app('LINKFLAGS', x) elif x == '-framework': appu('FRAMEWORK', lst.pop(0)) elif x.startswith('-F'): appu('FRAMEWORKPATH', x[2:]) elif x == '-Wl,-rpath' or x == '-Wl,-R': app('RPATH', lst.pop(0).lstrip('-Wl,')) elif x.startswith('-Wl,-R,'): app('RPATH', x[7:]) elif x.startswith('-Wl,-R'): app('RPATH', x[6:]) elif x.startswith('-Wl,-rpath,'): app('RPATH', x[11:]) elif x == '-Wl,-Bstatic' or x == '-Bstatic': static = True elif x == '-Wl,-Bdynamic' or x == '-Bdynamic': static = False elif x.startswith('-Wl') or x in ('-rdynamic', '-pie'): app('LINKFLAGS', x) elif x.startswith(('-m', '-f', '-dynamic', '-O', '-g')): # Adding the -W option breaks python builds on Openindiana app('CFLAGS', x) app('CXXFLAGS', x) elif x.startswith('-bundle'): app('LINKFLAGS', x) elif x.startswith(('-undefined', '-Xlinker')): arg = lst.pop(0) app('LINKFLAGS', [x, arg]) elif x.startswith(('-arch', '-isysroot')): tmp = [x, lst.pop(0)] app('CFLAGS', tmp) app('CXXFLAGS', tmp) app('LINKFLAGS', tmp) elif x.endswith(('.a', '.dylib', '.lib')) or so_re.search(x): appu('LINKFLAGS', x) # not cool, #762 else: self.to_log('Unhandled flag %r' % x) @conf def validate_cfg(self, kw): """ Searches for the program *pkg-config* if missing, and validates the parameters to pass to :py:func:`waflib.Tools.c_config.exec_cfg`. :param path: the **-config program to use** (default is *pkg-config*) :type path: list of string :param msg: message to display to describe the test executed :type msg: string :param okmsg: message to display when the test is successful :type okmsg: string :param errmsg: message to display in case of error :type errmsg: string """ if not 'path' in kw: if not self.env.PKGCONFIG: self.find_program('pkg-config', var='PKGCONFIG') kw['path'] = self.env.PKGCONFIG # verify that exactly one action is requested s = ('atleast_pkgconfig_version' in kw) + ('modversion' in kw) + ('package' in kw) if s != 1: raise ValueError('exactly one of atleast_pkgconfig_version, modversion and package must be set') if not 'msg' in kw: if 'atleast_pkgconfig_version' in kw: kw['msg'] = 'Checking for pkg-config version >= %r' % kw['atleast_pkgconfig_version'] elif 'modversion' in kw: kw['msg'] = 'Checking for %r version' % kw['modversion'] else: kw['msg'] = 'Checking for %r' %(kw['package']) # let the modversion check set the okmsg to the detected version if not 'okmsg' in kw and not 'modversion' in kw: kw['okmsg'] = 'yes' if not 'errmsg' in kw: kw['errmsg'] = 'not found' # pkg-config version if 'atleast_pkgconfig_version' in kw: pass elif 'modversion' in kw: if not 'uselib_store' in kw: kw['uselib_store'] = kw['modversion'] if not 'define_name' in kw: kw['define_name'] = '%s_VERSION' % Utils.quote_define_name(kw['uselib_store']) else: if not 'uselib_store' in kw: kw['uselib_store'] = Utils.to_list(kw['package'])[0].upper() if not 'define_name' in kw: kw['define_name'] = self.have_define(kw['uselib_store']) @conf def exec_cfg(self, kw): """ Executes ``pkg-config`` or other ``-config`` applications to collect configuration flags: * if atleast_pkgconfig_version is given, check that pkg-config has the version n and return * if modversion is given, then return the module version * else, execute the *-config* program with the *args* and *variables* given, and set the flags on the *conf.env.FLAGS_name* variable :param path: the **-config program to use** :type path: list of string :param atleast_pkgconfig_version: minimum pkg-config version to use (disable other tests) :type atleast_pkgconfig_version: string :param package: package name, for example *gtk+-2.0* :type package: string :param uselib_store: if the test is successful, define HAVE\\_*name*. It is also used to define *conf.env.FLAGS_name* variables. :type uselib_store: string :param modversion: if provided, return the version of the given module and define *name*\\_VERSION :type modversion: string :param args: arguments to give to *package* when retrieving flags :type args: list of string :param variables: return the values of particular variables :type variables: list of string :param define_variable: additional variables to define (also in conf.env.PKG_CONFIG_DEFINES) :type define_variable: dict(string: string) :param pkg_config_path: paths where pkg-config should search for .pc config files (overrides env.PKG_CONFIG_PATH if exists) :type pkg_config_path: string, list of directories separated by colon :param force_static: force usage of static libraries :type force_static: bool default False :param posix: usage of POSIX mode for shlex lexical analiysis library :type posix: bool default True """ path = Utils.to_list(kw['path']) env = self.env.env or None if kw.get('pkg_config_path'): if not env: env = dict(self.environ) env['PKG_CONFIG_PATH'] = kw['pkg_config_path'] def define_it(): define_name = kw['define_name'] # by default, add HAVE_X to the config.h, else provide DEFINES_X for use=X if kw.get('global_define', 1): self.define(define_name, 1, False) else: self.env.append_unique('DEFINES_%s' % kw['uselib_store'], "%s=1" % define_name) if kw.get('add_have_to_env', 1): self.env[define_name] = 1 # pkg-config version if 'atleast_pkgconfig_version' in kw: cmd = path + ['--atleast-pkgconfig-version=%s' % kw['atleast_pkgconfig_version']] self.cmd_and_log(cmd, env=env) return # single version for a module if 'modversion' in kw: version = self.cmd_and_log(path + ['--modversion', kw['modversion']], env=env).strip() if not 'okmsg' in kw: kw['okmsg'] = version self.define(kw['define_name'], version) return version lst = [] + path defi = kw.get('define_variable') if not defi: defi = self.env.PKG_CONFIG_DEFINES or {} for key, val in defi.items(): lst.append('--define-variable=%s=%s' % (key, val)) static = kw.get('force_static', False) if 'args' in kw: args = Utils.to_list(kw['args']) if '--static' in args or '--static-libs' in args: static = True lst += args # tools like pkgconf expect the package argument after the -- ones -_- lst.extend(Utils.to_list(kw['package'])) # retrieving variables of a module if 'variables' in kw: v_env = kw.get('env', self.env) vars = Utils.to_list(kw['variables']) for v in vars: val = self.cmd_and_log(lst + ['--variable=' + v], env=env).strip() var = '%s_%s' % (kw['uselib_store'], v) v_env[var] = val return # so we assume the command-line will output flags to be parsed afterwards ret = self.cmd_and_log(lst, env=env) define_it() self.parse_flags(ret, kw['uselib_store'], kw.get('env', self.env), force_static=static, posix=kw.get('posix')) return ret @conf def check_cfg(self, *k, **kw): """ Checks for configuration flags using a **-config**-like program (pkg-config, sdl-config, etc). This wraps internal calls to :py:func:`waflib.Tools.c_config.validate_cfg` and :py:func:`waflib.Tools.c_config.exec_cfg` so check exec_cfg parameters descriptions for more details on kw passed A few examples:: def configure(conf): conf.load('compiler_c') conf.check_cfg(package='glib-2.0', args='--libs --cflags') conf.check_cfg(package='pango') conf.check_cfg(package='pango', uselib_store='MYPANGO', args=['--cflags', '--libs']) conf.check_cfg(package='pango', args=['pango >= 0.1.0', 'pango < 9.9.9', '--cflags', '--libs'], msg="Checking for 'pango 0.1.0'") conf.check_cfg(path='sdl-config', args='--cflags --libs', package='', uselib_store='SDL') conf.check_cfg(path='mpicc', args='--showme:compile --showme:link', package='', uselib_store='OPEN_MPI', mandatory=False) # variables conf.check_cfg(package='gtk+-2.0', variables=['includedir', 'prefix'], uselib_store='FOO') print(conf.env.FOO_includedir) """ self.validate_cfg(kw) if 'msg' in kw: self.start_msg(kw['msg'], **kw) ret = None try: ret = self.exec_cfg(kw) except self.errors.WafError as e: if 'errmsg' in kw: self.end_msg(kw['errmsg'], 'YELLOW', **kw) if Logs.verbose > 1: self.to_log('Command failure: %s' % e) self.fatal('The configuration failed') else: if not ret: ret = True kw['success'] = ret if 'okmsg' in kw: self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw) return ret def build_fun(bld): """ Build function that is used for running configuration tests with ``conf.check()`` """ if bld.kw['compile_filename']: node = bld.srcnode.make_node(bld.kw['compile_filename']) node.write(bld.kw['code']) o = bld(features=bld.kw['features'], source=bld.kw['compile_filename'], target='testprog') for k, v in bld.kw.items(): setattr(o, k, v) if not bld.kw.get('quiet'): bld.conf.to_log("==>\n%s\n<==" % bld.kw['code']) @conf def validate_c(self, kw): """ Pre-checks the parameters that will be given to :py:func:`waflib.Configure.run_build` :param compiler: c or cxx (tries to guess what is best) :type compiler: string :param type: cprogram, cshlib, cstlib - not required if *features are given directly* :type type: binary to create :param feature: desired features for the task generator that will execute the test, for example ``cxx cxxstlib`` :type feature: list of string :param fragment: provide a piece of code for the test (default is to let the system create one) :type fragment: string :param uselib_store: define variables after the test is executed (IMPORTANT!) :type uselib_store: string :param use: parameters to use for building (just like the normal *use* keyword) :type use: list of string :param define_name: define to set when the check is over :type define_name: string :param execute: execute the resulting binary :type execute: bool :param define_ret: if execute is set to True, use the execution output in both the define and the return value :type define_ret: bool :param header_name: check for a particular header :type header_name: string :param auto_add_header_name: if header_name was set, add the headers in env.INCKEYS so the next tests will include these headers :type auto_add_header_name: bool """ for x in ('type_name', 'field_name', 'function_name'): if x in kw: Logs.warn('Invalid argument %r in test' % x) if not 'build_fun' in kw: kw['build_fun'] = build_fun if not 'env' in kw: kw['env'] = self.env.derive() env = kw['env'] if not 'compiler' in kw and not 'features' in kw: kw['compiler'] = 'c' if env.CXX_NAME and Task.classes.get('cxx'): kw['compiler'] = 'cxx' if not self.env.CXX: self.fatal('a c++ compiler is required') else: if not self.env.CC: self.fatal('a c compiler is required') if not 'compile_mode' in kw: kw['compile_mode'] = 'c' if 'cxx' in Utils.to_list(kw.get('features', [])) or kw.get('compiler') == 'cxx': kw['compile_mode'] = 'cxx' if not 'type' in kw: kw['type'] = 'cprogram' if not 'features' in kw: if not 'header_name' in kw or kw.get('link_header_test', True): kw['features'] = [kw['compile_mode'], kw['type']] # "c ccprogram" else: kw['features'] = [kw['compile_mode']] else: kw['features'] = Utils.to_list(kw['features']) if not 'compile_filename' in kw: kw['compile_filename'] = 'test.c' + ((kw['compile_mode'] == 'cxx') and 'pp' or '') def to_header(dct): if 'header_name' in dct: dct = Utils.to_list(dct['header_name']) return ''.join(['#include <%s>\n' % x for x in dct]) return '' if 'framework_name' in kw: # OSX, not sure this is used anywhere fwkname = kw['framework_name'] if not 'uselib_store' in kw: kw['uselib_store'] = fwkname.upper() if not kw.get('no_header'): fwk = '%s/%s.h' % (fwkname, fwkname) if kw.get('remove_dot_h'): fwk = fwk[:-2] val = kw.get('header_name', []) kw['header_name'] = Utils.to_list(val) + [fwk] kw['msg'] = 'Checking for framework %s' % fwkname kw['framework'] = fwkname elif 'header_name' in kw: if not 'msg' in kw: kw['msg'] = 'Checking for header %s' % kw['header_name'] l = Utils.to_list(kw['header_name']) assert len(l), 'list of headers in header_name is empty' kw['code'] = to_header(kw) + SNIP_EMPTY_PROGRAM if not 'uselib_store' in kw: kw['uselib_store'] = l[0].upper() if not 'define_name' in kw: kw['define_name'] = self.have_define(l[0]) if 'lib' in kw: if not 'msg' in kw: kw['msg'] = 'Checking for library %s' % kw['lib'] if not 'uselib_store' in kw: kw['uselib_store'] = kw['lib'].upper() if 'stlib' in kw: if not 'msg' in kw: kw['msg'] = 'Checking for static library %s' % kw['stlib'] if not 'uselib_store' in kw: kw['uselib_store'] = kw['stlib'].upper() if 'fragment' in kw: # an additional code fragment may be provided to replace the predefined code # in custom headers kw['code'] = kw['fragment'] if not 'msg' in kw: kw['msg'] = 'Checking for code snippet' if not 'errmsg' in kw: kw['errmsg'] = 'no' for (flagsname,flagstype) in (('cxxflags','compiler'), ('cflags','compiler'), ('linkflags','linker')): if flagsname in kw: if not 'msg' in kw: kw['msg'] = 'Checking for %s flags %s' % (flagstype, kw[flagsname]) if not 'errmsg' in kw: kw['errmsg'] = 'no' if not 'execute' in kw: kw['execute'] = False if kw['execute']: kw['features'].append('test_exec') kw['chmod'] = Utils.O755 if not 'errmsg' in kw: kw['errmsg'] = 'not found' if not 'okmsg' in kw: kw['okmsg'] = 'yes' if not 'code' in kw: kw['code'] = SNIP_EMPTY_PROGRAM # if there are headers to append automatically to the next tests if self.env[INCKEYS]: kw['code'] = '\n'.join(['#include <%s>' % x for x in self.env[INCKEYS]]) + '\n' + kw['code'] # in case defines lead to very long command-lines if kw.get('merge_config_header') or env.merge_config_header: kw['code'] = '%s\n\n%s' % (self.get_config_header(), kw['code']) env.DEFINES = [] # modify the copy if not kw.get('success'): kw['success'] = None if 'define_name' in kw: self.undefine(kw['define_name']) if not 'msg' in kw: self.fatal('missing "msg" in conf.check(...)') @conf def post_check(self, *k, **kw): """ Sets the variables after a test executed in :py:func:`waflib.Tools.c_config.check` was run successfully """ is_success = 0 if kw['execute']: if kw['success'] is not None: if kw.get('define_ret'): is_success = kw['success'] else: is_success = (kw['success'] == 0) else: is_success = (kw['success'] == 0) if kw.get('define_name'): comment = kw.get('comment', '') define_name = kw['define_name'] if kw['execute'] and kw.get('define_ret') and isinstance(is_success, str): if kw.get('global_define', 1): self.define(define_name, is_success, quote=kw.get('quote', 1), comment=comment) else: if kw.get('quote', 1): succ = '"%s"' % is_success else: succ = int(is_success) val = '%s=%s' % (define_name, succ) var = 'DEFINES_%s' % kw['uselib_store'] self.env.append_value(var, val) else: if kw.get('global_define', 1): self.define_cond(define_name, is_success, comment=comment) else: var = 'DEFINES_%s' % kw['uselib_store'] self.env.append_value(var, '%s=%s' % (define_name, int(is_success))) # define conf.env.HAVE_X to 1 if kw.get('add_have_to_env', 1): if kw.get('uselib_store'): self.env[self.have_define(kw['uselib_store'])] = 1 elif kw['execute'] and kw.get('define_ret'): self.env[define_name] = is_success else: self.env[define_name] = int(is_success) if 'header_name' in kw: if kw.get('auto_add_header_name'): self.env.append_value(INCKEYS, Utils.to_list(kw['header_name'])) if is_success and 'uselib_store' in kw: from waflib.Tools import ccroot # See get_uselib_vars in ccroot.py _vars = set() for x in kw['features']: if x in ccroot.USELIB_VARS: _vars |= ccroot.USELIB_VARS[x] for k in _vars: x = k.lower() if x in kw: self.env.append_value(k + '_' + kw['uselib_store'], kw[x]) return is_success @conf def check(self, *k, **kw): """ Performs a configuration test by calling :py:func:`waflib.Configure.run_build`. For the complete list of parameters, see :py:func:`waflib.Tools.c_config.validate_c`. To force a specific compiler, pass ``compiler='c'`` or ``compiler='cxx'`` to the list of arguments Besides build targets, complete builds can be given through a build function. All files will be written to a temporary directory:: def build(bld): lib_node = bld.srcnode.make_node('libdir/liblc1.c') lib_node.parent.mkdir() lib_node.write('#include \\nint lib_func(void) { FILE *f = fopen("foo", "r");}\\n', 'w') bld(features='c cshlib', source=[lib_node], linkflags=conf.env.EXTRA_LDFLAGS, target='liblc') conf.check(build_fun=build, msg=msg) """ self.validate_c(kw) self.start_msg(kw['msg'], **kw) ret = None try: ret = self.run_build(*k, **kw) except self.errors.ConfigurationError: self.end_msg(kw['errmsg'], 'YELLOW', **kw) if Logs.verbose > 1: raise else: self.fatal('The configuration failed') else: kw['success'] = ret ret = self.post_check(*k, **kw) if not ret: self.end_msg(kw['errmsg'], 'YELLOW', **kw) self.fatal('The configuration failed %r' % ret) else: self.end_msg(self.ret_msg(kw['okmsg'], kw), **kw) return ret class test_exec(Task.Task): """ A task that runs programs after they are built. See :py:func:`waflib.Tools.c_config.test_exec_fun`. """ color = 'PINK' def run(self): cmd = [self.inputs[0].abspath()] + getattr(self.generator, 'test_args', []) if getattr(self.generator, 'rpath', None): if getattr(self.generator, 'define_ret', False): self.generator.bld.retval = self.generator.bld.cmd_and_log(cmd) else: self.generator.bld.retval = self.generator.bld.exec_command(cmd) else: env = self.env.env or {} env.update(dict(os.environ)) for var in ('LD_LIBRARY_PATH', 'DYLD_LIBRARY_PATH', 'PATH'): env[var] = self.inputs[0].parent.abspath() + os.path.pathsep + env.get(var, '') if getattr(self.generator, 'define_ret', False): self.generator.bld.retval = self.generator.bld.cmd_and_log(cmd, env=env) else: self.generator.bld.retval = self.generator.bld.exec_command(cmd, env=env) @feature('test_exec') @after_method('apply_link') def test_exec_fun(self): """ The feature **test_exec** is used to create a task that will to execute the binary created (link task output) during the build. The exit status will be set on the build context, so only one program may have the feature *test_exec*. This is used by configuration tests:: def configure(conf): conf.check(execute=True) """ self.create_task('test_exec', self.link_task.outputs[0]) @conf def check_cxx(self, *k, **kw): """ Runs a test with a task generator of the form:: conf.check(features='cxx cxxprogram', ...) """ kw['compiler'] = 'cxx' return self.check(*k, **kw) @conf def check_cc(self, *k, **kw): """ Runs a test with a task generator of the form:: conf.check(features='c cprogram', ...) """ kw['compiler'] = 'c' return self.check(*k, **kw) @conf def set_define_comment(self, key, comment): """ Sets a comment that will appear in the configuration header :type key: string :type comment: string """ coms = self.env.DEFINE_COMMENTS if not coms: coms = self.env.DEFINE_COMMENTS = {} coms[key] = comment or '' @conf def get_define_comment(self, key): """ Returns the comment associated to a define :type key: string """ coms = self.env.DEFINE_COMMENTS or {} return coms.get(key, '') @conf def define(self, key, val, quote=True, comment=''): """ Stores a single define and its state into ``conf.env.DEFINES``. The value is cast to an integer (0/1). :param key: define name :type key: string :param val: value :type val: int or string :param quote: enclose strings in quotes (yes by default) :type quote: bool """ assert isinstance(key, str) if not key: return if val is True: val = 1 elif val in (False, None): val = 0 if isinstance(val, int) or isinstance(val, float): s = '%s=%s' else: s = quote and '%s="%s"' or '%s=%s' app = s % (key, str(val)) ban = key + '=' lst = self.env.DEFINES for x in lst: if x.startswith(ban): lst[lst.index(x)] = app break else: self.env.append_value('DEFINES', app) self.env.append_unique(DEFKEYS, key) self.set_define_comment(key, comment) @conf def undefine(self, key, comment=''): """ Removes a global define from ``conf.env.DEFINES`` :param key: define name :type key: string """ assert isinstance(key, str) if not key: return ban = key + '=' lst = [x for x in self.env.DEFINES if not x.startswith(ban)] self.env.DEFINES = lst self.env.append_unique(DEFKEYS, key) self.set_define_comment(key, comment) @conf def define_cond(self, key, val, comment=''): """ Conditionally defines a name:: def configure(conf): conf.define_cond('A', True) # equivalent to: # if val: conf.define('A', 1) # else: conf.undefine('A') :param key: define name :type key: string :param val: value :type val: int or string """ assert isinstance(key, str) if not key: return if val: self.define(key, 1, comment=comment) else: self.undefine(key, comment=comment) @conf def is_defined(self, key): """ Indicates whether a particular define is globally set in ``conf.env.DEFINES``. :param key: define name :type key: string :return: True if the define is set :rtype: bool """ assert key and isinstance(key, str) ban = key + '=' for x in self.env.DEFINES: if x.startswith(ban): return True return False @conf def get_define(self, key): """ Returns the value of an existing define, or None if not found :param key: define name :type key: string :rtype: string """ assert key and isinstance(key, str) ban = key + '=' for x in self.env.DEFINES: if x.startswith(ban): return x[len(ban):] return None @conf def have_define(self, key): """ Returns a variable suitable for command-line or header use by removing invalid characters and prefixing it with ``HAVE_`` :param key: define name :type key: string :return: the input key prefixed by *HAVE_* and substitute any invalid characters. :rtype: string """ return (self.env.HAVE_PAT or 'HAVE_%s') % Utils.quote_define_name(key) @conf def write_config_header(self, configfile='', guard='', top=False, defines=True, headers=False, remove=True, define_prefix=''): """ Writes a configuration header containing defines and includes:: def configure(cnf): cnf.define('A', 1) cnf.write_config_header('config.h') This function only adds include guards (if necessary), consult :py:func:`waflib.Tools.c_config.get_config_header` for details on the body. :param configfile: path to the file to create (relative or absolute) :type configfile: string :param guard: include guard name to add, by default it is computed from the file name :type guard: string :param top: write the configuration header from the build directory (default is from the current path) :type top: bool :param defines: add the defines (yes by default) :type defines: bool :param headers: add #include in the file :type headers: bool :param remove: remove the defines after they are added (yes by default, works like in autoconf) :type remove: bool :type define_prefix: string :param define_prefix: prefix all the defines in the file with a particular prefix """ if not configfile: configfile = WAF_CONFIG_H waf_guard = guard or 'W_%s_WAF' % Utils.quote_define_name(configfile) node = top and self.bldnode or self.path.get_bld() node = node.make_node(configfile) node.parent.mkdir() lst = ['/* WARNING! All changes made to this file will be lost! */\n'] lst.append('#ifndef %s\n#define %s\n' % (waf_guard, waf_guard)) lst.append(self.get_config_header(defines, headers, define_prefix=define_prefix)) lst.append('\n#endif /* %s */\n' % waf_guard) node.write('\n'.join(lst)) # config files must not be removed on "waf clean" self.env.append_unique(Build.CFG_FILES, [node.abspath()]) if remove: for key in self.env[DEFKEYS]: self.undefine(key) self.env[DEFKEYS] = [] @conf def get_config_header(self, defines=True, headers=False, define_prefix=''): """ Creates the contents of a ``config.h`` file from the defines and includes set in conf.env.define_key / conf.env.include_key. No include guards are added. A prelude will be added from the variable env.WAF_CONFIG_H_PRELUDE if provided. This can be used to insert complex macros or include guards:: def configure(conf): conf.env.WAF_CONFIG_H_PRELUDE = '#include \\n' conf.write_config_header('config.h') :param defines: write the defines values :type defines: bool :param headers: write include entries for each element in self.env.INCKEYS :type headers: bool :type define_prefix: string :param define_prefix: prefix all the defines with a particular prefix :return: the contents of a ``config.h`` file :rtype: string """ lst = [] if self.env.WAF_CONFIG_H_PRELUDE: lst.append(self.env.WAF_CONFIG_H_PRELUDE) if headers: for x in self.env[INCKEYS]: lst.append('#include <%s>' % x) if defines: tbl = {} for k in self.env.DEFINES: a, _, b = k.partition('=') tbl[a] = b for k in self.env[DEFKEYS]: caption = self.get_define_comment(k) if caption: caption = ' /* %s */' % caption try: txt = '#define %s%s %s%s' % (define_prefix, k, tbl[k], caption) except KeyError: txt = '/* #undef %s%s */%s' % (define_prefix, k, caption) lst.append(txt) return "\n".join(lst) @conf def cc_add_flags(conf): """ Adds CFLAGS / CPPFLAGS from os.environ to conf.env """ conf.add_os_flags('CPPFLAGS', dup=False) conf.add_os_flags('CFLAGS', dup=False) @conf def cxx_add_flags(conf): """ Adds CXXFLAGS / CPPFLAGS from os.environ to conf.env """ conf.add_os_flags('CPPFLAGS', dup=False) conf.add_os_flags('CXXFLAGS', dup=False) @conf def link_add_flags(conf): """ Adds LINKFLAGS / LDFLAGS from os.environ to conf.env """ conf.add_os_flags('LINKFLAGS', dup=False) conf.add_os_flags('LDFLAGS', dup=False) @conf def cc_load_tools(conf): """ Loads the Waf c extensions """ if not conf.env.DEST_OS: conf.env.DEST_OS = Utils.unversioned_sys_platform() conf.load('c') @conf def cxx_load_tools(conf): """ Loads the Waf c++ extensions """ if not conf.env.DEST_OS: conf.env.DEST_OS = Utils.unversioned_sys_platform() conf.load('cxx') @conf def get_cc_version(conf, cc, gcc=False, icc=False, clang=False): """ Runs the preprocessor to determine the gcc/icc/clang version The variables CC_VERSION, DEST_OS, DEST_BINFMT and DEST_CPU will be set in *conf.env* :raise: :py:class:`waflib.Errors.ConfigurationError` """ cmd = cc + ['-dM', '-E', '-'] env = conf.env.env or None try: out, err = conf.cmd_and_log(cmd, output=0, input='\n'.encode(), env=env) except Errors.WafError: conf.fatal('Could not determine the compiler version %r' % cmd) if gcc: if out.find('__INTEL_COMPILER') >= 0: conf.fatal('The intel compiler pretends to be gcc') if out.find('__GNUC__') < 0 and out.find('__clang__') < 0: conf.fatal('Could not determine the compiler type') if icc and out.find('__INTEL_COMPILER') < 0: conf.fatal('Not icc/icpc') if clang and out.find('__clang__') < 0: conf.fatal('Not clang/clang++') if not clang and out.find('__clang__') >= 0: conf.fatal('Could not find gcc/g++ (only Clang), if renamed try eg: CC=gcc48 CXX=g++48 waf configure') k = {} if icc or gcc or clang: out = out.splitlines() for line in out: lst = shlex.split(line) if len(lst)>2: key = lst[1] val = lst[2] k[key] = val def isD(var): return var in k # Some documentation is available at http://predef.sourceforge.net # The names given to DEST_OS must match what Utils.unversioned_sys_platform() returns. if not conf.env.DEST_OS: conf.env.DEST_OS = '' for i in MACRO_TO_DESTOS: if isD(i): conf.env.DEST_OS = MACRO_TO_DESTOS[i] break else: if isD('__APPLE__') and isD('__MACH__'): conf.env.DEST_OS = 'darwin' elif isD('__unix__'): # unix must be tested last as it's a generic fallback conf.env.DEST_OS = 'generic' if isD('__ELF__'): conf.env.DEST_BINFMT = 'elf' elif isD('__WINNT__') or isD('__CYGWIN__') or isD('_WIN32'): conf.env.DEST_BINFMT = 'pe' if not conf.env.IMPLIBDIR: conf.env.IMPLIBDIR = conf.env.LIBDIR # for .lib or .dll.a files conf.env.LIBDIR = conf.env.BINDIR elif isD('__APPLE__'): conf.env.DEST_BINFMT = 'mac-o' if not conf.env.DEST_BINFMT: # Infer the binary format from the os name. conf.env.DEST_BINFMT = Utils.destos_to_binfmt(conf.env.DEST_OS) for i in MACRO_TO_DEST_CPU: if isD(i): conf.env.DEST_CPU = MACRO_TO_DEST_CPU[i] break Logs.debug('ccroot: dest platform: ' + ' '.join([conf.env[x] or '?' for x in ('DEST_OS', 'DEST_BINFMT', 'DEST_CPU')])) if icc: ver = k['__INTEL_COMPILER'] conf.env.CC_VERSION = (ver[:-2], ver[-2], ver[-1]) else: if isD('__clang__') and isD('__clang_major__'): conf.env.CC_VERSION = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__']) else: # older clang versions and gcc conf.env.CC_VERSION = (k['__GNUC__'], k['__GNUC_MINOR__'], k.get('__GNUC_PATCHLEVEL__', '0')) return k @conf def get_xlc_version(conf, cc): """ Returns the Aix compiler version :raise: :py:class:`waflib.Errors.ConfigurationError` """ cmd = cc + ['-qversion'] try: out, err = conf.cmd_and_log(cmd, output=0) except Errors.WafError: conf.fatal('Could not find xlc %r' % cmd) # the intention is to catch the 8.0 in "IBM XL C/C++ Enterprise Edition V8.0 for AIX..." for v in (r"IBM XL C/C\+\+.* V(?P\d*)\.(?P\d*)",): version_re = re.compile(v, re.I).search match = version_re(out or err) if match: k = match.groupdict() conf.env.CC_VERSION = (k['major'], k['minor']) break else: conf.fatal('Could not determine the XLC version.') @conf def get_suncc_version(conf, cc): """ Returns the Sun compiler version :raise: :py:class:`waflib.Errors.ConfigurationError` """ cmd = cc + ['-V'] try: out, err = conf.cmd_and_log(cmd, output=0) except Errors.WafError as e: # Older versions of the compiler exit with non-zero status when reporting their version if not (hasattr(e, 'returncode') and hasattr(e, 'stdout') and hasattr(e, 'stderr')): conf.fatal('Could not find suncc %r' % cmd) out = e.stdout err = e.stderr version = (out or err) version = version.splitlines()[0] # cc: Sun C 5.10 SunOS_i386 2009/06/03 # cc: Studio 12.5 Sun C++ 5.14 SunOS_sparc Beta 2015/11/17 # cc: WorkShop Compilers 5.0 98/12/15 C 5.0 version_re = re.compile(r'cc: (studio.*?|\s+)?(sun\s+(c\+\+|c)|(WorkShop\s+Compilers))?\s+(?P\d*)\.(?P\d*)', re.I).search match = version_re(version) if match: k = match.groupdict() conf.env.CC_VERSION = (k['major'], k['minor']) else: conf.fatal('Could not determine the suncc version.') # ============ the --as-needed flag should added during the configuration, not at runtime ========= @conf def add_as_needed(self): """ Adds ``--as-needed`` to the *LINKFLAGS* On some platforms, it is a default flag. In some cases (e.g., in NS-3) it is necessary to explicitly disable this feature with `-Wl,--no-as-needed` flag. """ if self.env.DEST_BINFMT == 'elf' and 'gcc' in (self.env.CXX_NAME, self.env.CC_NAME): self.env.append_unique('LINKFLAGS', '-Wl,--as-needed') # ============ parallel configuration class cfgtask(Task.Task): """ A task that executes build configuration tests (calls conf.check) Make sure to use locks if concurrent access to the same conf.env data is necessary. """ def __init__(self, *k, **kw): Task.Task.__init__(self, *k, **kw) self.run_after = set() def display(self): return '' def runnable_status(self): for x in self.run_after: if not x.hasrun: return Task.ASK_LATER return Task.RUN_ME def uid(self): return Utils.SIG_NIL def signature(self): return Utils.SIG_NIL def run(self): conf = self.conf bld = Build.BuildContext(top_dir=conf.srcnode.abspath(), out_dir=conf.bldnode.abspath()) bld.env = conf.env bld.init_dirs() bld.in_msg = 1 # suppress top-level start_msg bld.logger = self.logger bld.multicheck_task = self args = self.args try: if 'func' in args: bld.test(build_fun=args['func'], msg=args.get('msg', ''), okmsg=args.get('okmsg', ''), errmsg=args.get('errmsg', ''), ) else: args['multicheck_mandatory'] = args.get('mandatory', True) args['mandatory'] = True try: bld.check(**args) finally: args['mandatory'] = args['multicheck_mandatory'] except Exception: return 1 def process(self): Task.Task.process(self) if 'msg' in self.args: with self.generator.bld.multicheck_lock: self.conf.start_msg(self.args['msg']) if self.hasrun == Task.NOT_RUN: self.conf.end_msg('test cancelled', 'YELLOW') elif self.hasrun != Task.SUCCESS: self.conf.end_msg(self.args.get('errmsg', 'no'), 'YELLOW') else: self.conf.end_msg(self.args.get('okmsg', 'yes'), 'GREEN') @conf def multicheck(self, *k, **kw): """ Runs configuration tests in parallel; results are printed sequentially at the end of the build but each test must provide its own msg value to display a line:: def test_build(ctx): ctx.in_msg = True # suppress console outputs ctx.check_large_file(mandatory=False) conf.multicheck( {'header_name':'stdio.h', 'msg':'... stdio', 'uselib_store':'STDIO', 'global_define':False}, {'header_name':'xyztabcd.h', 'msg':'... optional xyztabcd.h', 'mandatory': False}, {'header_name':'stdlib.h', 'msg':'... stdlib', 'okmsg': 'aye', 'errmsg': 'nope'}, {'func': test_build, 'msg':'... testing an arbitrary build function', 'okmsg':'ok'}, msg = 'Checking for headers in parallel', mandatory = True, # mandatory tests raise an error at the end run_all_tests = True, # try running all tests ) The configuration tests may modify the values in conf.env in any order, and the define values can affect configuration tests being executed. It is hence recommended to provide `uselib_store` values with `global_define=False` to prevent such issues. """ self.start_msg(kw.get('msg', 'Executing %d configuration tests' % len(k)), **kw) # Force a copy so that threads append to the same list at least # no order is guaranteed, but the values should not disappear at least for var in ('DEFINES', DEFKEYS): self.env.append_value(var, []) self.env.DEFINE_COMMENTS = self.env.DEFINE_COMMENTS or {} # define a task object that will execute our tests class par(object): def __init__(self): self.keep = False self.task_sigs = {} self.progress_bar = 0 def total(self): return len(tasks) def to_log(self, *k, **kw): return bld = par() bld.keep = kw.get('run_all_tests', True) bld.imp_sigs = {} tasks = [] id_to_task = {} for counter, dct in enumerate(k): x = Task.classes['cfgtask'](bld=bld, env=None) tasks.append(x) x.args = dct x.args['multicheck_counter'] = counter x.bld = bld x.conf = self x.args = dct # bind a logger that will keep the info in memory x.logger = Logs.make_mem_logger(str(id(x)), self.logger) if 'id' in dct: id_to_task[dct['id']] = x # second pass to set dependencies with after_test/before_test for x in tasks: for key in Utils.to_list(x.args.get('before_tests', [])): tsk = id_to_task[key] if not tsk: raise ValueError('No test named %r' % key) tsk.run_after.add(x) for key in Utils.to_list(x.args.get('after_tests', [])): tsk = id_to_task[key] if not tsk: raise ValueError('No test named %r' % key) x.run_after.add(tsk) def it(): yield tasks while 1: yield [] bld.producer = p = Runner.Parallel(bld, Options.options.jobs) bld.multicheck_lock = Utils.threading.Lock() p.biter = it() self.end_msg('started') p.start() # flush the logs in order into the config.log for x in tasks: x.logger.memhandler.flush() self.start_msg('-> processing test results') if p.error: for x in p.error: if getattr(x, 'err_msg', None): self.to_log(x.err_msg) self.end_msg('fail', color='RED') raise Errors.WafError('There is an error in the library, read config.log for more information') failure_count = 0 for x in tasks: if x.hasrun not in (Task.SUCCESS, Task.NOT_RUN): failure_count += 1 if failure_count: self.end_msg(kw.get('errmsg', '%s test failed' % failure_count), color='YELLOW', **kw) else: self.end_msg('all ok', **kw) for x in tasks: if x.hasrun != Task.SUCCESS: if x.args.get('mandatory', True): self.fatal(kw.get('fatalmsg') or 'One of the tests has failed, read config.log for more information') @conf def check_gcc_o_space(self, mode='c'): if int(self.env.CC_VERSION[0]) > 4: # this is for old compilers return self.env.stash() if mode == 'c': self.env.CCLNK_TGT_F = ['-o', ''] elif mode == 'cxx': self.env.CXXLNK_TGT_F = ['-o', ''] features = '%s %sshlib' % (mode, mode) try: self.check(msg='Checking if the -o link must be split from arguments', fragment=SNIP_EMPTY_PROGRAM, features=features) except self.errors.ConfigurationError: self.env.revert() else: self.env.commit() hamster-3.0.3/waflib/Tools/c_osx.py000066400000000000000000000133261452646177100172330ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy 2008-2018 (ita) """ MacOSX related tools """ import os, shutil, platform from waflib import Task, Utils from waflib.TaskGen import taskgen_method, feature, after_method, before_method app_info = ''' CFBundlePackageType APPL CFBundleGetInfoString Created by Waf CFBundleSignature ???? NOTE THIS IS A GENERATED FILE, DO NOT MODIFY CFBundleExecutable {app_name} ''' """ plist template """ @feature('c', 'cxx') def set_macosx_deployment_target(self): """ see WAF issue 285 and also and also http://trac.macports.org/ticket/17059 """ if self.env.MACOSX_DEPLOYMENT_TARGET: os.environ['MACOSX_DEPLOYMENT_TARGET'] = self.env.MACOSX_DEPLOYMENT_TARGET elif 'MACOSX_DEPLOYMENT_TARGET' not in os.environ: if Utils.unversioned_sys_platform() == 'darwin': os.environ['MACOSX_DEPLOYMENT_TARGET'] = '.'.join(platform.mac_ver()[0].split('.')[:2]) @taskgen_method def create_bundle_dirs(self, name, out): """ Creates bundle folders, used by :py:func:`create_task_macplist` and :py:func:`create_task_macapp` """ dir = out.parent.find_or_declare(name) dir.mkdir() macos = dir.find_or_declare(['Contents', 'MacOS']) macos.mkdir() return dir def bundle_name_for_output(out): name = out.name k = name.rfind('.') if k >= 0: name = name[:k] + '.app' else: name = name + '.app' return name @feature('cprogram', 'cxxprogram') @after_method('apply_link') def create_task_macapp(self): """ To compile an executable into a Mac application (a .app), set its *mac_app* attribute:: def build(bld): bld.shlib(source='a.c', target='foo', mac_app=True) To force *all* executables to be transformed into Mac applications:: def build(bld): bld.env.MACAPP = True bld.shlib(source='a.c', target='foo') """ if self.env.MACAPP or getattr(self, 'mac_app', False): out = self.link_task.outputs[0] name = bundle_name_for_output(out) dir = self.create_bundle_dirs(name, out) n1 = dir.find_or_declare(['Contents', 'MacOS', out.name]) self.apptask = self.create_task('macapp', self.link_task.outputs, n1) inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/MacOS/' % name self.add_install_files(install_to=inst_to, install_from=n1, chmod=Utils.O755) if getattr(self, 'mac_files', None): # this only accepts files; they will be installed as seen from mac_files_root mac_files_root = getattr(self, 'mac_files_root', None) if isinstance(mac_files_root, str): mac_files_root = self.path.find_node(mac_files_root) if not mac_files_root: self.bld.fatal('Invalid mac_files_root %r' % self.mac_files_root) res_dir = n1.parent.parent.make_node('Resources') inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Resources' % name for node in self.to_nodes(self.mac_files): relpath = node.path_from(mac_files_root or node.parent) self.create_task('macapp', node, res_dir.make_node(relpath)) self.add_install_as(install_to=os.path.join(inst_to, relpath), install_from=node) if getattr(self.bld, 'is_install', None): # disable regular binary installation self.install_task.hasrun = Task.SKIP_ME @feature('cprogram', 'cxxprogram') @after_method('apply_link') def create_task_macplist(self): """ Creates a :py:class:`waflib.Tools.c_osx.macplist` instance. """ if self.env.MACAPP or getattr(self, 'mac_app', False): out = self.link_task.outputs[0] name = bundle_name_for_output(out) dir = self.create_bundle_dirs(name, out) n1 = dir.find_or_declare(['Contents', 'Info.plist']) self.plisttask = plisttask = self.create_task('macplist', [], n1) plisttask.context = { 'app_name': self.link_task.outputs[0].name, 'env': self.env } plist_ctx = getattr(self, 'plist_context', None) if (plist_ctx): plisttask.context.update(plist_ctx) if getattr(self, 'mac_plist', False): node = self.path.find_resource(self.mac_plist) if node: plisttask.inputs.append(node) else: plisttask.code = self.mac_plist else: plisttask.code = app_info inst_to = getattr(self, 'install_path', '/Applications') + '/%s/Contents/' % name self.add_install_files(install_to=inst_to, install_from=n1) @feature('cshlib', 'cxxshlib') @before_method('apply_link', 'propagate_uselib_vars') def apply_bundle(self): """ To make a bundled shared library (a ``.bundle``), set the *mac_bundle* attribute:: def build(bld): bld.shlib(source='a.c', target='foo', mac_bundle = True) To force *all* executables to be transformed into bundles:: def build(bld): bld.env.MACBUNDLE = True bld.shlib(source='a.c', target='foo') """ if self.env.MACBUNDLE or getattr(self, 'mac_bundle', False): self.env.LINKFLAGS_cshlib = self.env.LINKFLAGS_cxxshlib = [] # disable the '-dynamiclib' flag self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.macbundle_PATTERN use = self.use = self.to_list(getattr(self, 'use', [])) if not 'MACBUNDLE' in use: use.append('MACBUNDLE') app_dirs = ['Contents', 'Contents/MacOS', 'Contents/Resources'] class macapp(Task.Task): """ Creates mac applications """ color = 'PINK' def run(self): self.outputs[0].parent.mkdir() shutil.copy2(self.inputs[0].srcpath(), self.outputs[0].abspath()) class macplist(Task.Task): """ Creates plist files """ color = 'PINK' ext_in = ['.bin'] def run(self): if getattr(self, 'code', None): txt = self.code else: txt = self.inputs[0].read() context = getattr(self, 'context', {}) txt = txt.format(**context) self.outputs[0].write(txt) hamster-3.0.3/waflib/Tools/c_preproc.py000066400000000000000000000660651452646177100201040ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ C/C++ preprocessor for finding dependencies Reasons for using the Waf preprocessor by default #. Some c/c++ extensions (Qt) require a custom preprocessor for obtaining the dependencies (.moc files) #. Not all compilers provide .d files for obtaining the dependencies (portability) #. A naive file scanner will not catch the constructs such as "#include foo()" #. A naive file scanner will catch unnecessary dependencies (change an unused header -> recompile everything) Regarding the speed concerns: * the preprocessing is performed only when files must be compiled * the macros are evaluated only for #if/#elif/#include * system headers are not scanned by default Now if you do not want the Waf preprocessor, the tool +gccdeps* uses the .d files produced during the compilation to track the dependencies (useful when used with the boost libraries). It only works with gcc >= 4.4 though. A dumb preprocessor is also available in the tool *c_dumbpreproc* """ # TODO: more varargs, pragma once import re, string, traceback from waflib import Logs, Utils, Errors class PreprocError(Errors.WafError): pass FILE_CACHE_SIZE = 100000 LINE_CACHE_SIZE = 100000 POPFILE = '-' "Constant representing a special token used in :py:meth:`waflib.Tools.c_preproc.c_parser.start` iteration to switch to a header read previously" recursion_limit = 150 "Limit on the amount of files to read in the dependency scanner" go_absolute = False "Set to True to track headers on files in /usr/include, else absolute paths are ignored (but it becomes very slow)" standard_includes = ['/usr/local/include', '/usr/include'] if Utils.is_win32: standard_includes = [] use_trigraphs = 0 """Apply trigraph rules (False by default)""" # obsolete, do not use strict_quotes = 0 g_optrans = { 'not':'!', 'not_eq':'!', 'and':'&&', 'and_eq':'&=', 'or':'||', 'or_eq':'|=', 'xor':'^', 'xor_eq':'^=', 'bitand':'&', 'bitor':'|', 'compl':'~', } """Operators such as and/or/xor for c++. Set an empty dict to disable.""" # ignore #warning and #error re_lines = re.compile( '^[ \t]*(?:#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*)\r*$', re.IGNORECASE | re.MULTILINE) """Match #include lines""" re_mac = re.compile(r"^[a-zA-Z_]\w*") """Match macro definitions""" re_fun = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*[(]') """Match macro functions""" re_pragma_once = re.compile(r'^\s*once\s*', re.IGNORECASE) """Match #pragma once statements""" re_nl = re.compile('\\\\\r*\n', re.MULTILINE) """Match newlines""" re_cpp = re.compile(r'//.*?$|/\*.*?\*/|\'(?:\\.|[^\\\'])*\'|"(?:\\.|[^\\"])*"', re.DOTALL | re.MULTILINE ) """Filter C/C++ comments""" trig_def = [('??'+a, b) for a, b in zip("=-/!'()<>", r'#~\|^[]{}')] """Trigraph definitions""" chr_esc = {'0':0, 'a':7, 'b':8, 't':9, 'n':10, 'f':11, 'v':12, 'r':13, '\\':92, "'":39} """Escape characters""" NUM = 'i' """Number token""" OP = 'O' """Operator token""" IDENT = 'T' """Identifier token""" STR = 's' """String token""" CHAR = 'c' """Character token""" tok_types = [NUM, STR, IDENT, OP] """Token types""" exp_types = [ r"""0[xX](?P[a-fA-F0-9]+)(?P[uUlL]*)|L*?'(?P(\\.|[^\\'])+)'|(?P\d+)[Ee](?P[+-]*?\d+)(?P[fFlL]*)|(?P\d*\.\d+)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P\d+\.\d*)([Ee](?P[+-]*?\d+))?(?P[fFlL]*)|(?P0*)(?P\d+)(?P[uUlL]*)""", r'L?"([^"\\]|\\.)*"', r'[a-zA-Z_]\w*', r'%:%:|<<=|>>=|\.\.\.|<<|<%|<:|<=|>>|>=|\+\+|\+=|--|->|-=|\*=|/=|%:|%=|%>|==|&&|&=|\|\||\|=|\^=|:>|!=|##|[\(\)\{\}\[\]<>\?\|\^\*\+&=:!#;,%/\-\?\~\.]', ] """Expression types""" re_clexer = re.compile('|'.join(["(?P<%s>%s)" % (name, part) for name, part in zip(tok_types, exp_types)]), re.M) """Match expressions into tokens""" accepted = 'a' """Parser state is *accepted*""" ignored = 'i' """Parser state is *ignored*, for example preprocessor lines in an #if 0 block""" undefined = 'u' """Parser state is *undefined* at the moment""" skipped = 's' """Parser state is *skipped*, for example preprocessor lines in a #elif 0 block""" def repl(m): """Replace function used with :py:attr:`waflib.Tools.c_preproc.re_cpp`""" s = m.group() if s[0] == '/': return ' ' return s prec = {} """ Operator precedence rules required for parsing expressions of the form:: #if 1 && 2 != 0 """ ops = ['* / %', '+ -', '<< >>', '< <= >= >', '== !=', '& | ^', '&& ||', ','] for x, syms in enumerate(ops): for u in syms.split(): prec[u] = x def reduce_nums(val_1, val_2, val_op): """ Apply arithmetic rules to compute a result :param val1: input parameter :type val1: int or string :param val2: input parameter :type val2: int or string :param val_op: C operator in *+*, */*, *-*, etc :type val_op: string :rtype: int """ #print val_1, val_2, val_op # now perform the operation, make certain a and b are numeric try: a = 0 + val_1 except TypeError: a = int(val_1) try: b = 0 + val_2 except TypeError: b = int(val_2) d = val_op if d == '%': c = a % b elif d=='+': c = a + b elif d=='-': c = a - b elif d=='*': c = a * b elif d=='/': c = a / b elif d=='^': c = a ^ b elif d=='==': c = int(a == b) elif d=='|' or d == 'bitor': c = a | b elif d=='||' or d == 'or' : c = int(a or b) elif d=='&' or d == 'bitand': c = a & b elif d=='&&' or d == 'and': c = int(a and b) elif d=='!=' or d == 'not_eq': c = int(a != b) elif d=='^' or d == 'xor': c = int(a^b) elif d=='<=': c = int(a <= b) elif d=='<': c = int(a < b) elif d=='>': c = int(a > b) elif d=='>=': c = int(a >= b) elif d=='<<': c = a << b elif d=='>>': c = a >> b else: c = 0 return c def get_num(lst): """ Try to obtain a number from a list of tokens. The token types are defined in :py:attr:`waflib.Tools.ccroot.tok_types`. :param lst: list of preprocessor tokens :type lst: list of tuple (tokentype, value) :return: a pair containing the number and the rest of the list :rtype: tuple(value, list) """ if not lst: raise PreprocError('empty list for get_num') (p, v) = lst[0] if p == OP: if v == '(': count_par = 1 i = 1 while i < len(lst): (p, v) = lst[i] if p == OP: if v == ')': count_par -= 1 if count_par == 0: break elif v == '(': count_par += 1 i += 1 else: raise PreprocError('rparen expected %r' % lst) (num, _) = get_term(lst[1:i]) return (num, lst[i+1:]) elif v == '+': return get_num(lst[1:]) elif v == '-': num, lst = get_num(lst[1:]) return (reduce_nums('-1', num, '*'), lst) elif v == '!': num, lst = get_num(lst[1:]) return (int(not int(num)), lst) elif v == '~': num, lst = get_num(lst[1:]) return (~ int(num), lst) else: raise PreprocError('Invalid op token %r for get_num' % lst) elif p == NUM: return v, lst[1:] elif p == IDENT: # all macros should have been replaced, remaining identifiers eval to 0 return 0, lst[1:] else: raise PreprocError('Invalid token %r for get_num' % lst) def get_term(lst): """ Evaluate an expression recursively, for example:: 1+1+1 -> 2+1 -> 3 :param lst: list of tokens :type lst: list of tuple(token, value) :return: the value and the remaining tokens :rtype: value, list """ if not lst: raise PreprocError('empty list for get_term') num, lst = get_num(lst) if not lst: return (num, []) (p, v) = lst[0] if p == OP: if v == ',': # skip return get_term(lst[1:]) elif v == '?': count_par = 0 i = 1 while i < len(lst): (p, v) = lst[i] if p == OP: if v == ')': count_par -= 1 elif v == '(': count_par += 1 elif v == ':': if count_par == 0: break i += 1 else: raise PreprocError('rparen expected %r' % lst) if int(num): return get_term(lst[1:i]) else: return get_term(lst[i+1:]) else: num2, lst = get_num(lst[1:]) if not lst: # no more tokens to process num2 = reduce_nums(num, num2, v) return get_term([(NUM, num2)] + lst) # operator precedence p2, v2 = lst[0] if p2 != OP: raise PreprocError('op expected %r' % lst) if prec[v2] >= prec[v]: num2 = reduce_nums(num, num2, v) return get_term([(NUM, num2)] + lst) else: num3, lst = get_num(lst[1:]) num3 = reduce_nums(num2, num3, v2) return get_term([(NUM, num), (p, v), (NUM, num3)] + lst) raise PreprocError('cannot reduce %r' % lst) def reduce_eval(lst): """ Take a list of tokens and output true or false for #if/#elif conditions. :param lst: a list of tokens :type lst: list of tuple(token, value) :return: a token :rtype: tuple(NUM, int) """ num, lst = get_term(lst) return (NUM, num) def stringize(lst): """ Merge a list of tokens into a string :param lst: a list of tokens :type lst: list of tuple(token, value) :rtype: string """ lst = [str(v2) for (p2, v2) in lst] return "".join(lst) def paste_tokens(t1, t2): """ Token pasting works between identifiers, particular operators, and identifiers and numbers:: a ## b -> ab > ## = -> >= a ## 2 -> a2 :param t1: token :type t1: tuple(type, value) :param t2: token :type t2: tuple(type, value) """ p1 = None if t1[0] == OP and t2[0] == OP: p1 = OP elif t1[0] == IDENT and (t2[0] == IDENT or t2[0] == NUM): p1 = IDENT elif t1[0] == NUM and t2[0] == NUM: p1 = NUM if not p1: raise PreprocError('tokens do not make a valid paste %r and %r' % (t1, t2)) return (p1, t1[1] + t2[1]) def reduce_tokens(lst, defs, ban=[]): """ Replace the tokens in lst, using the macros provided in defs, and a list of macros that cannot be re-applied :param lst: list of tokens :type lst: list of tuple(token, value) :param defs: macro definitions :type defs: dict :param ban: macros that cannot be substituted (recursion is not allowed) :type ban: list of string :return: the new list of tokens :rtype: value, list """ i = 0 while i < len(lst): (p, v) = lst[i] if p == IDENT and v == "defined": del lst[i] if i < len(lst): (p2, v2) = lst[i] if p2 == IDENT: if v2 in defs: lst[i] = (NUM, 1) else: lst[i] = (NUM, 0) elif p2 == OP and v2 == '(': del lst[i] (p2, v2) = lst[i] del lst[i] # remove the ident, and change the ) for the value if v2 in defs: lst[i] = (NUM, 1) else: lst[i] = (NUM, 0) else: raise PreprocError('Invalid define expression %r' % lst) elif p == IDENT and v in defs: if isinstance(defs[v], str): a, b = extract_macro(defs[v]) defs[v] = b macro_def = defs[v] to_add = macro_def[1] if isinstance(macro_def[0], list): # macro without arguments del lst[i] accu = to_add[:] reduce_tokens(accu, defs, ban+[v]) for tmp in accu: lst.insert(i, tmp) i += 1 else: # collect the arguments for the funcall args = [] del lst[i] if i >= len(lst): raise PreprocError('expected ( after %r (got nothing)' % v) (p2, v2) = lst[i] if p2 != OP or v2 != '(': raise PreprocError('expected ( after %r' % v) del lst[i] one_param = [] count_paren = 0 while i < len(lst): p2, v2 = lst[i] del lst[i] if p2 == OP and count_paren == 0: if v2 == '(': one_param.append((p2, v2)) count_paren += 1 elif v2 == ')': if one_param: args.append(one_param) break elif v2 == ',': if not one_param: raise PreprocError('empty param in funcall %r' % v) args.append(one_param) one_param = [] else: one_param.append((p2, v2)) else: one_param.append((p2, v2)) if v2 == '(': count_paren += 1 elif v2 == ')': count_paren -= 1 else: raise PreprocError('malformed macro') # substitute the arguments within the define expression accu = [] arg_table = macro_def[0] j = 0 while j < len(to_add): (p2, v2) = to_add[j] if p2 == OP and v2 == '#': # stringize is for arguments only if j+1 < len(to_add) and to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table: toks = args[arg_table[to_add[j+1][1]]] accu.append((STR, stringize(toks))) j += 1 else: accu.append((p2, v2)) elif p2 == OP and v2 == '##': # token pasting, how can man invent such a complicated system? if accu and j+1 < len(to_add): # we have at least two tokens t1 = accu[-1] if to_add[j+1][0] == IDENT and to_add[j+1][1] in arg_table: toks = args[arg_table[to_add[j+1][1]]] if toks: accu[-1] = paste_tokens(t1, toks[0]) #(IDENT, accu[-1][1] + toks[0][1]) accu.extend(toks[1:]) else: # error, case "a##" accu.append((p2, v2)) accu.extend(toks) elif to_add[j+1][0] == IDENT and to_add[j+1][1] == '__VA_ARGS__': # first collect the tokens va_toks = [] st = len(macro_def[0]) pt = len(args) for x in args[pt-st+1:]: va_toks.extend(x) va_toks.append((OP, ',')) if va_toks: va_toks.pop() # extra comma if len(accu)>1: (p3, v3) = accu[-1] (p4, v4) = accu[-2] if v3 == '##': # remove the token paste accu.pop() if v4 == ',' and pt < st: # remove the comma accu.pop() accu += va_toks else: accu[-1] = paste_tokens(t1, to_add[j+1]) j += 1 else: # Invalid paste, case "##a" or "b##" accu.append((p2, v2)) elif p2 == IDENT and v2 in arg_table: toks = args[arg_table[v2]] reduce_tokens(toks, defs, ban+[v]) accu.extend(toks) else: accu.append((p2, v2)) j += 1 reduce_tokens(accu, defs, ban+[v]) for x in range(len(accu)-1, -1, -1): lst.insert(i, accu[x]) i += 1 def eval_macro(lst, defs): """ Reduce the tokens by :py:func:`waflib.Tools.c_preproc.reduce_tokens` and try to return a 0/1 result by :py:func:`waflib.Tools.c_preproc.reduce_eval`. :param lst: list of tokens :type lst: list of tuple(token, value) :param defs: macro definitions :type defs: dict :rtype: int """ reduce_tokens(lst, defs, []) if not lst: raise PreprocError('missing tokens to evaluate') if lst: p, v = lst[0] if p == IDENT and v not in defs: raise PreprocError('missing macro %r' % lst) p, v = reduce_eval(lst) return int(v) != 0 def extract_macro(txt): """ Process a macro definition of the form:: #define f(x, y) x * y into a function or a simple macro without arguments :param txt: expression to exact a macro definition from :type txt: string :return: a tuple containing the name, the list of arguments and the replacement :rtype: tuple(string, [list, list]) """ t = tokenize(txt) if re_fun.search(txt): p, name = t[0] p, v = t[1] if p != OP: raise PreprocError('expected (') i = 1 pindex = 0 params = {} prev = '(' while 1: i += 1 p, v = t[i] if prev == '(': if p == IDENT: params[v] = pindex pindex += 1 prev = p elif p == OP and v == ')': break else: raise PreprocError('unexpected token (3)') elif prev == IDENT: if p == OP and v == ',': prev = v elif p == OP and v == ')': break else: raise PreprocError('comma or ... expected') elif prev == ',': if p == IDENT: params[v] = pindex pindex += 1 prev = p elif p == OP and v == '...': raise PreprocError('not implemented (1)') else: raise PreprocError('comma or ... expected (2)') elif prev == '...': raise PreprocError('not implemented (2)') else: raise PreprocError('unexpected else') #~ print (name, [params, t[i+1:]]) return (name, [params, t[i+1:]]) else: (p, v) = t[0] if len(t) > 1: return (v, [[], t[1:]]) else: # empty define, assign an empty token return (v, [[], [('T','')]]) re_include = re.compile(r'^\s*(<(?:.*)>|"(?:.*)")') def extract_include(txt, defs): """ Process a line in the form:: #include foo :param txt: include line to process :type txt: string :param defs: macro definitions :type defs: dict :return: the file name :rtype: string """ m = re_include.search(txt) if m: txt = m.group(1) return txt[0], txt[1:-1] # perform preprocessing and look at the result, it must match an include toks = tokenize(txt) reduce_tokens(toks, defs, ['waf_include']) if not toks: raise PreprocError('could not parse include %r' % txt) if len(toks) == 1: if toks[0][0] == STR: return '"', toks[0][1] else: if toks[0][1] == '<' and toks[-1][1] == '>': ret = '<', stringize(toks).lstrip('<').rstrip('>') return ret raise PreprocError('could not parse include %r' % txt) def parse_char(txt): """ Parse a c character :param txt: character to parse :type txt: string :return: a character literal :rtype: string """ if not txt: raise PreprocError('attempted to parse a null char') if txt[0] != '\\': return ord(txt) c = txt[1] if c == 'x': if len(txt) == 4 and txt[3] in string.hexdigits: return int(txt[2:], 16) return int(txt[2:], 16) elif c.isdigit(): if c == '0' and len(txt)==2: return 0 for i in 3, 2, 1: if len(txt) > i and txt[1:1+i].isdigit(): return (1+i, int(txt[1:1+i], 8)) else: try: return chr_esc[c] except KeyError: raise PreprocError('could not parse char literal %r' % txt) def tokenize(s): """ Convert a string into a list of tokens (shlex.split does not apply to c/c++/d) :param s: input to tokenize :type s: string :return: a list of tokens :rtype: list of tuple(token, value) """ return tokenize_private(s)[:] # force a copy of the results def tokenize_private(s): ret = [] for match in re_clexer.finditer(s): m = match.group for name in tok_types: v = m(name) if v: if name == IDENT: if v in g_optrans: name = OP elif v.lower() == "true": v = 1 name = NUM elif v.lower() == "false": v = 0 name = NUM elif name == NUM: if m('oct'): v = int(v, 8) elif m('hex'): v = int(m('hex'), 16) elif m('n0'): v = m('n0') else: v = m('char') if v: v = parse_char(v) else: v = m('n2') or m('n4') elif name == OP: if v == '%:': v = '#' elif v == '%:%:': v = '##' elif name == STR: # remove the quotes around the string v = v[1:-1] ret.append((name, v)) break return ret def format_defines(lst): ret = [] for y in lst: if y: pos = y.find('=') if pos == -1: # "-DFOO" should give "#define FOO 1" ret.append(y) elif pos > 0: # all others are assumed to be -DX=Y ret.append('%s %s' % (y[:pos], y[pos+1:])) else: raise ValueError('Invalid define expression %r' % y) return ret class c_parser(object): """ Used by :py:func:`waflib.Tools.c_preproc.scan` to parse c/h files. Note that by default, only project headers are parsed. """ def __init__(self, nodepaths=None, defines=None): self.lines = [] """list of lines read""" if defines is None: self.defs = {} else: self.defs = dict(defines) # make a copy self.state = [] self.count_files = 0 self.currentnode_stack = [] self.nodepaths = nodepaths or [] """Include paths""" self.nodes = [] """List of :py:class:`waflib.Node.Node` found so far""" self.names = [] """List of file names that could not be matched by any file""" self.curfile = '' """Current file""" self.ban_includes = set() """Includes that must not be read (#pragma once)""" self.listed = set() """Include nodes/names already listed to avoid duplicates in self.nodes/self.names""" def cached_find_resource(self, node, filename): """ Find a file from the input directory :param node: directory :type node: :py:class:`waflib.Node.Node` :param filename: header to find :type filename: string :return: the node if found, or None :rtype: :py:class:`waflib.Node.Node` """ try: cache = node.ctx.preproc_cache_node except AttributeError: cache = node.ctx.preproc_cache_node = Utils.lru_cache(FILE_CACHE_SIZE) key = (node, filename) try: return cache[key] except KeyError: ret = node.find_resource(filename) if ret: if getattr(ret, 'children', None): ret = None elif ret.is_child_of(node.ctx.bldnode): tmp = node.ctx.srcnode.search_node(ret.path_from(node.ctx.bldnode)) if tmp and getattr(tmp, 'children', None): ret = None cache[key] = ret return ret def tryfind(self, filename, kind='"', env=None): """ Try to obtain a node from the filename based from the include paths. Will add the node found to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes` or the file name to :py:attr:`waflib.Tools.c_preproc.c_parser.names` if no corresponding file is found. Called by :py:attr:`waflib.Tools.c_preproc.c_parser.start`. :param filename: header to find :type filename: string :return: the node if found :rtype: :py:class:`waflib.Node.Node` """ if filename.endswith('.moc'): # we could let the qt4 module use a subclass, but then the function "scan" below must be duplicated # in the qt4 and in the qt5 classes. So we have two lines here and it is sufficient. self.names.append(filename) return None self.curfile = filename found = None if kind == '"': if env.MSVC_VERSION: for n in reversed(self.currentnode_stack): found = self.cached_find_resource(n, filename) if found: break else: found = self.cached_find_resource(self.currentnode_stack[-1], filename) if not found: for n in self.nodepaths: found = self.cached_find_resource(n, filename) if found: break listed = self.listed if found and not found in self.ban_includes: if found not in listed: listed.add(found) self.nodes.append(found) self.addlines(found) else: if filename not in listed: listed.add(filename) self.names.append(filename) return found def filter_comments(self, node): """ Filter the comments from a c/h file, and return the preprocessor lines. The regexps :py:attr:`waflib.Tools.c_preproc.re_cpp`, :py:attr:`waflib.Tools.c_preproc.re_nl` and :py:attr:`waflib.Tools.c_preproc.re_lines` are used internally. :return: the preprocessor directives as a list of (keyword, line) :rtype: a list of string pairs """ # return a list of tuples : keyword, line code = node.read() if use_trigraphs: for (a, b) in trig_def: code = code.split(a).join(b) code = re_nl.sub('', code) code = re_cpp.sub(repl, code) return re_lines.findall(code) def parse_lines(self, node): try: cache = node.ctx.preproc_cache_lines except AttributeError: cache = node.ctx.preproc_cache_lines = Utils.lru_cache(LINE_CACHE_SIZE) try: return cache[node] except KeyError: cache[node] = lines = self.filter_comments(node) lines.append((POPFILE, '')) lines.reverse() return lines def addlines(self, node): """ Add the lines from a header in the list of preprocessor lines to parse :param node: header :type node: :py:class:`waflib.Node.Node` """ self.currentnode_stack.append(node.parent) self.count_files += 1 if self.count_files > recursion_limit: # issue #812 raise PreprocError('recursion limit exceeded') if Logs.verbose: Logs.debug('preproc: reading file %r', node) try: lines = self.parse_lines(node) except EnvironmentError: raise PreprocError('could not read the file %r' % node) except Exception: if Logs.verbose > 0: Logs.error('parsing %r failed %s', node, traceback.format_exc()) else: self.lines.extend(lines) def start(self, node, env): """ Preprocess a source file to obtain the dependencies, which are accumulated to :py:attr:`waflib.Tools.c_preproc.c_parser.nodes` and :py:attr:`waflib.Tools.c_preproc.c_parser.names`. :param node: source file :type node: :py:class:`waflib.Node.Node` :param env: config set containing additional defines to take into account :type env: :py:class:`waflib.ConfigSet.ConfigSet` """ Logs.debug('preproc: scanning %s (in %s)', node.name, node.parent.name) self.current_file = node self.addlines(node) # macros may be defined on the command-line, so they must be parsed as if they were part of the file if env.DEFINES: lst = format_defines(env.DEFINES) lst.reverse() self.lines.extend([('define', x) for x in lst]) while self.lines: (token, line) = self.lines.pop() if token == POPFILE: self.count_files -= 1 self.currentnode_stack.pop() continue try: state = self.state # make certain we define the state if we are about to enter in an if block if token[:2] == 'if': state.append(undefined) elif token == 'endif': state.pop() # skip lines when in a dead 'if' branch, wait for the endif if token[0] != 'e': if skipped in self.state or ignored in self.state: continue if token == 'if': ret = eval_macro(tokenize(line), self.defs) if ret: state[-1] = accepted else: state[-1] = ignored elif token == 'ifdef': m = re_mac.match(line) if m and m.group() in self.defs: state[-1] = accepted else: state[-1] = ignored elif token == 'ifndef': m = re_mac.match(line) if m and m.group() in self.defs: state[-1] = ignored else: state[-1] = accepted elif token == 'include' or token == 'import': (kind, inc) = extract_include(line, self.defs) self.current_file = self.tryfind(inc, kind, env) if token == 'import': self.ban_includes.add(self.current_file) elif token == 'elif': if state[-1] == accepted: state[-1] = skipped elif state[-1] == ignored: if eval_macro(tokenize(line), self.defs): state[-1] = accepted elif token == 'else': if state[-1] == accepted: state[-1] = skipped elif state[-1] == ignored: state[-1] = accepted elif token == 'define': try: self.defs[self.define_name(line)] = line except AttributeError: raise PreprocError('Invalid define line %r' % line) elif token == 'undef': m = re_mac.match(line) if m and m.group() in self.defs: self.defs.__delitem__(m.group()) #print "undef %s" % name elif token == 'pragma': if re_pragma_once.match(line.lower()): self.ban_includes.add(self.current_file) except Exception as e: if Logs.verbose: Logs.debug('preproc: line parsing failed (%s): %s %s', e, line, traceback.format_exc()) def define_name(self, line): """ :param line: define line :type line: string :rtype: string :return: the define name """ return re_mac.match(line).group() def scan(task): """ Get the dependencies using a c/c++ preprocessor, this is required for finding dependencies of the kind:: #include some_macro() This function is bound as a task method on :py:class:`waflib.Tools.c.c` and :py:class:`waflib.Tools.cxx.cxx` for example """ try: incn = task.generator.includes_nodes except AttributeError: raise Errors.WafError('%r is missing a feature such as "c", "cxx" or "includes": ' % task.generator) if go_absolute: nodepaths = incn + [task.generator.bld.root.find_dir(x) for x in standard_includes] else: nodepaths = [x for x in incn if x.is_child_of(x.ctx.srcnode) or x.is_child_of(x.ctx.bldnode)] tmp = c_parser(nodepaths) tmp.start(task.inputs[0], task.env) return (tmp.nodes, tmp.names) hamster-3.0.3/waflib/Tools/c_tests.py000066400000000000000000000137531452646177100175700ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2016-2018 (ita) """ Various configuration tests. """ from waflib import Task from waflib.Configure import conf from waflib.TaskGen import feature, before_method, after_method LIB_CODE = ''' #ifdef _MSC_VER #define testEXPORT __declspec(dllexport) #else #define testEXPORT #endif testEXPORT int lib_func(void) { return 9; } ''' MAIN_CODE = ''' #ifdef _MSC_VER #define testEXPORT __declspec(dllimport) #else #define testEXPORT #endif testEXPORT int lib_func(void); int main(int argc, char **argv) { (void)argc; (void)argv; return !(lib_func() == 9); } ''' @feature('link_lib_test') @before_method('process_source') def link_lib_test_fun(self): """ The configuration test :py:func:`waflib.Configure.run_build` declares a unique task generator, so we need to create other task generators from here to check if the linker is able to link libraries. """ def write_test_file(task): task.outputs[0].write(task.generator.code) rpath = [] if getattr(self, 'add_rpath', False): rpath = [self.bld.path.get_bld().abspath()] mode = self.mode m = '%s %s' % (mode, mode) ex = self.test_exec and 'test_exec' or '' bld = self.bld bld(rule=write_test_file, target='test.' + mode, code=LIB_CODE) bld(rule=write_test_file, target='main.' + mode, code=MAIN_CODE) bld(features='%sshlib' % m, source='test.' + mode, target='test') bld(features='%sprogram %s' % (m, ex), source='main.' + mode, target='app', use='test', rpath=rpath) @conf def check_library(self, mode=None, test_exec=True): """ Checks if libraries can be linked with the current linker. Uses :py:func:`waflib.Tools.c_tests.link_lib_test_fun`. :param mode: c or cxx or d :type mode: string """ if not mode: mode = 'c' if self.env.CXX: mode = 'cxx' self.check( compile_filename = [], features = 'link_lib_test', msg = 'Checking for libraries', mode = mode, test_exec = test_exec) ######################################################################################## INLINE_CODE = ''' typedef int foo_t; static %s foo_t static_foo () {return 0; } %s foo_t foo () { return 0; } ''' INLINE_VALUES = ['inline', '__inline__', '__inline'] @conf def check_inline(self, **kw): """ Checks for the right value for inline macro. Define INLINE_MACRO to 1 if the define is found. If the inline macro is not 'inline', add a define to the ``config.h`` (#define inline __inline__) :param define_name: define INLINE_MACRO by default to 1 if the macro is defined :type define_name: string :param features: by default *c* or *cxx* depending on the compiler present :type features: list of string """ self.start_msg('Checking for inline') if not 'define_name' in kw: kw['define_name'] = 'INLINE_MACRO' if not 'features' in kw: if self.env.CXX: kw['features'] = ['cxx'] else: kw['features'] = ['c'] for x in INLINE_VALUES: kw['fragment'] = INLINE_CODE % (x, x) try: self.check(**kw) except self.errors.ConfigurationError: continue else: self.end_msg(x) if x != 'inline': self.define('inline', x, quote=False) return x self.fatal('could not use inline functions') ######################################################################################## LARGE_FRAGMENT = '''#include int main(int argc, char **argv) { (void)argc; (void)argv; return !(sizeof(off_t) >= 8); } ''' @conf def check_large_file(self, **kw): """ Checks for large file support and define the macro HAVE_LARGEFILE The test is skipped on win32 systems (DEST_BINFMT == pe). :param define_name: define to set, by default *HAVE_LARGEFILE* :type define_name: string :param execute: execute the test (yes by default) :type execute: bool """ if not 'define_name' in kw: kw['define_name'] = 'HAVE_LARGEFILE' if not 'execute' in kw: kw['execute'] = True if not 'features' in kw: if self.env.CXX: kw['features'] = ['cxx', 'cxxprogram'] else: kw['features'] = ['c', 'cprogram'] kw['fragment'] = LARGE_FRAGMENT kw['msg'] = 'Checking for large file support' ret = True try: if self.env.DEST_BINFMT != 'pe': ret = self.check(**kw) except self.errors.ConfigurationError: pass else: if ret: return True kw['msg'] = 'Checking for -D_FILE_OFFSET_BITS=64' kw['defines'] = ['_FILE_OFFSET_BITS=64'] try: ret = self.check(**kw) except self.errors.ConfigurationError: pass else: self.define('_FILE_OFFSET_BITS', 64) return ret self.fatal('There is no support for large files') ######################################################################################## ENDIAN_FRAGMENT = ''' #ifdef _MSC_VER #define testshlib_EXPORT __declspec(dllexport) #else #define testshlib_EXPORT #endif short int ascii_mm[] = { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; short int ascii_ii[] = { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; int testshlib_EXPORT use_ascii (int i) { return ascii_mm[i] + ascii_ii[i]; } short int ebcdic_ii[] = { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; short int ebcdic_mm[] = { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; int use_ebcdic (int i) { return ebcdic_mm[i] + ebcdic_ii[i]; } extern int foo; ''' class grep_for_endianness(Task.Task): """ Task that reads a binary and tries to determine the endianness """ color = 'PINK' def run(self): txt = self.inputs[0].read(flags='rb').decode('latin-1') if txt.find('LiTTleEnDian') > -1: self.generator.tmp.append('little') elif txt.find('BIGenDianSyS') > -1: self.generator.tmp.append('big') else: return -1 @feature('grep_for_endianness') @after_method('apply_link') def grep_for_endianness_fun(self): """ Used by the endianness configuration test """ self.create_task('grep_for_endianness', self.link_task.outputs[0]) @conf def check_endianness(self): """ Executes a configuration test to determine the endianness """ tmp = [] def check_msg(self): return tmp[0] self.check(fragment=ENDIAN_FRAGMENT, features='c cshlib grep_for_endianness', msg='Checking for endianness', define='ENDIANNESS', tmp=tmp, okmsg=check_msg, confcache=None) return tmp[0] hamster-3.0.3/waflib/Tools/ccroot.py000066400000000000000000000633031452646177100174110ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Classes and methods shared by tools providing support for C-like language such as C/C++/D/Assembly/Go (this support module is almost never used alone). """ import os, re from waflib import Task, Utils, Node, Errors, Logs from waflib.TaskGen import after_method, before_method, feature, taskgen_method, extension from waflib.Tools import c_aliases, c_preproc, c_config, c_osx, c_tests from waflib.Configure import conf SYSTEM_LIB_PATHS = ['/usr/lib64', '/usr/lib', '/usr/local/lib64', '/usr/local/lib'] USELIB_VARS = Utils.defaultdict(set) """ Mapping for features to :py:class:`waflib.ConfigSet.ConfigSet` variables. See :py:func:`waflib.Tools.ccroot.propagate_uselib_vars`. """ USELIB_VARS['c'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CCDEPS', 'CFLAGS', 'ARCH']) USELIB_VARS['cxx'] = set(['INCLUDES', 'FRAMEWORKPATH', 'DEFINES', 'CPPFLAGS', 'CXXDEPS', 'CXXFLAGS', 'ARCH']) USELIB_VARS['d'] = set(['INCLUDES', 'DFLAGS']) USELIB_VARS['includes'] = set(['INCLUDES', 'FRAMEWORKPATH', 'ARCH']) USELIB_VARS['cprogram'] = USELIB_VARS['cxxprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS']) USELIB_VARS['cshlib'] = USELIB_VARS['cxxshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'FRAMEWORK', 'FRAMEWORKPATH', 'ARCH', 'LDFLAGS']) USELIB_VARS['cstlib'] = USELIB_VARS['cxxstlib'] = set(['ARFLAGS', 'LINKDEPS']) USELIB_VARS['dprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS']) USELIB_VARS['dshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS']) USELIB_VARS['dstlib'] = set(['ARFLAGS', 'LINKDEPS']) USELIB_VARS['asm'] = set(['ASFLAGS']) # ================================================================================================= @taskgen_method def create_compiled_task(self, name, node): """ Create the compilation task: c, cxx, asm, etc. The output node is created automatically (object file with a typical **.o** extension). The task is appended to the list *compiled_tasks* which is then used by :py:func:`waflib.Tools.ccroot.apply_link` :param name: name of the task class :type name: string :param node: the file to compile :type node: :py:class:`waflib.Node.Node` :return: The task created :rtype: :py:class:`waflib.Task.Task` """ out = '%s.%d.o' % (node.name, self.idx) task = self.create_task(name, node, node.parent.find_or_declare(out)) try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] return task @taskgen_method def to_incnodes(self, inlst): """ Task generator method provided to convert a list of string/nodes into a list of includes folders. The paths are assumed to be relative to the task generator path, except if they begin by **#** in which case they are searched from the top-level directory (``bld.srcnode``). The folders are simply assumed to be existing. The node objects in the list are returned in the output list. The strings are converted into node objects if possible. The node is searched from the source directory, and if a match is found, the equivalent build directory is created and added to the returned list too. When a folder cannot be found, it is ignored. :param inlst: list of folders :type inlst: space-delimited string or a list of string/nodes :rtype: list of :py:class:`waflib.Node.Node` :return: list of include folders as nodes """ lst = [] seen = set() for x in self.to_list(inlst): if x in seen or not x: continue seen.add(x) # with a real lot of targets, it is sometimes interesting to cache the results below if isinstance(x, Node.Node): lst.append(x) else: if os.path.isabs(x): lst.append(self.bld.root.make_node(x) or x) else: if x[0] == '#': p = self.bld.bldnode.make_node(x[1:]) v = self.bld.srcnode.make_node(x[1:]) else: p = self.path.get_bld().make_node(x) v = self.path.make_node(x) if p.is_child_of(self.bld.bldnode): p.mkdir() lst.append(p) lst.append(v) return lst @feature('c', 'cxx', 'd', 'asm', 'fc', 'includes') @after_method('propagate_uselib_vars', 'process_source') def apply_incpaths(self): """ Task generator method that processes the attribute *includes*:: tg = bld(features='includes', includes='.') The folders only need to be relative to the current directory, the equivalent build directory is added automatically (for headers created in the build directory). This enables using a build directory or not (``top == out``). This method will add a list of nodes read by :py:func:`waflib.Tools.ccroot.to_incnodes` in ``tg.env.INCPATHS``, and the list of include paths in ``tg.env.INCLUDES``. """ lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env.INCLUDES) self.includes_nodes = lst cwd = self.get_cwd() self.env.INCPATHS = [x.path_from(cwd) for x in lst] class link_task(Task.Task): """ Base class for all link tasks. A task generator is supposed to have at most one link task bound in the attribute *link_task*. See :py:func:`waflib.Tools.ccroot.apply_link`. .. inheritance-diagram:: waflib.Tools.ccroot.stlink_task waflib.Tools.c.cprogram waflib.Tools.c.cshlib waflib.Tools.cxx.cxxstlib waflib.Tools.cxx.cxxprogram waflib.Tools.cxx.cxxshlib waflib.Tools.d.dprogram waflib.Tools.d.dshlib waflib.Tools.d.dstlib waflib.Tools.ccroot.fake_shlib waflib.Tools.ccroot.fake_stlib waflib.Tools.asm.asmprogram waflib.Tools.asm.asmshlib waflib.Tools.asm.asmstlib :top-classes: waflib.Tools.ccroot.link_task """ color = 'YELLOW' weight = 3 """Try to process link tasks as early as possible""" inst_to = None """Default installation path for the link task outputs, or None to disable""" chmod = Utils.O755 """Default installation mode for the link task outputs""" def add_target(self, target): """ Process the *target* attribute to add the platform-specific prefix/suffix such as *.so* or *.exe*. The settings are retrieved from ``env.clsname_PATTERN`` """ if isinstance(target, str): base = self.generator.path if target.startswith('#'): # for those who like flat structures target = target[1:] base = self.generator.bld.bldnode pattern = self.env[self.__class__.__name__ + '_PATTERN'] if not pattern: pattern = '%s' folder, name = os.path.split(target) if self.__class__.__name__.find('shlib') > 0 and getattr(self.generator, 'vnum', None): nums = self.generator.vnum.split('.') if self.env.DEST_BINFMT == 'pe': # include the version in the dll file name, # the import lib file name stays unversioned. name = name + '-' + nums[0] elif self.env.DEST_OS == 'openbsd': pattern = '%s.%s' % (pattern, nums[0]) if len(nums) >= 2: pattern += '.%s' % nums[1] if folder: tmp = folder + os.sep + pattern % name else: tmp = pattern % name target = base.find_or_declare(tmp) self.set_outputs(target) def exec_command(self, *k, **kw): ret = super(link_task, self).exec_command(*k, **kw) if not ret and self.env.DO_MANIFEST: ret = self.exec_mf() return ret def exec_mf(self): """ Create manifest files for VS-like compilers (msvc, ifort, ...) """ if not self.env.MT: return 0 manifest = None for out_node in self.outputs: if out_node.name.endswith('.manifest'): manifest = out_node.abspath() break else: # Should never get here. If we do, it means the manifest file was # never added to the outputs list, thus we don't have a manifest file # to embed, so we just return. return 0 # embedding mode. Different for EXE's and DLL's. # see: http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx mode = '' for x in Utils.to_list(self.generator.features): if x in ('cprogram', 'cxxprogram', 'fcprogram', 'fcprogram_test'): mode = 1 elif x in ('cshlib', 'cxxshlib', 'fcshlib'): mode = 2 Logs.debug('msvc: embedding manifest in mode %r', mode) lst = [] + self.env.MT lst.extend(Utils.to_list(self.env.MTFLAGS)) lst.extend(['-manifest', manifest]) lst.append('-outputresource:%s;%s' % (self.outputs[0].abspath(), mode)) return super(link_task, self).exec_command(lst) class stlink_task(link_task): """ Base for static link tasks, which use *ar* most of the time. The target is always removed before being written. """ run_str = '${AR} ${ARFLAGS} ${AR_TGT_F}${TGT} ${AR_SRC_F}${SRC}' chmod = Utils.O644 """Default installation mode for the static libraries""" def rm_tgt(cls): old = cls.run def wrap(self): try: os.remove(self.outputs[0].abspath()) except OSError: pass return old(self) setattr(cls, 'run', wrap) rm_tgt(stlink_task) @feature('skip_stlib_link_deps') @before_method('process_use') def apply_skip_stlib_link_deps(self): """ This enables an optimization in the :py:func:wafilb.Tools.ccroot.processes_use: method that skips dependency and link flag optimizations for targets that generate static libraries (via the :py:class:Tools.ccroot.stlink_task task). The actual behavior is implemented in :py:func:wafilb.Tools.ccroot.processes_use: method so this feature only tells waf to enable the new behavior. """ self.env.SKIP_STLIB_LINK_DEPS = True @feature('c', 'cxx', 'd', 'fc', 'asm') @after_method('process_source') def apply_link(self): """ Collect the tasks stored in ``compiled_tasks`` (created by :py:func:`waflib.Tools.ccroot.create_compiled_task`), and use the outputs for a new instance of :py:class:`waflib.Tools.ccroot.link_task`. The class to use is the first link task matching a name from the attribute *features*, for example:: def build(bld): tg = bld(features='cxx cxxprogram cprogram', source='main.c', target='app') will create the task ``tg.link_task`` as a new instance of :py:class:`waflib.Tools.cxx.cxxprogram` """ for x in self.features: if x == 'cprogram' and 'cxx' in self.features: # limited compat x = 'cxxprogram' elif x == 'cshlib' and 'cxx' in self.features: x = 'cxxshlib' if x in Task.classes: if issubclass(Task.classes[x], link_task): link = x break else: return objs = [t.outputs[0] for t in getattr(self, 'compiled_tasks', [])] self.link_task = self.create_task(link, objs) self.link_task.add_target(self.target) # remember that the install paths are given by the task generators try: inst_to = self.install_path except AttributeError: inst_to = self.link_task.inst_to if inst_to: # install a copy of the node list we have at this moment (implib not added) self.install_task = self.add_install_files( install_to=inst_to, install_from=self.link_task.outputs[:], chmod=self.link_task.chmod, task=self.link_task) @taskgen_method def use_rec(self, name, **kw): """ Processes the ``use`` keyword recursively. This method is kind of private and only meant to be used from ``process_use`` """ if name in self.tmp_use_not or name in self.tmp_use_seen: return try: y = self.bld.get_tgen_by_name(name) except Errors.WafError: self.uselib.append(name) self.tmp_use_not.add(name) return self.tmp_use_seen.append(name) y.post() # bind temporary attributes on the task generator y.tmp_use_objects = objects = kw.get('objects', True) y.tmp_use_stlib = stlib = kw.get('stlib', True) try: link_task = y.link_task except AttributeError: y.tmp_use_var = '' else: objects = False if not isinstance(link_task, stlink_task): stlib = False y.tmp_use_var = 'LIB' else: y.tmp_use_var = 'STLIB' p = self.tmp_use_prec for x in self.to_list(getattr(y, 'use', [])): if self.env["STLIB_" + x]: continue try: p[x].append(name) except KeyError: p[x] = [name] self.use_rec(x, objects=objects, stlib=stlib) @feature('c', 'cxx', 'd', 'use', 'fc') @before_method('apply_incpaths', 'propagate_uselib_vars') @after_method('apply_link', 'process_source') def process_use(self): """ Process the ``use`` attribute which contains a list of task generator names:: def build(bld): bld.shlib(source='a.c', target='lib1') bld.program(source='main.c', target='app', use='lib1') See :py:func:`waflib.Tools.ccroot.use_rec`. """ use_not = self.tmp_use_not = set() self.tmp_use_seen = [] # we would like an ordered set use_prec = self.tmp_use_prec = {} self.uselib = self.to_list(getattr(self, 'uselib', [])) self.includes = self.to_list(getattr(self, 'includes', [])) names = self.to_list(getattr(self, 'use', [])) for x in names: self.use_rec(x) for x in use_not: if x in use_prec: del use_prec[x] # topological sort out = self.tmp_use_sorted = [] tmp = [] for x in self.tmp_use_seen: for k in use_prec.values(): if x in k: break else: tmp.append(x) while tmp: e = tmp.pop() out.append(e) try: nlst = use_prec[e] except KeyError: pass else: del use_prec[e] for x in nlst: for y in use_prec: if x in use_prec[y]: break else: tmp.append(x) if use_prec: raise Errors.WafError('Cycle detected in the use processing %r' % use_prec) out.reverse() link_task = getattr(self, 'link_task', None) for x in out: y = self.bld.get_tgen_by_name(x) var = y.tmp_use_var if var and link_task: if self.env.SKIP_STLIB_LINK_DEPS and isinstance(link_task, stlink_task): # If the skip_stlib_link_deps feature is enabled then we should # avoid adding lib deps to the stlink_task instance. pass elif var == 'LIB' or y.tmp_use_stlib or x in names: self.env.append_value(var, [y.target[y.target.rfind(os.sep) + 1:]]) self.link_task.dep_nodes.extend(y.link_task.outputs) tmp_path = y.link_task.outputs[0].parent.path_from(self.get_cwd()) self.env.append_unique(var + 'PATH', [tmp_path]) else: if y.tmp_use_objects: self.add_objects_from_tgen(y) if getattr(y, 'export_includes', None): # self.includes may come from a global variable #2035 self.includes = self.includes + y.to_incnodes(y.export_includes) if getattr(y, 'export_defines', None): self.env.append_value('DEFINES', self.to_list(y.export_defines)) # and finally, add the use variables (no recursion needed) for x in names: try: y = self.bld.get_tgen_by_name(x) except Errors.WafError: if not self.env['STLIB_' + x] and not x in self.uselib: self.uselib.append(x) else: for k in self.to_list(getattr(y, 'use', [])): if not self.env['STLIB_' + k] and not k in self.uselib: self.uselib.append(k) @taskgen_method def accept_node_to_link(self, node): """ PRIVATE INTERNAL USE ONLY """ return not node.name.endswith('.pdb') @taskgen_method def add_objects_from_tgen(self, tg): """ Add the objects from the depending compiled tasks as link task inputs. Some objects are filtered: for instance, .pdb files are added to the compiled tasks but not to the link tasks (to avoid errors) PRIVATE INTERNAL USE ONLY """ try: link_task = self.link_task except AttributeError: pass else: for tsk in getattr(tg, 'compiled_tasks', []): for x in tsk.outputs: if self.accept_node_to_link(x): link_task.inputs.append(x) @taskgen_method def get_uselib_vars(self): """ :return: the *uselib* variables associated to the *features* attribute (see :py:attr:`waflib.Tools.ccroot.USELIB_VARS`) :rtype: list of string """ _vars = set() for x in self.features: if x in USELIB_VARS: _vars |= USELIB_VARS[x] return _vars @feature('c', 'cxx', 'd', 'fc', 'javac', 'cs', 'uselib', 'asm') @after_method('process_use') def propagate_uselib_vars(self): """ Process uselib variables for adding flags. For example, the following target:: def build(bld): bld.env.AFLAGS_aaa = ['bar'] from waflib.Tools.ccroot import USELIB_VARS USELIB_VARS['aaa'] = ['AFLAGS'] tg = bld(features='aaa', aflags='test') The *aflags* attribute will be processed and this method will set:: tg.env.AFLAGS = ['bar', 'test'] """ _vars = self.get_uselib_vars() env = self.env app = env.append_value feature_uselib = self.features + self.to_list(getattr(self, 'uselib', [])) for var in _vars: y = var.lower() val = getattr(self, y, []) if val: app(var, self.to_list(val)) for x in feature_uselib: val = env['%s_%s' % (var, x)] if val: app(var, val) # ============ the code above must not know anything about import libs ========== @feature('cshlib', 'cxxshlib', 'fcshlib') @after_method('apply_link') def apply_implib(self): """ Handle dlls and their import libs on Windows-like systems. A ``.dll.a`` file called *import library* is generated. It must be installed as it is required for linking the library. """ if not self.env.DEST_BINFMT == 'pe': return dll = self.link_task.outputs[0] if isinstance(self.target, Node.Node): name = self.target.name else: name = os.path.split(self.target)[1] implib = self.env.implib_PATTERN % name implib = dll.parent.find_or_declare(implib) self.env.append_value('LINKFLAGS', self.env.IMPLIB_ST % implib.bldpath()) self.link_task.outputs.append(implib) if getattr(self, 'defs', None) and self.env.DEST_BINFMT == 'pe': node = self.path.find_resource(self.defs) if not node: raise Errors.WafError('invalid def file %r' % self.defs) if self.env.def_PATTERN: self.env.append_value('LINKFLAGS', self.env.def_PATTERN % node.path_from(self.get_cwd())) self.link_task.dep_nodes.append(node) else: # gcc for windows takes *.def file as input without any special flag self.link_task.inputs.append(node) # where to put the import library if getattr(self, 'install_task', None): try: # user has given a specific installation path for the import library inst_to = self.install_path_implib except AttributeError: try: # user has given an installation path for the main library, put the import library in it inst_to = self.install_path except AttributeError: # else, put the library in BINDIR and the import library in LIBDIR inst_to = '${IMPLIBDIR}' self.install_task.install_to = '${BINDIR}' if not self.env.IMPLIBDIR: self.env.IMPLIBDIR = self.env.LIBDIR self.implib_install_task = self.add_install_files(install_to=inst_to, install_from=implib, chmod=self.link_task.chmod, task=self.link_task) # ============ the code above must not know anything about vnum processing on unix platforms ========= re_vnum = re.compile('^([1-9]\\d*|0)([.]([1-9]\\d*|0)){0,2}?$') @feature('cshlib', 'cxxshlib', 'dshlib', 'fcshlib', 'vnum') @after_method('apply_link', 'propagate_uselib_vars') def apply_vnum(self): """ Enforce version numbering on shared libraries. The valid version numbers must have either zero or two dots:: def build(bld): bld.shlib(source='a.c', target='foo', vnum='14.15.16') In this example on Linux platform, ``libfoo.so`` is installed as ``libfoo.so.14.15.16``, and the following symbolic links are created: * ``libfoo.so → libfoo.so.14.15.16`` * ``libfoo.so.14 → libfoo.so.14.15.16`` By default, the library will be assigned SONAME ``libfoo.so.14``, effectively declaring ABI compatibility between all minor and patch releases for the major version of the library. When necessary, the compatibility can be explicitly defined using `cnum` parameter: def build(bld): bld.shlib(source='a.c', target='foo', vnum='14.15.16', cnum='14.15') In this case, the assigned SONAME will be ``libfoo.so.14.15`` with ABI compatibility only between path releases for a specific major and minor version of the library. On OS X platform, install-name parameter will follow the above logic for SONAME with exception that it also specifies an absolute path (based on install_path) of the library. """ if not getattr(self, 'vnum', '') or os.name != 'posix' or self.env.DEST_BINFMT not in ('elf', 'mac-o'): return link = self.link_task if not re_vnum.match(self.vnum): raise Errors.WafError('Invalid vnum %r for target %r' % (self.vnum, getattr(self, 'name', self))) nums = self.vnum.split('.') node = link.outputs[0] cnum = getattr(self, 'cnum', str(nums[0])) cnums = cnum.split('.') if len(cnums)>len(nums) or nums[0:len(cnums)] != cnums: raise Errors.WafError('invalid compatibility version %s' % cnum) libname = node.name if libname.endswith('.dylib'): name3 = libname.replace('.dylib', '.%s.dylib' % self.vnum) name2 = libname.replace('.dylib', '.%s.dylib' % cnum) else: name3 = libname + '.' + self.vnum name2 = libname + '.' + cnum # add the so name for the ld linker - to disable, just unset env.SONAME_ST if self.env.SONAME_ST: v = self.env.SONAME_ST % name2 self.env.append_value('LINKFLAGS', v.split()) # the following task is just to enable execution from the build dir :-/ if self.env.DEST_OS != 'openbsd': outs = [node.parent.make_node(name3)] if name2 != name3: outs.append(node.parent.make_node(name2)) self.create_task('vnum', node, outs) if getattr(self, 'install_task', None): self.install_task.hasrun = Task.SKIPPED self.install_task.no_errcheck_out = True path = self.install_task.install_to if self.env.DEST_OS == 'openbsd': libname = self.link_task.outputs[0].name t1 = self.add_install_as(install_to='%s/%s' % (path, libname), install_from=node, chmod=self.link_task.chmod) self.vnum_install_task = (t1,) else: t1 = self.add_install_as(install_to=path + os.sep + name3, install_from=node, chmod=self.link_task.chmod) t3 = self.add_symlink_as(install_to=path + os.sep + libname, install_from=name3) if name2 != name3: t2 = self.add_symlink_as(install_to=path + os.sep + name2, install_from=name3) self.vnum_install_task = (t1, t2, t3) else: self.vnum_install_task = (t1, t3) if '-dynamiclib' in self.env.LINKFLAGS: # this requires after(propagate_uselib_vars) try: inst_to = self.install_path except AttributeError: inst_to = self.link_task.inst_to if inst_to: p = Utils.subst_vars(inst_to, self.env) path = os.path.join(p, name2) self.env.append_value('LINKFLAGS', ['-install_name', path]) self.env.append_value('LINKFLAGS', '-Wl,-compatibility_version,%s' % cnum) self.env.append_value('LINKFLAGS', '-Wl,-current_version,%s' % self.vnum) class vnum(Task.Task): """ Create the symbolic links for a versioned shared library. Instances are created by :py:func:`waflib.Tools.ccroot.apply_vnum` """ color = 'CYAN' ext_in = ['.bin'] def keyword(self): return 'Symlinking' def run(self): for x in self.outputs: path = x.abspath() try: os.remove(path) except OSError: pass try: os.symlink(self.inputs[0].name, path) except OSError: return 1 class fake_shlib(link_task): """ Task used for reading a system library and adding the dependency on it """ def runnable_status(self): for t in self.run_after: if not t.hasrun: return Task.ASK_LATER return Task.SKIP_ME class fake_stlib(stlink_task): """ Task used for reading a system library and adding the dependency on it """ def runnable_status(self): for t in self.run_after: if not t.hasrun: return Task.ASK_LATER return Task.SKIP_ME @conf def read_shlib(self, name, paths=[], export_includes=[], export_defines=[]): """ Read a system shared library, enabling its use as a local library. Will trigger a rebuild if the file changes:: def build(bld): bld.read_shlib('m') bld.program(source='main.c', use='m') """ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='shlib', export_includes=export_includes, export_defines=export_defines) @conf def read_stlib(self, name, paths=[], export_includes=[], export_defines=[]): """ Read a system static library, enabling a use as a local library. Will trigger a rebuild if the file changes. """ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='stlib', export_includes=export_includes, export_defines=export_defines) lib_patterns = { 'shlib' : ['lib%s.so', '%s.so', 'lib%s.dylib', 'lib%s.dll', '%s.dll'], 'stlib' : ['lib%s.a', '%s.a', 'lib%s.dll', '%s.dll', 'lib%s.lib', '%s.lib'], } @feature('fake_lib') def process_lib(self): """ Find the location of a foreign library. Used by :py:class:`waflib.Tools.ccroot.read_shlib` and :py:class:`waflib.Tools.ccroot.read_stlib`. """ node = None names = [x % self.name for x in lib_patterns[self.lib_type]] for x in self.lib_paths + [self.path] + SYSTEM_LIB_PATHS: if not isinstance(x, Node.Node): x = self.bld.root.find_node(x) or self.path.find_node(x) if not x: continue for y in names: node = x.find_node(y) if node: try: Utils.h_file(node.abspath()) except EnvironmentError: raise ValueError('Could not read %r' % y) break else: continue break else: raise Errors.WafError('could not find library %r' % self.name) self.link_task = self.create_task('fake_%s' % self.lib_type, [], [node]) self.target = self.name class fake_o(Task.Task): def runnable_status(self): return Task.SKIP_ME @extension('.o', '.obj') def add_those_o_files(self, node): tsk = self.create_task('fake_o', [], node) try: self.compiled_tasks.append(tsk) except AttributeError: self.compiled_tasks = [tsk] @feature('fake_obj') @before_method('process_source') def process_objs(self): """ Puts object files in the task generator outputs """ for node in self.to_nodes(self.source): self.add_those_o_files(node) self.source = [] @conf def read_object(self, obj): """ Read an object file, enabling injection in libs/programs. Will trigger a rebuild if the file changes. :param obj: object file path, as string or Node """ if not isinstance(obj, self.path.__class__): obj = self.path.find_resource(obj) return self(features='fake_obj', source=obj, name=obj.name) @feature('cxxprogram', 'cprogram') @after_method('apply_link', 'process_use') def set_full_paths_hpux(self): """ On hp-ux, extend the libpaths and static library paths to absolute paths """ if self.env.DEST_OS != 'hp-ux': return base = self.bld.bldnode.abspath() for var in ['LIBPATH', 'STLIBPATH']: lst = [] for x in self.env[var]: if x.startswith('/'): lst.append(x) else: lst.append(os.path.normpath(os.path.join(base, x))) self.env[var] = lst hamster-3.0.3/waflib/Tools/clang.py000066400000000000000000000011571452646177100172030ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Krzysztof Kosiński 2014 """ Detect the Clang C compiler """ from waflib.Tools import ccroot, ar, gcc from waflib.Configure import conf @conf def find_clang(conf): """ Finds the program clang and executes it to ensure it really is clang """ cc = conf.find_program('clang', var='CC') conf.get_cc_version(cc, clang=True) conf.env.CC_NAME = 'clang' def configure(conf): conf.find_clang() conf.find_program(['llvm-ar', 'ar'], var='AR') conf.find_ar() conf.gcc_common_flags() conf.gcc_modifier_platform() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/clangxx.py000066400000000000000000000012101452646177100175510ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy 2009-2018 (ita) """ Detect the Clang++ C++ compiler """ from waflib.Tools import ccroot, ar, gxx from waflib.Configure import conf @conf def find_clangxx(conf): """ Finds the program clang++, and executes it to ensure it really is clang++ """ cxx = conf.find_program('clang++', var='CXX') conf.get_cc_version(cxx, clang=True) conf.env.CXX_NAME = 'clang' def configure(conf): conf.find_clangxx() conf.find_program(['llvm-ar', 'ar'], var='AR') conf.find_ar() conf.gxx_common_flags() conf.gxx_modifier_platform() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/compiler_c.py000066400000000000000000000062631452646177100202360ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Matthias Jahn jahn dôt matthias ât freenet dôt de, 2007 (pmarat) """ Try to detect a C compiler from the list of supported compilers (gcc, msvc, etc):: def options(opt): opt.load('compiler_c') def configure(cnf): cnf.load('compiler_c') def build(bld): bld.program(source='main.c', target='app') The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_c.c_compiler`. To register a new C compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use:: from waflib.Tools.compiler_c import c_compiler c_compiler['win32'] = ['cfoo', 'msvc', 'gcc'] def options(opt): opt.load('compiler_c') def configure(cnf): cnf.load('compiler_c') def build(bld): bld.program(source='main.c', target='app') Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using:: $ CC=clang waf configure """ import re from waflib.Tools import ccroot from waflib import Utils from waflib.Logs import debug c_compiler = { 'win32': ['msvc', 'gcc', 'clang'], 'cygwin': ['gcc', 'clang'], 'darwin': ['clang', 'gcc'], 'aix': ['xlc', 'gcc', 'clang'], 'linux': ['gcc', 'clang', 'icc'], 'sunos': ['suncc', 'gcc'], 'irix': ['gcc', 'irixcc'], 'hpux': ['gcc'], 'osf1V': ['gcc'], 'gnu': ['gcc', 'clang'], 'java': ['gcc', 'msvc', 'clang', 'icc'], 'gnukfreebsd': ['gcc', 'clang'], 'default': ['clang', 'gcc'], } """ Dict mapping platform names to Waf tools finding specific C compilers:: from waflib.Tools.compiler_c import c_compiler c_compiler['linux'] = ['gcc', 'icc', 'suncc'] """ def default_compilers(): build_platform = Utils.unversioned_sys_platform() possible_compiler_list = c_compiler.get(build_platform, c_compiler['default']) return ' '.join(possible_compiler_list) def configure(conf): """ Detects a suitable C compiler :raises: :py:class:`waflib.Errors.ConfigurationError` when no suitable compiler is found """ try: test_for_compiler = conf.options.check_c_compiler or default_compilers() except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_c')") for compiler in re.split('[ ,]+', test_for_compiler): conf.env.stash() conf.start_msg('Checking for %r (C compiler)' % compiler) try: conf.load(compiler) except conf.errors.ConfigurationError as e: conf.env.revert() conf.end_msg(False) debug('compiler_c: %r', e) else: if conf.env.CC: conf.end_msg(conf.env.get_flat('CC')) conf.env.COMPILER_CC = compiler conf.env.commit() break conf.env.revert() conf.end_msg(False) else: conf.fatal('could not configure a C compiler!') def options(opt): """ This is how to provide compiler preferences on the command-line:: $ waf configure --check-c-compiler=gcc """ test_for_compiler = default_compilers() opt.load_special_tools('c_*.py', ban=['c_dumbpreproc.py']) cc_compiler_opts = opt.add_option_group('Configuration options') cc_compiler_opts.add_option('--check-c-compiler', default=None, help='list of C compilers to try [%s]' % test_for_compiler, dest="check_c_compiler") for x in test_for_compiler.split(): opt.load('%s' % x) hamster-3.0.3/waflib/Tools/compiler_cxx.py000066400000000000000000000063551452646177100206200ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Matthias Jahn jahn dôt matthias ât freenet dôt de 2007 (pmarat) """ Try to detect a C++ compiler from the list of supported compilers (g++, msvc, etc):: def options(opt): opt.load('compiler_cxx') def configure(cnf): cnf.load('compiler_cxx') def build(bld): bld.program(source='main.cpp', target='app') The compilers are associated to platforms in :py:attr:`waflib.Tools.compiler_cxx.cxx_compiler`. To register a new C++ compiler named *cfoo* (assuming the tool ``waflib/extras/cfoo.py`` exists), use:: from waflib.Tools.compiler_cxx import cxx_compiler cxx_compiler['win32'] = ['cfoo', 'msvc', 'gcc'] def options(opt): opt.load('compiler_cxx') def configure(cnf): cnf.load('compiler_cxx') def build(bld): bld.program(source='main.c', target='app') Not all compilers need to have a specific tool. For example, the clang compilers can be detected by the gcc tools when using:: $ CXX=clang waf configure """ import re from waflib.Tools import ccroot from waflib import Utils from waflib.Logs import debug cxx_compiler = { 'win32': ['msvc', 'g++', 'clang++'], 'cygwin': ['g++', 'clang++'], 'darwin': ['clang++', 'g++'], 'aix': ['xlc++', 'g++', 'clang++'], 'linux': ['g++', 'clang++', 'icpc'], 'sunos': ['sunc++', 'g++'], 'irix': ['g++'], 'hpux': ['g++'], 'osf1V': ['g++'], 'gnu': ['g++', 'clang++'], 'java': ['g++', 'msvc', 'clang++', 'icpc'], 'gnukfreebsd': ['g++', 'clang++'], 'default': ['clang++', 'g++'] } """ Dict mapping the platform names to Waf tools finding specific C++ compilers:: from waflib.Tools.compiler_cxx import cxx_compiler cxx_compiler['linux'] = ['gxx', 'icpc', 'suncxx'] """ def default_compilers(): build_platform = Utils.unversioned_sys_platform() possible_compiler_list = cxx_compiler.get(build_platform, cxx_compiler['default']) return ' '.join(possible_compiler_list) def configure(conf): """ Detects a suitable C++ compiler :raises: :py:class:`waflib.Errors.ConfigurationError` when no suitable compiler is found """ try: test_for_compiler = conf.options.check_cxx_compiler or default_compilers() except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_cxx')") for compiler in re.split('[ ,]+', test_for_compiler): conf.env.stash() conf.start_msg('Checking for %r (C++ compiler)' % compiler) try: conf.load(compiler) except conf.errors.ConfigurationError as e: conf.env.revert() conf.end_msg(False) debug('compiler_cxx: %r', e) else: if conf.env.CXX: conf.end_msg(conf.env.get_flat('CXX')) conf.env.COMPILER_CXX = compiler conf.env.commit() break conf.env.revert() conf.end_msg(False) else: conf.fatal('could not configure a C++ compiler!') def options(opt): """ This is how to provide compiler preferences on the command-line:: $ waf configure --check-cxx-compiler=gxx """ test_for_compiler = default_compilers() opt.load_special_tools('cxx_*.py') cxx_compiler_opts = opt.add_option_group('Configuration options') cxx_compiler_opts.add_option('--check-cxx-compiler', default=None, help='list of C++ compilers to try [%s]' % test_for_compiler, dest="check_cxx_compiler") for x in test_for_compiler.split(): opt.load('%s' % x) hamster-3.0.3/waflib/Tools/compiler_d.py000066400000000000000000000043311452646177100202310ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2007 (dv) # Thomas Nagy, 2016-2018 (ita) """ Try to detect a D compiler from the list of supported compilers:: def options(opt): opt.load('compiler_d') def configure(cnf): cnf.load('compiler_d') def build(bld): bld.program(source='main.d', target='app') Only three D compilers are really present at the moment: * gdc * dmd, the ldc compiler having a very similar command-line interface * ldc2 """ import re from waflib import Utils, Logs d_compiler = { 'default' : ['gdc', 'dmd', 'ldc2'] } """ Dict mapping the platform names to lists of names of D compilers to try, in order of preference:: from waflib.Tools.compiler_d import d_compiler d_compiler['default'] = ['gdc', 'dmd', 'ldc2'] """ def default_compilers(): build_platform = Utils.unversioned_sys_platform() possible_compiler_list = d_compiler.get(build_platform, d_compiler['default']) return ' '.join(possible_compiler_list) def configure(conf): """ Detects a suitable D compiler :raises: :py:class:`waflib.Errors.ConfigurationError` when no suitable compiler is found """ try: test_for_compiler = conf.options.check_d_compiler or default_compilers() except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_d')") for compiler in re.split('[ ,]+', test_for_compiler): conf.env.stash() conf.start_msg('Checking for %r (D compiler)' % compiler) try: conf.load(compiler) except conf.errors.ConfigurationError as e: conf.env.revert() conf.end_msg(False) Logs.debug('compiler_d: %r', e) else: if conf.env.D: conf.end_msg(conf.env.get_flat('D')) conf.env.COMPILER_D = compiler conf.env.commit() break conf.env.revert() conf.end_msg(False) else: conf.fatal('could not configure a D compiler!') def options(opt): """ This is how to provide compiler preferences on the command-line:: $ waf configure --check-d-compiler=dmd """ test_for_compiler = default_compilers() d_compiler_opts = opt.add_option_group('Configuration options') d_compiler_opts.add_option('--check-d-compiler', default=None, help='list of D compilers to try [%s]' % test_for_compiler, dest='check_d_compiler') for x in test_for_compiler.split(): opt.load('%s' % x) hamster-3.0.3/waflib/Tools/compiler_fc.py000066400000000000000000000041621452646177100204000ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 import re from waflib import Utils, Logs from waflib.Tools import fc fc_compiler = { 'win32' : ['gfortran','ifort'], 'darwin' : ['gfortran', 'g95', 'ifort'], 'linux' : ['gfortran', 'g95', 'ifort'], 'java' : ['gfortran', 'g95', 'ifort'], 'default': ['gfortran'], 'aix' : ['gfortran'] } """ Dict mapping the platform names to lists of names of Fortran compilers to try, in order of preference:: from waflib.Tools.compiler_c import c_compiler c_compiler['linux'] = ['gfortran', 'g95', 'ifort'] """ def default_compilers(): build_platform = Utils.unversioned_sys_platform() possible_compiler_list = fc_compiler.get(build_platform, fc_compiler['default']) return ' '.join(possible_compiler_list) def configure(conf): """ Detects a suitable Fortran compiler :raises: :py:class:`waflib.Errors.ConfigurationError` when no suitable compiler is found """ try: test_for_compiler = conf.options.check_fortran_compiler or default_compilers() except AttributeError: conf.fatal("Add options(opt): opt.load('compiler_fc')") for compiler in re.split('[ ,]+', test_for_compiler): conf.env.stash() conf.start_msg('Checking for %r (Fortran compiler)' % compiler) try: conf.load(compiler) except conf.errors.ConfigurationError as e: conf.env.revert() conf.end_msg(False) Logs.debug('compiler_fortran: %r', e) else: if conf.env.FC: conf.end_msg(conf.env.get_flat('FC')) conf.env.COMPILER_FORTRAN = compiler conf.env.commit() break conf.env.revert() conf.end_msg(False) else: conf.fatal('could not configure a Fortran compiler!') def options(opt): """ This is how to provide compiler preferences on the command-line:: $ waf configure --check-fortran-compiler=ifort """ test_for_compiler = default_compilers() opt.load_special_tools('fc_*.py') fortran_compiler_opts = opt.add_option_group('Configuration options') fortran_compiler_opts.add_option('--check-fortran-compiler', default=None, help='list of Fortran compiler to try [%s]' % test_for_compiler, dest="check_fortran_compiler") for x in test_for_compiler.split(): opt.load('%s' % x) hamster-3.0.3/waflib/Tools/cs.py000066400000000000000000000143751452646177100165320ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ C# support. A simple example:: def configure(conf): conf.load('cs') def build(bld): bld(features='cs', source='main.cs', gen='foo') Note that the configuration may compile C# snippets:: FRAG = ''' namespace Moo { public class Test { public static int Main(string[] args) { return 0; } } }''' def configure(conf): conf.check(features='cs', fragment=FRAG, compile_filename='test.cs', gen='test.exe', bintype='exe', csflags=['-pkg:gtk-sharp-2.0'], msg='Checking for Gtksharp support') """ from waflib import Utils, Task, Options, Errors from waflib.TaskGen import before_method, after_method, feature from waflib.Tools import ccroot from waflib.Configure import conf ccroot.USELIB_VARS['cs'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES']) ccroot.lib_patterns['csshlib'] = ['%s'] @feature('cs') @before_method('process_source') def apply_cs(self): """ Create a C# task bound to the attribute *cs_task*. There can be only one C# task by task generator. """ cs_nodes = [] no_nodes = [] for x in self.to_nodes(self.source): if x.name.endswith('.cs'): cs_nodes.append(x) else: no_nodes.append(x) self.source = no_nodes bintype = getattr(self, 'bintype', self.gen.endswith('.dll') and 'library' or 'exe') self.cs_task = tsk = self.create_task('mcs', cs_nodes, self.path.find_or_declare(self.gen)) tsk.env.CSTYPE = '/target:%s' % bintype tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath() self.env.append_value('CSFLAGS', '/platform:%s' % getattr(self, 'platform', 'anycpu')) inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}') if inst_to: # note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644) self.install_task = self.add_install_files(install_to=inst_to, install_from=self.cs_task.outputs[:], chmod=mod) @feature('cs') @after_method('apply_cs') def use_cs(self): """ C# applications honor the **use** keyword:: def build(bld): bld(features='cs', source='My.cs', bintype='library', gen='my.dll', name='mylib') bld(features='cs', source='Hi.cs', includes='.', bintype='exe', gen='hi.exe', use='mylib', name='hi') """ names = self.to_list(getattr(self, 'use', [])) get = self.bld.get_tgen_by_name for x in names: try: y = get(x) except Errors.WafError: self.env.append_value('CSFLAGS', '/reference:%s' % x) continue y.post() tsk = getattr(y, 'cs_task', None) or getattr(y, 'link_task', None) if not tsk: self.bld.fatal('cs task has no link task for use %r' % self) self.cs_task.dep_nodes.extend(tsk.outputs) # dependency self.cs_task.set_run_after(tsk) # order (redundant, the order is inferred from the nodes inputs/outputs) self.env.append_value('CSFLAGS', '/reference:%s' % tsk.outputs[0].abspath()) @feature('cs') @after_method('apply_cs', 'use_cs') def debug_cs(self): """ The C# targets may create .mdb or .pdb files:: def build(bld): bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdebug='full') # csdebug is a value in (True, 'full', 'pdbonly') """ csdebug = getattr(self, 'csdebug', self.env.CSDEBUG) if not csdebug: return node = self.cs_task.outputs[0] if self.env.CS_NAME == 'mono': out = node.parent.find_or_declare(node.name + '.mdb') else: out = node.change_ext('.pdb') self.cs_task.outputs.append(out) if getattr(self, 'install_task', None): self.pdb_install_task = self.add_install_files( install_to=self.install_task.install_to, install_from=out) if csdebug == 'pdbonly': val = ['/debug+', '/debug:pdbonly'] elif csdebug == 'full': val = ['/debug+', '/debug:full'] else: val = ['/debug-'] self.env.append_value('CSFLAGS', val) @feature('cs') @after_method('debug_cs') def doc_cs(self): """ The C# targets may create .xml documentation files:: def build(bld): bld(features='cs', source='My.cs', bintype='library', gen='my.dll', csdoc=True) # csdoc is a boolean value """ csdoc = getattr(self, 'csdoc', self.env.CSDOC) if not csdoc: return node = self.cs_task.outputs[0] out = node.change_ext('.xml') self.cs_task.outputs.append(out) if getattr(self, 'install_task', None): self.doc_install_task = self.add_install_files( install_to=self.install_task.install_to, install_from=out) self.env.append_value('CSFLAGS', '/doc:%s' % out.abspath()) class mcs(Task.Task): """ Compile C# files """ color = 'YELLOW' run_str = '${MCS} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}' def split_argfile(self, cmd): inline = [cmd[0]] infile = [] for x in cmd[1:]: # csc doesn't want /noconfig in @file if x.lower() == '/noconfig': inline.append(x) else: infile.append(self.quote_flag(x)) return (inline, infile) def configure(conf): """ Find a C# compiler, set the variable MCS for the compiler and CS_NAME (mono or csc) """ csc = getattr(Options.options, 'cscbinary', None) if csc: conf.env.MCS = csc conf.find_program(['csc', 'mcs', 'gmcs'], var='MCS') conf.env.ASS_ST = '/r:%s' conf.env.RES_ST = '/resource:%s' conf.env.CS_NAME = 'csc' if str(conf.env.MCS).lower().find('mcs') > -1: conf.env.CS_NAME = 'mono' def options(opt): """ Add a command-line option for the configuration:: $ waf configure --with-csc-binary=/foo/bar/mcs """ opt.add_option('--with-csc-binary', type='string', dest='cscbinary') class fake_csshlib(Task.Task): """ Task used for reading a foreign .net assembly and adding the dependency on it """ color = 'YELLOW' inst_to = None def runnable_status(self): return Task.SKIP_ME @conf def read_csshlib(self, name, paths=[]): """ Read a foreign .net assembly for the *use* system:: def build(bld): bld.read_csshlib('ManagedLibrary.dll', paths=[bld.env.mylibrarypath]) bld(features='cs', source='Hi.cs', bintype='exe', gen='hi.exe', use='ManagedLibrary.dll') :param name: Name of the library :type name: string :param paths: Folders in which the library may be found :type paths: list of string :return: A task generator having the feature *fake_lib* which will call :py:func:`waflib.Tools.ccroot.process_lib` :rtype: :py:class:`waflib.TaskGen.task_gen` """ return self(name=name, features='fake_lib', lib_paths=paths, lib_type='csshlib') hamster-3.0.3/waflib/Tools/cxx.py000066400000000000000000000031261452646177100167170ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) "Base for c++ programs and libraries" from waflib import TaskGen, Task from waflib.Tools import c_preproc from waflib.Tools.ccroot import link_task, stlink_task @TaskGen.extension('.cpp','.cc','.cxx','.C','.c++') def cxx_hook(self, node): "Binds c++ file extensions to create :py:class:`waflib.Tools.cxx.cxx` instances" return self.create_compiled_task('cxx', node) if not '.c' in TaskGen.task_gen.mappings: TaskGen.task_gen.mappings['.c'] = TaskGen.task_gen.mappings['.cpp'] class cxx(Task.Task): "Compiles C++ files into object files" run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXX_SRC_F}${SRC} ${CXX_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}' vars = ['CXXDEPS'] # unused variable to depend on, just in case ext_in = ['.h'] # set the build order easily by using ext_out=['.h'] scan = c_preproc.scan class cxxprogram(link_task): "Links object files into c++ programs" run_str = '${LINK_CXX} ${LINKFLAGS} ${CXXLNK_SRC_F}${SRC} ${CXXLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LDFLAGS}' vars = ['LINKDEPS'] ext_out = ['.bin'] inst_to = '${BINDIR}' class cxxshlib(cxxprogram): "Links object files into c++ shared libraries" inst_to = '${LIBDIR}' class cxxstlib(stlink_task): "Links object files into c++ static libraries" pass # do not remove hamster-3.0.3/waflib/Tools/d.py000066400000000000000000000057061452646177100163460ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2007 (dv) # Thomas Nagy, 2007-2018 (ita) from waflib import Utils, Task, Errors from waflib.TaskGen import taskgen_method, feature, extension from waflib.Tools import d_scan, d_config from waflib.Tools.ccroot import link_task, stlink_task class d(Task.Task): "Compile a d file into an object file" color = 'GREEN' run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_SRC_F:SRC} ${D_TGT_F:TGT}' scan = d_scan.scan class d_with_header(d): "Compile a d file and generate a header" run_str = '${D} ${DFLAGS} ${DINC_ST:INCPATHS} ${D_HDR_F:tgt.outputs[1].bldpath()} ${D_SRC_F:SRC} ${D_TGT_F:tgt.outputs[0].bldpath()}' class d_header(Task.Task): "Compile d headers" color = 'BLUE' run_str = '${D} ${D_HEADER} ${SRC}' class dprogram(link_task): "Link object files into a d program" run_str = '${D_LINKER} ${LINKFLAGS} ${DLNK_SRC_F}${SRC} ${DLNK_TGT_F:TGT} ${RPATH_ST:RPATH} ${DSTLIB_MARKER} ${DSTLIBPATH_ST:STLIBPATH} ${DSTLIB_ST:STLIB} ${DSHLIB_MARKER} ${DLIBPATH_ST:LIBPATH} ${DSHLIB_ST:LIB}' inst_to = '${BINDIR}' class dshlib(dprogram): "Link object files into a d shared library" inst_to = '${LIBDIR}' class dstlib(stlink_task): "Link object files into a d static library" pass # do not remove @extension('.d', '.di', '.D') def d_hook(self, node): """ Compile *D* files. To get .di files as well as .o files, set the following:: def build(bld): bld.program(source='foo.d', target='app', generate_headers=True) """ ext = Utils.destos_to_binfmt(self.env.DEST_OS) == 'pe' and 'obj' or 'o' out = '%s.%d.%s' % (node.name, self.idx, ext) def create_compiled_task(self, name, node): task = self.create_task(name, node, node.parent.find_or_declare(out)) try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] return task if getattr(self, 'generate_headers', None): tsk = create_compiled_task(self, 'd_with_header', node) tsk.outputs.append(node.change_ext(self.env.DHEADER_ext)) else: tsk = create_compiled_task(self, 'd', node) return tsk @taskgen_method def generate_header(self, filename): """ See feature request #104:: def build(bld): tg = bld.program(source='foo.d', target='app') tg.generate_header('blah.d') # is equivalent to: #tg = bld.program(source='foo.d', target='app', header_lst='blah.d') :param filename: header to create :type filename: string """ try: self.header_lst.append([filename, self.install_path]) except AttributeError: self.header_lst = [[filename, self.install_path]] @feature('d') def process_header(self): """ Process the attribute 'header_lst' to create the d header compilation tasks:: def build(bld): bld.program(source='foo.d', target='app', header_lst='blah.d') """ for i in getattr(self, 'header_lst', []): node = self.path.find_resource(i[0]) if not node: raise Errors.WafError('file %r not found on d obj' % i[0]) self.create_task('d_header', node, node.change_ext('.di')) hamster-3.0.3/waflib/Tools/d_config.py000066400000000000000000000026071452646177100176700ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2016-2018 (ita) from waflib import Utils from waflib.Configure import conf @conf def d_platform_flags(self): """ Sets the extensions dll/so for d programs and libraries """ v = self.env if not v.DEST_OS: v.DEST_OS = Utils.unversioned_sys_platform() binfmt = Utils.destos_to_binfmt(self.env.DEST_OS) if binfmt == 'pe': v.dprogram_PATTERN = '%s.exe' v.dshlib_PATTERN = 'lib%s.dll' v.dstlib_PATTERN = 'lib%s.a' elif binfmt == 'mac-o': v.dprogram_PATTERN = '%s' v.dshlib_PATTERN = 'lib%s.dylib' v.dstlib_PATTERN = 'lib%s.a' else: v.dprogram_PATTERN = '%s' v.dshlib_PATTERN = 'lib%s.so' v.dstlib_PATTERN = 'lib%s.a' DLIB = ''' version(D_Version2) { import std.stdio; int main() { writefln("phobos2"); return 0; } } else { version(Tango) { import tango.stdc.stdio; int main() { printf("tango"); return 0; } } else { import std.stdio; int main() { writefln("phobos1"); return 0; } } } ''' """Detection string for the D standard library""" @conf def check_dlibrary(self, execute=True): """ Detects the kind of standard library that comes with the compiler, and sets conf.env.DLIBRARY to tango, phobos1 or phobos2 """ ret = self.check_cc(features='d dprogram', fragment=DLIB, compile_filename='test.d', execute=execute, define_ret=True) if execute: self.env.DLIBRARY = ret.strip() hamster-3.0.3/waflib/Tools/d_scan.py000066400000000000000000000117001452646177100173410ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2016-2018 (ita) """ Provide a scanner for finding dependencies on d files """ import re from waflib import Utils def filter_comments(filename): """ :param filename: d file name :type filename: string :rtype: list :return: a list of characters """ txt = Utils.readf(filename) i = 0 buf = [] max = len(txt) begin = 0 while i < max: c = txt[i] if c == '"' or c == "'": # skip a string or character literal buf.append(txt[begin:i]) delim = c i += 1 while i < max: c = txt[i] if c == delim: break elif c == '\\': # skip the character following backslash i += 1 i += 1 i += 1 begin = i elif c == '/': # try to replace a comment with whitespace buf.append(txt[begin:i]) i += 1 if i == max: break c = txt[i] if c == '+': # eat nesting /+ +/ comment i += 1 nesting = 1 c = None while i < max: prev = c c = txt[i] if prev == '/' and c == '+': nesting += 1 c = None elif prev == '+' and c == '/': nesting -= 1 if nesting == 0: break c = None i += 1 elif c == '*': # eat /* */ comment i += 1 c = None while i < max: prev = c c = txt[i] if prev == '*' and c == '/': break i += 1 elif c == '/': # eat // comment i += 1 while i < max and txt[i] != '\n': i += 1 else: # no comment begin = i - 1 continue i += 1 begin = i buf.append(' ') else: i += 1 buf.append(txt[begin:]) return buf class d_parser(object): """ Parser for d files """ def __init__(self, env, incpaths): #self.code = '' #self.module = '' #self.imports = [] self.allnames = [] self.re_module = re.compile(r"module\s+([^;]+)") self.re_import = re.compile(r"import\s+([^;]+)") self.re_import_bindings = re.compile("([^:]+):(.*)") self.re_import_alias = re.compile("[^=]+=(.+)") self.env = env self.nodes = [] self.names = [] self.incpaths = incpaths def tryfind(self, filename): """ Search file a file matching an module/import directive :param filename: file to read :type filename: string """ found = 0 for n in self.incpaths: found = n.find_resource(filename.replace('.', '/') + '.d') if found: self.nodes.append(found) self.waiting.append(found) break if not found: if not filename in self.names: self.names.append(filename) def get_strings(self, code): """ :param code: d code to parse :type code: string :return: the modules that the code uses :rtype: a list of match objects """ #self.imports = [] self.module = '' lst = [] # get the module name (if present) mod_name = self.re_module.search(code) if mod_name: self.module = re.sub(r'\s+', '', mod_name.group(1)) # strip all whitespaces # go through the code, have a look at all import occurrences # first, lets look at anything beginning with "import" and ending with ";" import_iterator = self.re_import.finditer(code) if import_iterator: for import_match in import_iterator: import_match_str = re.sub(r'\s+', '', import_match.group(1)) # strip all whitespaces # does this end with an import bindings declaration? # (import bindings always terminate the list of imports) bindings_match = self.re_import_bindings.match(import_match_str) if bindings_match: import_match_str = bindings_match.group(1) # if so, extract the part before the ":" (since the module declaration(s) is/are located there) # split the matching string into a bunch of strings, separated by a comma matches = import_match_str.split(',') for match in matches: alias_match = self.re_import_alias.match(match) if alias_match: # is this an alias declaration? (alias = module name) if so, extract the module name match = alias_match.group(1) lst.append(match) return lst def start(self, node): """ The parsing starts here :param node: input file :type node: :py:class:`waflib.Node.Node` """ self.waiting = [node] # while the stack is not empty, add the dependencies while self.waiting: nd = self.waiting.pop(0) self.iter(nd) def iter(self, node): """ Find all the modules that a file depends on, uses :py:meth:`waflib.Tools.d_scan.d_parser.tryfind` to process dependent files :param node: input file :type node: :py:class:`waflib.Node.Node` """ path = node.abspath() # obtain the absolute path code = "".join(filter_comments(path)) # read the file and filter the comments names = self.get_strings(code) # obtain the import strings for x in names: # optimization if x in self.allnames: continue self.allnames.append(x) # for each name, see if it is like a node or not self.tryfind(x) def scan(self): "look for .d/.di used by a d file" env = self.env gruik = d_parser(env, self.generator.includes_nodes) node = self.inputs[0] gruik.start(node) nodes = gruik.nodes names = gruik.names return (nodes, names) hamster-3.0.3/waflib/Tools/dbus.py000066400000000000000000000040161452646177100170510ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Ali Sabil, 2007 """ Compiles dbus files with **dbus-binding-tool** Typical usage:: def options(opt): opt.load('compiler_c dbus') def configure(conf): conf.load('compiler_c dbus') def build(bld): tg = bld.program( includes = '.', source = bld.path.ant_glob('*.c'), target = 'gnome-hello') tg.add_dbus_file('test.xml', 'test_prefix', 'glib-server') """ from waflib import Task, Errors from waflib.TaskGen import taskgen_method, before_method @taskgen_method def add_dbus_file(self, filename, prefix, mode): """ Adds a dbus file to the list of dbus files to process. Store them in the attribute *dbus_lst*. :param filename: xml file to compile :type filename: string :param prefix: dbus binding tool prefix (--prefix=prefix) :type prefix: string :param mode: dbus binding tool mode (--mode=mode) :type mode: string """ if not hasattr(self, 'dbus_lst'): self.dbus_lst = [] if not 'process_dbus' in self.meths: self.meths.append('process_dbus') self.dbus_lst.append([filename, prefix, mode]) @before_method('process_source') def process_dbus(self): """ Processes the dbus files stored in the attribute *dbus_lst* to create :py:class:`waflib.Tools.dbus.dbus_binding_tool` instances. """ for filename, prefix, mode in getattr(self, 'dbus_lst', []): node = self.path.find_resource(filename) if not node: raise Errors.WafError('file not found ' + filename) tsk = self.create_task('dbus_binding_tool', node, node.change_ext('.h')) tsk.env.DBUS_BINDING_TOOL_PREFIX = prefix tsk.env.DBUS_BINDING_TOOL_MODE = mode class dbus_binding_tool(Task.Task): """ Compiles a dbus file """ color = 'BLUE' ext_out = ['.h'] run_str = '${DBUS_BINDING_TOOL} --prefix=${DBUS_BINDING_TOOL_PREFIX} --mode=${DBUS_BINDING_TOOL_MODE} --output=${TGT} ${SRC}' shell = True # temporary workaround for #795 def configure(conf): """ Detects the program dbus-binding-tool and sets ``conf.env.DBUS_BINDING_TOOL`` """ conf.find_program('dbus-binding-tool', var='DBUS_BINDING_TOOL') hamster-3.0.3/waflib/Tools/dmd.py000066400000000000000000000035301452646177100166600ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2007 (dv) # Thomas Nagy, 2008-2018 (ita) import sys from waflib.Tools import ar, d from waflib.Configure import conf @conf def find_dmd(conf): """ Finds the program *dmd*, *dmd2*, or *ldc* and set the variable *D* """ conf.find_program(['dmd', 'dmd2', 'ldc'], var='D') # make sure that we're dealing with dmd1, dmd2, or ldc(1) out = conf.cmd_and_log(conf.env.D + ['--help']) if out.find("D Compiler v") == -1: out = conf.cmd_and_log(conf.env.D + ['-version']) if out.find("based on DMD v1.") == -1: conf.fatal("detected compiler is not dmd/ldc") @conf def common_flags_ldc(conf): """ Sets the D flags required by *ldc* """ v = conf.env v.DFLAGS = ['-d-version=Posix'] v.LINKFLAGS = [] v.DFLAGS_dshlib = ['-relocation-model=pic'] @conf def common_flags_dmd(conf): """ Set the flags required by *dmd* or *dmd2* """ v = conf.env v.D_SRC_F = ['-c'] v.D_TGT_F = '-of%s' v.D_LINKER = v.D v.DLNK_SRC_F = '' v.DLNK_TGT_F = '-of%s' v.DINC_ST = '-I%s' v.DSHLIB_MARKER = v.DSTLIB_MARKER = '' v.DSTLIB_ST = v.DSHLIB_ST = '-L-l%s' v.DSTLIBPATH_ST = v.DLIBPATH_ST = '-L-L%s' v.LINKFLAGS_dprogram= ['-quiet'] v.DFLAGS_dshlib = ['-fPIC'] v.LINKFLAGS_dshlib = ['-L-shared'] v.DHEADER_ext = '.di' v.DFLAGS_d_with_header = ['-H', '-Hf'] v.D_HDR_F = '%s' def configure(conf): """ Configuration for *dmd*, *dmd2*, and *ldc* """ conf.find_dmd() if sys.platform == 'win32': out = conf.cmd_and_log(conf.env.D + ['--help']) if out.find('D Compiler v2.') > -1: conf.fatal('dmd2 on Windows is not supported, use gdc or ldc2 instead') conf.load('ar') conf.load('d') conf.common_flags_dmd() conf.d_platform_flags() if str(conf.env.D).find('ldc') > -1: conf.common_flags_ldc() hamster-3.0.3/waflib/Tools/errcheck.py000066400000000000000000000172221452646177100177050ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) """ Common mistakes highlighting. There is a performance impact, so this tool is only loaded when running ``waf -v`` """ typos = { 'feature':'features', 'sources':'source', 'targets':'target', 'include':'includes', 'export_include':'export_includes', 'define':'defines', 'importpath':'includes', 'installpath':'install_path', 'iscopy':'is_copy', 'uses':'use', } meths_typos = ['__call__', 'program', 'shlib', 'stlib', 'objects'] import sys from waflib import Logs, Build, Node, Task, TaskGen, ConfigSet, Errors, Utils from waflib.Tools import ccroot def check_same_targets(self): mp = Utils.defaultdict(list) uids = {} def check_task(tsk): if not isinstance(tsk, Task.Task): return if hasattr(tsk, 'no_errcheck_out'): return for node in tsk.outputs: mp[node].append(tsk) try: uids[tsk.uid()].append(tsk) except KeyError: uids[tsk.uid()] = [tsk] for g in self.groups: for tg in g: try: for tsk in tg.tasks: check_task(tsk) except AttributeError: # raised if not a task generator, which should be uncommon check_task(tg) dupe = False for (k, v) in mp.items(): if len(v) > 1: dupe = True msg = '* Node %r is created more than once%s. The task generators are:' % (k, Logs.verbose == 1 and " (full message on 'waf -v -v')" or "") Logs.error(msg) for x in v: if Logs.verbose > 1: Logs.error(' %d. %r', 1 + v.index(x), x.generator) else: Logs.error(' %d. %r in %r', 1 + v.index(x), x.generator.name, getattr(x.generator, 'path', None)) Logs.error('If you think that this is an error, set no_errcheck_out on the task instance') if not dupe: for (k, v) in uids.items(): if len(v) > 1: Logs.error('* Several tasks use the same identifier. Please check the information on\n https://waf.io/apidocs/Task.html?highlight=uid#waflib.Task.Task.uid') tg_details = tsk.generator.name if Logs.verbose > 2: tg_details = tsk.generator for tsk in v: Logs.error(' - object %r (%r) defined in %r', tsk.__class__.__name__, tsk, tg_details) def check_invalid_constraints(self): feat = set() for x in list(TaskGen.feats.values()): feat.union(set(x)) for (x, y) in TaskGen.task_gen.prec.items(): feat.add(x) feat.union(set(y)) ext = set() for x in TaskGen.task_gen.mappings.values(): ext.add(x.__name__) invalid = ext & feat if invalid: Logs.error('The methods %r have invalid annotations: @extension <-> @feature/@before_method/@after_method', list(invalid)) # the build scripts have been read, so we can check for invalid after/before attributes on task classes for cls in list(Task.classes.values()): if sys.hexversion > 0x3000000 and issubclass(cls, Task.Task) and isinstance(cls.hcode, str): raise Errors.WafError('Class %r has hcode value %r of type , expecting (use Utils.h_cmd() ?)' % (cls, cls.hcode)) for x in ('before', 'after'): for y in Utils.to_list(getattr(cls, x, [])): if not Task.classes.get(y): Logs.error('Erroneous order constraint %r=%r on task class %r', x, y, cls.__name__) if getattr(cls, 'rule', None): Logs.error('Erroneous attribute "rule" on task class %r (rename to "run_str")', cls.__name__) def replace(m): """ Replaces existing BuildContext methods to verify parameter names, for example ``bld(source=)`` has no ending *s* """ oldcall = getattr(Build.BuildContext, m) def call(self, *k, **kw): ret = oldcall(self, *k, **kw) for x in typos: if x in kw: if x == 'iscopy' and 'subst' in getattr(self, 'features', ''): continue Logs.error('Fix the typo %r -> %r on %r', x, typos[x], ret) return ret setattr(Build.BuildContext, m, call) def enhance_lib(): """ Modifies existing classes and methods to enable error verification """ for m in meths_typos: replace(m) # catch '..' in ant_glob patterns def ant_glob(self, *k, **kw): if k: lst = Utils.to_list(k[0]) for pat in lst: sp = pat.split('/') if '..' in sp: Logs.error("In ant_glob pattern %r: '..' means 'two dots', not 'parent directory'", k[0]) if '.' in sp: Logs.error("In ant_glob pattern %r: '.' means 'one dot', not 'current directory'", k[0]) return self.old_ant_glob(*k, **kw) Node.Node.old_ant_glob = Node.Node.ant_glob Node.Node.ant_glob = ant_glob # catch ant_glob on build folders def ant_iter(self, accept=None, maxdepth=25, pats=[], dir=False, src=True, remove=True, quiet=False): if remove: try: if self.is_child_of(self.ctx.bldnode) and not quiet: quiet = True Logs.error('Calling ant_glob on build folders (%r) is dangerous: add quiet=True / remove=False', self) except AttributeError: pass return self.old_ant_iter(accept, maxdepth, pats, dir, src, remove, quiet) Node.Node.old_ant_iter = Node.Node.ant_iter Node.Node.ant_iter = ant_iter # catch conflicting ext_in/ext_out/before/after declarations old = Task.is_before def is_before(t1, t2): ret = old(t1, t2) if ret and old(t2, t1): Logs.error('Contradictory order constraints in classes %r %r', t1, t2) return ret Task.is_before = is_before # check for bld(feature='cshlib') where no 'c' is given - this can be either a mistake or on purpose # so we only issue a warning def check_err_features(self): lst = self.to_list(self.features) if 'shlib' in lst: Logs.error('feature shlib -> cshlib, dshlib or cxxshlib') for x in ('c', 'cxx', 'd', 'fc'): if not x in lst and lst and lst[0] in [x+y for y in ('program', 'shlib', 'stlib')]: Logs.error('%r features is probably missing %r', self, x) TaskGen.feature('*')(check_err_features) # check for erroneous order constraints def check_err_order(self): if not hasattr(self, 'rule') and not 'subst' in Utils.to_list(self.features): for x in ('before', 'after', 'ext_in', 'ext_out'): if hasattr(self, x): Logs.warn('Erroneous order constraint %r on non-rule based task generator %r', x, self) else: for x in ('before', 'after'): for y in self.to_list(getattr(self, x, [])): if not Task.classes.get(y): Logs.error('Erroneous order constraint %s=%r on %r (no such class)', x, y, self) TaskGen.feature('*')(check_err_order) # check for @extension used with @feature/@before_method/@after_method def check_compile(self): check_invalid_constraints(self) try: ret = self.orig_compile() finally: check_same_targets(self) return ret Build.BuildContext.orig_compile = Build.BuildContext.compile Build.BuildContext.compile = check_compile # check for invalid build groups #914 def use_rec(self, name, **kw): try: y = self.bld.get_tgen_by_name(name) except Errors.WafError: pass else: idx = self.bld.get_group_idx(self) odx = self.bld.get_group_idx(y) if odx > idx: msg = "Invalid 'use' across build groups:" if Logs.verbose > 1: msg += '\n target %r\n uses:\n %r' % (self, y) else: msg += " %r uses %r (try 'waf -v -v' for the full error)" % (self.name, name) raise Errors.WafError(msg) self.orig_use_rec(name, **kw) TaskGen.task_gen.orig_use_rec = TaskGen.task_gen.use_rec TaskGen.task_gen.use_rec = use_rec # check for env.append def _getattr(self, name, default=None): if name == 'append' or name == 'add': raise Errors.WafError('env.append and env.add do not exist: use env.append_value/env.append_unique') elif name == 'prepend': raise Errors.WafError('env.prepend does not exist: use env.prepend_value') if name in self.__slots__: return super(ConfigSet.ConfigSet, self).__getattr__(name, default) else: return self[name] ConfigSet.ConfigSet.__getattr__ = _getattr def options(opt): """ Error verification can be enabled by default (not just on ``waf -v``) by adding to the user script options """ enhance_lib() hamster-3.0.3/waflib/Tools/fc.py000066400000000000000000000151531452646177100165100ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # DC 2008 # Thomas Nagy 2016-2018 (ita) """ Fortran support """ from waflib import Utils, Task, Errors from waflib.Tools import ccroot, fc_config, fc_scan from waflib.TaskGen import extension from waflib.Configure import conf ccroot.USELIB_VARS['fc'] = set(['FCFLAGS', 'DEFINES', 'INCLUDES', 'FCPPFLAGS']) ccroot.USELIB_VARS['fcprogram_test'] = ccroot.USELIB_VARS['fcprogram'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'LDFLAGS']) ccroot.USELIB_VARS['fcshlib'] = set(['LIB', 'STLIB', 'LIBPATH', 'STLIBPATH', 'LINKFLAGS', 'RPATH', 'LINKDEPS', 'LDFLAGS']) ccroot.USELIB_VARS['fcstlib'] = set(['ARFLAGS', 'LINKDEPS']) @extension('.f','.F','.f90','.F90','.for','.FOR','.f95','.F95','.f03','.F03','.f08','.F08') def fc_hook(self, node): "Binds the Fortran file extensions create :py:class:`waflib.Tools.fc.fc` instances" return self.create_compiled_task('fc', node) @conf def modfile(conf, name): """ Turns a module name into the right module file name. Defaults to all lower case. """ if name.find(':') >= 0: # Depending on a submodule! separator = conf.env.FC_SUBMOD_SEPARATOR or '@' # Ancestors of the submodule will be prefixed to the # submodule name, separated by a colon. modpath = name.split(':') # Only the ancestor (actual) module and the submodule name # will be used for the filename. modname = modpath[0] + separator + modpath[-1] suffix = conf.env.FC_SUBMOD_SUFFIX or '.smod' else: modname = name suffix = '.mod' return {'lower' :modname.lower() + suffix.lower(), 'lower.MOD' :modname.lower() + suffix.upper(), 'UPPER.mod' :modname.upper() + suffix.lower(), 'UPPER' :modname.upper() + suffix.upper()}[conf.env.FC_MOD_CAPITALIZATION or 'lower'] def get_fortran_tasks(tsk): """ Obtains all fortran tasks from the same build group. Those tasks must not have the attribute 'nomod' or 'mod_fortran_done' :return: a list of :py:class:`waflib.Tools.fc.fc` instances """ bld = tsk.generator.bld tasks = bld.get_tasks_group(bld.get_group_idx(tsk.generator)) return [x for x in tasks if isinstance(x, fc) and not getattr(x, 'nomod', None) and not getattr(x, 'mod_fortran_done', None)] class fc(Task.Task): """ Fortran tasks can only run when all fortran tasks in a current task group are ready to be executed This may cause a deadlock if some fortran task is waiting for something that cannot happen (circular dependency) Should this ever happen, set the 'nomod=True' on those tasks instances to break the loop """ color = 'GREEN' run_str = '${FC} ${FCFLAGS} ${FCINCPATH_ST:INCPATHS} ${FCDEFINES_ST:DEFINES} ${_FCMODOUTFLAGS} ${FC_TGT_F}${TGT[0].abspath()} ${FC_SRC_F}${SRC[0].abspath()} ${FCPPFLAGS}' vars = ["FORTRANMODPATHFLAG"] def scan(self): """Fortran dependency scanner""" tmp = fc_scan.fortran_parser(self.generator.includes_nodes) tmp.task = self tmp.start(self.inputs[0]) return (tmp.nodes, tmp.names) def runnable_status(self): """ Sets the mod file outputs and the dependencies on the mod files over all Fortran tasks executed by the main thread so there are no concurrency issues """ if getattr(self, 'mod_fortran_done', None): return super(fc, self).runnable_status() # now, if we reach this part it is because this fortran task is the first in the list bld = self.generator.bld # obtain the fortran tasks lst = get_fortran_tasks(self) # disable this method for other tasks for tsk in lst: tsk.mod_fortran_done = True # wait for all the .f tasks to be ready for execution # and ensure that the scanners are called at least once for tsk in lst: ret = tsk.runnable_status() if ret == Task.ASK_LATER: # we have to wait for one of the other fortran tasks to be ready # this may deadlock if there are dependencies between fortran tasks # but this should not happen (we are setting them here!) for x in lst: x.mod_fortran_done = None return Task.ASK_LATER ins = Utils.defaultdict(set) outs = Utils.defaultdict(set) # the .mod files to create for tsk in lst: key = tsk.uid() for x in bld.raw_deps[key]: if x.startswith('MOD@'): name = bld.modfile(x.replace('MOD@', '')) node = bld.srcnode.find_or_declare(name) tsk.set_outputs(node) outs[node].add(tsk) # the .mod files to use for tsk in lst: key = tsk.uid() for x in bld.raw_deps[key]: if x.startswith('USE@'): name = bld.modfile(x.replace('USE@', '')) node = bld.srcnode.find_resource(name) if node and node not in tsk.outputs: if not node in bld.node_deps[key]: bld.node_deps[key].append(node) ins[node].add(tsk) # if the intersection matches, set the order for k in ins.keys(): for a in ins[k]: a.run_after.update(outs[k]) for x in outs[k]: self.generator.bld.producer.revdeps[x].add(a) # the scanner cannot output nodes, so we have to set them # ourselves as task.dep_nodes (additional input nodes) tmp = [] for t in outs[k]: tmp.extend(t.outputs) a.dep_nodes.extend(tmp) a.dep_nodes.sort(key=lambda x: x.abspath()) # the task objects have changed: clear the signature cache for tsk in lst: try: delattr(tsk, 'cache_sig') except AttributeError: pass return super(fc, self).runnable_status() class fcprogram(ccroot.link_task): """Links Fortran programs""" color = 'YELLOW' run_str = '${FC} ${LINKFLAGS} ${FCLNK_SRC_F}${SRC} ${FCLNK_TGT_F}${TGT[0].abspath()} ${RPATH_ST:RPATH} ${FCSTLIB_MARKER} ${FCSTLIBPATH_ST:STLIBPATH} ${FCSTLIB_ST:STLIB} ${FCSHLIB_MARKER} ${FCLIBPATH_ST:LIBPATH} ${FCLIB_ST:LIB} ${LDFLAGS}' inst_to = '${BINDIR}' class fcshlib(fcprogram): """Links Fortran libraries""" inst_to = '${LIBDIR}' class fcstlib(ccroot.stlink_task): """Links Fortran static libraries (uses ar by default)""" pass # do not remove the pass statement class fcprogram_test(fcprogram): """Custom link task to obtain compiler outputs for Fortran configuration tests""" def runnable_status(self): """This task is always executed""" ret = super(fcprogram_test, self).runnable_status() if ret == Task.SKIP_ME: ret = Task.RUN_ME return ret def exec_command(self, cmd, **kw): """Stores the compiler std our/err onto the build context, to bld.out + bld.err""" bld = self.generator.bld kw['shell'] = isinstance(cmd, str) kw['stdout'] = kw['stderr'] = Utils.subprocess.PIPE kw['cwd'] = self.get_cwd() bld.out = bld.err = '' bld.to_log('command: %s\n' % cmd) kw['output'] = 0 try: (bld.out, bld.err) = bld.cmd_and_log(cmd, **kw) except Errors.WafError: return -1 if bld.out: bld.to_log('out: %s\n' % bld.out) if bld.err: bld.to_log('err: %s\n' % bld.err) hamster-3.0.3/waflib/Tools/fc_config.py000066400000000000000000000332421452646177100200340ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # DC 2008 # Thomas Nagy 2016-2018 (ita) """ Fortran configuration helpers """ import re, os, sys, shlex from waflib.Configure import conf from waflib.TaskGen import feature, before_method FC_FRAGMENT = ' program main\n end program main\n' FC_FRAGMENT2 = ' PROGRAM MAIN\n END\n' # what's the actual difference between these? @conf def fc_flags(conf): """ Defines common fortran configuration flags and file extensions """ v = conf.env v.FC_SRC_F = [] v.FC_TGT_F = ['-c', '-o'] v.FCINCPATH_ST = '-I%s' v.FCDEFINES_ST = '-D%s' if not v.LINK_FC: v.LINK_FC = v.FC v.FCLNK_SRC_F = [] v.FCLNK_TGT_F = ['-o'] v.FCFLAGS_fcshlib = ['-fpic'] v.LINKFLAGS_fcshlib = ['-shared'] v.fcshlib_PATTERN = 'lib%s.so' v.fcstlib_PATTERN = 'lib%s.a' v.FCLIB_ST = '-l%s' v.FCLIBPATH_ST = '-L%s' v.FCSTLIB_ST = '-l%s' v.FCSTLIBPATH_ST = '-L%s' v.FCSTLIB_MARKER = '-Wl,-Bstatic' v.FCSHLIB_MARKER = '-Wl,-Bdynamic' v.SONAME_ST = '-Wl,-h,%s' @conf def fc_add_flags(conf): """ Adds FCFLAGS / LDFLAGS / LINKFLAGS from os.environ to conf.env """ conf.add_os_flags('FCPPFLAGS', dup=False) conf.add_os_flags('FCFLAGS', dup=False) conf.add_os_flags('LINKFLAGS', dup=False) conf.add_os_flags('LDFLAGS', dup=False) @conf def check_fortran(self, *k, **kw): """ Compiles a Fortran program to ensure that the settings are correct """ self.check_cc( fragment = FC_FRAGMENT, compile_filename = 'test.f', features = 'fc fcprogram', msg = 'Compiling a simple fortran app') @conf def check_fc(self, *k, **kw): """ Same as :py:func:`waflib.Tools.c_config.check` but defaults to the *Fortran* programming language (this overrides the C defaults in :py:func:`waflib.Tools.c_config.validate_c`) """ kw['compiler'] = 'fc' if not 'compile_mode' in kw: kw['compile_mode'] = 'fc' if not 'type' in kw: kw['type'] = 'fcprogram' if not 'compile_filename' in kw: kw['compile_filename'] = 'test.f90' if not 'code' in kw: kw['code'] = FC_FRAGMENT return self.check(*k, **kw) # ------------------------------------------------------------------------ # --- These are the default platform modifiers, refactored here for # convenience. gfortran and g95 have much overlap. # ------------------------------------------------------------------------ @conf def fortran_modifier_darwin(conf): """ Defines Fortran flags and extensions for OSX systems """ v = conf.env v.FCFLAGS_fcshlib = ['-fPIC'] v.LINKFLAGS_fcshlib = ['-dynamiclib'] v.fcshlib_PATTERN = 'lib%s.dylib' v.FRAMEWORKPATH_ST = '-F%s' v.FRAMEWORK_ST = ['-framework'] v.LINKFLAGS_fcstlib = [] v.FCSHLIB_MARKER = '' v.FCSTLIB_MARKER = '' v.SONAME_ST = '' @conf def fortran_modifier_win32(conf): """ Defines Fortran flags for Windows platforms """ v = conf.env v.fcprogram_PATTERN = v.fcprogram_test_PATTERN = '%s.exe' v.fcshlib_PATTERN = '%s.dll' v.implib_PATTERN = '%s.dll.a' v.IMPLIB_ST = '-Wl,--out-implib,%s' v.FCFLAGS_fcshlib = [] # Auto-import is enabled by default even without this option, # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages # that the linker emits otherwise. v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import']) @conf def fortran_modifier_cygwin(conf): """ Defines Fortran flags for use on cygwin """ fortran_modifier_win32(conf) v = conf.env v.fcshlib_PATTERN = 'cyg%s.dll' v.append_value('LINKFLAGS_fcshlib', ['-Wl,--enable-auto-image-base']) v.FCFLAGS_fcshlib = [] # ------------------------------------------------------------------------ @conf def check_fortran_dummy_main(self, *k, **kw): """ Determines if a main function is needed by compiling a code snippet with the C compiler and linking it with the Fortran compiler (useful on unix-like systems) """ if not self.env.CC: self.fatal('A c compiler is required for check_fortran_dummy_main') lst = ['MAIN__', '__MAIN', '_MAIN', 'MAIN_', 'MAIN'] lst.extend([m.lower() for m in lst]) lst.append('') self.start_msg('Detecting whether we need a dummy main') for main in lst: kw['fortran_main'] = main try: self.check_cc( fragment = 'int %s() { return 0; }\n' % (main or 'test'), features = 'c fcprogram', mandatory = True ) if not main: self.env.FC_MAIN = -1 self.end_msg('no') else: self.env.FC_MAIN = main self.end_msg('yes %s' % main) break except self.errors.ConfigurationError: pass else: self.end_msg('not found') self.fatal('could not detect whether fortran requires a dummy main, see the config.log') # ------------------------------------------------------------------------ GCC_DRIVER_LINE = re.compile('^Driving:') POSIX_STATIC_EXT = re.compile(r'\S+\.a') POSIX_LIB_FLAGS = re.compile(r'-l\S+') @conf def is_link_verbose(self, txt): """Returns True if 'useful' link options can be found in txt""" assert isinstance(txt, str) for line in txt.splitlines(): if not GCC_DRIVER_LINE.search(line): if POSIX_STATIC_EXT.search(line) or POSIX_LIB_FLAGS.search(line): return True return False @conf def check_fortran_verbose_flag(self, *k, **kw): """ Checks what kind of verbose (-v) flag works, then sets it to env.FC_VERBOSE_FLAG """ self.start_msg('fortran link verbose flag') for x in ('-v', '--verbose', '-verbose', '-V'): try: self.check_cc( features = 'fc fcprogram_test', fragment = FC_FRAGMENT2, compile_filename = 'test.f', linkflags = [x], mandatory=True) except self.errors.ConfigurationError: pass else: # output is on stderr or stdout (for xlf) if self.is_link_verbose(self.test_bld.err) or self.is_link_verbose(self.test_bld.out): self.end_msg(x) break else: self.end_msg('failure') self.fatal('Could not obtain the fortran link verbose flag (see config.log)') self.env.FC_VERBOSE_FLAG = x return x # ------------------------------------------------------------------------ # linkflags which match those are ignored LINKFLAGS_IGNORED = [r'-lang*', r'-lcrt[a-zA-Z0-9\.]*\.o', r'-lc$', r'-lSystem', r'-libmil', r'-LIST:*', r'-LNO:*'] if os.name == 'nt': LINKFLAGS_IGNORED.extend([r'-lfrt*', r'-luser32', r'-lkernel32', r'-ladvapi32', r'-lmsvcrt', r'-lshell32', r'-lmingw', r'-lmoldname']) else: LINKFLAGS_IGNORED.append(r'-lgcc*') RLINKFLAGS_IGNORED = [re.compile(f) for f in LINKFLAGS_IGNORED] def _match_ignore(line): """Returns True if the line should be ignored (Fortran verbose flag test)""" for i in RLINKFLAGS_IGNORED: if i.match(line): return True return False def parse_fortran_link(lines): """Given the output of verbose link of Fortran compiler, this returns a list of flags necessary for linking using the standard linker.""" final_flags = [] for line in lines: if not GCC_DRIVER_LINE.match(line): _parse_flink_line(line, final_flags) return final_flags SPACE_OPTS = re.compile('^-[LRuYz]$') NOSPACE_OPTS = re.compile('^-[RL]') def _parse_flink_token(lexer, token, tmp_flags): # Here we go (convention for wildcard is shell, not regex !) # 1 TODO: we first get some root .a libraries # 2 TODO: take everything starting by -bI:* # 3 Ignore the following flags: -lang* | -lcrt*.o | -lc | # -lgcc* | -lSystem | -libmil | -LANG:=* | -LIST:* | -LNO:*) # 4 take into account -lkernel32 # 5 For options of the kind -[[LRuYz]], as they take one argument # after, the actual option is the next token # 6 For -YP,*: take and replace by -Larg where arg is the old # argument # 7 For -[lLR]*: take # step 3 if _match_ignore(token): pass # step 4 elif token.startswith('-lkernel32') and sys.platform == 'cygwin': tmp_flags.append(token) # step 5 elif SPACE_OPTS.match(token): t = lexer.get_token() if t.startswith('P,'): t = t[2:] for opt in t.split(os.pathsep): tmp_flags.append('-L%s' % opt) # step 6 elif NOSPACE_OPTS.match(token): tmp_flags.append(token) # step 7 elif POSIX_LIB_FLAGS.match(token): tmp_flags.append(token) else: # ignore anything not explicitly taken into account pass t = lexer.get_token() return t def _parse_flink_line(line, final_flags): """private""" lexer = shlex.shlex(line, posix = True) lexer.whitespace_split = True t = lexer.get_token() tmp_flags = [] while t: t = _parse_flink_token(lexer, t, tmp_flags) final_flags.extend(tmp_flags) return final_flags @conf def check_fortran_clib(self, autoadd=True, *k, **kw): """ Obtains the flags for linking with the C library if this check works, add uselib='CLIB' to your task generators """ if not self.env.FC_VERBOSE_FLAG: self.fatal('env.FC_VERBOSE_FLAG is not set: execute check_fortran_verbose_flag?') self.start_msg('Getting fortran runtime link flags') try: self.check_cc( fragment = FC_FRAGMENT2, compile_filename = 'test.f', features = 'fc fcprogram_test', linkflags = [self.env.FC_VERBOSE_FLAG] ) except Exception: self.end_msg(False) if kw.get('mandatory', True): conf.fatal('Could not find the c library flags') else: out = self.test_bld.err flags = parse_fortran_link(out.splitlines()) self.end_msg('ok (%s)' % ' '.join(flags)) self.env.LINKFLAGS_CLIB = flags return flags return [] def getoutput(conf, cmd, stdin=False): """ Obtains Fortran command outputs """ from waflib import Errors if conf.env.env: env = conf.env.env else: env = dict(os.environ) env['LANG'] = 'C' input = stdin and '\n'.encode() or None try: out, err = conf.cmd_and_log(cmd, env=env, output=0, input=input) except Errors.WafError as e: # An WafError might indicate an error code during the command # execution, in this case we still obtain the stderr and stdout, # which we can use to find the version string. if not (hasattr(e, 'stderr') and hasattr(e, 'stdout')): raise e else: # Ignore the return code and return the original # stdout and stderr. out = e.stdout err = e.stderr except Exception: conf.fatal('could not determine the compiler version %r' % cmd) return (out, err) # ------------------------------------------------------------------------ ROUTINES_CODE = """\ subroutine foobar() return end subroutine foo_bar() return end """ MAIN_CODE = """ void %(dummy_func_nounder)s(void); void %(dummy_func_under)s(void); int %(main_func_name)s() { %(dummy_func_nounder)s(); %(dummy_func_under)s(); return 0; } """ @feature('link_main_routines_func') @before_method('process_source') def link_main_routines_tg_method(self): """ The configuration test declares a unique task generator, so we create other task generators from there for fortran link tests """ def write_test_file(task): task.outputs[0].write(task.generator.code) bld = self.bld bld(rule=write_test_file, target='main.c', code=MAIN_CODE % self.__dict__) bld(rule=write_test_file, target='test.f', code=ROUTINES_CODE) bld(features='fc fcstlib', source='test.f', target='test') bld(features='c fcprogram', source='main.c', target='app', use='test') def mangling_schemes(): """ Generate triplets for use with mangle_name (used in check_fortran_mangling) the order is tuned for gfortan """ for u in ('_', ''): for du in ('', '_'): for c in ("lower", "upper"): yield (u, du, c) def mangle_name(u, du, c, name): """Mangle a name from a triplet (used in check_fortran_mangling)""" return getattr(name, c)() + u + (name.find('_') != -1 and du or '') @conf def check_fortran_mangling(self, *k, **kw): """ Detect the mangling scheme, sets FORTRAN_MANGLING to the triplet found This test will compile a fortran static library, then link a c app against it """ if not self.env.CC: self.fatal('A c compiler is required for link_main_routines') if not self.env.FC: self.fatal('A fortran compiler is required for link_main_routines') if not self.env.FC_MAIN: self.fatal('Checking for mangling requires self.env.FC_MAIN (execute "check_fortran_dummy_main" first?)') self.start_msg('Getting fortran mangling scheme') for (u, du, c) in mangling_schemes(): try: self.check_cc( compile_filename = [], features = 'link_main_routines_func', msg = 'nomsg', errmsg = 'nomsg', dummy_func_nounder = mangle_name(u, du, c, 'foobar'), dummy_func_under = mangle_name(u, du, c, 'foo_bar'), main_func_name = self.env.FC_MAIN ) except self.errors.ConfigurationError: pass else: self.end_msg("ok ('%s', '%s', '%s-case')" % (u, du, c)) self.env.FORTRAN_MANGLING = (u, du, c) break else: self.end_msg(False) self.fatal('mangler not found') return (u, du, c) @feature('pyext') @before_method('propagate_uselib_vars', 'apply_link') def set_lib_pat(self): """Sets the Fortran flags for linking with Python""" self.env.fcshlib_PATTERN = self.env.pyext_PATTERN @conf def detect_openmp(self): """ Detects openmp flags and sets the OPENMP ``FCFLAGS``/``LINKFLAGS`` """ for x in ('-fopenmp','-openmp','-mp','-xopenmp','-omp','-qsmp=omp'): try: self.check_fc( msg = 'Checking for OpenMP flag %s' % x, fragment = 'program main\n call omp_get_num_threads()\nend program main', fcflags = x, linkflags = x, uselib_store = 'OPENMP' ) except self.errors.ConfigurationError: pass else: break else: self.fatal('Could not find OpenMP') @conf def check_gfortran_o_space(self): if self.env.FC_NAME != 'GFORTRAN' or int(self.env.FC_VERSION[0]) > 4: # This is for old compilers and only for gfortran. # No idea how other implementations handle this. Be safe and bail out. return self.env.stash() self.env.FCLNK_TGT_F = ['-o', ''] try: self.check_fc(msg='Checking if the -o link must be split from arguments', fragment=FC_FRAGMENT, features='fc fcshlib') except self.errors.ConfigurationError: self.env.revert() else: self.env.commit() hamster-3.0.3/waflib/Tools/fc_scan.py000066400000000000000000000060211452646177100175060ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # DC 2008 # Thomas Nagy 2016-2018 (ita) import re INC_REGEX = r"""(?:^|['">]\s*;)\s*(?:|#\s*)INCLUDE\s+(?:\w+_)?[<"'](.+?)(?=["'>])""" USE_REGEX = r"""(?:^|;)\s*USE(?:\s+|(?:(?:\s*,\s*(?:NON_)?INTRINSIC)?\s*::))\s*(\w+)""" MOD_REGEX = r"""(?:^|;)\s*MODULE(?!\s+(?:PROCEDURE|SUBROUTINE|FUNCTION))\s+(\w+)""" SMD_REGEX = r"""(?:^|;)\s*SUBMODULE\s*\(([\w:]+)\)\s*(\w+)""" re_inc = re.compile(INC_REGEX, re.I) re_use = re.compile(USE_REGEX, re.I) re_mod = re.compile(MOD_REGEX, re.I) re_smd = re.compile(SMD_REGEX, re.I) class fortran_parser(object): """ This parser returns: * the nodes corresponding to the module names to produce * the nodes corresponding to the include files used * the module names used by the fortran files """ def __init__(self, incpaths): self.seen = [] """Files already parsed""" self.nodes = [] """List of :py:class:`waflib.Node.Node` representing the dependencies to return""" self.names = [] """List of module names to return""" self.incpaths = incpaths """List of :py:class:`waflib.Node.Node` representing the include paths""" def find_deps(self, node): """ Parses a Fortran file to obtain the dependencies used/provided :param node: fortran file to read :type node: :py:class:`waflib.Node.Node` :return: lists representing the includes, the modules used, and the modules created by a fortran file :rtype: tuple of list of strings """ txt = node.read() incs = [] uses = [] mods = [] for line in txt.splitlines(): # line by line regexp search? optimize? m = re_inc.search(line) if m: incs.append(m.group(1)) m = re_use.search(line) if m: uses.append(m.group(1)) m = re_mod.search(line) if m: mods.append(m.group(1)) m = re_smd.search(line) if m: uses.append(m.group(1)) mods.append('{0}:{1}'.format(m.group(1),m.group(2))) return (incs, uses, mods) def start(self, node): """ Start parsing. Use the stack ``self.waiting`` to hold nodes to iterate on :param node: fortran file :type node: :py:class:`waflib.Node.Node` """ self.waiting = [node] while self.waiting: nd = self.waiting.pop(0) self.iter(nd) def iter(self, node): """ Processes a single file during dependency parsing. Extracts files used modules used and modules provided. """ incs, uses, mods = self.find_deps(node) for x in incs: if x in self.seen: continue self.seen.append(x) self.tryfind_header(x) for x in uses: name = "USE@%s" % x if not name in self.names: self.names.append(name) for x in mods: name = "MOD@%s" % x if not name in self.names: self.names.append(name) def tryfind_header(self, filename): """ Adds an include file to the list of nodes to process :param filename: file name :type filename: string """ found = None for n in self.incpaths: found = n.find_resource(filename) if found: self.nodes.append(found) self.waiting.append(found) break if not found: if not filename in self.names: self.names.append(filename) hamster-3.0.3/waflib/Tools/flex.py000066400000000000000000000030211452646177100170450ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # John O'Meara, 2006 # Thomas Nagy, 2006-2018 (ita) """ The **flex** program is a code generator which creates C or C++ files. The generated files are compiled into object files. """ import os, re from waflib import Task, TaskGen from waflib.Tools import ccroot def decide_ext(self, node): if 'cxx' in self.features: return ['.lex.cc'] return ['.lex.c'] def flexfun(tsk): env = tsk.env bld = tsk.generator.bld wd = bld.variant_dir def to_list(xx): if isinstance(xx, str): return [xx] return xx tsk.last_cmd = lst = [] lst.extend(to_list(env.FLEX)) lst.extend(to_list(env.FLEXFLAGS)) inputs = [a.path_from(tsk.get_cwd()) for a in tsk.inputs] if env.FLEX_MSYS: inputs = [x.replace(os.sep, '/') for x in inputs] lst.extend(inputs) lst = [x for x in lst if x] txt = bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0) tsk.outputs[0].write(txt.replace('\r\n', '\n').replace('\r', '\n')) # issue #1207 TaskGen.declare_chain( name = 'flex', rule = flexfun, # issue #854 ext_in = '.l', decider = decide_ext, ) # To support the following: # bld(features='c', flexflags='-P/foo') Task.classes['flex'].vars = ['FLEXFLAGS', 'FLEX'] ccroot.USELIB_VARS['c'].add('FLEXFLAGS') ccroot.USELIB_VARS['cxx'].add('FLEXFLAGS') def configure(conf): """ Detect the *flex* program """ conf.find_program('flex', var='FLEX') conf.env.FLEXFLAGS = ['-t'] if re.search (r"\\msys\\[0-9.]+\\bin\\flex.exe$", conf.env.FLEX[0]): # this is the flex shipped with MSYS conf.env.FLEX_MSYS = True hamster-3.0.3/waflib/Tools/g95.py000066400000000000000000000027621452646177100165260ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # KWS 2010 # Thomas Nagy 2016-2018 (ita) import re from waflib import Utils from waflib.Tools import fc, fc_config, fc_scan, ar from waflib.Configure import conf @conf def find_g95(conf): fc = conf.find_program('g95', var='FC') conf.get_g95_version(fc) conf.env.FC_NAME = 'G95' @conf def g95_flags(conf): v = conf.env v.FCFLAGS_fcshlib = ['-fPIC'] v.FORTRANMODFLAG = ['-fmod=', ''] # template for module path v.FCFLAGS_DEBUG = ['-Werror'] # why not @conf def g95_modifier_win32(conf): fc_config.fortran_modifier_win32(conf) @conf def g95_modifier_cygwin(conf): fc_config.fortran_modifier_cygwin(conf) @conf def g95_modifier_darwin(conf): fc_config.fortran_modifier_darwin(conf) @conf def g95_modifier_platform(conf): dest_os = conf.env.DEST_OS or Utils.unversioned_sys_platform() g95_modifier_func = getattr(conf, 'g95_modifier_' + dest_os, None) if g95_modifier_func: g95_modifier_func() @conf def get_g95_version(conf, fc): """get the compiler version""" version_re = re.compile(r"g95\s*(?P\d*)\.(?P\d*)").search cmd = fc + ['--version'] out, err = fc_config.getoutput(conf, cmd, stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('cannot determine g95 version') k = match.groupdict() conf.env.FC_VERSION = (k['major'], k['minor']) def configure(conf): conf.find_g95() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.g95_flags() conf.g95_modifier_platform() hamster-3.0.3/waflib/Tools/gas.py000066400000000000000000000007001452646177100166620ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2008-2018 (ita) "Detect as/gas/gcc for compiling assembly files" import waflib.Tools.asm # - leave this from waflib.Tools import ar def configure(conf): """ Find the programs gas/as/gcc and set the variable *AS* """ conf.find_program(['gas', 'gcc'], var='AS') conf.env.AS_TGT_F = ['-c', '-o'] conf.env.ASLNK_TGT_F = ['-o'] conf.find_ar() conf.load('asm') conf.env.ASM_NAME = 'gas' hamster-3.0.3/waflib/Tools/gcc.py000066400000000000000000000077011452646177100166540ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) # Yinon Ehrlich, 2009 """ gcc/llvm detection. """ from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_gcc(conf): """ Find the program gcc, and if present, try to detect its version number """ cc = conf.find_program(['gcc', 'cc'], var='CC') conf.get_cc_version(cc, gcc=True) conf.env.CC_NAME = 'gcc' @conf def gcc_common_flags(conf): """ Common flags for gcc on nearly all platforms """ v = conf.env v.CC_SRC_F = [] v.CC_TGT_F = ['-c', '-o'] if not v.LINK_CC: v.LINK_CC = v.CC v.CCLNK_SRC_F = [] v.CCLNK_TGT_F = ['-o'] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.RPATH_ST = '-Wl,-rpath,%s' v.SONAME_ST = '-Wl,-h,%s' v.SHLIB_MARKER = '-Wl,-Bdynamic' v.STLIB_MARKER = '-Wl,-Bstatic' v.cprogram_PATTERN = '%s' v.CFLAGS_cshlib = ['-fPIC'] v.LINKFLAGS_cshlib = ['-shared'] v.cshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cstlib = ['-Wl,-Bstatic'] v.cstlib_PATTERN = 'lib%s.a' v.LINKFLAGS_MACBUNDLE = ['-bundle', '-undefined', 'dynamic_lookup'] v.CFLAGS_MACBUNDLE = ['-fPIC'] v.macbundle_PATTERN = '%s.bundle' @conf def gcc_modifier_win32(conf): """Configuration flags for executing gcc on Windows""" v = conf.env v.cprogram_PATTERN = '%s.exe' v.cshlib_PATTERN = '%s.dll' v.implib_PATTERN = '%s.dll.a' v.IMPLIB_ST = '-Wl,--out-implib,%s' v.CFLAGS_cshlib = [] # Auto-import is enabled by default even without this option, # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages # that the linker emits otherwise. v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import']) @conf def gcc_modifier_cygwin(conf): """Configuration flags for executing gcc on Cygwin""" gcc_modifier_win32(conf) v = conf.env v.cshlib_PATTERN = 'cyg%s.dll' v.append_value('LINKFLAGS_cshlib', ['-Wl,--enable-auto-image-base']) v.CFLAGS_cshlib = [] @conf def gcc_modifier_darwin(conf): """Configuration flags for executing gcc on MacOS""" v = conf.env v.CFLAGS_cshlib = ['-fPIC'] v.LINKFLAGS_cshlib = ['-dynamiclib'] v.cshlib_PATTERN = 'lib%s.dylib' v.FRAMEWORKPATH_ST = '-F%s' v.FRAMEWORK_ST = ['-framework'] v.ARCH_ST = ['-arch'] v.LINKFLAGS_cstlib = [] v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.SONAME_ST = [] @conf def gcc_modifier_aix(conf): """Configuration flags for executing gcc on AIX""" v = conf.env v.LINKFLAGS_cprogram = ['-Wl,-brtl'] v.LINKFLAGS_cshlib = ['-shared','-Wl,-brtl,-bexpfull'] v.SHLIB_MARKER = [] @conf def gcc_modifier_hpux(conf): v = conf.env v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.CFLAGS_cshlib = ['-fPIC','-DPIC'] v.cshlib_PATTERN = 'lib%s.sl' @conf def gcc_modifier_openbsd(conf): conf.env.SONAME_ST = [] @conf def gcc_modifier_osf1V(conf): v = conf.env v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.SONAME_ST = [] @conf def gcc_modifier_platform(conf): """Execute platform-specific functions based on *gcc_modifier_+NAME*""" # * set configurations specific for a platform. # * the destination platform is detected automatically by looking at the macros the compiler predefines, # and if it's not recognised, it fallbacks to sys.platform. gcc_modifier_func = getattr(conf, 'gcc_modifier_' + conf.env.DEST_OS, None) if gcc_modifier_func: gcc_modifier_func() def configure(conf): """ Configuration for gcc """ conf.find_gcc() conf.find_ar() conf.gcc_common_flags() conf.gcc_modifier_platform() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() conf.check_gcc_o_space() hamster-3.0.3/waflib/Tools/gdc.py000066400000000000000000000021231452646177100166460ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2007 (dv) from waflib.Tools import ar, d from waflib.Configure import conf @conf def find_gdc(conf): """ Finds the program gdc and set the variable *D* """ conf.find_program('gdc', var='D') out = conf.cmd_and_log(conf.env.D + ['--version']) if out.find("gdc") == -1: conf.fatal("detected compiler is not gdc") @conf def common_flags_gdc(conf): """ Sets the flags required by *gdc* """ v = conf.env v.DFLAGS = [] v.D_SRC_F = ['-c'] v.D_TGT_F = '-o%s' v.D_LINKER = v.D v.DLNK_SRC_F = '' v.DLNK_TGT_F = '-o%s' v.DINC_ST = '-I%s' v.DSHLIB_MARKER = v.DSTLIB_MARKER = '' v.DSTLIB_ST = v.DSHLIB_ST = '-l%s' v.DSTLIBPATH_ST = v.DLIBPATH_ST = '-L%s' v.LINKFLAGS_dshlib = ['-shared'] v.DHEADER_ext = '.di' v.DFLAGS_d_with_header = '-fintfc' v.D_HDR_F = '-fintfc-file=%s' def configure(conf): """ Configuration for gdc """ conf.find_gdc() conf.load('ar') conf.load('d') conf.common_flags_gdc() conf.d_platform_flags() hamster-3.0.3/waflib/Tools/gfortran.py000066400000000000000000000044221452646177100177370ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # DC 2008 # Thomas Nagy 2016-2018 (ita) import re from waflib import Utils from waflib.Tools import fc, fc_config, fc_scan, ar from waflib.Configure import conf @conf def find_gfortran(conf): """Find the gfortran program (will look in the environment variable 'FC')""" fc = conf.find_program(['gfortran','g77'], var='FC') # (fallback to g77 for systems, where no gfortran is available) conf.get_gfortran_version(fc) conf.env.FC_NAME = 'GFORTRAN' @conf def gfortran_flags(conf): v = conf.env v.FCFLAGS_fcshlib = ['-fPIC'] v.FORTRANMODFLAG = ['-J', ''] # template for module path v.FCFLAGS_DEBUG = ['-Werror'] # why not @conf def gfortran_modifier_win32(conf): fc_config.fortran_modifier_win32(conf) @conf def gfortran_modifier_cygwin(conf): fc_config.fortran_modifier_cygwin(conf) @conf def gfortran_modifier_darwin(conf): fc_config.fortran_modifier_darwin(conf) @conf def gfortran_modifier_platform(conf): dest_os = conf.env.DEST_OS or Utils.unversioned_sys_platform() gfortran_modifier_func = getattr(conf, 'gfortran_modifier_' + dest_os, None) if gfortran_modifier_func: gfortran_modifier_func() @conf def get_gfortran_version(conf, fc): """Get the compiler version""" # ensure this is actually gfortran, not an imposter. version_re = re.compile(r"GNU\s*Fortran", re.I).search cmd = fc + ['--version'] out, err = fc_config.getoutput(conf, cmd, stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the compiler type') # --- now get more detailed info -- see c_config.get_cc_version cmd = fc + ['-dM', '-E', '-'] out, err = fc_config.getoutput(conf, cmd, stdin=True) if out.find('__GNUC__') < 0: conf.fatal('Could not determine the compiler type') k = {} out = out.splitlines() import shlex for line in out: lst = shlex.split(line) if len(lst)>2: key = lst[1] val = lst[2] k[key] = val def isD(var): return var in k def isT(var): return var in k and k[var] != '0' conf.env.FC_VERSION = (k['__GNUC__'], k['__GNUC_MINOR__'], k['__GNUC_PATCHLEVEL__']) def configure(conf): conf.find_gfortran() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.gfortran_flags() conf.gfortran_modifier_platform() conf.check_gfortran_o_space() hamster-3.0.3/waflib/Tools/glib2.py000066400000000000000000000366331452646177100171250ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ Support for GLib2 tools: * marshal * enums * gsettings * gresource """ import os import functools from waflib import Context, Task, Utils, Options, Errors, Logs from waflib.TaskGen import taskgen_method, before_method, feature, extension from waflib.Configure import conf ################## marshal files @taskgen_method def add_marshal_file(self, filename, prefix): """ Adds a file to the list of marshal files to process. Store them in the attribute *marshal_list*. :param filename: xml file to compile :type filename: string :param prefix: marshal prefix (--prefix=prefix) :type prefix: string """ if not hasattr(self, 'marshal_list'): self.marshal_list = [] self.meths.append('process_marshal') self.marshal_list.append((filename, prefix)) @before_method('process_source') def process_marshal(self): """ Processes the marshal files stored in the attribute *marshal_list* to create :py:class:`waflib.Tools.glib2.glib_genmarshal` instances. Adds the c file created to the list of source to process. """ for f, prefix in getattr(self, 'marshal_list', []): node = self.path.find_resource(f) if not node: raise Errors.WafError('file not found %r' % f) h_node = node.change_ext('.h') c_node = node.change_ext('.c') task = self.create_task('glib_genmarshal', node, [h_node, c_node]) task.env.GLIB_GENMARSHAL_PREFIX = prefix self.source = self.to_nodes(getattr(self, 'source', [])) self.source.append(c_node) class glib_genmarshal(Task.Task): vars = ['GLIB_GENMARSHAL_PREFIX', 'GLIB_GENMARSHAL'] color = 'BLUE' ext_out = ['.h'] def run(self): bld = self.generator.bld get = self.env.get_flat cmd1 = "%s %s --prefix=%s --header > %s" % ( get('GLIB_GENMARSHAL'), self.inputs[0].srcpath(), get('GLIB_GENMARSHAL_PREFIX'), self.outputs[0].abspath() ) ret = bld.exec_command(cmd1) if ret: return ret #print self.outputs[1].abspath() c = '''#include "%s"\n''' % self.outputs[0].name self.outputs[1].write(c) cmd2 = "%s %s --prefix=%s --body >> %s" % ( get('GLIB_GENMARSHAL'), self.inputs[0].srcpath(), get('GLIB_GENMARSHAL_PREFIX'), self.outputs[1].abspath() ) return bld.exec_command(cmd2) ########################## glib-mkenums @taskgen_method def add_enums_from_template(self, source='', target='', template='', comments=''): """ Adds a file to the list of enum files to process. Stores them in the attribute *enums_list*. :param source: enum file to process :type source: string :param target: target file :type target: string :param template: template file :type template: string :param comments: comments :type comments: string """ if not hasattr(self, 'enums_list'): self.enums_list = [] self.meths.append('process_enums') self.enums_list.append({'source': source, 'target': target, 'template': template, 'file-head': '', 'file-prod': '', 'file-tail': '', 'enum-prod': '', 'value-head': '', 'value-prod': '', 'value-tail': '', 'comments': comments}) @taskgen_method def add_enums(self, source='', target='', file_head='', file_prod='', file_tail='', enum_prod='', value_head='', value_prod='', value_tail='', comments=''): """ Adds a file to the list of enum files to process. Stores them in the attribute *enums_list*. :param source: enum file to process :type source: string :param target: target file :type target: string :param file_head: unused :param file_prod: unused :param file_tail: unused :param enum_prod: unused :param value_head: unused :param value_prod: unused :param value_tail: unused :param comments: comments :type comments: string """ if not hasattr(self, 'enums_list'): self.enums_list = [] self.meths.append('process_enums') self.enums_list.append({'source': source, 'template': '', 'target': target, 'file-head': file_head, 'file-prod': file_prod, 'file-tail': file_tail, 'enum-prod': enum_prod, 'value-head': value_head, 'value-prod': value_prod, 'value-tail': value_tail, 'comments': comments}) @before_method('process_source') def process_enums(self): """ Processes the enum files stored in the attribute *enum_list* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. """ for enum in getattr(self, 'enums_list', []): task = self.create_task('glib_mkenums') env = task.env inputs = [] # process the source source_list = self.to_list(enum['source']) if not source_list: raise Errors.WafError('missing source ' + str(enum)) source_list = [self.path.find_resource(k) for k in source_list] inputs += source_list env.GLIB_MKENUMS_SOURCE = [k.abspath() for k in source_list] # find the target if not enum['target']: raise Errors.WafError('missing target ' + str(enum)) tgt_node = self.path.find_or_declare(enum['target']) if tgt_node.name.endswith('.c'): self.source.append(tgt_node) env.GLIB_MKENUMS_TARGET = tgt_node.abspath() options = [] if enum['template']: # template, if provided template_node = self.path.find_resource(enum['template']) options.append('--template %s' % (template_node.abspath())) inputs.append(template_node) params = {'file-head' : '--fhead', 'file-prod' : '--fprod', 'file-tail' : '--ftail', 'enum-prod' : '--eprod', 'value-head' : '--vhead', 'value-prod' : '--vprod', 'value-tail' : '--vtail', 'comments': '--comments'} for param, option in params.items(): if enum[param]: options.append('%s %r' % (option, enum[param])) env.GLIB_MKENUMS_OPTIONS = ' '.join(options) # update the task instance task.set_inputs(inputs) task.set_outputs(tgt_node) class glib_mkenums(Task.Task): """ Processes enum files """ run_str = '${GLIB_MKENUMS} ${GLIB_MKENUMS_OPTIONS} ${GLIB_MKENUMS_SOURCE} > ${GLIB_MKENUMS_TARGET}' color = 'PINK' ext_out = ['.h'] ######################################### gsettings @taskgen_method def add_settings_schemas(self, filename_list): """ Adds settings files to process to *settings_schema_files* :param filename_list: files :type filename_list: list of string """ if not hasattr(self, 'settings_schema_files'): self.settings_schema_files = [] if not isinstance(filename_list, list): filename_list = [filename_list] self.settings_schema_files.extend(filename_list) @taskgen_method def add_settings_enums(self, namespace, filename_list): """ Called only once by task generator to set the enums namespace. :param namespace: namespace :type namespace: string :param filename_list: enum files to process :type filename_list: file list """ if hasattr(self, 'settings_enum_namespace'): raise Errors.WafError("Tried to add gsettings enums to %r more than once" % self.name) self.settings_enum_namespace = namespace if not isinstance(filename_list, list): filename_list = [filename_list] self.settings_enum_files = filename_list @feature('glib2') def process_settings(self): """ Processes the schema files in *settings_schema_files* to create :py:class:`waflib.Tools.glib2.glib_mkenums` instances. The same files are validated through :py:class:`waflib.Tools.glib2.glib_validate_schema` tasks. """ enums_tgt_node = [] install_files = [] settings_schema_files = getattr(self, 'settings_schema_files', []) if settings_schema_files and not self.env.GLIB_COMPILE_SCHEMAS: raise Errors.WafError ("Unable to process GSettings schemas - glib-compile-schemas was not found during configure") # 1. process gsettings_enum_files (generate .enums.xml) # if hasattr(self, 'settings_enum_files'): enums_task = self.create_task('glib_mkenums') source_list = self.settings_enum_files source_list = [self.path.find_resource(k) for k in source_list] enums_task.set_inputs(source_list) enums_task.env.GLIB_MKENUMS_SOURCE = [k.abspath() for k in source_list] target = self.settings_enum_namespace + '.enums.xml' tgt_node = self.path.find_or_declare(target) enums_task.set_outputs(tgt_node) enums_task.env.GLIB_MKENUMS_TARGET = tgt_node.abspath() enums_tgt_node = [tgt_node] install_files.append(tgt_node) options = '--comments "" --fhead "" --vhead " <@type@ id=\\"%s.@EnumName@\\">" --vprod " " --vtail " " --ftail "" ' % (self.settings_enum_namespace) enums_task.env.GLIB_MKENUMS_OPTIONS = options # 2. process gsettings_schema_files (validate .gschema.xml files) # for schema in settings_schema_files: schema_task = self.create_task ('glib_validate_schema') schema_node = self.path.find_resource(schema) if not schema_node: raise Errors.WafError("Cannot find the schema file %r" % schema) install_files.append(schema_node) source_list = enums_tgt_node + [schema_node] schema_task.set_inputs (source_list) schema_task.env.GLIB_COMPILE_SCHEMAS_OPTIONS = [("--schema-file=" + k.abspath()) for k in source_list] target_node = schema_node.change_ext('.xml.valid') schema_task.set_outputs (target_node) schema_task.env.GLIB_VALIDATE_SCHEMA_OUTPUT = target_node.abspath() # 3. schemas install task def compile_schemas_callback(bld): if not bld.is_install: return compile_schemas = Utils.to_list(bld.env.GLIB_COMPILE_SCHEMAS) destdir = Options.options.destdir paths = bld._compile_schemas_registered if destdir: paths = (os.path.join(destdir, path.lstrip(os.sep)) for path in paths) for path in paths: Logs.pprint('YELLOW', 'Updating GSettings schema cache %r' % path) if self.bld.exec_command(compile_schemas + [path]): Logs.warn('Could not update GSettings schema cache %r' % path) if self.bld.is_install: schemadir = self.env.GSETTINGSSCHEMADIR if not schemadir: raise Errors.WafError ('GSETTINGSSCHEMADIR not defined (should have been set up automatically during configure)') if install_files: self.add_install_files(install_to=schemadir, install_from=install_files) registered_schemas = getattr(self.bld, '_compile_schemas_registered', None) if not registered_schemas: registered_schemas = self.bld._compile_schemas_registered = set() self.bld.add_post_fun(compile_schemas_callback) registered_schemas.add(schemadir) class glib_validate_schema(Task.Task): """ Validates schema files """ run_str = 'rm -f ${GLIB_VALIDATE_SCHEMA_OUTPUT} && ${GLIB_COMPILE_SCHEMAS} --dry-run ${GLIB_COMPILE_SCHEMAS_OPTIONS} && touch ${GLIB_VALIDATE_SCHEMA_OUTPUT}' color = 'PINK' ################## gresource @extension('.gresource.xml') def process_gresource_source(self, node): """ Creates tasks that turn ``.gresource.xml`` files to C code """ if not self.env.GLIB_COMPILE_RESOURCES: raise Errors.WafError ("Unable to process GResource file - glib-compile-resources was not found during configure") if 'gresource' in self.features: return h_node = node.change_ext('_xml.h') c_node = node.change_ext('_xml.c') self.create_task('glib_gresource_source', node, [h_node, c_node]) self.source.append(c_node) @feature('gresource') def process_gresource_bundle(self): """ Creates tasks to turn ``.gresource`` files from ``.gresource.xml`` files:: def build(bld): bld( features='gresource', source=['resources1.gresource.xml', 'resources2.gresource.xml'], install_path='${LIBDIR}/${PACKAGE}' ) :param source: XML files to process :type source: list of string :param install_path: installation path :type install_path: string """ for i in self.to_list(self.source): node = self.path.find_resource(i) task = self.create_task('glib_gresource_bundle', node, node.change_ext('')) inst_to = getattr(self, 'install_path', None) if inst_to: self.add_install_files(install_to=inst_to, install_from=task.outputs) class glib_gresource_base(Task.Task): """ Base class for gresource based tasks """ color = 'BLUE' base_cmd = '${GLIB_COMPILE_RESOURCES} --sourcedir=${SRC[0].parent.srcpath()} --sourcedir=${SRC[0].bld_dir()}' def scan(self): """ Scans gresource dependencies through ``glib-compile-resources --generate-dependencies command`` """ bld = self.generator.bld kw = {} kw['cwd'] = self.get_cwd() kw['quiet'] = Context.BOTH cmd = Utils.subst_vars('${GLIB_COMPILE_RESOURCES} --sourcedir=%s --sourcedir=%s --generate-dependencies %s' % ( self.inputs[0].parent.srcpath(), self.inputs[0].bld_dir(), self.inputs[0].bldpath() ), self.env) output = bld.cmd_and_log(cmd, **kw) nodes = [] names = [] for dep in output.splitlines(): if dep: node = bld.bldnode.find_node(dep) if node: nodes.append(node) else: names.append(dep) return (nodes, names) class glib_gresource_source(glib_gresource_base): """ Task to generate C source code (.h and .c files) from a gresource.xml file """ vars = ['GLIB_COMPILE_RESOURCES'] fun_h = Task.compile_fun_shell(glib_gresource_base.base_cmd + ' --target=${TGT[0].abspath()} --generate-header ${SRC}') fun_c = Task.compile_fun_shell(glib_gresource_base.base_cmd + ' --target=${TGT[1].abspath()} --generate-source ${SRC}') ext_out = ['.h'] def run(self): return self.fun_h[0](self) or self.fun_c[0](self) class glib_gresource_bundle(glib_gresource_base): """ Task to generate a .gresource binary file from a gresource.xml file """ run_str = glib_gresource_base.base_cmd + ' --target=${TGT} ${SRC}' shell = True # temporary workaround for #795 @conf def find_glib_genmarshal(conf): conf.find_program('glib-genmarshal', var='GLIB_GENMARSHAL') @conf def find_glib_mkenums(conf): if not conf.env.PERL: conf.find_program('perl', var='PERL') conf.find_program('glib-mkenums', interpreter='PERL', var='GLIB_MKENUMS') @conf def find_glib_compile_schemas(conf): # when cross-compiling, gsettings.m4 locates the program with the following: # pkg-config --variable glib_compile_schemas gio-2.0 conf.find_program('glib-compile-schemas', var='GLIB_COMPILE_SCHEMAS') def getstr(varname): return getattr(Options.options, varname, getattr(conf.env,varname, '')) gsettingsschemadir = getstr('GSETTINGSSCHEMADIR') if not gsettingsschemadir: datadir = getstr('DATADIR') if not datadir: prefix = conf.env.PREFIX datadir = os.path.join(prefix, 'share') gsettingsschemadir = os.path.join(datadir, 'glib-2.0', 'schemas') conf.env.GSETTINGSSCHEMADIR = gsettingsschemadir @conf def find_glib_compile_resources(conf): conf.find_program('glib-compile-resources', var='GLIB_COMPILE_RESOURCES') def configure(conf): """ Finds the following programs: * *glib-genmarshal* and set *GLIB_GENMARSHAL* * *glib-mkenums* and set *GLIB_MKENUMS* * *glib-compile-schemas* and set *GLIB_COMPILE_SCHEMAS* (not mandatory) * *glib-compile-resources* and set *GLIB_COMPILE_RESOURCES* (not mandatory) """ conf.find_glib_genmarshal() conf.find_glib_mkenums() conf.find_glib_compile_schemas(mandatory=False) conf.find_glib_compile_resources(mandatory=False) def options(opt): """ Adds the ``--gsettingsschemadir`` command-line option """ gr = opt.add_option_group('Installation directories') gr.add_option('--gsettingsschemadir', help='GSettings schema location [DATADIR/glib-2.0/schemas]', default='', dest='GSETTINGSSCHEMADIR') hamster-3.0.3/waflib/Tools/gnu_dirs.py000066400000000000000000000120761452646177100177330ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Ali Sabil, 2007 """ Sets various standard variables such as INCLUDEDIR. SBINDIR and others. To use this module just call:: opt.load('gnu_dirs') and:: conf.load('gnu_dirs') Add options for the standard GNU directories, this tool will add the options found in autotools, and will update the environment with the following installation variables: ============== ========================================= ======================= Variable Description Default Value ============== ========================================= ======================= PREFIX installation prefix /usr/local EXEC_PREFIX installation prefix for binaries PREFIX BINDIR user commands EXEC_PREFIX/bin SBINDIR system binaries EXEC_PREFIX/sbin LIBEXECDIR program-specific binaries EXEC_PREFIX/libexec SYSCONFDIR host-specific configuration PREFIX/etc SHAREDSTATEDIR architecture-independent variable data PREFIX/com LOCALSTATEDIR variable data PREFIX/var LIBDIR object code libraries EXEC_PREFIX/lib INCLUDEDIR header files PREFIX/include OLDINCLUDEDIR header files for non-GCC compilers /usr/include DATAROOTDIR architecture-independent data root PREFIX/share DATADIR architecture-independent data DATAROOTDIR INFODIR GNU "info" documentation DATAROOTDIR/info LOCALEDIR locale-dependent data DATAROOTDIR/locale MANDIR manual pages DATAROOTDIR/man DOCDIR documentation root DATAROOTDIR/doc/APPNAME HTMLDIR HTML documentation DOCDIR DVIDIR DVI documentation DOCDIR PDFDIR PDF documentation DOCDIR PSDIR PostScript documentation DOCDIR ============== ========================================= ======================= """ import os, re from waflib import Utils, Options, Context gnuopts = ''' bindir, user commands, ${EXEC_PREFIX}/bin sbindir, system binaries, ${EXEC_PREFIX}/sbin libexecdir, program-specific binaries, ${EXEC_PREFIX}/libexec sysconfdir, host-specific configuration, ${PREFIX}/etc sharedstatedir, architecture-independent variable data, ${PREFIX}/com localstatedir, variable data, ${PREFIX}/var libdir, object code libraries, ${EXEC_PREFIX}/lib%s includedir, header files, ${PREFIX}/include oldincludedir, header files for non-GCC compilers, /usr/include datarootdir, architecture-independent data root, ${PREFIX}/share datadir, architecture-independent data, ${DATAROOTDIR} infodir, GNU "info" documentation, ${DATAROOTDIR}/info localedir, locale-dependent data, ${DATAROOTDIR}/locale mandir, manual pages, ${DATAROOTDIR}/man docdir, documentation root, ${DATAROOTDIR}/doc/${PACKAGE} htmldir, HTML documentation, ${DOCDIR} dvidir, DVI documentation, ${DOCDIR} pdfdir, PDF documentation, ${DOCDIR} psdir, PostScript documentation, ${DOCDIR} ''' % Utils.lib64() _options = [x.split(', ') for x in gnuopts.splitlines() if x] def configure(conf): """ Reads the command-line options to set lots of variables in *conf.env*. The variables BINDIR and LIBDIR will be overwritten. """ def get_param(varname, default): return getattr(Options.options, varname, '') or default env = conf.env env.LIBDIR = env.BINDIR = [] env.EXEC_PREFIX = get_param('EXEC_PREFIX', env.PREFIX) env.PACKAGE = getattr(Context.g_module, 'APPNAME', None) or env.PACKAGE complete = False iter = 0 while not complete and iter < len(_options) + 1: iter += 1 complete = True for name, help, default in _options: name = name.upper() if not env[name]: try: env[name] = Utils.subst_vars(get_param(name, default).replace('/', os.sep), env) except TypeError: complete = False if not complete: lst = [x for x, _, _ in _options if not env[x.upper()]] raise conf.errors.WafError('Variable substitution failure %r' % lst) def options(opt): """ Adds lots of command-line options, for example:: --exec-prefix: EXEC_PREFIX """ inst_dir = opt.add_option_group('Installation prefix', 'By default, "waf install" will put the files in\ "/usr/local/bin", "/usr/local/lib" etc. An installation prefix other\ than "/usr/local" can be given using "--prefix", for example "--prefix=$HOME"') for k in ('--prefix', '--destdir'): option = opt.parser.get_option(k) if option: opt.parser.remove_option(k) inst_dir.add_option(option) inst_dir.add_option('--exec-prefix', help = 'installation prefix for binaries [PREFIX]', default = '', dest = 'EXEC_PREFIX') dirs_options = opt.add_option_group('Installation directories') for name, help, default in _options: option_name = '--' + name str_default = default str_help = '%s [%s]' % (help, re.sub(r'\$\{([^}]+)\}', r'\1', str_default)) dirs_options.add_option(option_name, help=str_help, default='', dest=name.upper()) hamster-3.0.3/waflib/Tools/gxx.py000066400000000000000000000077401452646177100167310ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) # Yinon Ehrlich, 2009 """ g++/llvm detection. """ from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_gxx(conf): """ Finds the program g++, and if present, try to detect its version number """ cxx = conf.find_program(['g++', 'c++'], var='CXX') conf.get_cc_version(cxx, gcc=True) conf.env.CXX_NAME = 'gcc' @conf def gxx_common_flags(conf): """ Common flags for g++ on nearly all platforms """ v = conf.env v.CXX_SRC_F = [] v.CXX_TGT_F = ['-c', '-o'] if not v.LINK_CXX: v.LINK_CXX = v.CXX v.CXXLNK_SRC_F = [] v.CXXLNK_TGT_F = ['-o'] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.RPATH_ST = '-Wl,-rpath,%s' v.SONAME_ST = '-Wl,-h,%s' v.SHLIB_MARKER = '-Wl,-Bdynamic' v.STLIB_MARKER = '-Wl,-Bstatic' v.cxxprogram_PATTERN = '%s' v.CXXFLAGS_cxxshlib = ['-fPIC'] v.LINKFLAGS_cxxshlib = ['-shared'] v.cxxshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cxxstlib = ['-Wl,-Bstatic'] v.cxxstlib_PATTERN = 'lib%s.a' v.LINKFLAGS_MACBUNDLE = ['-bundle', '-undefined', 'dynamic_lookup'] v.CXXFLAGS_MACBUNDLE = ['-fPIC'] v.macbundle_PATTERN = '%s.bundle' @conf def gxx_modifier_win32(conf): """Configuration flags for executing gcc on Windows""" v = conf.env v.cxxprogram_PATTERN = '%s.exe' v.cxxshlib_PATTERN = '%s.dll' v.implib_PATTERN = '%s.dll.a' v.IMPLIB_ST = '-Wl,--out-implib,%s' v.CXXFLAGS_cxxshlib = [] # Auto-import is enabled by default even without this option, # but enabling it explicitly has the nice effect of suppressing the rather boring, debug-level messages # that the linker emits otherwise. v.append_value('LINKFLAGS', ['-Wl,--enable-auto-import']) @conf def gxx_modifier_cygwin(conf): """Configuration flags for executing g++ on Cygwin""" gxx_modifier_win32(conf) v = conf.env v.cxxshlib_PATTERN = 'cyg%s.dll' v.append_value('LINKFLAGS_cxxshlib', ['-Wl,--enable-auto-image-base']) v.CXXFLAGS_cxxshlib = [] @conf def gxx_modifier_darwin(conf): """Configuration flags for executing g++ on MacOS""" v = conf.env v.CXXFLAGS_cxxshlib = ['-fPIC'] v.LINKFLAGS_cxxshlib = ['-dynamiclib'] v.cxxshlib_PATTERN = 'lib%s.dylib' v.FRAMEWORKPATH_ST = '-F%s' v.FRAMEWORK_ST = ['-framework'] v.ARCH_ST = ['-arch'] v.LINKFLAGS_cxxstlib = [] v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.SONAME_ST = [] @conf def gxx_modifier_aix(conf): """Configuration flags for executing g++ on AIX""" v = conf.env v.LINKFLAGS_cxxprogram= ['-Wl,-brtl'] v.LINKFLAGS_cxxshlib = ['-shared', '-Wl,-brtl,-bexpfull'] v.SHLIB_MARKER = [] @conf def gxx_modifier_hpux(conf): v = conf.env v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.CFLAGS_cxxshlib = ['-fPIC','-DPIC'] v.cxxshlib_PATTERN = 'lib%s.sl' @conf def gxx_modifier_openbsd(conf): conf.env.SONAME_ST = [] @conf def gcc_modifier_osf1V(conf): v = conf.env v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.SONAME_ST = [] @conf def gxx_modifier_platform(conf): """Execute platform-specific functions based on *gxx_modifier_+NAME*""" # * set configurations specific for a platform. # * the destination platform is detected automatically by looking at the macros the compiler predefines, # and if it's not recognised, it fallbacks to sys.platform. gxx_modifier_func = getattr(conf, 'gxx_modifier_' + conf.env.DEST_OS, None) if gxx_modifier_func: gxx_modifier_func() def configure(conf): """ Configuration for g++ """ conf.find_gxx() conf.find_ar() conf.gxx_common_flags() conf.gxx_modifier_platform() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() conf.check_gcc_o_space('cxx') hamster-3.0.3/waflib/Tools/icc.py000066400000000000000000000011341452646177100166500ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Stian Selnes 2008 # Thomas Nagy 2009-2018 (ita) """ Detects the Intel C compiler """ import sys from waflib.Tools import ccroot, ar, gcc from waflib.Configure import conf @conf def find_icc(conf): """ Finds the program icc and execute it to ensure it really is icc """ cc = conf.find_program(['icc', 'ICL'], var='CC') conf.get_cc_version(cc, icc=True) conf.env.CC_NAME = 'icc' def configure(conf): conf.find_icc() conf.find_ar() conf.gcc_common_flags() conf.gcc_modifier_platform() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/icpc.py000066400000000000000000000011161452646177100170300ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy 2009-2018 (ita) """ Detects the Intel C++ compiler """ import sys from waflib.Tools import ccroot, ar, gxx from waflib.Configure import conf @conf def find_icpc(conf): """ Finds the program icpc, and execute it to ensure it really is icpc """ cxx = conf.find_program('icpc', var='CXX') conf.get_cc_version(cxx, icc=True) conf.env.CXX_NAME = 'icc' def configure(conf): conf.find_icpc() conf.find_ar() conf.gxx_common_flags() conf.gxx_modifier_platform() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/ifort.py000066400000000000000000000302711452646177100172410ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # DC 2008 # Thomas Nagy 2016-2018 (ita) import os, re, traceback from waflib import Utils, Logs, Errors from waflib.Tools import fc, fc_config, fc_scan, ar, ccroot from waflib.Configure import conf from waflib.TaskGen import after_method, feature @conf def find_ifort(conf): fc = conf.find_program('ifort', var='FC') conf.get_ifort_version(fc) conf.env.FC_NAME = 'IFORT' @conf def ifort_modifier_win32(self): v = self.env v.IFORT_WIN32 = True v.FCSTLIB_MARKER = '' v.FCSHLIB_MARKER = '' v.FCLIB_ST = v.FCSTLIB_ST = '%s.lib' v.FCLIBPATH_ST = v.STLIBPATH_ST = '/LIBPATH:%s' v.FCINCPATH_ST = '/I%s' v.FCDEFINES_ST = '/D%s' v.fcprogram_PATTERN = v.fcprogram_test_PATTERN = '%s.exe' v.fcshlib_PATTERN = '%s.dll' v.fcstlib_PATTERN = v.implib_PATTERN = '%s.lib' v.FCLNK_TGT_F = '/out:' v.FC_TGT_F = ['/c', '/o', ''] v.FCFLAGS_fcshlib = '' v.LINKFLAGS_fcshlib = '/DLL' v.AR_TGT_F = '/out:' v.IMPLIB_ST = '/IMPLIB:%s' v.append_value('LINKFLAGS', '/subsystem:console') if v.IFORT_MANIFEST: v.append_value('LINKFLAGS', ['/MANIFEST']) @conf def ifort_modifier_darwin(conf): fc_config.fortran_modifier_darwin(conf) @conf def ifort_modifier_platform(conf): dest_os = conf.env.DEST_OS or Utils.unversioned_sys_platform() ifort_modifier_func = getattr(conf, 'ifort_modifier_' + dest_os, None) if ifort_modifier_func: ifort_modifier_func() @conf def get_ifort_version(conf, fc): """ Detects the compiler version and sets ``conf.env.FC_VERSION`` """ version_re = re.compile(r"\bIntel\b.*\bVersion\s*(?P\d*)\.(?P\d*)",re.I).search if Utils.is_win32: cmd = fc else: cmd = fc + ['-logo'] out, err = fc_config.getoutput(conf, cmd, stdin=False) match = version_re(out) or version_re(err) if not match: conf.fatal('cannot determine ifort version.') k = match.groupdict() conf.env.FC_VERSION = (k['major'], k['minor']) def configure(conf): """ Detects the Intel Fortran compilers """ if Utils.is_win32: compiler, version, path, includes, libdirs, arch = conf.detect_ifort() v = conf.env v.DEST_CPU = arch v.PATH = path v.INCLUDES = includes v.LIBPATH = libdirs v.MSVC_COMPILER = compiler try: v.MSVC_VERSION = float(version) except ValueError: v.MSVC_VERSION = float(version[:-3]) conf.find_ifort_win32() conf.ifort_modifier_win32() else: conf.find_ifort() conf.find_program('xiar', var='AR') conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.ifort_modifier_platform() all_ifort_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')] """List of icl platforms""" @conf def gather_ifort_versions(conf, versions): """ List compiler versions by looking up registry keys """ version_pattern = re.compile(r'^...?.?\....?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\Fortran') except OSError: try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\Fortran') except OSError: return index = 0 while 1: try: version = Utils.winreg.EnumKey(all_versions, index) except OSError: break index += 1 if not version_pattern.match(version): continue targets = {} for target,arch in all_ifort_platforms: if target=='intel64': targetDir='EM64T_NATIVE' else: targetDir=target try: Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir) icl_version=Utils.winreg.OpenKey(all_versions,version) path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir') except OSError: pass else: batch_file=os.path.join(path,'bin','ifortvars.bat') if os.path.isfile(batch_file): targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) for target,arch in all_ifort_platforms: try: icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target) path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir') except OSError: continue else: batch_file=os.path.join(path,'bin','ifortvars.bat') if os.path.isfile(batch_file): targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) major = version[0:2] versions['intel ' + major] = targets @conf def setup_ifort(conf, versiondict): """ Checks installed compilers and targets and returns the first combination from the user's options, env, or the global supported lists that checks. :param versiondict: dict(platform -> dict(architecture -> configuration)) :type versiondict: dict(string -> dict(string -> target_compiler) :return: the compiler, revision, path, include dirs, library paths and target architecture :rtype: tuple of strings """ platforms = Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_ifort_platforms] desired_versions = conf.env.MSVC_VERSIONS or list(reversed(list(versiondict.keys()))) for version in desired_versions: try: targets = versiondict[version] except KeyError: continue for arch in platforms: try: cfg = targets[arch] except KeyError: continue cfg.evaluate() if cfg.is_valid: compiler,revision = version.rsplit(' ', 1) return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu conf.fatal('ifort: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys()))) @conf def get_ifort_version_win32(conf, compiler, version, target, vcvars): # FIXME hack try: conf.msvc_cnt += 1 except AttributeError: conf.msvc_cnt = 1 batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt) batfile.write("""@echo off set INCLUDE= set LIB= call "%s" %s echo PATH=%%PATH%% echo INCLUDE=%%INCLUDE%% echo LIB=%%LIB%%;%%LIBPATH%% """ % (vcvars,target)) sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()]) batfile.delete() lines = sout.splitlines() if not lines[0]: lines.pop(0) MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None for line in lines: if line.startswith('PATH='): path = line[5:] MSVC_PATH = path.split(';') elif line.startswith('INCLUDE='): MSVC_INCDIR = [i for i in line[8:].split(';') if i] elif line.startswith('LIB='): MSVC_LIBDIR = [i for i in line[4:].split(';') if i] if None in (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR): conf.fatal('ifort: Could not find a valid architecture for building (get_ifort_version_win32)') # Check if the compiler is usable at all. # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run. env = dict(os.environ) env.update(PATH = path) compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) fc = conf.find_program(compiler_name, path_list=MSVC_PATH) # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically. if 'CL' in env: del(env['CL']) try: conf.cmd_and_log(fc + ['/help'], env=env) except UnicodeError: st = traceback.format_exc() if conf.logger: conf.logger.error(st) conf.fatal('ifort: Unicode error - check the code page?') except Exception as e: Logs.debug('ifort: get_ifort_version: %r %r %r -> failure %s', compiler, version, target, str(e)) conf.fatal('ifort: cannot run the compiler in get_ifort_version (run with -v to display errors)') else: Logs.debug('ifort: get_ifort_version: %r %r %r -> OK', compiler, version, target) finally: conf.env[compiler_name] = '' return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR) class target_compiler(object): """ Wraps a compiler configuration; call evaluate() to determine whether the configuration is usable. """ def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None): """ :param ctx: configuration context to use to eventually get the version environment :param compiler: compiler name :param cpu: target cpu :param version: compiler version number :param bat_target: ? :param bat: path to the batch file to run :param callback: optional function to take the realized environment variables tup and map it (e.g. to combine other constant paths) """ self.conf = ctx self.name = None self.is_valid = False self.is_done = False self.compiler = compiler self.cpu = cpu self.version = version self.bat_target = bat_target self.bat = bat self.callback = callback def evaluate(self): if self.is_done: return self.is_done = True try: vs = self.conf.get_ifort_version_win32(self.compiler, self.version, self.bat_target, self.bat) except Errors.ConfigurationError: self.is_valid = False return if self.callback: vs = self.callback(self, vs) self.is_valid = True (self.bindirs, self.incdirs, self.libdirs) = vs def __str__(self): return str((self.bindirs, self.incdirs, self.libdirs)) def __repr__(self): return repr((self.bindirs, self.incdirs, self.libdirs)) @conf def detect_ifort(self): return self.setup_ifort(self.get_ifort_versions(False)) @conf def get_ifort_versions(self, eval_and_save=True): """ :return: platforms to compiler configurations :rtype: dict """ dct = {} self.gather_ifort_versions(dct) return dct def _get_prog_names(self, compiler): if compiler=='intel': compiler_name = 'ifort' linker_name = 'XILINK' lib_name = 'XILIB' else: # assumes CL.exe compiler_name = 'CL' linker_name = 'LINK' lib_name = 'LIB' return compiler_name, linker_name, lib_name @conf def find_ifort_win32(conf): # the autodetection is supposed to be performed before entering in this method v = conf.env path = v.PATH compiler = v.MSVC_COMPILER version = v.MSVC_VERSION compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) v.IFORT_MANIFEST = (compiler == 'intel' and version >= 11) # compiler fc = conf.find_program(compiler_name, var='FC', path_list=path) # before setting anything, check if the compiler is really intel fortran env = dict(conf.environ) if path: env.update(PATH = ';'.join(path)) if not conf.cmd_and_log(fc + ['/nologo', '/help'], env=env): conf.fatal('not intel fortran compiler could not be identified') v.FC_NAME = 'IFORT' if not v.LINK_FC: conf.find_program(linker_name, var='LINK_FC', path_list=path, mandatory=True) if not v.AR: conf.find_program(lib_name, path_list=path, var='AR', mandatory=True) v.ARFLAGS = ['/nologo'] # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later if v.IFORT_MANIFEST: conf.find_program('MT', path_list=path, var='MT') v.MTFLAGS = ['/nologo'] try: conf.load('winres') except Errors.WafError: Logs.warn('Resource compiler not found. Compiling resource file is disabled') ####################################################################################################### ##### conf above, build below @after_method('apply_link') @feature('fc') def apply_flags_ifort(self): """ Adds additional flags implied by msvc, such as subsystems and pdb files:: def build(bld): bld.stlib(source='main.c', target='bar', subsystem='gruik') """ if not self.env.IFORT_WIN32 or not getattr(self, 'link_task', None): return is_static = isinstance(self.link_task, ccroot.stlink_task) subsystem = getattr(self, 'subsystem', '') if subsystem: subsystem = '/subsystem:%s' % subsystem flags = is_static and 'ARFLAGS' or 'LINKFLAGS' self.env.append_value(flags, subsystem) if not is_static: for f in self.env.LINKFLAGS: d = f.lower() if d[1:] == 'debug': pdbnode = self.link_task.outputs[0].change_ext('.pdb') self.link_task.outputs.append(pdbnode) if getattr(self, 'install_task', None): self.pdb_install_task = self.add_install_files(install_to=self.install_task.install_to, install_from=pdbnode) break @feature('fcprogram', 'fcshlib', 'fcprogram_test') @after_method('apply_link') def apply_manifest_ifort(self): """ Enables manifest embedding in Fortran DLLs when using ifort on Windows See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx """ if self.env.IFORT_WIN32 and getattr(self, 'link_task', None): # it seems ifort.exe cannot be called for linking self.link_task.env.FC = self.env.LINK_FC if self.env.IFORT_WIN32 and self.env.IFORT_MANIFEST and getattr(self, 'link_task', None): out_node = self.link_task.outputs[0] man_node = out_node.parent.find_or_declare(out_node.name + '.manifest') self.link_task.outputs.append(man_node) self.env.DO_MANIFEST = True hamster-3.0.3/waflib/Tools/intltool.py000066400000000000000000000152001452646177100177550ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ Support for translation tools such as msgfmt and intltool Usage:: def configure(conf): conf.load('gnu_dirs intltool') def build(bld): # process the .po files into .gmo files, and install them in LOCALEDIR bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}") # process an input file, substituting the translations from the po dir bld( features = "intltool_in", podir = "../po", style = "desktop", flags = ["-u"], source = 'kupfer.desktop.in', install_path = "${DATADIR}/applications", ) Usage of the :py:mod:`waflib.Tools.gnu_dirs` is recommended, but not obligatory. """ from __future__ import with_statement import os, re from waflib import Context, Task, Utils, Logs import waflib.Tools.ccroot from waflib.TaskGen import feature, before_method, taskgen_method from waflib.Logs import error from waflib.Configure import conf _style_flags = { 'ba': '-b', 'desktop': '-d', 'keys': '-k', 'quoted': '--quoted-style', 'quotedxml': '--quotedxml-style', 'rfc822deb': '-r', 'schemas': '-s', 'xml': '-x', } @taskgen_method def ensure_localedir(self): """ Expands LOCALEDIR from DATAROOTDIR/locale if possible, or falls back to PREFIX/share/locale """ # use the tool gnu_dirs to provide options to define this if not self.env.LOCALEDIR: if self.env.DATAROOTDIR: self.env.LOCALEDIR = os.path.join(self.env.DATAROOTDIR, 'locale') else: self.env.LOCALEDIR = os.path.join(self.env.PREFIX, 'share', 'locale') @before_method('process_source') @feature('intltool_in') def apply_intltool_in_f(self): """ Creates tasks to translate files by intltool-merge:: def build(bld): bld( features = "intltool_in", podir = "../po", style = "desktop", flags = ["-u"], source = 'kupfer.desktop.in', install_path = "${DATADIR}/applications", ) :param podir: location of the .po files :type podir: string :param source: source files to process :type source: list of string :param style: the intltool-merge mode of operation, can be one of the following values: ``ba``, ``desktop``, ``keys``, ``quoted``, ``quotedxml``, ``rfc822deb``, ``schemas`` and ``xml``. See the ``intltool-merge`` man page for more information about supported modes of operation. :type style: string :param flags: compilation flags ("-quc" by default) :type flags: list of string :param install_path: installation path :type install_path: string """ try: self.meths.remove('process_source') except ValueError: pass self.ensure_localedir() podir = getattr(self, 'podir', '.') podirnode = self.path.find_dir(podir) if not podirnode: error("could not find the podir %r" % podir) return cache = getattr(self, 'intlcache', '.intlcache') self.env.INTLCACHE = [os.path.join(str(self.path.get_bld()), podir, cache)] self.env.INTLPODIR = podirnode.bldpath() self.env.append_value('INTLFLAGS', getattr(self, 'flags', self.env.INTLFLAGS_DEFAULT)) if '-c' in self.env.INTLFLAGS: self.bld.fatal('Redundant -c flag in intltool task %r' % self) style = getattr(self, 'style', None) if style: try: style_flag = _style_flags[style] except KeyError: self.bld.fatal('intltool_in style "%s" is not valid' % style) self.env.append_unique('INTLFLAGS', [style_flag]) for i in self.to_list(self.source): node = self.path.find_resource(i) task = self.create_task('intltool', node, node.change_ext('')) inst = getattr(self, 'install_path', None) if inst: self.add_install_files(install_to=inst, install_from=task.outputs) @feature('intltool_po') def apply_intltool_po(self): """ Creates tasks to process po files:: def build(bld): bld(features='intltool_po', appname='myapp', podir='po', install_path="${LOCALEDIR}") The relevant task generator arguments are: :param podir: directory of the .po files :type podir: string :param appname: name of the application :type appname: string :param install_path: installation directory :type install_path: string The file LINGUAS must be present in the directory pointed by *podir* and list the translation files to process. """ try: self.meths.remove('process_source') except ValueError: pass self.ensure_localedir() appname = getattr(self, 'appname', getattr(Context.g_module, Context.APPNAME, 'set_your_app_name')) podir = getattr(self, 'podir', '.') inst = getattr(self, 'install_path', '${LOCALEDIR}') linguas = self.path.find_node(os.path.join(podir, 'LINGUAS')) if linguas: # scan LINGUAS file for locales to process with open(linguas.abspath()) as f: langs = [] for line in f.readlines(): # ignore lines containing comments if not line.startswith('#'): langs += line.split() re_linguas = re.compile('[-a-zA-Z_@.]+') for lang in langs: # Make sure that we only process lines which contain locales if re_linguas.match(lang): node = self.path.find_resource(os.path.join(podir, re_linguas.match(lang).group() + '.po')) task = self.create_task('po', node, node.change_ext('.mo')) if inst: filename = task.outputs[0].name (langname, ext) = os.path.splitext(filename) inst_file = inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + appname + '.mo' self.add_install_as(install_to=inst_file, install_from=task.outputs[0], chmod=getattr(self, 'chmod', Utils.O644)) else: Logs.pprint('RED', "Error no LINGUAS file found in po directory") class po(Task.Task): """ Compiles .po files into .gmo files """ run_str = '${MSGFMT} -o ${TGT} ${SRC}' color = 'BLUE' class intltool(Task.Task): """ Calls intltool-merge to update translation files """ run_str = '${INTLTOOL} ${INTLFLAGS} ${INTLCACHE_ST:INTLCACHE} ${INTLPODIR} ${SRC} ${TGT}' color = 'BLUE' @conf def find_msgfmt(conf): """ Detects msgfmt and sets the ``MSGFMT`` variable """ conf.find_program('msgfmt', var='MSGFMT') @conf def find_intltool_merge(conf): """ Detects intltool-merge """ if not conf.env.PERL: conf.find_program('perl', var='PERL') conf.env.INTLCACHE_ST = '--cache=%s' conf.env.INTLFLAGS_DEFAULT = ['-q', '-u'] conf.find_program('intltool-merge', interpreter='PERL', var='INTLTOOL') def configure(conf): """ Detects the program *msgfmt* and set *conf.env.MSGFMT*. Detects the program *intltool-merge* and set *conf.env.INTLTOOL*. It is possible to set INTLTOOL in the environment, but it must not have spaces in it:: $ INTLTOOL="/path/to/the program/intltool" waf configure If a C/C++ compiler is present, execute a compilation test to find the header *locale.h*. """ conf.find_msgfmt() conf.find_intltool_merge() if conf.env.CC or conf.env.CXX: conf.check(header_name='locale.h') hamster-3.0.3/waflib/Tools/irixcc.py000066400000000000000000000022231452646177100173730ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # imported from samba """ Compiler definition for irix/MIPSpro cc compiler """ from waflib import Errors from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_irixcc(conf): v = conf.env cc = conf.find_program('cc', var='CC') try: conf.cmd_and_log(cc + ['-version']) except Errors.WafError: conf.fatal('%r -version could not be executed' % cc) v.CC_NAME = 'irix' @conf def irixcc_common_flags(conf): v = conf.env v.CC_SRC_F = '' v.CC_TGT_F = ['-c', '-o'] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' if not v.LINK_CC: v.LINK_CC = v.CC v.CCLNK_SRC_F = '' v.CCLNK_TGT_F = ['-o'] v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.cprogram_PATTERN = '%s' v.cshlib_PATTERN = 'lib%s.so' v.cstlib_PATTERN = 'lib%s.a' def configure(conf): conf.find_irixcc() conf.find_ar() conf.irixcc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/javaw.py000066400000000000000000000407621452646177100172340ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ Java support Javac is one of the few compilers that behaves very badly: #. it outputs files where it wants to (-d is only for the package root) #. it recompiles files silently behind your back #. it outputs an undefined amount of files (inner classes) Remember that the compilation can be performed using Jython[1] rather than regular Python. Instead of running one of the following commands:: ./waf configure python waf configure You would have to run:: java -jar /path/to/jython.jar waf configure [1] http://www.jython.org/ Usage ===== Load the "java" tool. def configure(conf): conf.load('java') Java tools will be autodetected and eventually, if present, the quite standard JAVA_HOME environment variable will be used. The also standard CLASSPATH variable is used for library searching. In configuration phase checks can be done on the system environment, for example to check if a class is known in the classpath:: conf.check_java_class('java.io.FileOutputStream') or if the system supports JNI applications building:: conf.check_jni_headers() The java tool supports compiling java code, creating jar files and creating javadoc documentation. This can be either done separately or together in a single definition. For example to manage them separately:: bld(features = 'javac', srcdir = 'src', compat = '1.7', use = 'animals', name = 'cats-src', ) bld(features = 'jar', basedir = '.', destfile = '../cats.jar', name = 'cats', use = 'cats-src' ) Or together by defining all the needed attributes:: bld(features = 'javac jar javadoc', srcdir = 'src/', # folder containing the sources to compile outdir = 'src', # folder where to output the classes (in the build directory) compat = '1.6', # java compatibility version number classpath = ['.', '..'], # jar basedir = 'src', # folder containing the classes and other files to package (must match outdir) destfile = 'foo.jar', # do not put the destfile in the folder of the java classes! use = 'NNN', jaropts = ['-C', 'default/src/', '.'], # can be used to give files manifest = 'src/Manifest.mf', # Manifest file to include # javadoc javadoc_package = ['com.meow' , 'com.meow.truc.bar', 'com.meow.truc.foo'], javadoc_output = 'javadoc', ) External jar dependencies can be mapped to a standard waf "use" dependency by setting an environment variable with a CLASSPATH prefix in the configuration, for example:: conf.env.CLASSPATH_NNN = ['aaaa.jar', 'bbbb.jar'] and then NNN can be freely used in rules as:: use = 'NNN', In the java tool the dependencies via use are not transitive by default, as this necessity depends on the code. To enable recursive dependency scanning use on a specific rule: recurse_use = True Or build-wise by setting RECURSE_JAVA: bld.env.RECURSE_JAVA = True Unit tests can be integrated in the waf unit test environment using the javatest extra. """ import os, shutil from waflib import Task, Utils, Errors, Node from waflib.Configure import conf from waflib.TaskGen import feature, before_method, after_method, taskgen_method from waflib.Tools import ccroot ccroot.USELIB_VARS['javac'] = set(['CLASSPATH', 'JAVACFLAGS']) SOURCE_RE = '**/*.java' JAR_RE = '**/*' class_check_source = ''' public class Test { public static void main(String[] argv) { Class lib; if (argv.length < 1) { System.err.println("Missing argument"); System.exit(77); } try { lib = Class.forName(argv[0]); } catch (ClassNotFoundException e) { System.err.println("ClassNotFoundException"); System.exit(1); } lib = null; System.exit(0); } } ''' @feature('javac') @before_method('process_source') def apply_java(self): """ Create a javac task for compiling *.java files*. There can be only one javac task by task generator. """ Utils.def_attrs(self, jarname='', classpath='', sourcepath='.', srcdir='.', jar_mf_attributes={}, jar_mf_classpath=[]) outdir = getattr(self, 'outdir', None) if outdir: if not isinstance(outdir, Node.Node): outdir = self.path.get_bld().make_node(self.outdir) else: outdir = self.path.get_bld() outdir.mkdir() self.outdir = outdir self.env.OUTDIR = outdir.abspath() self.javac_task = tsk = self.create_task('javac') tmp = [] srcdir = getattr(self, 'srcdir', '') if isinstance(srcdir, Node.Node): srcdir = [srcdir] for x in Utils.to_list(srcdir): if isinstance(x, Node.Node): y = x else: y = self.path.find_dir(x) if not y: self.bld.fatal('Could not find the folder %s from %s' % (x, self.path)) tmp.append(y) tsk.srcdir = tmp if getattr(self, 'compat', None): tsk.env.append_value('JAVACFLAGS', ['-source', str(self.compat)]) if hasattr(self, 'sourcepath'): fold = [isinstance(x, Node.Node) and x or self.path.find_dir(x) for x in self.to_list(self.sourcepath)] names = os.pathsep.join([x.srcpath() for x in fold]) else: names = [x.srcpath() for x in tsk.srcdir] if names: tsk.env.append_value('JAVACFLAGS', ['-sourcepath', names]) @taskgen_method def java_use_rec(self, name, **kw): """ Processes recursively the *use* attribute for each referred java compilation """ if name in self.tmp_use_seen: return self.tmp_use_seen.append(name) try: y = self.bld.get_tgen_by_name(name) except Errors.WafError: self.uselib.append(name) return else: y.post() # Add generated JAR name for CLASSPATH. Task ordering (set_run_after) # is already guaranteed by ordering done between the single tasks if hasattr(y, 'jar_task'): self.use_lst.append(y.jar_task.outputs[0].abspath()) else: if hasattr(y,'outdir'): self.use_lst.append(y.outdir.abspath()) else: self.use_lst.append(y.path.get_bld().abspath()) for x in self.to_list(getattr(y, 'use', [])): self.java_use_rec(x) @feature('javac') @before_method('propagate_uselib_vars') @after_method('apply_java') def use_javac_files(self): """ Processes the *use* attribute referring to other java compilations """ self.use_lst = [] self.tmp_use_seen = [] self.uselib = self.to_list(getattr(self, 'uselib', [])) names = self.to_list(getattr(self, 'use', [])) get = self.bld.get_tgen_by_name for x in names: try: tg = get(x) except Errors.WafError: self.uselib.append(x) else: tg.post() if hasattr(tg, 'jar_task'): self.use_lst.append(tg.jar_task.outputs[0].abspath()) self.javac_task.set_run_after(tg.jar_task) self.javac_task.dep_nodes.extend(tg.jar_task.outputs) else: if hasattr(tg, 'outdir'): base_node = tg.outdir else: base_node = tg.path.get_bld() self.use_lst.append(base_node.abspath()) self.javac_task.dep_nodes.extend([dx for dx in base_node.ant_glob(JAR_RE, remove=False, quiet=True)]) for tsk in tg.tasks: self.javac_task.set_run_after(tsk) # If recurse use scan is enabled recursively add use attribute for each used one if getattr(self, 'recurse_use', False) or self.bld.env.RECURSE_JAVA: self.java_use_rec(x) self.env.append_value('CLASSPATH', self.use_lst) @feature('javac') @after_method('apply_java', 'propagate_uselib_vars', 'use_javac_files') def set_classpath(self): """ Sets the CLASSPATH value on the *javac* task previously created. """ if getattr(self, 'classpath', None): self.env.append_unique('CLASSPATH', getattr(self, 'classpath', [])) for x in self.tasks: x.env.CLASSPATH = os.pathsep.join(self.env.CLASSPATH) + os.pathsep @feature('jar') @after_method('apply_java', 'use_javac_files') @before_method('process_source') def jar_files(self): """ Creates a jar task (one maximum per task generator) """ destfile = getattr(self, 'destfile', 'test.jar') jaropts = getattr(self, 'jaropts', []) manifest = getattr(self, 'manifest', None) basedir = getattr(self, 'basedir', None) if basedir: if not isinstance(self.basedir, Node.Node): basedir = self.path.get_bld().make_node(basedir) else: basedir = self.path.get_bld() if not basedir: self.bld.fatal('Could not find the basedir %r for %r' % (self.basedir, self)) self.jar_task = tsk = self.create_task('jar_create') if manifest: jarcreate = getattr(self, 'jarcreate', 'cfm') if not isinstance(manifest,Node.Node): node = self.path.find_resource(manifest) else: node = manifest if not node: self.bld.fatal('invalid manifest file %r for %r' % (manifest, self)) tsk.dep_nodes.append(node) jaropts.insert(0, node.abspath()) else: jarcreate = getattr(self, 'jarcreate', 'cf') if not isinstance(destfile, Node.Node): destfile = self.path.find_or_declare(destfile) if not destfile: self.bld.fatal('invalid destfile %r for %r' % (destfile, self)) tsk.set_outputs(destfile) tsk.basedir = basedir jaropts.append('-C') jaropts.append(basedir.bldpath()) jaropts.append('.') tsk.env.JAROPTS = jaropts tsk.env.JARCREATE = jarcreate if getattr(self, 'javac_task', None): tsk.set_run_after(self.javac_task) @feature('jar') @after_method('jar_files') def use_jar_files(self): """ Processes the *use* attribute to set the build order on the tasks created by another task generator. """ self.uselib = self.to_list(getattr(self, 'uselib', [])) names = self.to_list(getattr(self, 'use', [])) get = self.bld.get_tgen_by_name for x in names: try: y = get(x) except Errors.WafError: self.uselib.append(x) else: y.post() self.jar_task.run_after.update(y.tasks) class JTask(Task.Task): """ Base class for java and jar tasks; provides functionality to run long commands """ def split_argfile(self, cmd): inline = [cmd[0]] infile = [] for x in cmd[1:]: # jar and javac do not want -J flags in @file if x.startswith('-J'): inline.append(x) else: infile.append(self.quote_flag(x)) return (inline, infile) class jar_create(JTask): """ Creates a jar file """ color = 'GREEN' run_str = '${JAR} ${JARCREATE} ${TGT} ${JAROPTS}' def runnable_status(self): """ Wait for dependent tasks to be executed, then read the files to update the list of inputs. """ for t in self.run_after: if not t.hasrun: return Task.ASK_LATER if not self.inputs: try: self.inputs = [x for x in self.basedir.ant_glob(JAR_RE, remove=False, quiet=True) if id(x) != id(self.outputs[0])] except Exception: raise Errors.WafError('Could not find the basedir %r for %r' % (self.basedir, self)) return super(jar_create, self).runnable_status() class javac(JTask): """ Compiles java files """ color = 'BLUE' run_str = '${JAVAC} -classpath ${CLASSPATH} -d ${OUTDIR} ${JAVACFLAGS} ${SRC}' vars = ['CLASSPATH', 'JAVACFLAGS', 'JAVAC', 'OUTDIR'] """ The javac task will be executed again if the variables CLASSPATH, JAVACFLAGS, JAVAC or OUTDIR change. """ def uid(self): """Identify java tasks by input&output folder""" lst = [self.__class__.__name__, self.generator.outdir.abspath()] for x in self.srcdir: lst.append(x.abspath()) return Utils.h_list(lst) def runnable_status(self): """ Waits for dependent tasks to be complete, then read the file system to find the input nodes. """ for t in self.run_after: if not t.hasrun: return Task.ASK_LATER if not self.inputs: self.inputs = [] for x in self.srcdir: if x.exists(): self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False, quiet=True)) return super(javac, self).runnable_status() def post_run(self): """ List class files created """ for node in self.generator.outdir.ant_glob('**/*.class', quiet=True): self.generator.bld.node_sigs[node] = self.uid() self.generator.bld.task_sigs[self.uid()] = self.cache_sig @feature('javadoc') @after_method('process_rule') def create_javadoc(self): """ Creates a javadoc task (feature 'javadoc') """ tsk = self.create_task('javadoc') tsk.classpath = getattr(self, 'classpath', []) self.javadoc_package = Utils.to_list(self.javadoc_package) if not isinstance(self.javadoc_output, Node.Node): self.javadoc_output = self.bld.path.find_or_declare(self.javadoc_output) class javadoc(Task.Task): """ Builds java documentation """ color = 'BLUE' def __str__(self): return '%s: %s -> %s\n' % (self.__class__.__name__, self.generator.srcdir, self.generator.javadoc_output) def run(self): env = self.env bld = self.generator.bld wd = bld.bldnode #add src node + bld node (for generated java code) srcpath = self.generator.path.abspath() + os.sep + self.generator.srcdir srcpath += os.pathsep srcpath += self.generator.path.get_bld().abspath() + os.sep + self.generator.srcdir classpath = env.CLASSPATH classpath += os.pathsep classpath += os.pathsep.join(self.classpath) classpath = "".join(classpath) self.last_cmd = lst = [] lst.extend(Utils.to_list(env.JAVADOC)) lst.extend(['-d', self.generator.javadoc_output.abspath()]) lst.extend(['-sourcepath', srcpath]) lst.extend(['-classpath', classpath]) lst.extend(['-subpackages']) lst.extend(self.generator.javadoc_package) lst = [x for x in lst if x] self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, quiet=0) def post_run(self): nodes = self.generator.javadoc_output.ant_glob('**', quiet=True) for node in nodes: self.generator.bld.node_sigs[node] = self.uid() self.generator.bld.task_sigs[self.uid()] = self.cache_sig def configure(self): """ Detects the javac, java and jar programs """ # If JAVA_PATH is set, we prepend it to the path list java_path = self.environ['PATH'].split(os.pathsep) v = self.env if 'JAVA_HOME' in self.environ: java_path = [os.path.join(self.environ['JAVA_HOME'], 'bin')] + java_path self.env.JAVA_HOME = [self.environ['JAVA_HOME']] for x in 'javac java jar javadoc'.split(): self.find_program(x, var=x.upper(), path_list=java_path, mandatory=(x not in ('javadoc'))) if 'CLASSPATH' in self.environ: v.CLASSPATH = self.environ['CLASSPATH'] if not v.JAR: self.fatal('jar is required for making java packages') if not v.JAVAC: self.fatal('javac is required for compiling java classes') v.JARCREATE = 'cf' # can use cvf v.JAVACFLAGS = [] @conf def check_java_class(self, classname, with_classpath=None): """ Checks if the specified java class exists :param classname: class to check, like java.util.HashMap :type classname: string :param with_classpath: additional classpath to give :type with_classpath: string """ javatestdir = '.waf-javatest' classpath = javatestdir if self.env.CLASSPATH: classpath += os.pathsep + self.env.CLASSPATH if isinstance(with_classpath, str): classpath += os.pathsep + with_classpath shutil.rmtree(javatestdir, True) os.mkdir(javatestdir) Utils.writef(os.path.join(javatestdir, 'Test.java'), class_check_source) # Compile the source self.exec_command(self.env.JAVAC + [os.path.join(javatestdir, 'Test.java')], shell=False) # Try to run the app cmd = self.env.JAVA + ['-cp', classpath, 'Test', classname] self.to_log("%s\n" % str(cmd)) found = self.exec_command(cmd, shell=False) self.msg('Checking for java class %s' % classname, not found) shutil.rmtree(javatestdir, True) return found @conf def check_jni_headers(conf): """ Checks for jni headers and libraries. On success the conf.env variables xxx_JAVA are added for use in C/C++ targets:: def options(opt): opt.load('compiler_c') def configure(conf): conf.load('compiler_c java') conf.check_jni_headers() def build(bld): bld.shlib(source='a.c', target='app', use='JAVA') """ if not conf.env.CC_NAME and not conf.env.CXX_NAME: conf.fatal('load a compiler first (gcc, g++, ..)') if not conf.env.JAVA_HOME: conf.fatal('set JAVA_HOME in the system environment') # jni requires the jvm javaHome = conf.env.JAVA_HOME[0] dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/include') if dir is None: dir = conf.root.find_dir(conf.env.JAVA_HOME[0] + '/../Headers') # think different?! if dir is None: conf.fatal('JAVA_HOME does not seem to be set properly') f = dir.ant_glob('**/(jni|jni_md).h') incDirs = [x.parent.abspath() for x in f] dir = conf.root.find_dir(conf.env.JAVA_HOME[0]) f = dir.ant_glob('**/*jvm.(so|dll|dylib)') libDirs = [x.parent.abspath() for x in f] or [javaHome] # On windows, we need both the .dll and .lib to link. On my JDK, they are # in different directories... f = dir.ant_glob('**/*jvm.(lib)') if f: libDirs = [[x, y.parent.abspath()] for x in libDirs for y in f] if conf.env.DEST_OS == 'freebsd': conf.env.append_unique('LINKFLAGS_JAVA', '-pthread') for d in libDirs: try: conf.check(header_name='jni.h', define_name='HAVE_JNI_H', lib='jvm', libpath=d, includes=incDirs, uselib_store='JAVA', uselib='JAVA') except Exception: pass else: break else: conf.fatal('could not find lib jvm in %r (see config.log)' % libDirs) hamster-3.0.3/waflib/Tools/ldc2.py000066400000000000000000000022411452646177100167360ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Alex Rønne Petersen, 2012 (alexrp/Zor) from waflib.Tools import ar, d from waflib.Configure import conf @conf def find_ldc2(conf): """ Finds the program *ldc2* and set the variable *D* """ conf.find_program(['ldc2'], var='D') out = conf.cmd_and_log(conf.env.D + ['-version']) if out.find("based on DMD v2.") == -1: conf.fatal("detected compiler is not ldc2") @conf def common_flags_ldc2(conf): """ Sets the D flags required by *ldc2* """ v = conf.env v.D_SRC_F = ['-c'] v.D_TGT_F = '-of%s' v.D_LINKER = v.D v.DLNK_SRC_F = '' v.DLNK_TGT_F = '-of%s' v.DINC_ST = '-I%s' v.DSHLIB_MARKER = v.DSTLIB_MARKER = '' v.DSTLIB_ST = v.DSHLIB_ST = '-L-l%s' v.DSTLIBPATH_ST = v.DLIBPATH_ST = '-L-L%s' v.LINKFLAGS_dshlib = ['-L-shared'] v.DHEADER_ext = '.di' v.DFLAGS_d_with_header = ['-H', '-Hf'] v.D_HDR_F = '%s' v.LINKFLAGS = [] v.DFLAGS_dshlib = ['-relocation-model=pic'] def configure(conf): """ Configuration for *ldc2* """ conf.find_ldc2() conf.load('ar') conf.load('d') conf.common_flags_ldc2() conf.d_platform_flags() hamster-3.0.3/waflib/Tools/lua.py000066400000000000000000000015231452646177100166750ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Sebastian Schlingmann, 2008 # Thomas Nagy, 2008-2018 (ita) """ Lua support. Compile *.lua* files into *.luac*:: def configure(conf): conf.load('lua') conf.env.LUADIR = '/usr/local/share/myapp/scripts/' def build(bld): bld(source='foo.lua') """ from waflib.TaskGen import extension from waflib import Task @extension('.lua') def add_lua(self, node): tsk = self.create_task('luac', node, node.change_ext('.luac')) inst_to = getattr(self, 'install_path', self.env.LUADIR and '${LUADIR}' or None) if inst_to: self.add_install_files(install_to=inst_to, install_from=tsk.outputs) return tsk class luac(Task.Task): run_str = '${LUAC} -s -o ${TGT} ${SRC}' color = 'PINK' def configure(conf): """ Detect the luac compiler and set *conf.env.LUAC* """ conf.find_program('luac', var='LUAC') hamster-3.0.3/waflib/Tools/md5_tstamp.py000066400000000000000000000017031452646177100201710ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ Re-calculate md5 hashes of files only when the file time have changed:: def options(opt): opt.load('md5_tstamp') The hashes can also reflect either the file contents (STRONGEST=True) or the file time and file size. The performance benefits of this module are usually insignificant. """ import os, stat from waflib import Utils, Build, Node STRONGEST = True Build.SAVED_ATTRS.append('hashes_md5_tstamp') def h_file(self): filename = self.abspath() st = os.stat(filename) cache = self.ctx.hashes_md5_tstamp if filename in cache and cache[filename][0] == st.st_mtime: return cache[filename][1] if STRONGEST: ret = Utils.h_file(filename) else: if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('Not a file') ret = Utils.md5(str((st.st_mtime, st.st_size)).encode()).digest() cache[filename] = (st.st_mtime, ret) return ret h_file.__doc__ = Node.Node.h_file.__doc__ Node.Node.h_file = h_file hamster-3.0.3/waflib/Tools/msvc.py000066400000000000000000001053001452646177100170620ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2006 (dv) # Tamas Pal, 2007 (folti) # Nicolas Mercier, 2009 # Matt Clarkson, 2012 """ Microsoft Visual C++/Intel C++ compiler support If you get detection problems, first try any of the following:: chcp 65001 set PYTHONIOENCODING=... set PYTHONLEGACYWINDOWSSTDIO=1 Usage:: $ waf configure --msvc_version="msvc 10.0,msvc 9.0" --msvc_target="x64" or:: def configure(conf): conf.env.MSVC_VERSIONS = ['msvc 10.0', 'msvc 9.0', 'msvc 8.0', 'msvc 7.1', 'msvc 7.0', 'msvc 6.0', 'wsdk 7.0', 'intel 11', 'PocketPC 9.0', 'Smartphone 8.0'] conf.env.MSVC_TARGETS = ['x64'] conf.load('msvc') or:: def configure(conf): conf.load('msvc', funs='no_autodetect') conf.check_lib_msvc('gdi32') conf.check_libs_msvc('kernel32 user32') def build(bld): tg = bld.program(source='main.c', target='app', use='KERNEL32 USER32 GDI32') Platforms and targets will be tested in the order they appear; the first good configuration will be used. To force testing all the configurations that are not used, use the ``--no-msvc-lazy`` option or set ``conf.env.MSVC_LAZY_AUTODETECT=False``. Supported platforms: ia64, x64, x86, x86_amd64, x86_ia64, x86_arm, amd64_x86, amd64_arm Compilers supported: * msvc => Visual Studio, versions 6.0 (VC 98, VC .NET 2002) to 15 (Visual Studio 2017) * wsdk => Windows SDK, versions 6.0, 6.1, 7.0, 7.1, 8.0 * icl => Intel compiler, versions 9, 10, 11, 13 * winphone => Visual Studio to target Windows Phone 8 native (version 8.0 for now) * Smartphone => Compiler/SDK for Smartphone devices (armv4/v4i) * PocketPC => Compiler/SDK for PocketPC devices (armv4/v4i) To use WAF in a VS2008 Make file project (see http://code.google.com/p/waf/issues/detail?id=894) You may consider to set the environment variable "VS_UNICODE_OUTPUT" to nothing before calling waf. So in your project settings use something like 'cmd.exe /C "set VS_UNICODE_OUTPUT=& set PYTHONUNBUFFERED=true & waf build"'. cmd.exe /C "chcp 1252 & set PYTHONUNBUFFERED=true && set && waf configure" Setting PYTHONUNBUFFERED gives the unbuffered output. """ import os, sys, re, traceback from waflib import Utils, Logs, Options, Errors from waflib.TaskGen import after_method, feature from waflib.Configure import conf from waflib.Tools import ccroot, c, cxx, ar g_msvc_systemlibs = ''' aclui activeds ad1 adptif adsiid advapi32 asycfilt authz bhsupp bits bufferoverflowu cabinet cap certadm certidl ciuuid clusapi comctl32 comdlg32 comsupp comsuppd comsuppw comsuppwd comsvcs credui crypt32 cryptnet cryptui d3d8thk daouuid dbgeng dbghelp dciman32 ddao35 ddao35d ddao35u ddao35ud delayimp dhcpcsvc dhcpsapi dlcapi dnsapi dsprop dsuiext dtchelp faultrep fcachdll fci fdi framedyd framedyn gdi32 gdiplus glauxglu32 gpedit gpmuuid gtrts32w gtrtst32hlink htmlhelp httpapi icm32 icmui imagehlp imm32 iphlpapi iprop kernel32 ksguid ksproxy ksuser libcmt libcmtd libcpmt libcpmtd loadperf lz32 mapi mapi32 mgmtapi minidump mmc mobsync mpr mprapi mqoa mqrt msacm32 mscms mscoree msdasc msimg32 msrating mstask msvcmrt msvcurt msvcurtd mswsock msxml2 mtx mtxdm netapi32 nmapinmsupp npptools ntdsapi ntdsbcli ntmsapi ntquery odbc32 odbcbcp odbccp32 oldnames ole32 oleacc oleaut32 oledb oledlgolepro32 opends60 opengl32 osptk parser pdh penter pgobootrun pgort powrprof psapi ptrustm ptrustmd ptrustu ptrustud qosname rasapi32 rasdlg rassapi resutils riched20 rpcndr rpcns4 rpcrt4 rtm rtutils runtmchk scarddlg scrnsave scrnsavw secur32 sensapi setupapi sfc shell32 shfolder shlwapi sisbkup snmpapi sporder srclient sti strsafe svcguid tapi32 thunk32 traffic unicows url urlmon user32 userenv usp10 uuid uxtheme vcomp vcompd vdmdbg version vfw32 wbemuuid webpost wiaguid wininet winmm winscard winspool winstrm wintrust wldap32 wmiutils wow32 ws2_32 wsnmp32 wsock32 wst wtsapi32 xaswitch xolehlp '''.split() """importlibs provided by MSVC/Platform SDK. Do NOT search them""" all_msvc_platforms = [ ('x64', 'amd64'), ('x86', 'x86'), ('ia64', 'ia64'), ('x86_amd64', 'amd64'), ('x86_ia64', 'ia64'), ('x86_arm', 'arm'), ('x86_arm64', 'arm64'), ('amd64_x86', 'x86'), ('amd64_arm', 'arm'), ('amd64_arm64', 'arm64') ] """List of msvc platforms""" all_wince_platforms = [ ('armv4', 'arm'), ('armv4i', 'arm'), ('mipsii', 'mips'), ('mipsii_fp', 'mips'), ('mipsiv', 'mips'), ('mipsiv_fp', 'mips'), ('sh4', 'sh'), ('x86', 'cex86') ] """List of wince platforms""" all_icl_platforms = [ ('intel64', 'amd64'), ('em64t', 'amd64'), ('ia32', 'x86'), ('Itanium', 'ia64')] """List of icl platforms""" def options(opt): default_ver = '' vsver = os.getenv('VSCMD_VER') if vsver: m = re.match(r'(^\d+\.\d+).*', vsver) if m: default_ver = 'msvc %s' % m.group(1) opt.add_option('--msvc_version', type='string', help = 'msvc version, eg: "msvc 10.0,msvc 9.0"', default=default_ver) opt.add_option('--msvc_targets', type='string', help = 'msvc targets, eg: "x64,arm"', default='') opt.add_option('--no-msvc-lazy', action='store_false', help = 'lazily check msvc target environments', default=True, dest='msvc_lazy') class MSVCVersion(object): def __init__(self, ver): m = re.search(r'^(.*)\s+(\d+[.]\d+)', ver) if m: self.name = m.group(1) self.number = float(m.group(2)) else: self.name = ver self.number = 0. def __lt__(self, other): if self.number == other.number: return self.name < other.name return self.number < other.number @conf def setup_msvc(conf, versiondict): """ Checks installed compilers and targets and returns the first combination from the user's options, env, or the global supported lists that checks. :param versiondict: dict(platform -> dict(architecture -> configuration)) :type versiondict: dict(string -> dict(string -> target_compiler) :return: the compiler, revision, path, include dirs, library paths and target architecture :rtype: tuple of strings """ platforms = getattr(Options.options, 'msvc_targets', '').split(',') if platforms == ['']: platforms=Utils.to_list(conf.env.MSVC_TARGETS) or [i for i,j in all_msvc_platforms+all_icl_platforms+all_wince_platforms] desired_versions = getattr(Options.options, 'msvc_version', '').split(',') if desired_versions == ['']: desired_versions = conf.env.MSVC_VERSIONS or list(sorted(versiondict.keys(), key=MSVCVersion, reverse=True)) # Override lazy detection by evaluating after the fact. lazy_detect = getattr(Options.options, 'msvc_lazy', True) if conf.env.MSVC_LAZY_AUTODETECT is False: lazy_detect = False if not lazy_detect: for val in versiondict.values(): for arch in list(val.keys()): cfg = val[arch] cfg.evaluate() if not cfg.is_valid: del val[arch] conf.env.MSVC_INSTALLED_VERSIONS = versiondict for version in desired_versions: Logs.debug('msvc: detecting %r - %r', version, desired_versions) try: targets = versiondict[version] except KeyError: continue seen = set() for arch in platforms: if arch in seen: continue else: seen.add(arch) try: cfg = targets[arch] except KeyError: continue cfg.evaluate() if cfg.is_valid: compiler,revision = version.rsplit(' ', 1) return compiler,revision,cfg.bindirs,cfg.incdirs,cfg.libdirs,cfg.cpu conf.fatal('msvc: Impossible to find a valid architecture for building %r - %r' % (desired_versions, list(versiondict.keys()))) @conf def get_msvc_version(conf, compiler, version, target, vcvars): """ Checks that an installed compiler actually runs and uses vcvars to obtain the environment needed by the compiler. :param compiler: compiler type, for looking up the executable name :param version: compiler version, for debugging only :param target: target architecture :param vcvars: batch file to run to check the environment :return: the location of the compiler executable, the location of include dirs, and the library paths :rtype: tuple of strings """ Logs.debug('msvc: get_msvc_version: %r %r %r', compiler, version, target) try: conf.msvc_cnt += 1 except AttributeError: conf.msvc_cnt = 1 batfile = conf.bldnode.make_node('waf-print-msvc-%d.bat' % conf.msvc_cnt) batfile.write("""@echo off set INCLUDE= set LIB= call "%s" %s echo PATH=%%PATH%% echo INCLUDE=%%INCLUDE%% echo LIB=%%LIB%%;%%LIBPATH%% """ % (vcvars,target)) sout = conf.cmd_and_log(['cmd.exe', '/E:on', '/V:on', '/C', batfile.abspath()], stdin=getattr(Utils.subprocess, 'DEVNULL', None)) lines = sout.splitlines() if not lines[0]: lines.pop(0) MSVC_PATH = MSVC_INCDIR = MSVC_LIBDIR = None for line in lines: if line.startswith('PATH='): path = line[5:] MSVC_PATH = path.split(';') elif line.startswith('INCLUDE='): MSVC_INCDIR = [i for i in line[8:].split(';') if i] elif line.startswith('LIB='): MSVC_LIBDIR = [i for i in line[4:].split(';') if i] if None in (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR): conf.fatal('msvc: Could not find a valid architecture for building (get_msvc_version_3)') # Check if the compiler is usable at all. # The detection may return 64-bit versions even on 32-bit systems, and these would fail to run. env = dict(os.environ) env.update(PATH = path) compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) cxx = conf.find_program(compiler_name, path_list=MSVC_PATH) # delete CL if exists. because it could contain parameters which can change cl's behaviour rather catastrophically. if 'CL' in env: del(env['CL']) try: conf.cmd_and_log(cxx + ['/help'], env=env) except UnicodeError: st = traceback.format_exc() if conf.logger: conf.logger.error(st) conf.fatal('msvc: Unicode error - check the code page?') except Exception as e: Logs.debug('msvc: get_msvc_version: %r %r %r -> failure %s', compiler, version, target, str(e)) conf.fatal('msvc: cannot run the compiler in get_msvc_version (run with -v to display errors)') else: Logs.debug('msvc: get_msvc_version: %r %r %r -> OK', compiler, version, target) finally: conf.env[compiler_name] = '' return (MSVC_PATH, MSVC_INCDIR, MSVC_LIBDIR) def gather_wince_supported_platforms(): """ Checks SmartPhones SDKs :param versions: list to modify :type versions: list """ supported_wince_platforms = [] try: ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Windows CE Tools\\SDKs') except OSError: try: ce_sdk = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Windows CE Tools\\SDKs') except OSError: ce_sdk = '' if not ce_sdk: return supported_wince_platforms index = 0 while 1: try: sdk_device = Utils.winreg.EnumKey(ce_sdk, index) sdk = Utils.winreg.OpenKey(ce_sdk, sdk_device) except OSError: break index += 1 try: path,type = Utils.winreg.QueryValueEx(sdk, 'SDKRootDir') except OSError: try: path,type = Utils.winreg.QueryValueEx(sdk,'SDKInformation') except OSError: continue path,xml = os.path.split(path) path = str(path) path,device = os.path.split(path) if not device: path,device = os.path.split(path) platforms = [] for arch,compiler in all_wince_platforms: if os.path.isdir(os.path.join(path, device, 'Lib', arch)): platforms.append((arch, compiler, os.path.join(path, device, 'Include', arch), os.path.join(path, device, 'Lib', arch))) if platforms: supported_wince_platforms.append((device, platforms)) return supported_wince_platforms def gather_msvc_detected_versions(): #Detected MSVC versions! version_pattern = re.compile(r'^(\d\d?\.\d\d?)(Exp)?$') detected_versions = [] for vcver,vcvar in (('VCExpress','Exp'), ('VisualStudio','')): prefix = 'SOFTWARE\\Wow6432node\\Microsoft\\' + vcver try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) except OSError: prefix = 'SOFTWARE\\Microsoft\\' + vcver try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, prefix) except OSError: continue index = 0 while 1: try: version = Utils.winreg.EnumKey(all_versions, index) except OSError: break index += 1 match = version_pattern.match(version) if match: versionnumber = float(match.group(1)) else: continue detected_versions.append((versionnumber, version+vcvar, prefix+'\\'+version)) def fun(tup): return tup[0] detected_versions.sort(key = fun) return detected_versions class target_compiler(object): """ Wrap a compiler configuration; call evaluate() to determine whether the configuration is usable. """ def __init__(self, ctx, compiler, cpu, version, bat_target, bat, callback=None): """ :param ctx: configuration context to use to eventually get the version environment :param compiler: compiler name :param cpu: target cpu :param version: compiler version number :param bat_target: ? :param bat: path to the batch file to run """ self.conf = ctx self.name = None self.is_valid = False self.is_done = False self.compiler = compiler self.cpu = cpu self.version = version self.bat_target = bat_target self.bat = bat self.callback = callback def evaluate(self): if self.is_done: return self.is_done = True try: vs = self.conf.get_msvc_version(self.compiler, self.version, self.bat_target, self.bat) except Errors.ConfigurationError: self.is_valid = False return if self.callback: vs = self.callback(self, vs) self.is_valid = True (self.bindirs, self.incdirs, self.libdirs) = vs def __str__(self): return str((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) def __repr__(self): return repr((self.compiler, self.cpu, self.version, self.bat_target, self.bat)) @conf def gather_wsdk_versions(conf, versions): """ Use winreg to add the msvc versions to the input list :param versions: list to modify :type versions: list """ version_pattern = re.compile(r'^v..?.?\...?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Microsoft\\Microsoft SDKs\\Windows') except OSError: try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows') except OSError: return index = 0 while 1: try: version = Utils.winreg.EnumKey(all_versions, index) except OSError: break index += 1 if not version_pattern.match(version): continue try: msvc_version = Utils.winreg.OpenKey(all_versions, version) path,type = Utils.winreg.QueryValueEx(msvc_version,'InstallationFolder') except OSError: continue if path and os.path.isfile(os.path.join(path, 'bin', 'SetEnv.cmd')): targets = {} for target,arch in all_msvc_platforms: targets[target] = target_compiler(conf, 'wsdk', arch, version, '/'+target, os.path.join(path, 'bin', 'SetEnv.cmd')) versions['wsdk ' + version[1:]] = targets @conf def gather_msvc_targets(conf, versions, version, vc_path): #Looking for normal MSVC compilers! targets = {} if os.path.isfile(os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')): for target,realtarget in all_msvc_platforms[::-1]: targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat')) elif os.path.isfile(os.path.join(vc_path, 'vcvarsall.bat')): for target,realtarget in all_msvc_platforms[::-1]: targets[target] = target_compiler(conf, 'msvc', realtarget, version, target, os.path.join(vc_path, 'vcvarsall.bat')) elif os.path.isfile(os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')): targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, 'x86', os.path.join(vc_path, 'Common7', 'Tools', 'vsvars32.bat')) elif os.path.isfile(os.path.join(vc_path, 'Bin', 'vcvars32.bat')): targets['x86'] = target_compiler(conf, 'msvc', 'x86', version, '', os.path.join(vc_path, 'Bin', 'vcvars32.bat')) if targets: versions['msvc %s' % version] = targets @conf def gather_wince_targets(conf, versions, version, vc_path, vsvars, supported_platforms): #Looking for Win CE compilers! for device,platforms in supported_platforms: targets = {} for platform,compiler,include,lib in platforms: winCEpath = os.path.join(vc_path, 'ce') if not os.path.isdir(winCEpath): continue if os.path.isdir(os.path.join(winCEpath, 'lib', platform)): bindirs = [os.path.join(winCEpath, 'bin', compiler), os.path.join(winCEpath, 'bin', 'x86_'+compiler)] incdirs = [os.path.join(winCEpath, 'include'), os.path.join(winCEpath, 'atlmfc', 'include'), include] libdirs = [os.path.join(winCEpath, 'lib', platform), os.path.join(winCEpath, 'atlmfc', 'lib', platform), lib] def combine_common(obj, compiler_env): # TODO this is likely broken, remove in waf 2.1 (common_bindirs,_1,_2) = compiler_env return (bindirs + common_bindirs, incdirs, libdirs) targets[platform] = target_compiler(conf, 'msvc', platform, version, 'x86', vsvars, combine_common) if targets: versions[device + ' ' + version] = targets @conf def gather_winphone_targets(conf, versions, version, vc_path, vsvars): #Looking for WinPhone compilers targets = {} for target,realtarget in all_msvc_platforms[::-1]: targets[target] = target_compiler(conf, 'winphone', realtarget, version, target, vsvars) if targets: versions['winphone ' + version] = targets @conf def gather_vswhere_versions(conf, versions): try: import json except ImportError: Logs.error('Visual Studio 2017 detection requires Python 2.6') return prg_path = os.environ.get('ProgramFiles(x86)', os.environ.get('ProgramFiles', 'C:\\Program Files (x86)')) vswhere = os.path.join(prg_path, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') args = [vswhere, '-products', '*', '-legacy', '-format', 'json'] try: txt = conf.cmd_and_log(args) except Errors.WafError as e: Logs.debug('msvc: vswhere.exe failed %s', e) return if sys.version_info[0] < 3: txt = txt.decode(Utils.console_encoding()) arr = json.loads(txt) arr.sort(key=lambda x: x['installationVersion']) for entry in arr: ver = entry['installationVersion'] ver = str('.'.join(ver.split('.')[:2])) path = str(os.path.abspath(entry['installationPath'])) if os.path.exists(path) and ('msvc %s' % ver) not in versions: conf.gather_msvc_targets(versions, ver, path) @conf def gather_msvc_versions(conf, versions): vc_paths = [] for (v,version,reg) in gather_msvc_detected_versions(): try: try: msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\VC") except OSError: msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, reg + "\\Setup\\Microsoft Visual C++") path,type = Utils.winreg.QueryValueEx(msvc_version, 'ProductDir') except OSError: try: msvc_version = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432node\\Microsoft\\VisualStudio\\SxS\\VS7") path,type = Utils.winreg.QueryValueEx(msvc_version, version) except OSError: continue else: vc_paths.append((version, os.path.abspath(str(path)))) continue else: vc_paths.append((version, os.path.abspath(str(path)))) wince_supported_platforms = gather_wince_supported_platforms() for version,vc_path in vc_paths: vs_path = os.path.dirname(vc_path) vsvars = os.path.join(vs_path, 'Common7', 'Tools', 'vsvars32.bat') if wince_supported_platforms and os.path.isfile(vsvars): conf.gather_wince_targets(versions, version, vc_path, vsvars, wince_supported_platforms) # WP80 works with 11.0Exp and 11.0, both of which resolve to the same vc_path. # Stop after one is found. for version,vc_path in vc_paths: vs_path = os.path.dirname(vc_path) vsvars = os.path.join(vs_path, 'VC', 'WPSDK', 'WP80', 'vcvarsphoneall.bat') if os.path.isfile(vsvars): conf.gather_winphone_targets(versions, '8.0', vc_path, vsvars) break for version,vc_path in vc_paths: vs_path = os.path.dirname(vc_path) conf.gather_msvc_targets(versions, version, vc_path) @conf def gather_icl_versions(conf, versions): """ Checks ICL compilers :param versions: list to modify :type versions: list """ version_pattern = re.compile(r'^...?.?\....?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Compilers\\C++') except OSError: try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Compilers\\C++') except OSError: return index = 0 while 1: try: version = Utils.winreg.EnumKey(all_versions, index) except OSError: break index += 1 if not version_pattern.match(version): continue targets = {} for target,arch in all_icl_platforms: if target=='intel64': targetDir='EM64T_NATIVE' else: targetDir=target try: Utils.winreg.OpenKey(all_versions,version+'\\'+targetDir) icl_version=Utils.winreg.OpenKey(all_versions,version) path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir') except OSError: pass else: batch_file=os.path.join(path,'bin','iclvars.bat') if os.path.isfile(batch_file): targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) for target,arch in all_icl_platforms: try: icl_version = Utils.winreg.OpenKey(all_versions, version+'\\'+target) path,type = Utils.winreg.QueryValueEx(icl_version,'ProductDir') except OSError: continue else: batch_file=os.path.join(path,'bin','iclvars.bat') if os.path.isfile(batch_file): targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) major = version[0:2] versions['intel ' + major] = targets @conf def gather_intel_composer_versions(conf, versions): """ Checks ICL compilers that are part of Intel Composer Suites :param versions: list to modify :type versions: list """ version_pattern = re.compile(r'^...?.?\...?.?.?') try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432node\\Intel\\Suites') except OSError: try: all_versions = Utils.winreg.OpenKey(Utils.winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Intel\\Suites') except OSError: return index = 0 while 1: try: version = Utils.winreg.EnumKey(all_versions, index) except OSError: break index += 1 if not version_pattern.match(version): continue targets = {} for target,arch in all_icl_platforms: if target=='intel64': targetDir='EM64T_NATIVE' else: targetDir=target try: try: defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\'+targetDir) except OSError: if targetDir == 'EM64T_NATIVE': defaults = Utils.winreg.OpenKey(all_versions,version+'\\Defaults\\C++\\EM64T') else: raise uid,type = Utils.winreg.QueryValueEx(defaults, 'SubKey') Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++\\'+targetDir) icl_version=Utils.winreg.OpenKey(all_versions,version+'\\'+uid+'\\C++') path,type=Utils.winreg.QueryValueEx(icl_version,'ProductDir') except OSError: pass else: batch_file=os.path.join(path,'bin','iclvars.bat') if os.path.isfile(batch_file): targets[target] = target_compiler(conf, 'intel', arch, version, target, batch_file) # The intel compilervar_arch.bat is broken when used with Visual Studio Express 2012 # http://software.intel.com/en-us/forums/topic/328487 compilervars_warning_attr = '_compilervars_warning_key' if version[0:2] == '13' and getattr(conf, compilervars_warning_attr, True): setattr(conf, compilervars_warning_attr, False) patch_url = 'http://software.intel.com/en-us/forums/topic/328487' compilervars_arch = os.path.join(path, 'bin', 'compilervars_arch.bat') for vscomntool in ('VS110COMNTOOLS', 'VS100COMNTOOLS'): if vscomntool in os.environ: vs_express_path = os.environ[vscomntool] + r'..\IDE\VSWinExpress.exe' dev_env_path = os.environ[vscomntool] + r'..\IDE\devenv.exe' if (r'if exist "%VS110COMNTOOLS%..\IDE\VSWinExpress.exe"' in Utils.readf(compilervars_arch) and not os.path.exists(vs_express_path) and not os.path.exists(dev_env_path)): Logs.warn(('The Intel compilervar_arch.bat only checks for one Visual Studio SKU ' '(VSWinExpress.exe) but it does not seem to be installed at %r. ' 'The intel command line set up will fail to configure unless the file %r' 'is patched. See: %s') % (vs_express_path, compilervars_arch, patch_url)) major = version[0:2] versions['intel ' + major] = targets @conf def detect_msvc(self): return self.setup_msvc(self.get_msvc_versions()) @conf def get_msvc_versions(self): """ :return: platform to compiler configurations :rtype: dict """ dct = Utils.ordered_iter_dict() self.gather_icl_versions(dct) self.gather_intel_composer_versions(dct) self.gather_wsdk_versions(dct) self.gather_msvc_versions(dct) self.gather_vswhere_versions(dct) Logs.debug('msvc: detected versions %r', list(dct.keys())) return dct @conf def find_lt_names_msvc(self, libname, is_static=False): """ Win32/MSVC specific code to glean out information from libtool la files. this function is not attached to the task_gen class. Returns a triplet: (library absolute path, library name without extension, whether the library is static) """ lt_names=[ 'lib%s.la' % libname, '%s.la' % libname, ] for path in self.env.LIBPATH: for la in lt_names: laf=os.path.join(path,la) dll=None if os.path.exists(laf): ltdict = Utils.read_la_file(laf) lt_libdir=None if ltdict.get('libdir', ''): lt_libdir = ltdict['libdir'] if not is_static and ltdict.get('library_names', ''): dllnames=ltdict['library_names'].split() dll=dllnames[0].lower() dll=re.sub(r'\.dll$', '', dll) return (lt_libdir, dll, False) elif ltdict.get('old_library', ''): olib=ltdict['old_library'] if os.path.exists(os.path.join(path,olib)): return (path, olib, True) elif lt_libdir != '' and os.path.exists(os.path.join(lt_libdir,olib)): return (lt_libdir, olib, True) else: return (None, olib, True) else: raise self.errors.WafError('invalid libtool object file: %s' % laf) return (None, None, None) @conf def libname_msvc(self, libname, is_static=False): lib = libname.lower() lib = re.sub(r'\.lib$','',lib) if lib in g_msvc_systemlibs: return lib lib=re.sub('^lib','',lib) if lib == 'm': return None (lt_path, lt_libname, lt_static) = self.find_lt_names_msvc(lib, is_static) if lt_path != None and lt_libname != None: if lt_static: # file existence check has been made by find_lt_names return os.path.join(lt_path,lt_libname) if lt_path != None: _libpaths = [lt_path] + self.env.LIBPATH else: _libpaths = self.env.LIBPATH static_libs=[ 'lib%ss.lib' % lib, 'lib%s.lib' % lib, '%ss.lib' % lib, '%s.lib' %lib, ] dynamic_libs=[ 'lib%s.dll.lib' % lib, 'lib%s.dll.a' % lib, '%s.dll.lib' % lib, '%s.dll.a' % lib, 'lib%s_d.lib' % lib, '%s_d.lib' % lib, '%s.lib' %lib, ] libnames=static_libs if not is_static: libnames=dynamic_libs + static_libs for path in _libpaths: for libn in libnames: if os.path.exists(os.path.join(path, libn)): Logs.debug('msvc: lib found: %s', os.path.join(path,libn)) return re.sub(r'\.lib$', '',libn) #if no lib can be found, just return the libname as msvc expects it self.fatal('The library %r could not be found' % libname) return re.sub(r'\.lib$', '', libname) @conf def check_lib_msvc(self, libname, is_static=False, uselib_store=None): """ Ideally we should be able to place the lib in the right env var, either STLIB or LIB, but we don't distinguish static libs from shared libs. This is ok since msvc doesn't have any special linker flag to select static libs (no env.STLIB_MARKER) """ libn = self.libname_msvc(libname, is_static) if not uselib_store: uselib_store = libname.upper() if False and is_static: # disabled self.env['STLIB_' + uselib_store] = [libn] else: self.env['LIB_' + uselib_store] = [libn] @conf def check_libs_msvc(self, libnames, is_static=False): for libname in Utils.to_list(libnames): self.check_lib_msvc(libname, is_static) def configure(conf): """ Configuration methods to call for detecting msvc """ conf.autodetect(True) conf.find_msvc() conf.msvc_common_flags() conf.cc_load_tools() conf.cxx_load_tools() conf.cc_add_flags() conf.cxx_add_flags() conf.link_add_flags() conf.visual_studio_add_flags() @conf def no_autodetect(conf): conf.env.NO_MSVC_DETECT = 1 configure(conf) @conf def autodetect(conf, arch=False): v = conf.env if v.NO_MSVC_DETECT: return compiler, version, path, includes, libdirs, cpu = conf.detect_msvc() if arch: v.DEST_CPU = cpu v.PATH = path v.INCLUDES = includes v.LIBPATH = libdirs v.MSVC_COMPILER = compiler try: v.MSVC_VERSION = float(version) except ValueError: v.MSVC_VERSION = float(version[:-3]) def _get_prog_names(conf, compiler): if compiler == 'intel': compiler_name = 'ICL' linker_name = 'XILINK' lib_name = 'XILIB' else: # assumes CL.exe compiler_name = 'CL' linker_name = 'LINK' lib_name = 'LIB' return compiler_name, linker_name, lib_name @conf def find_msvc(conf): """Due to path format limitations, limit operation only to native Win32. Yeah it sucks.""" if sys.platform == 'cygwin': conf.fatal('MSVC module does not work under cygwin Python!') # the autodetection is supposed to be performed before entering in this method v = conf.env path = v.PATH compiler = v.MSVC_COMPILER version = v.MSVC_VERSION compiler_name, linker_name, lib_name = _get_prog_names(conf, compiler) v.MSVC_MANIFEST = (compiler == 'msvc' and version >= 8) or (compiler == 'wsdk' and version >= 6) or (compiler == 'intel' and version >= 11) # compiler cxx = conf.find_program(compiler_name, var='CXX', path_list=path) # before setting anything, check if the compiler is really msvc env = dict(conf.environ) if path: env.update(PATH = ';'.join(path)) if not conf.cmd_and_log(cxx + ['/nologo', '/help'], env=env): conf.fatal('the msvc compiler could not be identified') # c/c++ compiler v.CC = v.CXX = cxx v.CC_NAME = v.CXX_NAME = 'msvc' # linker if not v.LINK_CXX: conf.find_program(linker_name, path_list=path, errmsg='%s was not found (linker)' % linker_name, var='LINK_CXX') if not v.LINK_CC: v.LINK_CC = v.LINK_CXX # staticlib linker if not v.AR: stliblink = conf.find_program(lib_name, path_list=path, var='AR') if not stliblink: return v.ARFLAGS = ['/nologo'] # manifest tool. Not required for VS 2003 and below. Must have for VS 2005 and later if v.MSVC_MANIFEST: conf.find_program('MT', path_list=path, var='MT') v.MTFLAGS = ['/nologo'] try: conf.load('winres') except Errors.ConfigurationError: Logs.warn('Resource compiler not found. Compiling resource file is disabled') @conf def visual_studio_add_flags(self): """visual studio flags found in the system environment""" v = self.env if self.environ.get('INCLUDE'): v.prepend_value('INCLUDES', [x for x in self.environ['INCLUDE'].split(';') if x]) # notice the 'S' if self.environ.get('LIB'): v.prepend_value('LIBPATH', [x for x in self.environ['LIB'].split(';') if x]) @conf def msvc_common_flags(conf): """ Setup the flags required for executing the msvc compiler """ v = conf.env v.DEST_BINFMT = 'pe' v.append_value('CFLAGS', ['/nologo']) v.append_value('CXXFLAGS', ['/nologo']) v.append_value('LINKFLAGS', ['/nologo']) v.DEFINES_ST = '/D%s' v.CC_SRC_F = '' v.CC_TGT_F = ['/c', '/Fo'] v.CXX_SRC_F = '' v.CXX_TGT_F = ['/c', '/Fo'] if (v.MSVC_COMPILER == 'msvc' and v.MSVC_VERSION >= 8) or (v.MSVC_COMPILER == 'wsdk' and v.MSVC_VERSION >= 6): v.CC_TGT_F = ['/FC'] + v.CC_TGT_F v.CXX_TGT_F = ['/FC'] + v.CXX_TGT_F v.CPPPATH_ST = '/I%s' # template for adding include paths v.AR_TGT_F = v.CCLNK_TGT_F = v.CXXLNK_TGT_F = '/OUT:' # CRT specific flags v.CFLAGS_CRT_MULTITHREADED = v.CXXFLAGS_CRT_MULTITHREADED = ['/MT'] v.CFLAGS_CRT_MULTITHREADED_DLL = v.CXXFLAGS_CRT_MULTITHREADED_DLL = ['/MD'] v.CFLAGS_CRT_MULTITHREADED_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DBG = ['/MTd'] v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = ['/MDd'] v.LIB_ST = '%s.lib' v.LIBPATH_ST = '/LIBPATH:%s' v.STLIB_ST = '%s.lib' v.STLIBPATH_ST = '/LIBPATH:%s' if v.MSVC_MANIFEST: v.append_value('LINKFLAGS', ['/MANIFEST']) v.CFLAGS_cshlib = [] v.CXXFLAGS_cxxshlib = [] v.LINKFLAGS_cshlib = v.LINKFLAGS_cxxshlib = ['/DLL'] v.cshlib_PATTERN = v.cxxshlib_PATTERN = '%s.dll' v.implib_PATTERN = '%s.lib' v.IMPLIB_ST = '/IMPLIB:%s' v.LINKFLAGS_cstlib = [] v.cstlib_PATTERN = v.cxxstlib_PATTERN = '%s.lib' v.cprogram_PATTERN = v.cxxprogram_PATTERN = '%s.exe' v.def_PATTERN = '/def:%s' ####################################################################################################### ##### conf above, build below @after_method('apply_link') @feature('c', 'cxx') def apply_flags_msvc(self): """ Add additional flags implied by msvc, such as subsystems and pdb files:: def build(bld): bld.stlib(source='main.c', target='bar', subsystem='gruik') """ if self.env.CC_NAME != 'msvc' or not getattr(self, 'link_task', None): return is_static = isinstance(self.link_task, ccroot.stlink_task) subsystem = getattr(self, 'subsystem', '') if subsystem: subsystem = '/subsystem:%s' % subsystem flags = is_static and 'ARFLAGS' or 'LINKFLAGS' self.env.append_value(flags, subsystem) if not is_static: for f in self.env.LINKFLAGS: d = f.lower() if d[1:] in ('debug', 'debug:full', 'debug:fastlink'): pdbnode = self.link_task.outputs[0].change_ext('.pdb') self.link_task.outputs.append(pdbnode) if getattr(self, 'install_task', None): self.pdb_install_task = self.add_install_files( install_to=self.install_task.install_to, install_from=pdbnode) break @feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib') @after_method('apply_link') def apply_manifest(self): """ Special linker for MSVC with support for embedding manifests into DLL's and executables compiled by Visual Studio 2005 or probably later. Without the manifest file, the binaries are unusable. See: http://msdn2.microsoft.com/en-us/library/ms235542(VS.80).aspx """ if self.env.CC_NAME == 'msvc' and self.env.MSVC_MANIFEST and getattr(self, 'link_task', None): out_node = self.link_task.outputs[0] man_node = out_node.parent.find_or_declare(out_node.name + '.manifest') self.link_task.outputs.append(man_node) self.env.DO_MANIFEST = True def make_winapp(self, family): append = self.env.append_unique append('DEFINES', 'WINAPI_FAMILY=%s' % family) append('CXXFLAGS', ['/ZW', '/TP']) for lib_path in self.env.LIBPATH: append('CXXFLAGS','/AI%s'%lib_path) @feature('winphoneapp') @after_method('process_use') @after_method('propagate_uselib_vars') def make_winphone_app(self): """ Insert configuration flags for windows phone applications (adds /ZW, /TP...) """ make_winapp(self, 'WINAPI_FAMILY_PHONE_APP') self.env.append_unique('LINKFLAGS', ['/NODEFAULTLIB:ole32.lib', 'PhoneAppModelHost.lib']) @feature('winapp') @after_method('process_use') @after_method('propagate_uselib_vars') def make_windows_app(self): """ Insert configuration flags for windows applications (adds /ZW, /TP...) """ make_winapp(self, 'WINAPI_FAMILY_DESKTOP_APP') hamster-3.0.3/waflib/Tools/nasm.py000066400000000000000000000013351452646177100170530ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2008-2018 (ita) """ Nasm tool (asm processing) """ import os import waflib.Tools.asm # leave this from waflib.TaskGen import feature @feature('asm') def apply_nasm_vars(self): """provided for compatibility""" self.env.append_value('ASFLAGS', self.to_list(getattr(self, 'nasm_flags', []))) def configure(conf): """ Detect nasm/yasm and set the variable *AS* """ conf.find_program(['nasm', 'yasm'], var='AS') conf.env.AS_TGT_F = ['-o'] conf.env.ASLNK_TGT_F = ['-o'] conf.load('asm') conf.env.ASMPATH_ST = '-I%s' + os.sep txt = conf.cmd_and_log(conf.env.AS + ['--version']) if 'yasm' in txt.lower(): conf.env.ASM_NAME = 'yasm' else: conf.env.ASM_NAME = 'nasm' hamster-3.0.3/waflib/Tools/nobuild.py000066400000000000000000000006431452646177100175520ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2015 (ita) """ Override the build commands to write empty files. This is useful for profiling and evaluating the Python overhead. To use:: def build(bld): ... bld.load('nobuild') """ from waflib import Task def build(bld): def run(self): for x in self.outputs: x.write('') for (name, cls) in Task.classes.items(): cls.run = run hamster-3.0.3/waflib/Tools/perl.py000066400000000000000000000106451452646177100170630ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # andersg at 0x63.nu 2007 # Thomas Nagy 2016-2018 (ita) """ Support for Perl extensions. A C/C++ compiler is required:: def options(opt): opt.load('compiler_c perl') def configure(conf): conf.load('compiler_c perl') conf.check_perl_version((5,6,0)) conf.check_perl_ext_devel() conf.check_perl_module('Cairo') conf.check_perl_module('Devel::PPPort 4.89') def build(bld): bld( features = 'c cshlib perlext', source = 'Mytest.xs', target = 'Mytest', install_path = '${ARCHDIR_PERL}/auto') bld.install_files('${ARCHDIR_PERL}', 'Mytest.pm') """ import os from waflib import Task, Options, Utils, Errors from waflib.Configure import conf from waflib.TaskGen import extension, feature, before_method @before_method('apply_incpaths', 'apply_link', 'propagate_uselib_vars') @feature('perlext') def init_perlext(self): """ Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the *lib* prefix from library names. """ self.uselib = self.to_list(getattr(self, 'uselib', [])) if not 'PERLEXT' in self.uselib: self.uselib.append('PERLEXT') self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.perlext_PATTERN @extension('.xs') def xsubpp_file(self, node): """ Create :py:class:`waflib.Tools.perl.xsubpp` tasks to process *.xs* files """ outnode = node.change_ext('.c') self.create_task('xsubpp', node, outnode) self.source.append(outnode) class xsubpp(Task.Task): """ Process *.xs* files """ run_str = '${PERL} ${XSUBPP} -noprototypes -typemap ${EXTUTILS_TYPEMAP} ${SRC} > ${TGT}' color = 'BLUE' ext_out = ['.h'] @conf def check_perl_version(self, minver=None): """ Check if Perl is installed, and set the variable PERL. minver is supposed to be a tuple """ res = True if minver: cver = '.'.join(map(str,minver)) else: cver = '' self.start_msg('Checking for minimum perl version %s' % cver) perl = self.find_program('perl', var='PERL', value=getattr(Options.options, 'perlbinary', None)) version = self.cmd_and_log(perl + ["-e", 'printf \"%vd\", $^V']) if not version: res = False version = "Unknown" elif not minver is None: ver = tuple(map(int, version.split("."))) if ver < minver: res = False self.end_msg(version, color=res and 'GREEN' or 'YELLOW') return res @conf def check_perl_module(self, module): """ Check if specified perlmodule is installed. The minimum version can be specified by specifying it after modulename like this:: def configure(conf): conf.check_perl_module("Some::Module 2.92") """ cmd = self.env.PERL + ['-e', 'use %s' % module] self.start_msg('perl module %s' % module) try: r = self.cmd_and_log(cmd) except Errors.WafError: self.end_msg(False) return None self.end_msg(r or True) return r @conf def check_perl_ext_devel(self): """ Check for configuration needed to build perl extensions. Sets different xxx_PERLEXT variables in the environment. Also sets the ARCHDIR_PERL variable useful as installation path, which can be overridden by ``--with-perl-archdir`` option. """ env = self.env perl = env.PERL if not perl: self.fatal('find perl first') def cmd_perl_config(s): return perl + ['-MConfig', '-e', 'print \"%s\"' % s] def cfg_str(cfg): return self.cmd_and_log(cmd_perl_config(cfg)) def cfg_lst(cfg): return Utils.to_list(cfg_str(cfg)) def find_xsubpp(): for var in ('privlib', 'vendorlib'): xsubpp = cfg_lst('$Config{%s}/ExtUtils/xsubpp$Config{exe_ext}' % var) if xsubpp and os.path.isfile(xsubpp[0]): return xsubpp return self.find_program('xsubpp') env.LINKFLAGS_PERLEXT = cfg_lst('$Config{lddlflags}') env.INCLUDES_PERLEXT = cfg_lst('$Config{archlib}/CORE') env.CFLAGS_PERLEXT = cfg_lst('$Config{ccflags} $Config{cccdlflags}') env.EXTUTILS_TYPEMAP = cfg_lst('$Config{privlib}/ExtUtils/typemap') env.XSUBPP = find_xsubpp() if not getattr(Options.options, 'perlarchdir', None): env.ARCHDIR_PERL = cfg_str('$Config{sitearch}') else: env.ARCHDIR_PERL = getattr(Options.options, 'perlarchdir') env.perlext_PATTERN = '%s.' + cfg_str('$Config{dlext}') def options(opt): """ Add the ``--with-perl-archdir`` and ``--with-perl-binary`` command-line options. """ opt.add_option('--with-perl-binary', type='string', dest='perlbinary', help = 'Specify alternate perl binary', default=None) opt.add_option('--with-perl-archdir', type='string', dest='perlarchdir', help = 'Specify directory where to install arch specific files', default=None) hamster-3.0.3/waflib/Tools/python.py000066400000000000000000000553401452646177100174430ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2007-2015 (ita) # Gustavo Carneiro (gjc), 2007 """ Support for Python, detect the headers and libraries and provide *use* variables to link C/C++ programs against them:: def options(opt): opt.load('compiler_c python') def configure(conf): conf.load('compiler_c python') conf.check_python_version((2,4,2)) conf.check_python_headers() def build(bld): bld.program(features='pyembed', source='a.c', target='myprog') bld.shlib(features='pyext', source='b.c', target='mylib') """ import os, sys from waflib import Errors, Logs, Node, Options, Task, Utils from waflib.TaskGen import extension, before_method, after_method, feature from waflib.Configure import conf FRAG = ''' #include #ifdef __cplusplus extern "C" { #endif void Py_Initialize(void); void Py_Finalize(void); #ifdef __cplusplus } #endif int main(int argc, char **argv) { (void)argc; (void)argv; Py_Initialize(); Py_Finalize(); return 0; } ''' """ Piece of C/C++ code used in :py:func:`waflib.Tools.python.check_python_headers` """ INST = ''' import sys, py_compile py_compile.compile(sys.argv[1], sys.argv[2], sys.argv[3], True) ''' """ Piece of Python code used in :py:class:`waflib.Tools.python.pyo` and :py:class:`waflib.Tools.python.pyc` for byte-compiling python files """ DISTUTILS_IMP = """ try: from distutils.sysconfig import get_config_var, get_python_lib except ImportError: from sysconfig import get_config_var, get_path def get_python_lib(*k, **kw): keyword='platlib' if kw.get('plat_specific') else 'purelib' if 'prefix' in kw: return get_path(keyword, vars={'installed_base': kw['prefix'], 'platbase': kw['prefix']}) return get_path(keyword) """.splitlines() @before_method('process_source') @feature('py') def feature_py(self): """ Create tasks to byte-compile .py files and install them, if requested """ self.install_path = getattr(self, 'install_path', '${PYTHONDIR}') install_from = getattr(self, 'install_from', None) if install_from and not isinstance(install_from, Node.Node): install_from = self.path.find_dir(install_from) self.install_from = install_from ver = self.env.PYTHON_VERSION if not ver: self.bld.fatal('Installing python files requires PYTHON_VERSION, try conf.check_python_version') if int(ver.replace('.', '')) > 31: self.install_32 = True @extension('.py') def process_py(self, node): """ Add signature of .py file, so it will be byte-compiled when necessary """ assert(hasattr(self, 'install_path')), 'add features="py" for target "%s" in "%s/wscript".' % (self.target, self.path.nice_path()) self.install_from = getattr(self, 'install_from', None) relative_trick = getattr(self, 'relative_trick', True) if self.install_from: assert isinstance(self.install_from, Node.Node), \ 'add features="py" for target "%s" in "%s/wscript" (%s).' % (self.target, self.path.nice_path(), type(self.install_from)) # where to install the python file if self.install_path: if self.install_from: self.add_install_files(install_to=self.install_path, install_from=node, cwd=self.install_from, relative_trick=relative_trick) else: self.add_install_files(install_to=self.install_path, install_from=node, relative_trick=relative_trick) lst = [] if self.env.PYC: lst.append('pyc') if self.env.PYO: lst.append('pyo') if self.install_path: if self.install_from: target_dir = node.path_from(self.install_from) if relative_trick else node.name pyd = Utils.subst_vars("%s/%s" % (self.install_path, target_dir), self.env) else: target_dir = node.path_from(self.path) if relative_trick else node.name pyd = Utils.subst_vars("%s/%s" % (self.install_path, target_dir), self.env) else: pyd = node.abspath() for ext in lst: if self.env.PYTAG and not self.env.NOPYCACHE: # __pycache__ installation for python 3.2 - PEP 3147 name = node.name[:-3] pyobj = node.parent.get_bld().make_node('__pycache__').make_node("%s.%s.%s" % (name, self.env.PYTAG, ext)) pyobj.parent.mkdir() else: pyobj = node.change_ext(".%s" % ext) tsk = self.create_task(ext, node, pyobj) tsk.pyd = pyd if self.install_path: self.add_install_files(install_to=os.path.dirname(pyd), install_from=pyobj, cwd=node.parent.get_bld(), relative_trick=relative_trick) class pyc(Task.Task): """ Byte-compiling python files """ color = 'PINK' def __str__(self): node = self.outputs[0] return node.path_from(node.ctx.launch_node()) def run(self): cmd = [Utils.subst_vars('${PYTHON}', self.env), '-c', INST, self.inputs[0].abspath(), self.outputs[0].abspath(), self.pyd] ret = self.generator.bld.exec_command(cmd) return ret class pyo(Task.Task): """ Byte-compiling python files """ color = 'PINK' def __str__(self): node = self.outputs[0] return node.path_from(node.ctx.launch_node()) def run(self): cmd = [Utils.subst_vars('${PYTHON}', self.env), Utils.subst_vars('${PYFLAGS_OPT}', self.env), '-c', INST, self.inputs[0].abspath(), self.outputs[0].abspath(), self.pyd] ret = self.generator.bld.exec_command(cmd) return ret @feature('pyext') @before_method('propagate_uselib_vars', 'apply_link') @after_method('apply_bundle') def init_pyext(self): """ Change the values of *cshlib_PATTERN* and *cxxshlib_PATTERN* to remove the *lib* prefix from library names. """ self.uselib = self.to_list(getattr(self, 'uselib', [])) if not 'PYEXT' in self.uselib: self.uselib.append('PYEXT') # override shlib_PATTERN set by the osx module self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.macbundle_PATTERN = self.env.pyext_PATTERN self.env.fcshlib_PATTERN = self.env.dshlib_PATTERN = self.env.pyext_PATTERN try: if not self.install_path: return except AttributeError: self.install_path = '${PYTHONARCHDIR}' @feature('pyext') @before_method('apply_link', 'apply_bundle') def set_bundle(self): """Mac-specific pyext extension that enables bundles from c_osx.py""" if Utils.unversioned_sys_platform() == 'darwin': self.mac_bundle = True @before_method('propagate_uselib_vars') @feature('pyembed') def init_pyembed(self): """ Add the PYEMBED variable. """ self.uselib = self.to_list(getattr(self, 'uselib', [])) if not 'PYEMBED' in self.uselib: self.uselib.append('PYEMBED') @conf def get_python_variables(self, variables, imports=None): """ Spawn a new python process to dump configuration variables :param variables: variables to print :type variables: list of string :param imports: one import by element :type imports: list of string :return: the variable values :rtype: list of string """ if not imports: try: imports = self.python_imports except AttributeError: imports = DISTUTILS_IMP program = list(imports) # copy program.append('') for v in variables: program.append("print(repr(%s))" % v) os_env = dict(os.environ) try: del os_env['MACOSX_DEPLOYMENT_TARGET'] # see comments in the OSX tool except KeyError: pass try: out = self.cmd_and_log(self.env.PYTHON + ['-c', '\n'.join(program)], env=os_env) except Errors.WafError: self.fatal('Could not run %r' % self.env.PYTHON) self.to_log(out) return_values = [] for s in out.splitlines(): s = s.strip() if not s: continue if s == 'None': return_values.append(None) elif (s[0] == "'" and s[-1] == "'") or (s[0] == '"' and s[-1] == '"'): return_values.append(eval(s)) elif s[0].isdigit(): return_values.append(int(s)) else: break return return_values @conf def test_pyembed(self, mode, msg='Testing pyembed configuration'): self.check(header_name='Python.h', define_name='HAVE_PYEMBED', msg=msg, fragment=FRAG, errmsg='Could not build a python embedded interpreter', features='%s %sprogram pyembed' % (mode, mode)) @conf def test_pyext(self, mode, msg='Testing pyext configuration'): self.check(header_name='Python.h', define_name='HAVE_PYEXT', msg=msg, fragment=FRAG, errmsg='Could not build python extensions', features='%s %sshlib pyext' % (mode, mode)) @conf def python_cross_compile(self, features='pyembed pyext'): """ For cross-compilation purposes, it is possible to bypass the normal detection and set the flags that you want: PYTHON_VERSION='3.4' PYTAG='cpython34' pyext_PATTERN="%s.so" PYTHON_LDFLAGS='-lpthread -ldl' waf configure The following variables are used: PYTHON_VERSION required PYTAG required PYTHON_LDFLAGS required pyext_PATTERN required PYTHON_PYEXT_LDFLAGS PYTHON_PYEMBED_LDFLAGS """ features = Utils.to_list(features) if not ('PYTHON_LDFLAGS' in self.environ or 'PYTHON_PYEXT_LDFLAGS' in self.environ or 'PYTHON_PYEMBED_LDFLAGS' in self.environ): return False for x in 'PYTHON_VERSION PYTAG pyext_PATTERN'.split(): if not x in self.environ: self.fatal('Please set %s in the os environment' % x) else: self.env[x] = self.environ[x] xx = self.env.CXX_NAME and 'cxx' or 'c' if 'pyext' in features: flags = self.environ.get('PYTHON_PYEXT_LDFLAGS', self.environ.get('PYTHON_LDFLAGS')) if flags is None: self.fatal('No flags provided through PYTHON_PYEXT_LDFLAGS as required') else: self.parse_flags(flags, 'PYEXT') self.test_pyext(xx) if 'pyembed' in features: flags = self.environ.get('PYTHON_PYEMBED_LDFLAGS', self.environ.get('PYTHON_LDFLAGS')) if flags is None: self.fatal('No flags provided through PYTHON_PYEMBED_LDFLAGS as required') else: self.parse_flags(flags, 'PYEMBED') self.test_pyembed(xx) return True @conf def check_python_headers(conf, features='pyembed pyext'): """ Check for headers and libraries necessary to extend or embed python. It may use the module *distutils* or sysconfig in newer Python versions. On success the environment variables xxx_PYEXT and xxx_PYEMBED are added: * PYEXT: for compiling python extensions * PYEMBED: for embedding a python interpreter """ features = Utils.to_list(features) assert ('pyembed' in features) or ('pyext' in features), "check_python_headers features must include 'pyembed' and/or 'pyext'" env = conf.env if not env.CC_NAME and not env.CXX_NAME: conf.fatal('load a compiler first (gcc, g++, ..)') # bypass all the code below for cross-compilation if conf.python_cross_compile(features): return if not env.PYTHON_VERSION: conf.check_python_version() pybin = env.PYTHON if not pybin: conf.fatal('Could not find the python executable') # so we actually do all this for compatibility reasons and for obtaining pyext_PATTERN below v = 'prefix SO EXT_SUFFIX LDFLAGS LIBDIR LIBPL INCLUDEPY Py_ENABLE_SHARED MACOSX_DEPLOYMENT_TARGET LDSHARED CFLAGS LDVERSION'.split() try: lst = conf.get_python_variables(["get_config_var('%s') or ''" % x for x in v]) except RuntimeError: conf.fatal("Python development headers not found (-v for details).") vals = ['%s = %r' % (x, y) for (x, y) in zip(v, lst)] conf.to_log("Configuration returned from %r:\n%s\n" % (pybin, '\n'.join(vals))) dct = dict(zip(v, lst)) x = 'MACOSX_DEPLOYMENT_TARGET' if dct[x]: env[x] = conf.environ[x] = str(dct[x]) env.pyext_PATTERN = '%s' + (dct['EXT_SUFFIX'] or dct['SO']) # SO is deprecated in 3.5 and removed in 3.11 # Try to get pythonX.Y-config num = '.'.join(env.PYTHON_VERSION.split('.')[:2]) conf.find_program([''.join(pybin) + '-config', 'python%s-config' % num, 'python-config-%s' % num, 'python%sm-config' % num], var='PYTHON_CONFIG', msg="python-config", mandatory=False) if env.PYTHON_CONFIG: # check python-config output only once if conf.env.HAVE_PYTHON_H: return # python2.6-config requires 3 runs all_flags = [['--cflags', '--libs', '--ldflags']] if sys.hexversion < 0x2070000: all_flags = [[k] for k in all_flags[0]] xx = env.CXX_NAME and 'cxx' or 'c' if 'pyembed' in features: for flags in all_flags: # Python 3.8 has different flags for pyembed, needs --embed embedflags = flags + ['--embed'] try: conf.check_cfg(msg='Asking python-config for pyembed %r flags' % ' '.join(embedflags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=embedflags) except conf.errors.ConfigurationError: # However Python < 3.8 doesn't accept --embed, so we need a fallback conf.check_cfg(msg='Asking python-config for pyembed %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEMBED', args=flags) try: conf.test_pyembed(xx) except conf.errors.ConfigurationError: # python bug 7352 if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']: env.append_unique('LIBPATH_PYEMBED', [dct['LIBDIR']]) conf.test_pyembed(xx) else: raise if 'pyext' in features: for flags in all_flags: conf.check_cfg(msg='Asking python-config for pyext %r flags' % ' '.join(flags), path=env.PYTHON_CONFIG, package='', uselib_store='PYEXT', args=flags) try: conf.test_pyext(xx) except conf.errors.ConfigurationError: # python bug 7352 if dct['Py_ENABLE_SHARED'] and dct['LIBDIR']: env.append_unique('LIBPATH_PYEXT', [dct['LIBDIR']]) conf.test_pyext(xx) else: raise conf.define('HAVE_PYTHON_H', 1) return # No python-config, do something else on windows systems all_flags = dct['LDFLAGS'] + ' ' + dct['CFLAGS'] conf.parse_flags(all_flags, 'PYEMBED') all_flags = dct['LDFLAGS'] + ' ' + dct['LDSHARED'] + ' ' + dct['CFLAGS'] conf.parse_flags(all_flags, 'PYEXT') result = None if not dct["LDVERSION"]: dct["LDVERSION"] = env.PYTHON_VERSION # further simplification will be complicated for name in ('python' + dct['LDVERSION'], 'python' + env.PYTHON_VERSION + 'm', 'python' + env.PYTHON_VERSION.replace('.', '')): # LIBPATH_PYEMBED is already set; see if it works. if not result and env.LIBPATH_PYEMBED: path = env.LIBPATH_PYEMBED conf.to_log("\n\n# Trying default LIBPATH_PYEMBED: %r\n" % path) result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBPATH_PYEMBED' % name) if not result and dct['LIBDIR']: path = [dct['LIBDIR']] conf.to_log("\n\n# try again with -L$python_LIBDIR: %r\n" % path) result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in LIBDIR' % name) if not result and dct['LIBPL']: path = [dct['LIBPL']] conf.to_log("\n\n# try again with -L$python_LIBPL (some systems don't install the python library in $prefix/lib)\n") result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in python_LIBPL' % name) if not result: path = [os.path.join(dct['prefix'], "libs")] conf.to_log("\n\n# try again with -L$prefix/libs, and pythonXY rather than pythonX.Y (win32)\n") result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $prefix/libs' % name) if not result: path = [os.path.normpath(os.path.join(dct['INCLUDEPY'], '..', 'libs'))] conf.to_log("\n\n# try again with -L$INCLUDEPY/../libs, and pythonXY rather than pythonX.Y (win32)\n") result = conf.check(lib=name, uselib='PYEMBED', libpath=path, mandatory=False, msg='Checking for library %s in $INCLUDEPY/../libs' % name) if result: break # do not forget to set LIBPATH_PYEMBED if result: env.LIBPATH_PYEMBED = path env.append_value('LIB_PYEMBED', [name]) else: conf.to_log("\n\n### LIB NOT FOUND\n") # under certain conditions, python extensions must link to # python libraries, not just python embedding programs. if Utils.is_win32 or dct['Py_ENABLE_SHARED']: env.LIBPATH_PYEXT = env.LIBPATH_PYEMBED env.LIB_PYEXT = env.LIB_PYEMBED conf.to_log("Found an include path for Python extensions: %r\n" % (dct['INCLUDEPY'],)) env.INCLUDES_PYEXT = [dct['INCLUDEPY']] env.INCLUDES_PYEMBED = [dct['INCLUDEPY']] # Code using the Python API needs to be compiled with -fno-strict-aliasing if env.CC_NAME == 'gcc': env.append_unique('CFLAGS_PYEMBED', ['-fno-strict-aliasing']) env.append_unique('CFLAGS_PYEXT', ['-fno-strict-aliasing']) if env.CXX_NAME == 'gcc': env.append_unique('CXXFLAGS_PYEMBED', ['-fno-strict-aliasing']) env.append_unique('CXXFLAGS_PYEXT', ['-fno-strict-aliasing']) if env.CC_NAME == "msvc": try: from distutils.msvccompiler import MSVCCompiler except ImportError: # From https://github.com/python/cpython/blob/main/Lib/distutils/msvccompiler.py env.append_value('CFLAGS_PYEXT', [ '/nologo', '/Ox', '/MD', '/W3', '/GX', '/DNDEBUG']) env.append_value('CXXFLAGS_PYEXT', [ '/nologo', '/Ox', '/MD', '/W3', '/GX', '/DNDEBUG']) env.append_value('LINKFLAGS_PYEXT', ['/DLL', '/nologo', '/INCREMENTAL:NO']) else: dist_compiler = MSVCCompiler() dist_compiler.initialize() env.append_value('CFLAGS_PYEXT', dist_compiler.compile_options) env.append_value('CXXFLAGS_PYEXT', dist_compiler.compile_options) env.append_value('LINKFLAGS_PYEXT', dist_compiler.ldflags_shared) conf.check(header_name='Python.h', define_name='HAVE_PYTHON_H', uselib='PYEMBED', fragment=FRAG, errmsg='Could not build a Python embedded interpreter') @conf def check_python_version(conf, minver=None): """ Check if the python interpreter is found matching a given minimum version. minver should be a tuple, eg. to check for python >= 2.4.2 pass (2,4,2) as minver. If successful, PYTHON_VERSION is defined as 'MAJOR.MINOR' (eg. '2.4') of the actual python version found, and PYTHONDIR and PYTHONARCHDIR are defined, pointing to the site-packages directories appropriate for this python version, where modules/packages/extensions should be installed. :param minver: minimum version :type minver: tuple of int """ assert minver is None or isinstance(minver, tuple) pybin = conf.env.PYTHON if not pybin: conf.fatal('could not find the python executable') # Get python version string cmd = pybin + ['-c', 'import sys\nfor x in sys.version_info: print(str(x))'] Logs.debug('python: Running python command %r', cmd) lines = conf.cmd_and_log(cmd).split() assert len(lines) == 5, "found %r lines, expected 5: %r" % (len(lines), lines) pyver_tuple = (int(lines[0]), int(lines[1]), int(lines[2]), lines[3], int(lines[4])) # Compare python version with the minimum required result = (minver is None) or (pyver_tuple >= minver) if result: # define useful environment variables pyver = '.'.join([str(x) for x in pyver_tuple[:2]]) conf.env.PYTHON_VERSION = pyver if 'PYTHONDIR' in conf.env: # Check if --pythondir was specified pydir = conf.env.PYTHONDIR elif 'PYTHONDIR' in conf.environ: # Check environment for PYTHONDIR pydir = conf.environ['PYTHONDIR'] else: # Finally, try to guess if Utils.is_win32: (pydir,) = conf.get_python_variables(["get_python_lib(standard_lib=0) or ''"]) else: (pydir,) = conf.get_python_variables(["get_python_lib(standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) if 'PYTHONARCHDIR' in conf.env: # Check if --pythonarchdir was specified pyarchdir = conf.env.PYTHONARCHDIR elif 'PYTHONARCHDIR' in conf.environ: # Check environment for PYTHONDIR pyarchdir = conf.environ['PYTHONARCHDIR'] else: # Finally, try to guess (pyarchdir, ) = conf.get_python_variables(["get_python_lib(plat_specific=1, standard_lib=0, prefix=%r) or ''" % conf.env.PREFIX]) if not pyarchdir: pyarchdir = pydir if hasattr(conf, 'define'): # conf.define is added by the C tool, so may not exist conf.define('PYTHONDIR', pydir) conf.define('PYTHONARCHDIR', pyarchdir) conf.env.PYTHONDIR = pydir conf.env.PYTHONARCHDIR = pyarchdir # Feedback pyver_full = '.'.join(map(str, pyver_tuple[:3])) if minver is None: conf.msg('Checking for python version', pyver_full) else: minver_str = '.'.join(map(str, minver)) conf.msg('Checking for python version >= %s' % (minver_str,), pyver_full, color=result and 'GREEN' or 'YELLOW') if not result: conf.fatal('The python version is too old, expecting %r' % (minver,)) PYTHON_MODULE_TEMPLATE = ''' import %s as current_module version = getattr(current_module, '__version__', None) if version is not None: print(str(version)) else: print('unknown version') ''' @conf def check_python_module(conf, module_name, condition=''): """ Check if the selected python interpreter can import the given python module:: def configure(conf): conf.check_python_module('pygccxml') conf.check_python_module('re', condition="ver > num(2, 0, 4) and ver <= num(3, 0, 0)") :param module_name: module :type module_name: string """ msg = "Checking for python module %r" % module_name if condition: msg = '%s (%s)' % (msg, condition) conf.start_msg(msg) try: ret = conf.cmd_and_log(conf.env.PYTHON + ['-c', PYTHON_MODULE_TEMPLATE % module_name]) except Errors.WafError: conf.end_msg(False) conf.fatal('Could not find the python module %r' % module_name) ret = ret.strip() if condition: conf.end_msg(ret) if ret == 'unknown version': conf.fatal('Could not check the %s version' % module_name) def num(*k): if isinstance(k[0], int): return Utils.loose_version('.'.join([str(x) for x in k])) else: return Utils.loose_version(k[0]) d = {'num': num, 'ver': Utils.loose_version(ret)} ev = eval(condition, {}, d) if not ev: conf.fatal('The %s version does not satisfy the requirements' % module_name) else: if ret == 'unknown version': conf.end_msg(True) else: conf.end_msg(ret) def configure(conf): """ Detect the python interpreter """ v = conf.env if getattr(Options.options, 'pythondir', None): v.PYTHONDIR = Options.options.pythondir if getattr(Options.options, 'pythonarchdir', None): v.PYTHONARCHDIR = Options.options.pythonarchdir if getattr(Options.options, 'nopycache', None): v.NOPYCACHE=Options.options.nopycache if not v.PYTHON: v.PYTHON = [getattr(Options.options, 'python', None) or sys.executable] v.PYTHON = Utils.to_list(v.PYTHON) conf.find_program('python', var='PYTHON') v.PYFLAGS = '' v.PYFLAGS_OPT = '-O' v.PYC = getattr(Options.options, 'pyc', 1) v.PYO = getattr(Options.options, 'pyo', 1) try: v.PYTAG = conf.cmd_and_log(conf.env.PYTHON + ['-c', "import sys\ntry:\n print(sys.implementation.cache_tag)\nexcept AttributeError:\n import imp\n print(imp.get_tag())\n"]).strip() except Errors.WafError: pass def options(opt): """ Add python-specific options """ pyopt=opt.add_option_group("Python Options") pyopt.add_option('--nopyc', dest = 'pyc', action='store_false', default=1, help = 'Do not install bytecode compiled .pyc files (configuration) [Default:install]') pyopt.add_option('--nopyo', dest='pyo', action='store_false', default=1, help='Do not install optimised compiled .pyo files (configuration) [Default:install]') pyopt.add_option('--nopycache',dest='nopycache', action='store_true', help='Do not use __pycache__ directory to install objects [Default:auto]') pyopt.add_option('--python', dest="python", help='python binary to be used [Default: %s]' % sys.executable) pyopt.add_option('--pythondir', dest='pythondir', help='Installation path for python modules (py, platform-independent .py and .pyc files)') pyopt.add_option('--pythonarchdir', dest='pythonarchdir', help='Installation path for python extension (pyext, platform-dependent .so or .dylib files)') hamster-3.0.3/waflib/Tools/qt5.py000066400000000000000000000645041452646177100166350ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Rafaël Kooi, 2023 (RA-Kooi) """ This tool helps with finding Qt5 and Qt6 tools and libraries, and also provides syntactic sugar for using Qt5 and Qt6 tools. The following snippet illustrates the tool usage:: def options(opt): opt.load('compiler_cxx qt5') def configure(conf): conf.load('compiler_cxx qt5') def build(bld): bld( features = 'qt5 cxx cxxprogram', uselib = 'QT5CORE QT5GUI QT5OPENGL QT5SVG', source = 'main.cpp textures.qrc aboutDialog.ui', target = 'window', ) Alternatively the following snippet illustrates Qt6 tool usage:: def options(opt): opt.load('compiler_cxx qt5') def configure(conf): conf.want_qt6 = True conf.load('compiler_cxx qt5') def build(bld): bld( features = 'qt6 cxx cxxprogram', uselib = 'QT6CORE QT6GUI QT6OPENGL QT6SVG', source = 'main.cpp textures.qrc aboutDialog.ui', target = 'window', ) Here, the UI description and resource files will be processed to generate code. Usage ===== Load the "qt5" tool. You also need to edit your sources accordingly: - the normal way of doing things is to have your C++ files include the .moc file. This is regarded as the best practice (and provides much faster compilations). It also implies that the include paths have beenset properly. - to have the include paths added automatically, use the following:: from waflib.TaskGen import feature, before_method, after_method @feature('cxx') @after_method('process_source') @before_method('apply_incpaths') def add_includes_paths(self): incs = set(self.to_list(getattr(self, 'includes', ''))) for x in self.compiled_tasks: incs.add(x.inputs[0].parent.path_from(self.path)) self.includes = sorted(incs) Note: another tool provides Qt processing that does not require .moc includes, see 'playground/slow_qt/'. A few options (--qt{dir,bin,...}) and environment variables (QT5_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool, tool path selection, etc; please read the source for more info. For Qt6 replace the QT5_ prefix with QT6_. The detection uses pkg-config on Linux by default. The list of libraries to be requested to pkg-config is formulated by scanning in the QTLIBS directory (that can be passed via --qtlibs or by setting the environment variable QT5_LIBDIR or QT6_LIBDIR otherwise is derived by querying qmake for QT_INSTALL_LIBS directory) for shared/static libraries present. Alternatively the list of libraries to be requested via pkg-config can be set using the qt5_vars attribute, ie: conf.qt5_vars = ['Qt5Core', 'Qt5Gui', 'Qt5Widgets', 'Qt5Test']; For Qt6 use the qt6_vars attribute. This can speed up configuration phase if needed libraries are known beforehand, can improve detection on systems with a sparse QT5/Qt6 libraries installation (ie. NIX) and can improve detection of some header-only Qt modules (ie. Qt5UiPlugin). To force static library detection use: QT5_XCOMPILE=1 QT5_FORCE_STATIC=1 waf configure To use Qt6 set the want_qt6 attribute, ie: conf.want_qt6 = True; """ from __future__ import with_statement try: from xml.sax import make_parser from xml.sax.handler import ContentHandler except ImportError: has_xml = False ContentHandler = object else: has_xml = True import os, sys, re from waflib.Tools import cxx from waflib import Build, Task, Utils, Options, Errors, Context from waflib.TaskGen import feature, after_method, extension, before_method from waflib.Configure import conf from waflib import Logs MOC_H = ['.h', '.hpp', '.hxx', '.hh'] """ File extensions associated to .moc files """ EXT_RCC = ['.qrc'] """ File extension for the resource (.qrc) files """ EXT_UI = ['.ui'] """ File extension for the user interface (.ui) files """ EXT_QT5 = ['.cpp', '.cc', '.cxx', '.C'] """ File extensions of C++ files that may require a .moc processing """ class qxx(Task.classes['cxx']): """ Each C++ file can have zero or several .moc files to create. They are known only when the files are scanned (preprocessor) To avoid scanning the c++ files each time (parsing C/C++), the results are retrieved from the task cache (bld.node_deps/bld.raw_deps). The moc tasks are also created *dynamically* during the build. """ def __init__(self, *k, **kw): Task.Task.__init__(self, *k, **kw) self.moc_done = 0 def runnable_status(self): """ Compute the task signature to make sure the scanner was executed. Create the moc tasks by using :py:meth:`waflib.Tools.qt5.qxx.add_moc_tasks` (if necessary), then postpone the task execution (there is no need to recompute the task signature). """ if self.moc_done: return Task.Task.runnable_status(self) else: for t in self.run_after: if not t.hasrun: return Task.ASK_LATER self.add_moc_tasks() return Task.Task.runnable_status(self) def create_moc_task(self, h_node, m_node): """ If several libraries use the same classes, it is possible that moc will run several times (Issue 1318) It is not possible to change the file names, but we can assume that the moc transformation will be identical, and the moc tasks can be shared in a global cache. """ try: moc_cache = self.generator.bld.moc_cache except AttributeError: moc_cache = self.generator.bld.moc_cache = {} try: return moc_cache[h_node] except KeyError: tsk = moc_cache[h_node] = Task.classes['moc'](env=self.env, generator=self.generator) tsk.set_inputs(h_node) tsk.set_outputs(m_node) tsk.env.append_unique('MOC_FLAGS', '-i') if self.generator: self.generator.tasks.append(tsk) # direct injection in the build phase (safe because called from the main thread) gen = self.generator.bld.producer gen.outstanding.append(tsk) gen.total += 1 return tsk else: # remove the signature, it must be recomputed with the moc task delattr(self, 'cache_sig') def add_moc_tasks(self): """ Creates moc tasks by looking in the list of file dependencies ``bld.raw_deps[self.uid()]`` """ node = self.inputs[0] bld = self.generator.bld # skip on uninstall due to generated files if bld.is_install == Build.UNINSTALL: return try: # compute the signature once to know if there is a moc file to create self.signature() except KeyError: # the moc file may be referenced somewhere else pass else: # remove the signature, it must be recomputed with the moc task delattr(self, 'cache_sig') include_nodes = [node.parent] + self.generator.includes_nodes moctasks = [] mocfiles = set() for d in bld.raw_deps.get(self.uid(), []): if not d.endswith('.moc'): continue # process that base.moc only once if d in mocfiles: continue mocfiles.add(d) # find the source associated with the moc file h_node = None base2 = d[:-4] # foo.moc from foo.cpp prefix = node.name[:node.name.rfind('.')] if base2 == prefix: h_node = node else: # this deviates from the standard # if bar.cpp includes foo.moc, then assume it is from foo.h for x in include_nodes: for e in MOC_H: h_node = x.find_node(base2 + e) if h_node: break else: continue break if h_node: m_node = h_node.change_ext('.moc') else: raise Errors.WafError('No source found for %r which is a moc file' % d) # create the moc task task = self.create_moc_task(h_node, m_node) moctasks.append(task) # simple scheduler dependency: run the moc task before others self.run_after.update(set(moctasks)) self.moc_done = 1 class trans_update(Task.Task): """Updates a .ts files from a list of C++ files""" run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}' color = 'BLUE' class XMLHandler(ContentHandler): """ Parses ``.qrc`` files """ def __init__(self): ContentHandler.__init__(self) self.buf = [] self.files = [] def startElement(self, name, attrs): if name == 'file': self.buf = [] def endElement(self, name): if name == 'file': self.files.append(str(''.join(self.buf))) def characters(self, cars): self.buf.append(cars) @extension(*EXT_RCC) def create_rcc_task(self, node): "Creates rcc and cxx tasks for ``.qrc`` files" rcnode = node.change_ext('_rc.%d.cpp' % self.idx) self.create_task('rcc', node, rcnode) cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o')) try: self.compiled_tasks.append(cpptask) except AttributeError: self.compiled_tasks = [cpptask] return cpptask @extension(*EXT_UI) def create_uic_task(self, node): "Create uic tasks for user interface ``.ui`` definition files" """ If UIC file is used in more than one bld, we would have a conflict in parallel execution It is not possible to change the file names (like .self.idx. as for objects) as they have to be referenced by the source file, but we can assume that the transformation will be identical and the tasks can be shared in a global cache. """ try: uic_cache = self.bld.uic_cache except AttributeError: uic_cache = self.bld.uic_cache = {} if node not in uic_cache: uictask = uic_cache[node] = self.create_task('ui5', node) uictask.outputs = [node.parent.find_or_declare(self.env.ui_PATTERN % node.name[:-3])] @extension('.ts') def add_lang(self, node): """Adds all the .ts file into ``self.lang``""" self.lang = self.to_list(getattr(self, 'lang', [])) + [node] @feature('qt5', 'qt6') @before_method('process_source') def process_mocs(self): """ Processes MOC files included in headers:: def build(bld): bld.program(features='qt5', source='main.cpp', target='app', use='QT5CORE', moc='foo.h') The build will run moc on foo.h to create moc_foo.n.cpp. The number in the file name is provided to avoid name clashes when the same headers are used by several targets. """ lst = self.to_nodes(getattr(self, 'moc', [])) self.source = self.to_list(getattr(self, 'source', [])) for x in lst: prefix = x.name[:x.name.rfind('.')] # foo.h -> foo moc_target = 'moc_%s.%d.cpp' % (prefix, self.idx) moc_node = x.parent.find_or_declare(moc_target) self.source.append(moc_node) self.create_task('moc', x, moc_node) @feature('qt5', 'qt6') @after_method('apply_link') def apply_qt5(self): """ Adds MOC_FLAGS which may be necessary for moc:: def build(bld): bld.program(features='qt5', source='main.cpp', target='app', use='QT5CORE') The additional parameters are: :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension :param update: whether to process the C++ files to update the \\*.ts files (use **waf --translate**) :type update: bool :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): qmtasks = [] for x in self.to_list(self.lang): if isinstance(x, str): x = self.path.find_resource(x + '.ts') qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.%d.qm' % self.idx))) if getattr(self, 'update', None) and Options.options.trans_qt5: cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [ a.inputs[0] for a in self.tasks if a.inputs and a.inputs[0].name.endswith('.ui')] for x in qmtasks: self.create_task('trans_update', cxxnodes, x.inputs) if getattr(self, 'langname', None): qmnodes = [x.outputs[0] for x in qmtasks] rcnode = self.langname if isinstance(rcnode, str): rcnode = self.path.find_or_declare(rcnode + ('.%d.qrc' % self.idx)) t = self.create_task('qm2rcc', qmnodes, rcnode) k = create_rcc_task(self, t.outputs[0]) self.link_task.inputs.append(k.outputs[0]) lst = [] for flag in self.to_list(self.env.CXXFLAGS): if len(flag) < 2: continue f = flag[0:2] if f in ('-D', '-I', '/D', '/I'): if (f[0] == '/'): lst.append('-' + flag[1:]) else: lst.append(flag) self.env.append_value('MOC_FLAGS', lst) @extension(*EXT_QT5) def cxx_hook(self, node): """ Re-maps C++ file extensions to the :py:class:`waflib.Tools.qt5.qxx` task. """ return self.create_compiled_task('qxx', node) class rcc(Task.Task): """ Processes ``.qrc`` files """ color = 'BLUE' run_str = '${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' ext_out = ['.h'] def rcname(self): return os.path.splitext(self.inputs[0].name)[0] def scan(self): """Parse the *.qrc* files""" if not has_xml: Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!') return ([], []) parser = make_parser() curHandler = XMLHandler() parser.setContentHandler(curHandler) with open(self.inputs[0].abspath(), 'r') as f: parser.parse(f) nodes = [] names = [] root = self.inputs[0].parent for x in curHandler.files: nd = root.find_resource(x) if nd: nodes.append(nd) else: names.append(x) return (nodes, names) def quote_flag(self, x): """ Override Task.quote_flag. QT parses the argument files differently than cl.exe and link.exe :param x: flag :type x: string :return: quoted flag :rtype: string """ return x class moc(Task.Task): """ Creates ``.moc`` files """ color = 'BLUE' run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}' def quote_flag(self, x): """ Override Task.quote_flag. QT parses the argument files differently than cl.exe and link.exe :param x: flag :type x: string :return: quoted flag :rtype: string """ return x class ui5(Task.Task): """ Processes ``.ui`` files """ color = 'BLUE' run_str = '${QT_UIC} ${SRC} -o ${TGT}' ext_out = ['.h'] class ts2qm(Task.Task): """ Generates ``.qm`` files from ``.ts`` files """ color = 'BLUE' run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}' class qm2rcc(Task.Task): """ Generates ``.qrc`` files from ``.qm`` files """ color = 'BLUE' after = 'ts2qm' def run(self): """Create a qrc file including the inputs""" txt = '\n'.join(['%s' % k.path_from(self.outputs[0].parent) for k in self.inputs]) code = '\n\n%s\n\n' % txt self.outputs[0].write(code) def configure(self): """ Besides the configuration options, the environment variable QT5_ROOT may be used to give the location of the qt5 libraries (absolute path). The detection uses the program ``pkg-config`` through :py:func:`waflib.Tools.config_c.check_cfg` """ if 'COMPILER_CXX' not in self.env: self.fatal('No CXX compiler defined: did you forget to configure compiler_cxx first?') self.want_qt6 = getattr(self, 'want_qt6', False) if self.want_qt6: self.qt_vars = Utils.to_list(getattr(self, 'qt6_vars', [])) else: self.qt_vars = Utils.to_list(getattr(self, 'qt5_vars', [])) self.find_qt5_binaries() self.set_qt5_libs_dir() self.set_qt5_libs_to_check() self.set_qt5_defines() self.find_qt5_libraries() self.add_qt5_rpath() self.simplify_qt5_libs() # warn about this during the configuration too if not has_xml: Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!') feature = 'qt6' if self.want_qt6 else 'qt5' # Qt6 requires C++17 (https://www.qt.io/blog/qt-6.0-released) stdflag = '-std=c++17' if self.want_qt6 else '-std=c++11' # Qt5 may be compiled with '-reduce-relocations' which requires dependent programs to have -fPIE or -fPIC? frag = '#include \nint main(int argc, char **argv) {QMap m;return m.keys().size();}\n' uses = 'QT6CORE' if self.want_qt6 else 'QT5CORE' for flag in [[], '-fPIE', '-fPIC', stdflag, [stdflag, '-fPIE'], [stdflag, '-fPIC']]: msg = 'See if Qt files compile ' if flag: msg += 'with %s' % flag try: self.check(features=feature + ' cxx', use=uses, uselib_store=feature, cxxflags=flag, fragment=frag, msg=msg) except self.errors.ConfigurationError: pass else: break else: self.fatal('Could not build a simple Qt application') # FreeBSD does not add /usr/local/lib and the pkg-config files do not provide it either :-/ if Utils.unversioned_sys_platform() == 'freebsd': frag = '#include \nint main(int argc, char **argv) {QMap m;return m.keys().size();}\n' try: self.check(features=feature + ' cxx cxxprogram', use=uses, fragment=frag, msg='Can we link Qt programs on FreeBSD directly?') except self.errors.ConfigurationError: self.check(features=feature + ' cxx cxxprogram', use=uses, uselib_store=feature, libpath='/usr/local/lib', fragment=frag, msg='Is /usr/local/lib required?') @conf def find_qt5_binaries(self): """ Detects Qt programs such as qmake, moc, uic, lrelease """ env = self.env opt = Options.options qtdir = getattr(opt, 'qtdir', '') qtbin = getattr(opt, 'qtbin', '') qt_ver = '6' if self.want_qt6 else '5' paths = [] if qtdir: qtbin = os.path.join(qtdir, 'bin') # the qt directory has been given from QT5_ROOT - deduce the qt binary path if not qtdir: qtdir = self.environ.get('QT' + qt_ver + '_ROOT', '') qtbin = self.environ.get('QT' + qt_ver + '_BIN') or os.path.join(qtdir, 'bin') if qtbin: paths = [qtbin] # no qtdir, look in the path and in /usr/local/Trolltech if not qtdir: paths = self.environ.get('PATH', '').split(os.pathsep) paths.extend([ '/usr/share/qt' + qt_ver + '/bin', '/usr/local/lib/qt' + qt_ver + '/bin']) try: lst = Utils.listdir('/usr/local/Trolltech/') except OSError: pass else: if lst: lst.sort() lst.reverse() # keep the highest version qtdir = '/usr/local/Trolltech/%s/' % lst[0] qtbin = os.path.join(qtdir, 'bin') paths.append(qtbin) # at the end, try to find qmake in the paths given # keep the one with the highest version cand = None prev_ver = ['0', '0', '0'] qmake_vars = ['qmake-qt' + qt_ver, 'qmake' + qt_ver, 'qmake'] for qmk in qmake_vars: try: qmake = self.find_program(qmk, path_list=paths) except self.errors.ConfigurationError: pass else: try: version = self.cmd_and_log(qmake + ['-query', 'QT_VERSION']).strip() except self.errors.WafError: pass else: if version: new_ver = version.split('.') if new_ver[0] == qt_ver and new_ver > prev_ver: cand = qmake prev_ver = new_ver # qmake could not be found easily, rely on qtchooser if not cand: try: self.find_program('qtchooser') except self.errors.ConfigurationError: pass else: cmd = self.env.QTCHOOSER + ['-qt=' + qt_ver, '-run-tool=qmake'] try: version = self.cmd_and_log(cmd + ['-query', 'QT_VERSION']) except self.errors.WafError: pass else: cand = cmd if cand: self.env.QMAKE = cand else: self.fatal('Could not find qmake for qt' + qt_ver) # Once we have qmake, we want to query qmake for the paths where we want to look for tools instead paths = [] self.env.QT_HOST_BINS = qtbin = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_HOST_BINS']).strip() paths.append(qtbin) if self.want_qt6: self.env.QT_HOST_LIBEXECS = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_HOST_LIBEXECS']).strip() paths.append(self.env.QT_HOST_LIBEXECS) def find_bin(lst, var): if var in env: return for f in lst: try: ret = self.find_program(f, path_list=paths) except self.errors.ConfigurationError: pass else: env[var]=ret break find_bin(['uic-qt' + qt_ver, 'uic'], 'QT_UIC') if not env.QT_UIC: self.fatal('cannot find the uic compiler for qt' + qt_ver) self.start_msg('Checking for uic version') uicver = self.cmd_and_log(env.QT_UIC + ['-version'], output=Context.BOTH) uicver = ''.join(uicver).strip() uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '') self.end_msg(uicver) if uicver.find(' 3.') != -1 or uicver.find(' 4.') != -1 or (self.want_qt6 and uicver.find(' 5.') != -1): if self.want_qt6: self.fatal('this uic compiler is for qt3 or qt4 or qt5, add uic for qt6 to your path') else: self.fatal('this uic compiler is for qt3 or qt4, add uic for qt5 to your path') find_bin(['moc-qt' + qt_ver, 'moc'], 'QT_MOC') find_bin(['rcc-qt' + qt_ver, 'rcc'], 'QT_RCC') find_bin(['lrelease-qt' + qt_ver, 'lrelease'], 'QT_LRELEASE') find_bin(['lupdate-qt' + qt_ver, 'lupdate'], 'QT_LUPDATE') env.UIC_ST = '%s -o %s' env.MOC_ST = '-o' env.ui_PATTERN = 'ui_%s.h' env.QT_LRELEASE_FLAGS = ['-silent'] env.MOCCPPPATH_ST = '-I%s' env.MOCDEFINES_ST = '-D%s' @conf def set_qt5_libs_dir(self): env = self.env qt_ver = '6' if self.want_qt6 else '5' qtlibs = getattr(Options.options, 'qtlibs', None) or self.environ.get('QT' + qt_ver + '_LIBDIR') if not qtlibs: try: qtlibs = self.cmd_and_log(env.QMAKE + ['-query', 'QT_INSTALL_LIBS']).strip() except Errors.WafError: qtdir = self.cmd_and_log(env.QMAKE + ['-query', 'QT_INSTALL_PREFIX']).strip() qtlibs = os.path.join(qtdir, 'lib') self.msg('Found the Qt' + qt_ver + ' library path', qtlibs) env.QTLIBS = qtlibs @conf def find_single_qt5_lib(self, name, uselib, qtlibs, qtincludes, force_static): env = self.env qt_ver = '6' if self.want_qt6 else '5' if force_static: exts = ('.a', '.lib') prefix = 'STLIB' else: exts = ('.so', '.lib') prefix = 'LIB' def lib_names(): for x in exts: for k in ('', qt_ver) if Utils.is_win32 else ['']: for p in ('lib', ''): yield (p, name, k, x) for tup in lib_names(): k = ''.join(tup) path = os.path.join(qtlibs, k) if os.path.exists(path): if env.DEST_OS == 'win32': libval = ''.join(tup[:-1]) else: libval = name env.append_unique(prefix + '_' + uselib, libval) env.append_unique('%sPATH_%s' % (prefix, uselib), qtlibs) env.append_unique('INCLUDES_' + uselib, qtincludes) env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, name.replace('Qt' + qt_ver, 'Qt'))) return k return False @conf def find_qt5_libraries(self): env = self.env qt_ver = '6' if self.want_qt6 else '5' qtincludes = self.environ.get('QT' + qt_ver + '_INCLUDES') or self.cmd_and_log(env.QMAKE + ['-query', 'QT_INSTALL_HEADERS']).strip() force_static = self.environ.get('QT' + qt_ver + '_FORCE_STATIC') try: if self.environ.get('QT' + qt_ver + '_XCOMPILE'): self.fatal('QT' + qt_ver + '_XCOMPILE Disables pkg-config detection') self.check_cfg(atleast_pkgconfig_version='0.1') except self.errors.ConfigurationError: for i in self.qt_vars: uselib = i.upper() if Utils.unversioned_sys_platform() == 'darwin': # Since at least qt 4.7.3 each library locates in separate directory fwk = i.replace('Qt' + qt_ver, 'Qt') frameworkName = fwk + '.framework' qtDynamicLib = os.path.join(env.QTLIBS, frameworkName, fwk) if os.path.exists(qtDynamicLib): env.append_unique('FRAMEWORK_' + uselib, fwk) env.append_unique('FRAMEWORKPATH_' + uselib, env.QTLIBS) self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN') else: self.msg('Checking for %s' % i, False, 'YELLOW') env.append_unique('INCLUDES_' + uselib, os.path.join(env.QTLIBS, frameworkName, 'Headers')) else: ret = self.find_single_qt5_lib(i, uselib, env.QTLIBS, qtincludes, force_static) if not force_static and not ret: ret = self.find_single_qt5_lib(i, uselib, env.QTLIBS, qtincludes, True) self.msg('Checking for %s' % i, ret, 'GREEN' if ret else 'YELLOW') else: path = '%s:%s:%s/pkgconfig:/usr/lib/qt%s/lib/pkgconfig:/opt/qt%s/lib/pkgconfig:/usr/lib/qt%s/lib:/opt/qt%s/lib' % ( self.environ.get('PKG_CONFIG_PATH', ''), env.QTLIBS, env.QTLIBS, qt_ver, qt_ver, qt_ver, qt_ver) for i in self.qt_vars: self.check_cfg(package=i, args='--cflags --libs', mandatory=False, force_static=force_static, pkg_config_path=path) @conf def simplify_qt5_libs(self): """ Since library paths make really long command-lines, and since everything depends on qtcore, remove the qtcore ones from qtgui, etc """ env = self.env def process_lib(vars_, coreval): for d in vars_: var = d.upper() if var == 'QTCORE': continue value = env['LIBPATH_'+var] if value: core = env[coreval] accu = [] for lib in value: if lib in core: continue accu.append(lib) env['LIBPATH_'+var] = accu process_lib(self.qt_vars, 'LIBPATH_QTCORE') @conf def add_qt5_rpath(self): """ Defines rpath entries for Qt libraries """ env = self.env if getattr(Options.options, 'want_rpath', False): def process_rpath(vars_, coreval): for d in vars_: var = d.upper() value = env['LIBPATH_' + var] if value: core = env[coreval] accu = [] for lib in value: if var != 'QTCORE': if lib in core: continue accu.append('-Wl,--rpath='+lib) env['RPATH_' + var] = accu process_rpath(self.qt_vars, 'LIBPATH_QTCORE') @conf def set_qt5_libs_to_check(self): qt_ver = '6' if self.want_qt6 else '5' if not self.qt_vars: dirlst = Utils.listdir(self.env.QTLIBS) pat = self.env.cxxshlib_PATTERN if Utils.is_win32: pat = pat.replace('.dll', '.lib') if self.environ.get('QT' + qt_ver + '_FORCE_STATIC'): pat = self.env.cxxstlib_PATTERN if Utils.unversioned_sys_platform() == 'darwin': pat = r"%s\.framework" # We only want to match Qt5 or Qt in the case of Qt5, in the case # of Qt6 we want to match Qt6 or Qt. This speeds up configuration # and reduces the chattiness of the configuration. Should also prevent # possible misconfiguration. if self.want_qt6: re_qt = re.compile(pat % 'Qt6?(?!\\d)(?P\\w+)' + '$') else: re_qt = re.compile(pat % 'Qt5?(?!\\d)(?P\\w+)' + '$') for x in sorted(dirlst): m = re_qt.match(x) if m: self.qt_vars.append("Qt%s%s" % (qt_ver, m.group('name'))) if not self.qt_vars: self.fatal('cannot find any Qt%s library (%r)' % (qt_ver, self.env.QTLIBS)) qtextralibs = getattr(Options.options, 'qtextralibs', None) if qtextralibs: self.qt_vars.extend(qtextralibs.split(',')) @conf def set_qt5_defines(self): qt_ver = '6' if self.want_qt6 else '5' if sys.platform != 'win32': return for x in self.qt_vars: y=x.replace('Qt' + qt_ver, 'Qt')[2:].upper() self.env.append_unique('DEFINES_%s' % x.upper(), 'QT_%s_LIB' % y) def options(opt): """ Command-line options """ opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries') for i in 'qtdir qtbin qtlibs'.split(): opt.add_option('--'+i, type='string', default='', dest=i) opt.add_option('--translate', action='store_true', help='collect translation strings', dest='trans_qt5', default=False) opt.add_option('--qtextralibs', type='string', default='', dest='qtextralibs', help='additional qt libraries on the system to add to default ones, comma separated') hamster-3.0.3/waflib/Tools/ruby.py000066400000000000000000000127131452646177100171000ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # daniel.svensson at purplescout.se 2008 # Thomas Nagy 2016-2018 (ita) """ Support for Ruby extensions. A C/C++ compiler is required:: def options(opt): opt.load('compiler_c ruby') def configure(conf): conf.load('compiler_c ruby') conf.check_ruby_version((1,8,0)) conf.check_ruby_ext_devel() conf.check_ruby_module('libxml') def build(bld): bld( features = 'c cshlib rubyext', source = 'rb_mytest.c', target = 'mytest_ext', install_path = '${ARCHDIR_RUBY}') bld.install_files('${LIBDIR_RUBY}', 'Mytest.rb') """ import os from waflib import Errors, Options, Task, Utils from waflib.TaskGen import before_method, feature, extension from waflib.Configure import conf @feature('rubyext') @before_method('apply_incpaths', 'process_source', 'apply_bundle', 'apply_link') def init_rubyext(self): """ Add required variables for ruby extensions """ self.install_path = '${ARCHDIR_RUBY}' self.uselib = self.to_list(getattr(self, 'uselib', '')) if not 'RUBY' in self.uselib: self.uselib.append('RUBY') if not 'RUBYEXT' in self.uselib: self.uselib.append('RUBYEXT') @feature('rubyext') @before_method('apply_link', 'propagate_uselib_vars') def apply_ruby_so_name(self): """ Strip the *lib* prefix from ruby extensions """ self.env.cshlib_PATTERN = self.env.cxxshlib_PATTERN = self.env.rubyext_PATTERN @conf def check_ruby_version(self, minver=()): """ Checks if ruby is installed. If installed the variable RUBY will be set in environment. The ruby binary can be overridden by ``--with-ruby-binary`` command-line option. """ ruby = self.find_program('ruby', var='RUBY', value=Options.options.rubybinary) try: version = self.cmd_and_log(ruby + ['-e', 'puts defined?(VERSION) ? VERSION : RUBY_VERSION']).strip() except Errors.WafError: self.fatal('could not determine ruby version') self.env.RUBY_VERSION = version try: ver = tuple(map(int, version.split('.'))) except Errors.WafError: self.fatal('unsupported ruby version %r' % version) cver = '' if minver: cver = '> ' + '.'.join(str(x) for x in minver) if ver < minver: self.fatal('ruby is too old %r' % ver) self.msg('Checking for ruby version %s' % cver, version) @conf def check_ruby_ext_devel(self): """ Check if a ruby extension can be created """ if not self.env.RUBY: self.fatal('ruby detection is required first') if not self.env.CC_NAME and not self.env.CXX_NAME: self.fatal('load a c/c++ compiler first') version = tuple(map(int, self.env.RUBY_VERSION.split("."))) def read_out(cmd): return Utils.to_list(self.cmd_and_log(self.env.RUBY + ['-rrbconfig', '-e', cmd])) def read_config(key): return read_out('puts RbConfig::CONFIG[%r]' % key) cpppath = archdir = read_config('archdir') if version >= (1, 9, 0): ruby_hdrdir = read_config('rubyhdrdir') cpppath += ruby_hdrdir if version >= (2, 0, 0): cpppath += read_config('rubyarchhdrdir') cpppath += [os.path.join(ruby_hdrdir[0], read_config('arch')[0])] self.check(header_name='ruby.h', includes=cpppath, errmsg='could not find ruby header file', link_header_test=False) self.env.LIBPATH_RUBYEXT = read_config('libdir') self.env.LIBPATH_RUBYEXT += archdir self.env.INCLUDES_RUBYEXT = cpppath self.env.CFLAGS_RUBYEXT = read_config('CCDLFLAGS') self.env.rubyext_PATTERN = '%s.' + read_config('DLEXT')[0] # ok this is really stupid, but the command and flags are combined. # so we try to find the first argument... flags = read_config('LDSHARED') while flags and flags[0][0] != '-': flags = flags[1:] # we also want to strip out the deprecated ppc flags if len(flags) > 1 and flags[1] == "ppc": flags = flags[2:] self.env.LINKFLAGS_RUBYEXT = flags self.env.LINKFLAGS_RUBYEXT += read_config('LIBS') self.env.LINKFLAGS_RUBYEXT += read_config('LIBRUBYARG_SHARED') if Options.options.rubyarchdir: self.env.ARCHDIR_RUBY = Options.options.rubyarchdir else: self.env.ARCHDIR_RUBY = read_config('sitearchdir')[0] if Options.options.rubylibdir: self.env.LIBDIR_RUBY = Options.options.rubylibdir else: self.env.LIBDIR_RUBY = read_config('sitelibdir')[0] @conf def check_ruby_module(self, module_name): """ Check if the selected ruby interpreter can require the given ruby module:: def configure(conf): conf.check_ruby_module('libxml') :param module_name: module :type module_name: string """ self.start_msg('Ruby module %s' % module_name) try: self.cmd_and_log(self.env.RUBY + ['-e', 'require \'%s\';puts 1' % module_name]) except Errors.WafError: self.end_msg(False) self.fatal('Could not find the ruby module %r' % module_name) self.end_msg(True) @extension('.rb') def process(self, node): return self.create_task('run_ruby', node) class run_ruby(Task.Task): """ Task to run ruby files detected by file extension .rb:: def options(opt): opt.load('ruby') def configure(ctx): ctx.check_ruby_version() def build(bld): bld.env.RBFLAGS = '-e puts "hello world"' bld(source='a_ruby_file.rb') """ run_str = '${RUBY} ${RBFLAGS} -I ${SRC[0].parent.abspath()} ${SRC}' def options(opt): """ Add the ``--with-ruby-archdir``, ``--with-ruby-libdir`` and ``--with-ruby-binary`` options """ opt.add_option('--with-ruby-archdir', type='string', dest='rubyarchdir', help='Specify directory where to install arch specific files') opt.add_option('--with-ruby-libdir', type='string', dest='rubylibdir', help='Specify alternate ruby library path') opt.add_option('--with-ruby-binary', type='string', dest='rubybinary', help='Specify alternate ruby binary') hamster-3.0.3/waflib/Tools/suncc.py000066400000000000000000000027231452646177100172320ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) from waflib import Errors from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_scc(conf): """ Detects the Sun C compiler """ v = conf.env cc = conf.find_program('cc', var='CC') try: conf.cmd_and_log(cc + ['-flags']) except Errors.WafError: conf.fatal('%r is not a Sun compiler' % cc) v.CC_NAME = 'sun' conf.get_suncc_version(cc) @conf def scc_common_flags(conf): """ Flags required for executing the sun C compiler """ v = conf.env v.CC_SRC_F = [] v.CC_TGT_F = ['-c', '-o', ''] if not v.LINK_CC: v.LINK_CC = v.CC v.CCLNK_SRC_F = '' v.CCLNK_TGT_F = ['-o', ''] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.SONAME_ST = '-Wl,-h,%s' v.SHLIB_MARKER = '-Bdynamic' v.STLIB_MARKER = '-Bstatic' v.cprogram_PATTERN = '%s' v.CFLAGS_cshlib = ['-xcode=pic32', '-DPIC'] v.LINKFLAGS_cshlib = ['-G'] v.cshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cstlib = ['-Bstatic'] v.cstlib_PATTERN = 'lib%s.a' def configure(conf): conf.find_scc() conf.find_ar() conf.scc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/suncxx.py000066400000000000000000000027471452646177100174550ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) from waflib import Errors from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_sxx(conf): """ Detects the sun C++ compiler """ v = conf.env cc = conf.find_program(['CC', 'c++'], var='CXX') try: conf.cmd_and_log(cc + ['-flags']) except Errors.WafError: conf.fatal('%r is not a Sun compiler' % cc) v.CXX_NAME = 'sun' conf.get_suncc_version(cc) @conf def sxx_common_flags(conf): """ Flags required for executing the sun C++ compiler """ v = conf.env v.CXX_SRC_F = [] v.CXX_TGT_F = ['-c', '-o', ''] if not v.LINK_CXX: v.LINK_CXX = v.CXX v.CXXLNK_SRC_F = [] v.CXXLNK_TGT_F = ['-o', ''] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.SONAME_ST = '-Wl,-h,%s' v.SHLIB_MARKER = '-Bdynamic' v.STLIB_MARKER = '-Bstatic' v.cxxprogram_PATTERN = '%s' v.CXXFLAGS_cxxshlib = ['-xcode=pic32', '-DPIC'] v.LINKFLAGS_cxxshlib = ['-G'] v.cxxshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cxxstlib = ['-Bstatic'] v.cxxstlib_PATTERN = 'lib%s.a' def configure(conf): conf.find_sxx() conf.find_ar() conf.sxx_common_flags() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/tex.py000066400000000000000000000360001452646177100167120ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) """ TeX/LaTeX/PDFLaTeX/XeLaTeX support Example:: def configure(conf): conf.load('tex') if not conf.env.LATEX: conf.fatal('The program LaTex is required') def build(bld): bld( features = 'tex', type = 'latex', # pdflatex or xelatex source = 'document.ltx', # mandatory, the source outs = 'ps', # 'pdf' or 'ps pdf' deps = 'crossreferencing.lst', # to give dependencies directly prompt = 1, # 0 for the batch mode ) Notes: - To configure with a special program, use:: $ PDFLATEX=luatex waf configure - This tool does not use the target attribute of the task generator (``bld(target=...)``); the target file name is built from the source base name and the output type(s) """ import os, re from waflib import Utils, Task, Errors, Logs, Node from waflib.TaskGen import feature, before_method re_bibunit = re.compile(r'\\(?Pputbib)\[(?P[^\[\]]*)\]',re.M) def bibunitscan(self): """ Parses TeX inputs and try to find the *bibunit* file dependencies :return: list of bibunit files :rtype: list of :py:class:`waflib.Node.Node` """ node = self.inputs[0] nodes = [] if not node: return nodes code = node.read() for match in re_bibunit.finditer(code): path = match.group('file') if path: found = None for k in ('', '.bib'): # add another loop for the tex include paths? Logs.debug('tex: trying %s%s', path, k) fi = node.parent.find_resource(path + k) if fi: found = True nodes.append(fi) # no break if not found: Logs.debug('tex: could not find %s', path) Logs.debug('tex: found the following bibunit files: %s', nodes) return nodes exts_deps_tex = ['', '.ltx', '.tex', '.bib', '.pdf', '.png', '.eps', '.ps', '.sty'] """List of typical file extensions included in latex files""" exts_tex = ['.ltx', '.tex'] """List of typical file extensions that contain latex""" re_tex = re.compile(r'\\(?Pusepackage|RequirePackage|include|bibliography([^\[\]{}]*)|putbib|includegraphics|input|import|bringin|lstinputlisting)(\[[^\[\]]*\])?{(?P[^{}]*)}',re.M) """Regexp for expressions that may include latex files""" g_bibtex_re = re.compile('bibdata', re.M) """Regexp for bibtex files""" g_glossaries_re = re.compile('\\@newglossary', re.M) """Regexp for expressions that create glossaries""" class tex(Task.Task): """ Compiles a tex/latex file. .. inheritance-diagram:: waflib.Tools.tex.latex waflib.Tools.tex.xelatex waflib.Tools.tex.pdflatex :top-classes: waflib.Tools.tex.tex """ bibtex_fun, _ = Task.compile_fun('${BIBTEX} ${BIBTEXFLAGS} ${SRCFILE}', shell=False) bibtex_fun.__doc__ = """ Execute the program **bibtex** """ makeindex_fun, _ = Task.compile_fun('${MAKEINDEX} ${MAKEINDEXFLAGS} ${SRCFILE}', shell=False) makeindex_fun.__doc__ = """ Execute the program **makeindex** """ makeglossaries_fun, _ = Task.compile_fun('${MAKEGLOSSARIES} ${SRCFILE}', shell=False) makeglossaries_fun.__doc__ = """ Execute the program **makeglossaries** """ def exec_command(self, cmd, **kw): """ Executes TeX commands without buffering (latex may prompt for inputs) :return: the return code :rtype: int """ if self.env.PROMPT_LATEX: # capture the outputs in configuration tests kw['stdout'] = kw['stderr'] = None return super(tex, self).exec_command(cmd, **kw) def scan_aux(self, node): """ Recursive regex-based scanner that finds included auxiliary files. """ nodes = [node] re_aux = re.compile(r'\\@input{(?P[^{}]*)}', re.M) def parse_node(node): code = node.read() for match in re_aux.finditer(code): path = match.group('file') found = node.parent.find_or_declare(path) if found and found not in nodes: Logs.debug('tex: found aux node %r', found) nodes.append(found) parse_node(found) parse_node(node) return nodes def scan(self): """ Recursive regex-based scanner that finds latex dependencies. It uses :py:attr:`waflib.Tools.tex.re_tex` Depending on your needs you might want: * to change re_tex:: from waflib.Tools import tex tex.re_tex = myregex * or to change the method scan from the latex tasks:: from waflib.Task import classes classes['latex'].scan = myscanfunction """ node = self.inputs[0] nodes = [] names = [] seen = [] if not node: return (nodes, names) def parse_node(node): if node in seen: return seen.append(node) code = node.read() for match in re_tex.finditer(code): multibib = match.group('type') if multibib and multibib.startswith('bibliography'): multibib = multibib[len('bibliography'):] if multibib.startswith('style'): continue else: multibib = None for path in match.group('file').split(','): if path: add_name = True found = None for k in exts_deps_tex: # issue 1067, scan in all texinputs folders for up in self.texinputs_nodes: Logs.debug('tex: trying %s%s', path, k) found = up.find_resource(path + k) if found: break for tsk in self.generator.tasks: if not found or found in tsk.outputs: break else: nodes.append(found) add_name = False for ext in exts_tex: if found.name.endswith(ext): parse_node(found) break # multibib stuff if found and multibib and found.name.endswith('.bib'): try: self.multibibs.append(found) except AttributeError: self.multibibs = [found] # no break, people are crazy if add_name: names.append(path) parse_node(node) for x in nodes: x.parent.get_bld().mkdir() Logs.debug("tex: found the following : %s and names %s", nodes, names) return (nodes, names) def check_status(self, msg, retcode): """ Checks an exit status and raise an error with a particular message :param msg: message to display if the code is non-zero :type msg: string :param retcode: condition :type retcode: boolean """ if retcode != 0: raise Errors.WafError('%r command exit status %r' % (msg, retcode)) def info(self, *k, **kw): try: info = self.generator.bld.conf.logger.info except AttributeError: info = Logs.info info(*k, **kw) def bibfile(self): """ Parses *.aux* files to find bibfiles to process. If present, execute :py:meth:`waflib.Tools.tex.tex.bibtex_fun` """ for aux_node in self.aux_nodes: try: ct = aux_node.read() except EnvironmentError: Logs.error('Error reading %s: %r', aux_node.abspath()) continue if g_bibtex_re.findall(ct): self.info('calling bibtex') self.env.env = {} self.env.env.update(os.environ) self.env.env.update({'BIBINPUTS': self.texinputs(), 'BSTINPUTS': self.texinputs()}) self.env.SRCFILE = aux_node.name[:-4] self.check_status('error when calling bibtex', self.bibtex_fun()) for node in getattr(self, 'multibibs', []): self.env.env = {} self.env.env.update(os.environ) self.env.env.update({'BIBINPUTS': self.texinputs(), 'BSTINPUTS': self.texinputs()}) self.env.SRCFILE = node.name[:-4] self.check_status('error when calling bibtex', self.bibtex_fun()) def bibunits(self): """ Parses *.aux* file to find bibunit files. If there are bibunit files, runs :py:meth:`waflib.Tools.tex.tex.bibtex_fun`. """ try: bibunits = bibunitscan(self) except OSError: Logs.error('error bibunitscan') else: if bibunits: fn = ['bu' + str(i) for i in range(1, len(bibunits) + 1)] if fn: self.info('calling bibtex on bibunits') for f in fn: self.env.env = {'BIBINPUTS': self.texinputs(), 'BSTINPUTS': self.texinputs()} self.env.SRCFILE = f self.check_status('error when calling bibtex', self.bibtex_fun()) def makeindex(self): """ Searches the filesystem for *.idx* files to process. If present, runs :py:meth:`waflib.Tools.tex.tex.makeindex_fun` """ self.idx_node = self.inputs[0].change_ext('.idx') try: idx_path = self.idx_node.abspath() os.stat(idx_path) except OSError: self.info('index file %s absent, not calling makeindex', idx_path) else: self.info('calling makeindex') self.env.SRCFILE = self.idx_node.name self.env.env = {} self.check_status('error when calling makeindex %s' % idx_path, self.makeindex_fun()) def bibtopic(self): """ Lists additional .aux files from the bibtopic package """ p = self.inputs[0].parent.get_bld() if os.path.exists(os.path.join(p.abspath(), 'btaux.aux')): self.aux_nodes += p.ant_glob('*[0-9].aux') def makeglossaries(self): """ Lists additional glossaries from .aux files. If present, runs the makeglossaries program. """ src_file = self.inputs[0].abspath() base_file = os.path.basename(src_file) base, _ = os.path.splitext(base_file) for aux_node in self.aux_nodes: try: ct = aux_node.read() except EnvironmentError: Logs.error('Error reading %s: %r', aux_node.abspath()) continue if g_glossaries_re.findall(ct): if not self.env.MAKEGLOSSARIES: raise Errors.WafError("The program 'makeglossaries' is missing!") Logs.warn('calling makeglossaries') self.env.SRCFILE = base self.check_status('error when calling makeglossaries %s' % base, self.makeglossaries_fun()) return def texinputs(self): """ Returns the list of texinput nodes as a string suitable for the TEXINPUTS environment variables :rtype: string """ return os.pathsep.join([k.abspath() for k in self.texinputs_nodes]) + os.pathsep def run(self): """ Runs the whole TeX build process Multiple passes are required depending on the usage of cross-references, bibliographies, glossaries, indexes and additional contents The appropriate TeX compiler is called until the *.aux* files stop changing. """ env = self.env if not env.PROMPT_LATEX: env.append_value('LATEXFLAGS', '-interaction=batchmode') env.append_value('PDFLATEXFLAGS', '-interaction=batchmode') env.append_value('XELATEXFLAGS', '-interaction=batchmode') # important, set the cwd for everybody self.cwd = self.inputs[0].parent.get_bld() self.info('first pass on %s', self.__class__.__name__) # Hash .aux files before even calling the LaTeX compiler cur_hash = self.hash_aux_nodes() self.call_latex() # Find the .aux files again since bibtex processing can require it self.hash_aux_nodes() self.bibtopic() self.bibfile() self.bibunits() self.makeindex() self.makeglossaries() for i in range(10): # There is no need to call latex again if the .aux hash value has not changed prev_hash = cur_hash cur_hash = self.hash_aux_nodes() if not cur_hash: Logs.error('No aux.h to process') if cur_hash and cur_hash == prev_hash: break # run the command self.info('calling %s', self.__class__.__name__) self.call_latex() def hash_aux_nodes(self): """ Returns a hash of the .aux file contents :rtype: string or bytes """ try: self.aux_nodes except AttributeError: try: self.aux_nodes = self.scan_aux(self.inputs[0].change_ext('.aux')) except IOError: return None return Utils.h_list([Utils.h_file(x.abspath()) for x in self.aux_nodes]) def call_latex(self): """ Runs the TeX compiler once """ self.env.env = {} self.env.env.update(os.environ) self.env.env.update({'TEXINPUTS': self.texinputs()}) self.env.SRCFILE = self.inputs[0].abspath() self.check_status('error when calling latex', self.texfun()) class latex(tex): "Compiles LaTeX files" texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False) class pdflatex(tex): "Compiles PdfLaTeX files" texfun, vars = Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False) class xelatex(tex): "XeLaTeX files" texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False) class dvips(Task.Task): "Converts dvi files to postscript" run_str = '${DVIPS} ${DVIPSFLAGS} ${SRC} -o ${TGT}' color = 'BLUE' after = ['latex', 'pdflatex', 'xelatex'] class dvipdf(Task.Task): "Converts dvi files to pdf" run_str = '${DVIPDF} ${DVIPDFFLAGS} ${SRC} ${TGT}' color = 'BLUE' after = ['latex', 'pdflatex', 'xelatex'] class pdf2ps(Task.Task): "Converts pdf files to postscript" run_str = '${PDF2PS} ${PDF2PSFLAGS} ${SRC} ${TGT}' color = 'BLUE' after = ['latex', 'pdflatex', 'xelatex'] @feature('tex') @before_method('process_source') def apply_tex(self): """ Creates :py:class:`waflib.Tools.tex.tex` objects, and dvips/dvipdf/pdf2ps tasks if necessary (outs='ps', etc). """ if not getattr(self, 'type', None) in ('latex', 'pdflatex', 'xelatex'): self.type = 'pdflatex' outs = Utils.to_list(getattr(self, 'outs', [])) # prompt for incomplete files (else the batchmode is used) try: self.generator.bld.conf except AttributeError: default_prompt = False else: default_prompt = True self.env.PROMPT_LATEX = getattr(self, 'prompt', default_prompt) deps_lst = [] if getattr(self, 'deps', None): deps = self.to_list(self.deps) for dep in deps: if isinstance(dep, str): n = self.path.find_resource(dep) if not n: self.bld.fatal('Could not find %r for %r' % (dep, self)) if not n in deps_lst: deps_lst.append(n) elif isinstance(dep, Node.Node): deps_lst.append(dep) for node in self.to_nodes(self.source): if self.type == 'latex': task = self.create_task('latex', node, node.change_ext('.dvi')) elif self.type == 'pdflatex': task = self.create_task('pdflatex', node, node.change_ext('.pdf')) elif self.type == 'xelatex': task = self.create_task('xelatex', node, node.change_ext('.pdf')) task.env = self.env # add the manual dependencies if deps_lst: for n in deps_lst: if not n in task.dep_nodes: task.dep_nodes.append(n) # texinputs is a nasty beast if hasattr(self, 'texinputs_nodes'): task.texinputs_nodes = self.texinputs_nodes else: task.texinputs_nodes = [node.parent, node.parent.get_bld(), self.path, self.path.get_bld()] lst = os.environ.get('TEXINPUTS', '') if self.env.TEXINPUTS: lst += os.pathsep + self.env.TEXINPUTS if lst: lst = lst.split(os.pathsep) for x in lst: if x: if os.path.isabs(x): p = self.bld.root.find_node(x) if p: task.texinputs_nodes.append(p) else: Logs.error('Invalid TEXINPUTS folder %s', x) else: Logs.error('Cannot resolve relative paths in TEXINPUTS %s', x) if self.type == 'latex': if 'ps' in outs: tsk = self.create_task('dvips', task.outputs, node.change_ext('.ps')) tsk.env.env = dict(os.environ) if 'pdf' in outs: tsk = self.create_task('dvipdf', task.outputs, node.change_ext('.pdf')) tsk.env.env = dict(os.environ) elif self.type == 'pdflatex': if 'ps' in outs: self.create_task('pdf2ps', task.outputs, node.change_ext('.ps')) self.source = [] def configure(self): """ Find the programs tex, latex and others without raising errors. """ v = self.env for p in 'tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps makeglossaries'.split(): try: self.find_program(p, var=p.upper()) except self.errors.ConfigurationError: pass v.DVIPSFLAGS = '-Ppdf' hamster-3.0.3/waflib/Tools/vala.py000066400000000000000000000261551452646177100170470ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Ali Sabil, 2007 # Radosław Szkodziński, 2010 """ At this point, vala is still unstable, so do not expect this tool to be too stable either (apis, etc) """ import re from waflib import Build, Context, Errors, Logs, Node, Options, Task, Utils from waflib.TaskGen import extension, taskgen_method from waflib.Configure import conf class valac(Task.Task): """ Compiles vala files """ #run_str = "${VALAC} ${VALAFLAGS}" # ideally #vars = ['VALAC_VERSION'] vars = ["VALAC", "VALAC_VERSION", "VALAFLAGS"] ext_out = ['.h'] def run(self): cmd = self.env.VALAC + self.env.VALAFLAGS resources = getattr(self, 'vala_exclude', []) cmd.extend([a.abspath() for a in self.inputs if a not in resources]) ret = self.exec_command(cmd, cwd=self.vala_dir_node.abspath()) if ret: return ret if self.generator.dump_deps_node: self.generator.dump_deps_node.write('\n'.join(self.generator.packages)) return ret @taskgen_method def init_vala_task(self): """ Initializes the vala task with the relevant data (acts as a constructor) """ self.profile = getattr(self, 'profile', 'gobject') self.packages = packages = Utils.to_list(getattr(self, 'packages', [])) self.use = Utils.to_list(getattr(self, 'use', [])) if packages and not self.use: self.use = packages[:] # copy if self.profile == 'gobject': if not 'GOBJECT' in self.use: self.use.append('GOBJECT') def addflags(flags): self.env.append_value('VALAFLAGS', flags) if self.profile: addflags('--profile=%s' % self.profile) valatask = self.valatask # output directory if hasattr(self, 'vala_dir'): if isinstance(self.vala_dir, str): valatask.vala_dir_node = self.path.get_bld().make_node(self.vala_dir) try: valatask.vala_dir_node.mkdir() except OSError: raise self.bld.fatal('Cannot create the vala dir %r' % valatask.vala_dir_node) else: valatask.vala_dir_node = self.vala_dir else: valatask.vala_dir_node = self.path.get_bld() addflags('--directory=%s' % valatask.vala_dir_node.abspath()) if hasattr(self, 'thread'): if self.profile == 'gobject': if not 'GTHREAD' in self.use: self.use.append('GTHREAD') else: #Vala doesn't have threading support for dova nor posix Logs.warn('Profile %s means no threading support', self.profile) self.thread = False if self.thread: addflags('--thread') self.is_lib = 'cprogram' not in self.features if self.is_lib: addflags('--library=%s' % self.target) h_node = valatask.vala_dir_node.find_or_declare('%s.h' % self.target) valatask.outputs.append(h_node) addflags('--header=%s' % h_node.name) valatask.outputs.append(valatask.vala_dir_node.find_or_declare('%s.vapi' % self.target)) if getattr(self, 'gir', None): gir_node = valatask.vala_dir_node.find_or_declare('%s.gir' % self.gir) addflags('--gir=%s' % gir_node.name) valatask.outputs.append(gir_node) self.vala_target_glib = getattr(self, 'vala_target_glib', getattr(Options.options, 'vala_target_glib', None)) if self.vala_target_glib: addflags('--target-glib=%s' % self.vala_target_glib) addflags(['--define=%s' % x for x in Utils.to_list(getattr(self, 'vala_defines', []))]) packages_private = Utils.to_list(getattr(self, 'packages_private', [])) addflags(['--pkg=%s' % x for x in packages_private]) def _get_api_version(): api_version = '1.0' if hasattr(Context.g_module, 'API_VERSION'): version = Context.g_module.API_VERSION.split(".") if version[0] == "0": api_version = "0." + version[1] else: api_version = version[0] + ".0" return api_version self.includes = Utils.to_list(getattr(self, 'includes', [])) valatask.install_path = getattr(self, 'install_path', '') valatask.vapi_path = getattr(self, 'vapi_path', '${DATAROOTDIR}/vala/vapi') valatask.pkg_name = getattr(self, 'pkg_name', self.env.PACKAGE) valatask.header_path = getattr(self, 'header_path', '${INCLUDEDIR}/%s-%s' % (valatask.pkg_name, _get_api_version())) valatask.install_binding = getattr(self, 'install_binding', True) self.vapi_dirs = vapi_dirs = Utils.to_list(getattr(self, 'vapi_dirs', [])) #includes = [] if hasattr(self, 'use'): local_packages = Utils.to_list(self.use)[:] # make sure to have a copy seen = [] while len(local_packages) > 0: package = local_packages.pop() if package in seen: continue seen.append(package) # check if the package exists try: package_obj = self.bld.get_tgen_by_name(package) except Errors.WafError: continue # in practice the other task is already processed # but this makes it explicit package_obj.post() package_name = package_obj.target task = getattr(package_obj, 'valatask', None) if task: for output in task.outputs: if output.name == package_name + ".vapi": valatask.set_run_after(task) if package_name not in packages: packages.append(package_name) if output.parent not in vapi_dirs: vapi_dirs.append(output.parent) if output.parent not in self.includes: self.includes.append(output.parent) if hasattr(package_obj, 'use'): lst = self.to_list(package_obj.use) lst.reverse() local_packages = [pkg for pkg in lst if pkg not in seen] + local_packages addflags(['--pkg=%s' % p for p in packages]) for vapi_dir in vapi_dirs: if isinstance(vapi_dir, Node.Node): v_node = vapi_dir else: v_node = self.path.find_dir(vapi_dir) if not v_node: Logs.warn('Unable to locate Vala API directory: %r', vapi_dir) else: addflags('--vapidir=%s' % v_node.abspath()) self.dump_deps_node = None if self.is_lib and self.packages: self.dump_deps_node = valatask.vala_dir_node.find_or_declare('%s.deps' % self.target) valatask.outputs.append(self.dump_deps_node) if self.is_lib and valatask.install_binding: headers_list = [o for o in valatask.outputs if o.suffix() == ".h"] if headers_list: self.install_vheader = self.add_install_files(install_to=valatask.header_path, install_from=headers_list) vapi_list = [o for o in valatask.outputs if (o.suffix() in (".vapi", ".deps"))] if vapi_list: self.install_vapi = self.add_install_files(install_to=valatask.vapi_path, install_from=vapi_list) gir_list = [o for o in valatask.outputs if o.suffix() == '.gir'] if gir_list: self.install_gir = self.add_install_files( install_to=getattr(self, 'gir_path', '${DATAROOTDIR}/gir-1.0'), install_from=gir_list) if hasattr(self, 'vala_resources'): nodes = self.to_nodes(self.vala_resources) valatask.vala_exclude = getattr(valatask, 'vala_exclude', []) + nodes valatask.inputs.extend(nodes) for x in nodes: addflags(['--gresources', x.abspath()]) @extension('.vala', '.gs') def vala_file(self, node): """ Compile a vala file and bind the task to *self.valatask*. If an existing vala task is already set, add the node to its inputs. The typical example is:: def build(bld): bld.program( packages = 'gtk+-2.0', target = 'vala-gtk-example', use = 'GTK GLIB', source = 'vala-gtk-example.vala foo.vala', vala_defines = ['DEBUG'] # adds --define= values to the command-line # the following arguments are for libraries #gir = 'hello-1.0', #gir_path = '/tmp', #vapi_path = '/tmp', #pkg_name = 'hello' # disable installing of gir, vapi and header #install_binding = False # profile = 'xyz' # adds --profile= to enable profiling # thread = True, # adds --thread, except if profile is on or not on 'gobject' # vala_target_glib = 'xyz' # adds --target-glib=, can be given through the command-line option --vala-target-glib= ) :param node: vala file :type node: :py:class:`waflib.Node.Node` """ try: valatask = self.valatask except AttributeError: valatask = self.valatask = self.create_task('valac') self.init_vala_task() valatask.inputs.append(node) name = node.name[:node.name.rfind('.')] + '.c' c_node = valatask.vala_dir_node.find_or_declare(name) valatask.outputs.append(c_node) self.source.append(c_node) @extension('.vapi') def vapi_file(self, node): try: valatask = self.valatask except AttributeError: valatask = self.valatask = self.create_task('valac') self.init_vala_task() valatask.inputs.append(node) @conf def find_valac(self, valac_name, min_version): """ Find the valac program, and execute it to store the version number in *conf.env.VALAC_VERSION* :param valac_name: program name :type valac_name: string or list of string :param min_version: minimum version acceptable :type min_version: tuple of int """ valac = self.find_program(valac_name, var='VALAC') try: output = self.cmd_and_log(valac + ['--version']) except Errors.WafError: valac_version = None else: ver = re.search(r'\d+.\d+.\d+', output).group().split('.') valac_version = tuple([int(x) for x in ver]) self.msg('Checking for %s version >= %r' % (valac_name, min_version), valac_version, valac_version and valac_version >= min_version) if valac and valac_version < min_version: self.fatal("%s version %r is too old, need >= %r" % (valac_name, valac_version, min_version)) self.env.VALAC_VERSION = valac_version return valac @conf def check_vala(self, min_version=(0,8,0), branch=None): """ Check if vala compiler from a given branch exists of at least a given version. :param min_version: minimum version acceptable (0.8.0) :type min_version: tuple :param branch: first part of the version number, in case a snapshot is used (0, 8) :type branch: tuple of int """ if self.env.VALA_MINVER: min_version = self.env.VALA_MINVER if self.env.VALA_MINVER_BRANCH: branch = self.env.VALA_MINVER_BRANCH if not branch: branch = min_version[:2] try: find_valac(self, 'valac-%d.%d' % (branch[0], branch[1]), min_version) except self.errors.ConfigurationError: find_valac(self, 'valac', min_version) @conf def check_vala_deps(self): """ Load the gobject and gthread packages if they are missing. """ if not self.env.HAVE_GOBJECT: pkg_args = {'package': 'gobject-2.0', 'uselib_store': 'GOBJECT', 'args': '--cflags --libs'} if getattr(Options.options, 'vala_target_glib', None): pkg_args['atleast_version'] = Options.options.vala_target_glib self.check_cfg(**pkg_args) if not self.env.HAVE_GTHREAD: pkg_args = {'package': 'gthread-2.0', 'uselib_store': 'GTHREAD', 'args': '--cflags --libs'} if getattr(Options.options, 'vala_target_glib', None): pkg_args['atleast_version'] = Options.options.vala_target_glib self.check_cfg(**pkg_args) def configure(self): """ Use the following to enforce minimum vala version:: def configure(conf): conf.env.VALA_MINVER = (0, 10, 0) conf.load('vala') """ self.load('gnu_dirs') self.check_vala_deps() self.check_vala() self.add_os_flags('VALAFLAGS') self.env.append_unique('VALAFLAGS', ['-C']) def options(opt): """ Load the :py:mod:`waflib.Tools.gnu_dirs` tool and add the ``--vala-target-glib`` command-line option """ opt.load('gnu_dirs') valaopts = opt.add_option_group('Vala Compiler Options') valaopts.add_option('--vala-target-glib', default=None, dest='vala_target_glib', metavar='MAJOR.MINOR', help='Target version of glib for Vala GObject code generation') hamster-3.0.3/waflib/Tools/waf_unit_test.py000066400000000000000000000231431452646177100207710ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Carlos Rafael Giani, 2006 # Thomas Nagy, 2010-2018 (ita) """ Unit testing system for C/C++/D and interpreted languages providing test execution: * in parallel, by using ``waf -j`` * partial (only the tests that have changed) or full (by using ``waf --alltests``) The tests are declared by adding the **test** feature to programs:: def options(opt): opt.load('compiler_cxx waf_unit_test') def configure(conf): conf.load('compiler_cxx waf_unit_test') def build(bld): bld(features='cxx cxxprogram test', source='main.cpp', target='app') # or bld.program(features='test', source='main2.cpp', target='app2') When the build is executed, the program 'test' will be built and executed without arguments. The success/failure is detected by looking at the return code. The status and the standard output/error are stored on the build context. The results can be displayed by registering a callback function. Here is how to call the predefined callback:: def build(bld): bld(features='cxx cxxprogram test', source='main.c', target='app') from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.summary) By passing --dump-test-scripts the build outputs corresponding python files (with extension _run.py) that are useful for debugging purposes. """ import os, shlex, sys from waflib.TaskGen import feature, after_method, taskgen_method from waflib import Utils, Task, Logs, Options from waflib.Tools import ccroot testlock = Utils.threading.Lock() SCRIPT_TEMPLATE = """#! %(python)s import subprocess, sys cmd = %(cmd)r # if you want to debug with gdb: #cmd = ['gdb', '-args'] + cmd env = %(env)r status = subprocess.call(cmd, env=env, cwd=%(cwd)r, shell=isinstance(cmd, str)) sys.exit(status) """ @taskgen_method def handle_ut_cwd(self, key): """ Task generator method, used internally to limit code duplication. This method may disappear anytime. """ cwd = getattr(self, key, None) if cwd: if isinstance(cwd, str): # we want a Node instance if os.path.isabs(cwd): self.ut_cwd = self.bld.root.make_node(cwd) else: self.ut_cwd = self.path.make_node(cwd) @feature('test_scripts') def make_interpreted_test(self): """Create interpreted unit tests.""" for x in ['test_scripts_source', 'test_scripts_template']: if not hasattr(self, x): Logs.warn('a test_scripts taskgen i missing %s' % x) return self.ut_run, lst = Task.compile_fun(self.test_scripts_template, shell=getattr(self, 'test_scripts_shell', False)) script_nodes = self.to_nodes(self.test_scripts_source) for script_node in script_nodes: tsk = self.create_task('utest', [script_node]) tsk.vars = lst + tsk.vars tsk.env['SCRIPT'] = script_node.path_from(tsk.get_cwd()) self.handle_ut_cwd('test_scripts_cwd') env = getattr(self, 'test_scripts_env', None) if env: self.ut_env = env else: self.ut_env = dict(os.environ) paths = getattr(self, 'test_scripts_paths', {}) for (k,v) in paths.items(): p = self.ut_env.get(k, '').split(os.pathsep) if isinstance(v, str): v = v.split(os.pathsep) self.ut_env[k] = os.pathsep.join(p + v) self.env.append_value('UT_DEPS', ['%r%r' % (key, self.ut_env[key]) for key in self.ut_env]) @feature('test') @after_method('apply_link', 'process_use') def make_test(self): """Create the unit test task. There can be only one unit test task by task generator.""" if not getattr(self, 'link_task', None): return tsk = self.create_task('utest', self.link_task.outputs) if getattr(self, 'ut_str', None): self.ut_run, lst = Task.compile_fun(self.ut_str, shell=getattr(self, 'ut_shell', False)) tsk.vars = tsk.vars + lst self.env.append_value('UT_DEPS', self.ut_str) self.handle_ut_cwd('ut_cwd') if not hasattr(self, 'ut_paths'): paths = [] for x in self.tmp_use_sorted: try: y = self.bld.get_tgen_by_name(x).link_task except AttributeError: pass else: if not isinstance(y, ccroot.stlink_task): paths.append(y.outputs[0].parent.abspath()) self.ut_paths = os.pathsep.join(paths) + os.pathsep if not hasattr(self, 'ut_env'): self.ut_env = dct = dict(os.environ) def add_path(var): dct[var] = self.ut_paths + dct.get(var,'') if Utils.is_win32: add_path('PATH') elif Utils.unversioned_sys_platform() == 'darwin': add_path('DYLD_LIBRARY_PATH') add_path('LD_LIBRARY_PATH') else: add_path('LD_LIBRARY_PATH') if not hasattr(self, 'ut_cmd'): self.ut_cmd = getattr(Options.options, 'testcmd', False) self.env.append_value('UT_DEPS', str(self.ut_cmd)) self.env.append_value('UT_DEPS', self.ut_paths) self.env.append_value('UT_DEPS', ['%r%r' % (key, self.ut_env[key]) for key in self.ut_env]) @taskgen_method def add_test_results(self, tup): """Override and return tup[1] to interrupt the build immediately if a test does not run""" Logs.debug("ut: %r", tup) try: self.utest_results.append(tup) except AttributeError: self.utest_results = [tup] try: self.bld.utest_results.append(tup) except AttributeError: self.bld.utest_results = [tup] @Task.deep_inputs class utest(Task.Task): """ Execute a unit test """ color = 'PINK' after = ['vnum', 'inst'] vars = ['UT_DEPS'] def runnable_status(self): """ Always execute the task if `waf --alltests` was used or no tests if ``waf --notests`` was used """ if getattr(Options.options, 'no_tests', False): return Task.SKIP_ME ret = super(utest, self).runnable_status() if ret == Task.SKIP_ME: if getattr(Options.options, 'all_tests', False): return Task.RUN_ME return ret def get_test_env(self): """ In general, tests may require any library built anywhere in the project. Override this method if fewer paths are needed """ return self.generator.ut_env def post_run(self): super(utest, self).post_run() if getattr(Options.options, 'clear_failed_tests', False) and self.waf_unit_test_results[1]: self.generator.bld.task_sigs[self.uid()] = None def run(self): """ Execute the test. The execution is always successful, and the results are stored on ``self.generator.bld.utest_results`` for postprocessing. Override ``add_test_results`` to interrupt the build """ if hasattr(self.generator, 'ut_run'): return self.generator.ut_run(self) self.ut_exec = getattr(self.generator, 'ut_exec', [self.inputs[0].abspath()]) ut_cmd = getattr(self.generator, 'ut_cmd', False) if ut_cmd: self.ut_exec = shlex.split(ut_cmd % Utils.shell_escape(self.ut_exec)) return self.exec_command(self.ut_exec) def exec_command(self, cmd, **kw): self.generator.bld.log_command(cmd, kw) if getattr(Options.options, 'dump_test_scripts', False): script_code = SCRIPT_TEMPLATE % { 'python': sys.executable, 'env': self.get_test_env(), 'cwd': self.get_cwd().abspath(), 'cmd': cmd } script_file = self.inputs[0].abspath() + '_run.py' Utils.writef(script_file, script_code, encoding='utf-8') os.chmod(script_file, Utils.O755) if Logs.verbose > 1: Logs.info('Test debug file written as %r' % script_file) proc = Utils.subprocess.Popen(cmd, cwd=self.get_cwd().abspath(), env=self.get_test_env(), stderr=Utils.subprocess.PIPE, stdout=Utils.subprocess.PIPE, shell=isinstance(cmd,str)) (stdout, stderr) = proc.communicate() self.waf_unit_test_results = tup = (self.inputs[0].abspath(), proc.returncode, stdout, stderr) testlock.acquire() try: return self.generator.add_test_results(tup) finally: testlock.release() def get_cwd(self): return getattr(self.generator, 'ut_cwd', self.inputs[0].parent) def summary(bld): """ Display an execution summary:: def build(bld): bld(features='cxx cxxprogram test', source='main.c', target='app') from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.summary) """ lst = getattr(bld, 'utest_results', []) if lst: Logs.pprint('CYAN', 'execution summary') total = len(lst) tfail = len([x for x in lst if x[1]]) Logs.pprint('GREEN', ' tests that pass %d/%d' % (total-tfail, total)) for (f, code, out, err) in lst: if not code: Logs.pprint('GREEN', ' %s' % f) Logs.pprint('GREEN' if tfail == 0 else 'RED', ' tests that fail %d/%d' % (tfail, total)) for (f, code, out, err) in lst: if code: Logs.pprint('RED', ' %s' % f) def set_exit_code(bld): """ If any of the tests fail waf will exit with that exit code. This is useful if you have an automated build system which need to report on errors from the tests. You may use it like this: def build(bld): bld(features='cxx cxxprogram test', source='main.c', target='app') from waflib.Tools import waf_unit_test bld.add_post_fun(waf_unit_test.set_exit_code) """ lst = getattr(bld, 'utest_results', []) for (f, code, out, err) in lst: if code: msg = [] if out: msg.append('stdout:%s%s' % (os.linesep, out.decode('utf-8'))) if err: msg.append('stderr:%s%s' % (os.linesep, err.decode('utf-8'))) bld.fatal(os.linesep.join(msg)) def options(opt): """ Provide the ``--alltests``, ``--notests`` and ``--testcmd`` command-line options. """ opt.add_option('--notests', action='store_true', default=False, help='Exec no unit tests', dest='no_tests') opt.add_option('--alltests', action='store_true', default=False, help='Exec all unit tests', dest='all_tests') opt.add_option('--clear-failed', action='store_true', default=False, help='Force failed unit tests to run again next time', dest='clear_failed_tests') opt.add_option('--testcmd', action='store', default=False, dest='testcmd', help='Run the unit tests using the test-cmd string example "--testcmd="valgrind --error-exitcode=1 %s" to run under valgrind') opt.add_option('--dump-test-scripts', action='store_true', default=False, help='Create python scripts to help debug tests', dest='dump_test_scripts') hamster-3.0.3/waflib/Tools/winres.py000066400000000000000000000062051452646177100174250ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Brant Young, 2007 "Process *.rc* files for C/C++: X{.rc -> [.res|.rc.o]}" import os import re from waflib import Task from waflib.TaskGen import extension from waflib.Tools import c_preproc from waflib import Utils @extension('.rc') def rc_file(self, node): """ Binds the .rc extension to a winrc task """ obj_ext = '.rc.o' if self.env.WINRC_TGT_F == '/fo': obj_ext = '.res' rctask = self.create_task('winrc', node, node.change_ext(obj_ext)) try: self.compiled_tasks.append(rctask) except AttributeError: self.compiled_tasks = [rctask] re_lines = re.compile( r'(?:^[ \t]*(#|%:)[ \t]*(ifdef|ifndef|if|else|elif|endif|include|import|define|undef|pragma)[ \t]*(.*?)\s*$)|'\ r'(?:^\w+[ \t]*(ICON|BITMAP|CURSOR|HTML|FONT|MESSAGETABLE|TYPELIB|REGISTRY|D3DFX)[ \t]*(.*?)\s*$)', re.IGNORECASE | re.MULTILINE) class rc_parser(c_preproc.c_parser): """ Calculates dependencies in .rc files """ def filter_comments(self, node): """ Overrides :py:meth:`waflib.Tools.c_preproc.c_parser.filter_comments` """ code = node.read() if c_preproc.use_trigraphs: for (a, b) in c_preproc.trig_def: code = code.split(a).join(b) code = c_preproc.re_nl.sub('', code) code = c_preproc.re_cpp.sub(c_preproc.repl, code) ret = [] for m in re.finditer(re_lines, code): if m.group(2): ret.append((m.group(2), m.group(3))) else: ret.append(('include', m.group(5))) return ret class winrc(Task.Task): """ Compiles resource files """ run_str = '${WINRC} ${WINRCFLAGS} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${WINRC_TGT_F} ${TGT} ${WINRC_SRC_F} ${SRC}' color = 'BLUE' def scan(self): tmp = rc_parser(self.generator.includes_nodes) tmp.start(self.inputs[0], self.env) return (tmp.nodes, tmp.names) def exec_command(self, cmd, **kw): if self.env.WINRC_TGT_F == '/fo': # Since winres include paths may contain spaces, they do not fit in # response files and are best passed as environment variables replace_cmd = [] incpaths = [] while cmd: # filter include path flags flag = cmd.pop(0) if flag.upper().startswith('/I'): if len(flag) == 2: incpaths.append(cmd.pop(0)) else: incpaths.append(flag[2:]) else: replace_cmd.append(flag) cmd = replace_cmd if incpaths: # append to existing environment variables in INCLUDE env = kw['env'] = dict(kw.get('env') or self.env.env or os.environ) pre_includes = env.get('INCLUDE', '') env['INCLUDE'] = pre_includes + os.pathsep + os.pathsep.join(incpaths) return super(winrc, self).exec_command(cmd, **kw) def quote_flag(self, flag): if self.env.WINRC_TGT_F == '/fo': # winres does not support quotes around flags in response files return flag return super(winrc, self).quote_flag(flag) def configure(conf): """ Detects the programs RC or windres, depending on the C/C++ compiler in use """ v = conf.env if not v.WINRC: if v.CC_NAME == 'msvc': conf.find_program('RC', var='WINRC', path_list=v.PATH) v.WINRC_TGT_F = '/fo' v.WINRC_SRC_F = '' else: conf.find_program('windres', var='WINRC', path_list=v.PATH) v.WINRC_TGT_F = '-o' v.WINRC_SRC_F = '-i' hamster-3.0.3/waflib/Tools/xlc.py000066400000000000000000000026411452646177100167040ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) # Yinon Ehrlich, 2009 # Michael Kuhn, 2009 from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_xlc(conf): """ Detects the Aix C compiler """ cc = conf.find_program(['xlc_r', 'xlc'], var='CC') conf.get_xlc_version(cc) conf.env.CC_NAME = 'xlc' @conf def xlc_common_flags(conf): """ Flags required for executing the Aix C compiler """ v = conf.env v.CC_SRC_F = [] v.CC_TGT_F = ['-c', '-o'] if not v.LINK_CC: v.LINK_CC = v.CC v.CCLNK_SRC_F = [] v.CCLNK_TGT_F = ['-o'] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.RPATH_ST = '-Wl,-rpath,%s' v.SONAME_ST = [] v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.LINKFLAGS_cprogram = ['-Wl,-brtl'] v.cprogram_PATTERN = '%s' v.CFLAGS_cshlib = ['-fPIC'] v.LINKFLAGS_cshlib = ['-G', '-Wl,-brtl,-bexpfull'] v.cshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cstlib = [] v.cstlib_PATTERN = 'lib%s.a' def configure(conf): conf.find_xlc() conf.find_ar() conf.xlc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Tools/xlcxx.py000066400000000000000000000026741452646177100172720ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2018 (ita) # Ralf Habacker, 2006 (rh) # Yinon Ehrlich, 2009 # Michael Kuhn, 2009 from waflib.Tools import ccroot, ar from waflib.Configure import conf @conf def find_xlcxx(conf): """ Detects the Aix C++ compiler """ cxx = conf.find_program(['xlc++_r', 'xlc++'], var='CXX') conf.get_xlc_version(cxx) conf.env.CXX_NAME = 'xlc++' @conf def xlcxx_common_flags(conf): """ Flags required for executing the Aix C++ compiler """ v = conf.env v.CXX_SRC_F = [] v.CXX_TGT_F = ['-c', '-o'] if not v.LINK_CXX: v.LINK_CXX = v.CXX v.CXXLNK_SRC_F = [] v.CXXLNK_TGT_F = ['-o'] v.CPPPATH_ST = '-I%s' v.DEFINES_ST = '-D%s' v.LIB_ST = '-l%s' # template for adding libs v.LIBPATH_ST = '-L%s' # template for adding libpaths v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-L%s' v.RPATH_ST = '-Wl,-rpath,%s' v.SONAME_ST = [] v.SHLIB_MARKER = [] v.STLIB_MARKER = [] v.LINKFLAGS_cxxprogram= ['-Wl,-brtl'] v.cxxprogram_PATTERN = '%s' v.CXXFLAGS_cxxshlib = ['-fPIC'] v.LINKFLAGS_cxxshlib = ['-G', '-Wl,-brtl,-bexpfull'] v.cxxshlib_PATTERN = 'lib%s.so' v.LINKFLAGS_cxxstlib = [] v.cxxstlib_PATTERN = 'lib%s.a' def configure(conf): conf.find_xlcxx() conf.find_ar() conf.xlcxx_common_flags() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/Utils.py000066400000000000000000000623121452646177100161170ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) """ Utilities and platform-specific fixes The portability fixes try to provide a consistent behavior of the Waf API through Python versions 2.5 to 3.X and across different platforms (win32, linux, etc) """ from __future__ import with_statement import atexit, os, sys, errno, inspect, re, datetime, platform, base64, signal, functools, time, shlex try: import cPickle except ImportError: import pickle as cPickle # leave this if os.name == 'posix' and sys.version_info[0] < 3: try: import subprocess32 as subprocess except ImportError: import subprocess else: import subprocess try: TimeoutExpired = subprocess.TimeoutExpired except AttributeError: class TimeoutExpired(Exception): pass from collections import deque, defaultdict try: import _winreg as winreg except ImportError: try: import winreg except ImportError: winreg = None from waflib import Errors try: from hashlib import md5 except ImportError: try: from hashlib import sha1 as md5 except ImportError: # never fail to enable potential fixes from another module pass else: try: md5().digest() except ValueError: # Fips? #2213 from hashlib import sha1 as md5 try: import threading except ImportError: if not 'JOBS' in os.environ: # no threading :-( os.environ['JOBS'] = '1' class threading(object): """ A fake threading class for platforms lacking the threading module. Use ``waf -j1`` on those platforms """ pass class Lock(object): """Fake Lock class""" def acquire(self): pass def release(self): pass threading.Lock = threading.Thread = Lock SIG_NIL = 'SIG_NIL_SIG_NIL_'.encode() """Arbitrary null value for hashes. Modify this value according to the hash function in use""" O644 = 420 """Constant representing the permissions for regular files (0644 raises a syntax error on python 3)""" O755 = 493 """Constant representing the permissions for executable files (0755 raises a syntax error on python 3)""" rot_chr = ['\\', '|', '/', '-'] "List of characters to use when displaying the throbber (progress bar)" rot_idx = 0 "Index of the current throbber character (progress bar)" class ordered_iter_dict(dict): """Ordered dictionary that provides iteration from the most recently inserted keys first""" def __init__(self, *k, **kw): self.lst = deque() dict.__init__(self, *k, **kw) def clear(self): dict.clear(self) self.lst = deque() def __setitem__(self, key, value): if key in dict.keys(self): self.lst.remove(key) dict.__setitem__(self, key, value) self.lst.append(key) def __delitem__(self, key): dict.__delitem__(self, key) try: self.lst.remove(key) except ValueError: pass def __iter__(self): return reversed(self.lst) def keys(self): return reversed(self.lst) class lru_node(object): """ Used by :py:class:`waflib.Utils.lru_cache` """ __slots__ = ('next', 'prev', 'key', 'val') def __init__(self): self.next = self self.prev = self self.key = None self.val = None class lru_cache(object): """ A simple least-recently used cache with lazy allocation """ __slots__ = ('maxlen', 'table', 'head') def __init__(self, maxlen=100): self.maxlen = maxlen """ Maximum amount of elements in the cache """ self.table = {} """ Mapping key-value """ self.head = lru_node() self.head.next = self.head self.head.prev = self.head def __getitem__(self, key): node = self.table[key] # assert(key==node.key) if node is self.head: return node.val # detach the node found node.prev.next = node.next node.next.prev = node.prev # replace the head node.next = self.head.next node.prev = self.head self.head = node.next.prev = node.prev.next = node return node.val def __setitem__(self, key, val): if key in self.table: # update the value for an existing key node = self.table[key] node.val = val self.__getitem__(key) else: if len(self.table) < self.maxlen: # the very first item is unused until the maximum is reached node = lru_node() node.prev = self.head node.next = self.head.next node.prev.next = node.next.prev = node else: node = self.head = self.head.next try: # that's another key del self.table[node.key] except KeyError: pass node.key = key node.val = val self.table[key] = node class lazy_generator(object): def __init__(self, fun, params): self.fun = fun self.params = params def __iter__(self): return self def __next__(self): try: it = self.it except AttributeError: it = self.it = self.fun(*self.params) return next(it) next = __next__ is_win32 = os.sep == '\\' or sys.platform == 'win32' or os.name == 'nt' # msys2 """ Whether this system is a Windows series """ def readf(fname, m='r', encoding='latin-1'): """ Reads an entire file into a string. See also :py:meth:`waflib.Node.Node.readf`:: def build(ctx): from waflib import Utils txt = Utils.readf(self.path.find_node('wscript').abspath()) txt = ctx.path.find_node('wscript').read() :type fname: string :param fname: Path to file :type m: string :param m: Open mode :type encoding: string :param encoding: encoding value, only used for python 3 :rtype: string :return: Content of the file """ if sys.hexversion > 0x3000000 and not 'b' in m: m += 'b' with open(fname, m) as f: txt = f.read() if encoding: txt = txt.decode(encoding) else: txt = txt.decode() else: with open(fname, m) as f: txt = f.read() return txt def writef(fname, data, m='w', encoding='latin-1'): """ Writes an entire file from a string. See also :py:meth:`waflib.Node.Node.writef`:: def build(ctx): from waflib import Utils txt = Utils.writef(self.path.make_node('i_like_kittens').abspath(), 'some data') self.path.make_node('i_like_kittens').write('some data') :type fname: string :param fname: Path to file :type data: string :param data: The contents to write to the file :type m: string :param m: Open mode :type encoding: string :param encoding: encoding value, only used for python 3 """ if sys.hexversion > 0x3000000 and not 'b' in m: data = data.encode(encoding) m += 'b' with open(fname, m) as f: f.write(data) def h_file(fname): """ Computes a hash value for a file by using md5. Use the md5_tstamp extension to get faster build hashes if necessary. :type fname: string :param fname: path to the file to hash :return: hash of the file contents :rtype: string or bytes """ m = md5() with open(fname, 'rb') as f: while fname: fname = f.read(200000) m.update(fname) return m.digest() def readf_win32(f, m='r', encoding='latin-1'): flags = os.O_NOINHERIT | os.O_RDONLY if 'b' in m: flags |= os.O_BINARY if '+' in m: flags |= os.O_RDWR try: fd = os.open(f, flags) except OSError: raise IOError('Cannot read from %r' % f) if sys.hexversion > 0x3000000 and not 'b' in m: m += 'b' with os.fdopen(fd, m) as f: txt = f.read() if encoding: txt = txt.decode(encoding) else: txt = txt.decode() else: with os.fdopen(fd, m) as f: txt = f.read() return txt def writef_win32(f, data, m='w', encoding='latin-1'): if sys.hexversion > 0x3000000 and not 'b' in m: data = data.encode(encoding) m += 'b' flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT if 'b' in m: flags |= os.O_BINARY if '+' in m: flags |= os.O_RDWR try: fd = os.open(f, flags) except OSError: raise OSError('Cannot write to %r' % f) with os.fdopen(fd, m) as f: f.write(data) def h_file_win32(fname): try: fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT) except OSError: raise OSError('Cannot read from %r' % fname) m = md5() with os.fdopen(fd, 'rb') as f: while fname: fname = f.read(200000) m.update(fname) return m.digest() # always save these readf_unix = readf writef_unix = writef h_file_unix = h_file if hasattr(os, 'O_NOINHERIT') and sys.hexversion < 0x3040000: # replace the default functions readf = readf_win32 writef = writef_win32 h_file = h_file_win32 try: x = ''.encode('hex') except LookupError: import binascii def to_hex(s): ret = binascii.hexlify(s) if not isinstance(ret, str): ret = ret.decode('utf-8') return ret else: def to_hex(s): return s.encode('hex') to_hex.__doc__ = """ Return the hexadecimal representation of a string :param s: string to convert :type s: string """ def listdir_win32(s): """ Lists the contents of a folder in a portable manner. On Win32, returns the list of drive letters: ['C:', 'X:', 'Z:'] when an empty string is given. :type s: string :param s: a string, which can be empty on Windows """ if not s: try: import ctypes except ImportError: # there is nothing much we can do return [x + ':\\' for x in 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'] else: dlen = 4 # length of "?:\\x00" maxdrives = 26 buf = ctypes.create_string_buffer(maxdrives * dlen) ndrives = ctypes.windll.kernel32.GetLogicalDriveStringsA(maxdrives*dlen, ctypes.byref(buf)) return [ str(buf.raw[4*i:4*i+2].decode('ascii')) for i in range(int(ndrives/dlen)) ] if len(s) == 2 and s[1] == ":": s += os.sep if not os.path.isdir(s): e = OSError('%s is not a directory' % s) e.errno = errno.ENOENT raise e return os.listdir(s) listdir = os.listdir if is_win32: listdir = listdir_win32 def num2ver(ver): """ Converts a string, tuple or version number into an integer. The number is supposed to have at most 4 digits:: from waflib.Utils import num2ver num2ver('1.3.2') == num2ver((1,3,2)) == num2ver((1,3,2,0)) :type ver: string or tuple of numbers :param ver: a version number """ if isinstance(ver, str): ver = tuple(ver.split('.')) if isinstance(ver, tuple): ret = 0 for i in range(4): if i < len(ver): ret += 256**(3 - i) * int(ver[i]) return ret return ver def to_list(val): """ Converts a string argument to a list by splitting it by spaces. Returns the object if not a string:: from waflib.Utils import to_list lst = to_list('a b c d') :param val: list of string or space-separated string :rtype: list :return: Argument converted to list """ if isinstance(val, str): return val.split() else: return val def console_encoding(): try: import ctypes except ImportError: pass else: try: codepage = ctypes.windll.kernel32.GetConsoleCP() except AttributeError: pass else: if codepage: if 65001 == codepage and sys.version_info < (3, 3): return 'utf-8' return 'cp%d' % codepage return sys.stdout.encoding or ('cp1252' if is_win32 else 'latin-1') def split_path_unix(path): return path.split('/') def split_path_cygwin(path): if path.startswith('//'): ret = path.split('/')[2:] ret[0] = '/' + ret[0] return ret return path.split('/') re_sp = re.compile('[/\\\\]+') def split_path_win32(path): if path.startswith('\\\\'): ret = re_sp.split(path)[1:] ret[0] = '\\\\' + ret[0] if ret[0] == '\\\\?': return ret[1:] return ret return re_sp.split(path) msysroot = None def split_path_msys(path): if path.startswith(('/', '\\')) and not path.startswith(('//', '\\\\')): # msys paths can be in the form /usr/bin global msysroot if not msysroot: # msys has python 2.7 or 3, so we can use this msysroot = subprocess.check_output(['cygpath', '-w', '/']).decode(sys.stdout.encoding or 'latin-1') msysroot = msysroot.strip() path = os.path.normpath(msysroot + os.sep + path) return split_path_win32(path) if sys.platform == 'cygwin': split_path = split_path_cygwin elif is_win32: # Consider this an MSYSTEM environment if $MSYSTEM is set and python # reports is executable from a unix like path on a windows host. if os.environ.get('MSYSTEM') and sys.executable.startswith('/'): split_path = split_path_msys else: split_path = split_path_win32 else: split_path = split_path_unix split_path.__doc__ = """ Splits a path by / or \\; do not confuse this function with with ``os.path.split`` :type path: string :param path: path to split :return: list of string """ def check_dir(path): """ Ensures that a directory exists (similar to ``mkdir -p``). :type path: string :param path: Path to directory :raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added. """ if not os.path.isdir(path): try: os.makedirs(path) except OSError as e: if not os.path.isdir(path): raise Errors.WafError('Cannot create the folder %r' % path, ex=e) def check_exe(name, env=None): """ Ensures that a program exists :type name: string :param name: path to the program :param env: configuration object :type env: :py:class:`waflib.ConfigSet.ConfigSet` :return: path of the program or None :raises: :py:class:`waflib.Errors.WafError` if the folder cannot be added. """ if not name: raise ValueError('Cannot execute an empty string!') def is_exe(fpath): return os.path.isfile(fpath) and os.access(fpath, os.X_OK) fpath, fname = os.path.split(name) if fpath and is_exe(name): return os.path.abspath(name) else: env = env or os.environ for path in env['PATH'].split(os.pathsep): path = path.strip('"') exe_file = os.path.join(path, name) if is_exe(exe_file): return os.path.abspath(exe_file) return None def def_attrs(cls, **kw): """ Sets default attributes on a class instance :type cls: class :param cls: the class to update the given attributes in. :type kw: dict :param kw: dictionary of attributes names and values. """ for k, v in kw.items(): if not hasattr(cls, k): setattr(cls, k, v) def quote_define_name(s): """ Converts a string into an identifier suitable for C defines. :type s: string :param s: String to convert :rtype: string :return: Identifier suitable for C defines """ fu = re.sub('[^a-zA-Z0-9]', '_', s) fu = re.sub('_+', '_', fu) fu = fu.upper() return fu # shlex.quote didn't exist until python 3.3. Prior to that it was a non-documented # function in pipes. try: shell_quote = shlex.quote except AttributeError: import pipes shell_quote = pipes.quote def shell_escape(cmd): """ Escapes a command: ['ls', '-l', 'arg space'] -> ls -l 'arg space' """ if isinstance(cmd, str): return cmd return ' '.join(shell_quote(x) for x in cmd) def h_list(lst): """ Hashes lists of ordered data. Using hash(tup) for tuples would be much more efficient, but Python now enforces hash randomization :param lst: list to hash :type lst: list of strings :return: hash of the list """ return md5(repr(lst).encode()).digest() if sys.hexversion < 0x3000000: def h_list_python2(lst): return md5(repr(lst)).digest() h_list_python2.__doc__ = h_list.__doc__ h_list = h_list_python2 def h_fun(fun): """ Hash functions :param fun: function to hash :type fun: function :return: hash of the function :rtype: string or bytes """ try: return fun.code except AttributeError: if isinstance(fun, functools.partial): code = list(fun.args) # The method items() provides a sequence of tuples where the first element # represents an optional argument of the partial function application # # The sorting result outcome will be consistent because: # 1. tuples are compared in order of their elements # 2. optional argument namess are unique code.extend(sorted(fun.keywords.items())) code.append(h_fun(fun.func)) fun.code = h_list(code) return fun.code try: h = inspect.getsource(fun) except EnvironmentError: h = 'nocode' try: fun.code = h except AttributeError: pass return h def h_cmd(ins): """ Hashes objects recursively :param ins: input object :type ins: string or list or tuple or function :rtype: string or bytes """ # this function is not meant to be particularly fast if isinstance(ins, str): # a command is either a string ret = ins elif isinstance(ins, list) or isinstance(ins, tuple): # or a list of functions/strings ret = str([h_cmd(x) for x in ins]) else: # or just a python function ret = str(h_fun(ins)) if sys.hexversion > 0x3000000: ret = ret.encode('latin-1', 'xmlcharrefreplace') return ret reg_subst = re.compile(r"(\\\\)|(\$\$)|\$\{([^}]+)\}") def subst_vars(expr, params): """ Replaces ${VAR} with the value of VAR taken from a dict or a config set:: from waflib import Utils s = Utils.subst_vars('${PREFIX}/bin', env) :type expr: string :param expr: String to perform substitution on :param params: Dictionary or config set to look up variable values. """ def repl_var(m): if m.group(1): return '\\' if m.group(2): return '$' try: # ConfigSet instances may contain lists return params.get_flat(m.group(3)) except AttributeError: return params[m.group(3)] # if you get a TypeError, it means that 'expr' is not a string... # Utils.subst_vars(None, env) will not work return reg_subst.sub(repl_var, expr) def destos_to_binfmt(key): """ Returns the binary format based on the unversioned platform name, and defaults to ``elf`` if nothing is found. :param key: platform name :type key: string :return: string representing the binary format """ if key == 'darwin': return 'mac-o' elif key in ('win32', 'cygwin', 'uwin', 'msys'): return 'pe' return 'elf' def unversioned_sys_platform(): """ Returns the unversioned platform name. Some Python platform names contain versions, that depend on the build environment, e.g. linux2, freebsd6, etc. This returns the name without the version number. Exceptions are os2 and win32, which are returned verbatim. :rtype: string :return: Unversioned platform name """ s = sys.platform if s.startswith('java'): # The real OS is hidden under the JVM. from java.lang import System s = System.getProperty('os.name') # see http://lopica.sourceforge.net/os.html for a list of possible values if s == 'Mac OS X': return 'darwin' elif s.startswith('Windows '): return 'win32' elif s == 'OS/2': return 'os2' elif s == 'HP-UX': return 'hp-ux' elif s in ('SunOS', 'Solaris'): return 'sunos' else: s = s.lower() # powerpc == darwin for our purposes if s == 'powerpc': return 'darwin' if s == 'win32' or s == 'os2': return s if s == 'cli' and os.name == 'nt': # ironpython is only on windows as far as we know return 'win32' return re.split(r'\d+$', s)[0] def nada(*k, **kw): """ Does nothing :return: None """ pass class Timer(object): """ Simple object for timing the execution of commands. Its string representation is the duration:: from waflib.Utils import Timer timer = Timer() a_few_operations() s = str(timer) """ def __init__(self): self.start_time = self.now() def __str__(self): delta = self.now() - self.start_time if not isinstance(delta, datetime.timedelta): delta = datetime.timedelta(seconds=delta) days = delta.days hours, rem = divmod(delta.seconds, 3600) minutes, seconds = divmod(rem, 60) seconds += delta.microseconds * 1e-6 result = '' if days: result += '%dd' % days if days or hours: result += '%dh' % hours if days or hours or minutes: result += '%dm' % minutes return '%s%.3fs' % (result, seconds) def now(self): return datetime.datetime.utcnow() if hasattr(time, 'perf_counter'): def now(self): return time.perf_counter() def read_la_file(path): """ Reads property files, used by msvc.py :param path: file to read :type path: string """ sp = re.compile(r'^([^=]+)=\'(.*)\'$') dc = {} for line in readf(path).splitlines(): try: _, left, right, _ = sp.split(line.strip()) dc[left] = right except ValueError: pass return dc def run_once(fun): """ Decorator: let a function cache its results, use like this:: @run_once def foo(k): return 345*2343 .. note:: in practice this can cause memory leaks, prefer a :py:class:`waflib.Utils.lru_cache` :param fun: function to execute :type fun: function :return: the return value of the function executed """ cache = {} def wrap(*k): try: return cache[k] except KeyError: ret = fun(*k) cache[k] = ret return ret wrap.__cache__ = cache wrap.__name__ = fun.__name__ return wrap def get_registry_app_path(key, filename): """ Returns the value of a registry key for an executable :type key: string :type filename: list of string """ if not winreg: return None try: result = winreg.QueryValue(key, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\%s.exe" % filename[0]) except OSError: pass else: if os.path.isfile(result): return result def lib64(): """ Guess the default ``/usr/lib`` extension for 64-bit applications :return: '64' or '' :rtype: string """ # default settings for /usr/lib if os.sep == '/': if platform.architecture()[0] == '64bit': if os.path.exists('/usr/lib64') and not os.path.exists('/usr/lib32'): return '64' return '' def loose_version(ver_str): # private for the time being! # see #2402 lst = re.split(r'([.]|\\d+|[a-zA-Z])', ver_str) ver = [] for i, val in enumerate(lst): try: ver.append(int(val)) except ValueError: if val != '.': ver.append(val) return ver def sane_path(p): # private function for the time being! return os.path.abspath(os.path.expanduser(p)) process_pool = [] """ List of processes started to execute sub-process commands """ def get_process(): """ Returns a process object that can execute commands as sub-processes :rtype: subprocess.Popen """ try: return process_pool.pop() except IndexError: filepath = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'processor.py' cmd = [sys.executable, '-c', readf(filepath)] return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0, close_fds=not is_win32) def run_prefork_process(cmd, kwargs, cargs): """ Delegates process execution to a pre-forked process instance. """ if not kwargs.get('env'): kwargs['env'] = dict(os.environ) try: obj = base64.b64encode(cPickle.dumps([cmd, kwargs, cargs])) except (TypeError, AttributeError): return run_regular_process(cmd, kwargs, cargs) proc = get_process() if not proc: return run_regular_process(cmd, kwargs, cargs) proc.stdin.write(obj) proc.stdin.write('\n'.encode()) proc.stdin.flush() obj = proc.stdout.readline() if not obj: raise OSError('Preforked sub-process %r died' % proc.pid) process_pool.append(proc) lst = cPickle.loads(base64.b64decode(obj)) # Jython wrapper failures (bash/execvp) assert len(lst) == 5 ret, out, err, ex, trace = lst if ex: if ex == 'OSError': raise OSError(trace) elif ex == 'ValueError': raise ValueError(trace) elif ex == 'TimeoutExpired': exc = TimeoutExpired(cmd, timeout=cargs['timeout'], output=out) exc.stderr = err raise exc else: raise Exception(trace) return ret, out, err def lchown(path, user=-1, group=-1): """ Change the owner/group of a path, raises an OSError if the ownership change fails. :param user: user to change :type user: int or str :param group: group to change :type group: int or str """ if isinstance(user, str): import pwd entry = pwd.getpwnam(user) if not entry: raise OSError('Unknown user %r' % user) user = entry[2] if isinstance(group, str): import grp entry = grp.getgrnam(group) if not entry: raise OSError('Unknown group %r' % group) group = entry[2] return os.lchown(path, user, group) def run_regular_process(cmd, kwargs, cargs={}): """ Executes a subprocess command by using subprocess.Popen """ proc = subprocess.Popen(cmd, **kwargs) if kwargs.get('stdout') or kwargs.get('stderr'): try: out, err = proc.communicate(**cargs) except TimeoutExpired: if kwargs.get('start_new_session') and hasattr(os, 'killpg'): os.killpg(proc.pid, signal.SIGKILL) else: proc.kill() out, err = proc.communicate() exc = TimeoutExpired(proc.args, timeout=cargs['timeout'], output=out) exc.stderr = err raise exc status = proc.returncode else: out, err = (None, None) try: status = proc.wait(**cargs) except TimeoutExpired as e: if kwargs.get('start_new_session') and hasattr(os, 'killpg'): os.killpg(proc.pid, signal.SIGKILL) else: proc.kill() proc.wait() raise e return status, out, err def run_process(cmd, kwargs, cargs={}): """ Executes a subprocess by using a pre-forked process when possible or falling back to subprocess.Popen. See :py:func:`waflib.Utils.run_prefork_process` and :py:func:`waflib.Utils.run_regular_process` """ if kwargs.get('stdout') and kwargs.get('stderr'): return run_prefork_process(cmd, kwargs, cargs) else: return run_regular_process(cmd, kwargs, cargs) def alloc_process_pool(n, force=False): """ Allocates an amount of processes to the default pool so its size is at least *n*. It is useful to call this function early so that the pre-forked processes use as little memory as possible. :param n: pool size :type n: integer :param force: if True then *n* more processes are added to the existing pool :type force: bool """ # mandatory on python2, unnecessary on python >= 3.2 global run_process, get_process, alloc_process_pool if not force: n = max(n - len(process_pool), 0) try: lst = [get_process() for x in range(n)] except OSError: run_process = run_regular_process get_process = alloc_process_pool = nada else: for x in lst: process_pool.append(x) def atexit_pool(): for k in process_pool: try: os.kill(k.pid, 9) except OSError: pass else: k.wait() # see #1889 if (sys.hexversion<0x207000f and not is_win32) or sys.hexversion>=0x306000f: atexit.register(atexit_pool) if os.environ.get('WAF_NO_PREFORK') or sys.platform == 'cli' or not sys.executable: run_process = run_regular_process get_process = alloc_process_pool = nada hamster-3.0.3/waflib/__init__.py000066400000000000000000000001071452646177100165500ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2018 (ita) hamster-3.0.3/waflib/ansiterm.py000066400000000000000000000252731452646177100166460ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 """ Emulate a vt100 terminal in cmd.exe By wrapping sys.stdout / sys.stderr with Ansiterm, the vt100 escape characters will be interpreted and the equivalent actions will be performed with Win32 console commands. """ import os, re, sys from waflib import Utils wlock = Utils.threading.Lock() try: from ctypes import Structure, windll, c_short, c_ushort, c_ulong, c_int, byref, c_wchar, POINTER, c_long except ImportError: class AnsiTerm(object): def __init__(self, stream): self.stream = stream try: self.errors = self.stream.errors except AttributeError: pass # python 2.5 self.encoding = self.stream.encoding def write(self, txt): try: wlock.acquire() self.stream.write(txt) self.stream.flush() finally: wlock.release() def fileno(self): return self.stream.fileno() def flush(self): self.stream.flush() def isatty(self): return self.stream.isatty() else: class COORD(Structure): _fields_ = [("X", c_short), ("Y", c_short)] class SMALL_RECT(Structure): _fields_ = [("Left", c_short), ("Top", c_short), ("Right", c_short), ("Bottom", c_short)] class CONSOLE_SCREEN_BUFFER_INFO(Structure): _fields_ = [("Size", COORD), ("CursorPosition", COORD), ("Attributes", c_ushort), ("Window", SMALL_RECT), ("MaximumWindowSize", COORD)] class CONSOLE_CURSOR_INFO(Structure): _fields_ = [('dwSize', c_ulong), ('bVisible', c_int)] try: _type = unicode except NameError: _type = str to_int = lambda number, default: number and int(number) or default STD_OUTPUT_HANDLE = -11 STD_ERROR_HANDLE = -12 windll.kernel32.GetStdHandle.argtypes = [c_ulong] windll.kernel32.GetStdHandle.restype = c_ulong windll.kernel32.GetConsoleScreenBufferInfo.argtypes = [c_ulong, POINTER(CONSOLE_SCREEN_BUFFER_INFO)] windll.kernel32.GetConsoleScreenBufferInfo.restype = c_long windll.kernel32.SetConsoleTextAttribute.argtypes = [c_ulong, c_ushort] windll.kernel32.SetConsoleTextAttribute.restype = c_long windll.kernel32.FillConsoleOutputCharacterW.argtypes = [c_ulong, c_wchar, c_ulong, POINTER(COORD), POINTER(c_ulong)] windll.kernel32.FillConsoleOutputCharacterW.restype = c_long windll.kernel32.FillConsoleOutputAttribute.argtypes = [c_ulong, c_ushort, c_ulong, POINTER(COORD), POINTER(c_ulong) ] windll.kernel32.FillConsoleOutputAttribute.restype = c_long windll.kernel32.SetConsoleCursorPosition.argtypes = [c_ulong, POINTER(COORD) ] windll.kernel32.SetConsoleCursorPosition.restype = c_long windll.kernel32.SetConsoleCursorInfo.argtypes = [c_ulong, POINTER(CONSOLE_CURSOR_INFO)] windll.kernel32.SetConsoleCursorInfo.restype = c_long class AnsiTerm(object): """ emulate a vt100 terminal in cmd.exe """ def __init__(self, s): self.stream = s try: self.errors = s.errors except AttributeError: pass # python2.5 self.encoding = s.encoding self.cursor_history = [] handle = (s.fileno() == 2) and STD_ERROR_HANDLE or STD_OUTPUT_HANDLE self.hconsole = windll.kernel32.GetStdHandle(handle) self._sbinfo = CONSOLE_SCREEN_BUFFER_INFO() self._csinfo = CONSOLE_CURSOR_INFO() windll.kernel32.GetConsoleCursorInfo(self.hconsole, byref(self._csinfo)) # just to double check that the console is usable self._orig_sbinfo = CONSOLE_SCREEN_BUFFER_INFO() r = windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(self._orig_sbinfo)) self._isatty = r == 1 def screen_buffer_info(self): """ Updates self._sbinfo and returns it """ windll.kernel32.GetConsoleScreenBufferInfo(self.hconsole, byref(self._sbinfo)) return self._sbinfo def clear_line(self, param): mode = param and int(param) or 0 sbinfo = self.screen_buffer_info() if mode == 1: # Clear from beginning of line to cursor position line_start = COORD(0, sbinfo.CursorPosition.Y) line_length = sbinfo.Size.X elif mode == 2: # Clear entire line line_start = COORD(sbinfo.CursorPosition.X, sbinfo.CursorPosition.Y) line_length = sbinfo.Size.X - sbinfo.CursorPosition.X else: # Clear from cursor position to end of line line_start = sbinfo.CursorPosition line_length = sbinfo.Size.X - sbinfo.CursorPosition.X chars_written = c_ulong() windll.kernel32.FillConsoleOutputCharacterW(self.hconsole, c_wchar(' '), line_length, line_start, byref(chars_written)) windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, line_length, line_start, byref(chars_written)) def clear_screen(self, param): mode = to_int(param, 0) sbinfo = self.screen_buffer_info() if mode == 1: # Clear from beginning of screen to cursor position clear_start = COORD(0, 0) clear_length = sbinfo.CursorPosition.X * sbinfo.CursorPosition.Y elif mode == 2: # Clear entire screen and return cursor to home clear_start = COORD(0, 0) clear_length = sbinfo.Size.X * sbinfo.Size.Y windll.kernel32.SetConsoleCursorPosition(self.hconsole, clear_start) else: # Clear from cursor position to end of screen clear_start = sbinfo.CursorPosition clear_length = ((sbinfo.Size.X - sbinfo.CursorPosition.X) + sbinfo.Size.X * (sbinfo.Size.Y - sbinfo.CursorPosition.Y)) chars_written = c_ulong() windll.kernel32.FillConsoleOutputCharacterW(self.hconsole, c_wchar(' '), clear_length, clear_start, byref(chars_written)) windll.kernel32.FillConsoleOutputAttribute(self.hconsole, sbinfo.Attributes, clear_length, clear_start, byref(chars_written)) def push_cursor(self, param): sbinfo = self.screen_buffer_info() self.cursor_history.append(sbinfo.CursorPosition) def pop_cursor(self, param): if self.cursor_history: old_pos = self.cursor_history.pop() windll.kernel32.SetConsoleCursorPosition(self.hconsole, old_pos) def set_cursor(self, param): y, sep, x = param.partition(';') x = to_int(x, 1) - 1 y = to_int(y, 1) - 1 sbinfo = self.screen_buffer_info() new_pos = COORD( min(max(0, x), sbinfo.Size.X), min(max(0, y), sbinfo.Size.Y) ) windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) def set_column(self, param): x = to_int(param, 1) - 1 sbinfo = self.screen_buffer_info() new_pos = COORD( min(max(0, x), sbinfo.Size.X), sbinfo.CursorPosition.Y ) windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) def move_cursor(self, x_offset=0, y_offset=0): sbinfo = self.screen_buffer_info() new_pos = COORD( min(max(0, sbinfo.CursorPosition.X + x_offset), sbinfo.Size.X), min(max(0, sbinfo.CursorPosition.Y + y_offset), sbinfo.Size.Y) ) windll.kernel32.SetConsoleCursorPosition(self.hconsole, new_pos) def move_up(self, param): self.move_cursor(y_offset = -to_int(param, 1)) def move_down(self, param): self.move_cursor(y_offset = to_int(param, 1)) def move_left(self, param): self.move_cursor(x_offset = -to_int(param, 1)) def move_right(self, param): self.move_cursor(x_offset = to_int(param, 1)) def next_line(self, param): sbinfo = self.screen_buffer_info() self.move_cursor( x_offset = -sbinfo.CursorPosition.X, y_offset = to_int(param, 1) ) def prev_line(self, param): sbinfo = self.screen_buffer_info() self.move_cursor( x_offset = -sbinfo.CursorPosition.X, y_offset = -to_int(param, 1) ) def rgb2bgr(self, c): return ((c&1) << 2) | (c&2) | ((c&4)>>2) def set_color(self, param): cols = param.split(';') sbinfo = self.screen_buffer_info() attr = sbinfo.Attributes for c in cols: c = to_int(c, 0) if 29 < c < 38: # fgcolor attr = (attr & 0xfff0) | self.rgb2bgr(c - 30) elif 39 < c < 48: # bgcolor attr = (attr & 0xff0f) | (self.rgb2bgr(c - 40) << 4) elif c == 0: # reset attr = self._orig_sbinfo.Attributes elif c == 1: # strong attr |= 0x08 elif c == 4: # blink not available -> bg intensity attr |= 0x80 elif c == 7: # negative attr = (attr & 0xff88) | ((attr & 0x70) >> 4) | ((attr & 0x07) << 4) windll.kernel32.SetConsoleTextAttribute(self.hconsole, attr) def show_cursor(self,param): self._csinfo.bVisible = 1 windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(self._csinfo)) def hide_cursor(self,param): self._csinfo.bVisible = 0 windll.kernel32.SetConsoleCursorInfo(self.hconsole, byref(self._csinfo)) ansi_command_table = { 'A': move_up, 'B': move_down, 'C': move_right, 'D': move_left, 'E': next_line, 'F': prev_line, 'G': set_column, 'H': set_cursor, 'f': set_cursor, 'J': clear_screen, 'K': clear_line, 'h': show_cursor, 'l': hide_cursor, 'm': set_color, 's': push_cursor, 'u': pop_cursor, } # Match either the escape sequence or text not containing escape sequence ansi_tokens = re.compile(r'(?:\x1b\[([0-9?;]*)([a-zA-Z])|([^\x1b]+))') def write(self, text): try: wlock.acquire() if self._isatty: for param, cmd, txt in self.ansi_tokens.findall(text): if cmd: cmd_func = self.ansi_command_table.get(cmd) if cmd_func: cmd_func(self, param) else: self.writeconsole(txt) else: # no support for colors in the console, just output the text: # eclipse or msys may be able to interpret the escape sequences self.stream.write(text) finally: wlock.release() def writeconsole(self, txt): chars_written = c_ulong() writeconsole = windll.kernel32.WriteConsoleA if isinstance(txt, _type): writeconsole = windll.kernel32.WriteConsoleW # MSDN says that there is a shared buffer of 64 KB for the console # writes. Attempt to not get ERROR_NOT_ENOUGH_MEMORY, see waf issue #746 done = 0 todo = len(txt) chunk = 32<<10 while todo != 0: doing = min(chunk, todo) buf = txt[done:done+doing] r = writeconsole(self.hconsole, buf, doing, byref(chars_written), None) if r == 0: chunk >>= 1 continue done += doing todo -= doing def fileno(self): return self.stream.fileno() def flush(self): pass def isatty(self): return self._isatty if sys.stdout.isatty() or sys.stderr.isatty(): handle = sys.stdout.isatty() and STD_OUTPUT_HANDLE or STD_ERROR_HANDLE console = windll.kernel32.GetStdHandle(handle) sbinfo = CONSOLE_SCREEN_BUFFER_INFO() def get_term_cols(): windll.kernel32.GetConsoleScreenBufferInfo(console, byref(sbinfo)) # Issue 1401 - the progress bar cannot reach the last character return sbinfo.Size.X - 1 # just try and see try: import struct, fcntl, termios except ImportError: pass else: if (sys.stdout.isatty() or sys.stderr.isatty()) and os.environ.get('TERM', '') not in ('dumb', 'emacs'): FD = sys.stdout.isatty() and sys.stdout.fileno() or sys.stderr.fileno() def fun(): return struct.unpack("HHHH", fcntl.ioctl(FD, termios.TIOCGWINSZ, struct.pack("HHHH", 0, 0, 0, 0)))[1] try: fun() except Exception as e: pass else: get_term_cols = fun hamster-3.0.3/waflib/extras/000077500000000000000000000000001452646177100157475ustar00rootroot00000000000000hamster-3.0.3/waflib/extras/__init__.py000066400000000000000000000001071452646177100200560ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2005-2010 (ita) hamster-3.0.3/waflib/extras/batched_cc.py000066400000000000000000000111261452646177100203610ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2015 (ita) """ Instead of compiling object files one by one, c/c++ compilers are often able to compile at once: cc -c ../file1.c ../file2.c ../file3.c Files are output on the directory where the compiler is called, and dependencies are more difficult to track (do not run the command on all source files if only one file changes) As such, we do as if the files were compiled one by one, but no command is actually run: replace each cc/cpp Task by a TaskSlave. A new task called TaskMaster collects the signatures from each slave and finds out the command-line to run. Just import this module to start using it: def build(bld): bld.load('batched_cc') Note that this is provided as an example, unity builds are recommended for best performance results (fewer tasks and fewer jobs to execute). See waflib/extras/unity.py. """ from waflib import Task, Utils from waflib.TaskGen import extension, feature, after_method from waflib.Tools import c, cxx MAX_BATCH = 50 c_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${tsk.batch_incpaths()} ${DEFINES_ST:DEFINES} -c ${SRCLST} ${CXX_TGT_F_BATCHED} ${CPPFLAGS}' c_fun, _ = Task.compile_fun_noshell(c_str) cxx_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${tsk.batch_incpaths()} ${DEFINES_ST:DEFINES} -c ${SRCLST} ${CXX_TGT_F_BATCHED} ${CPPFLAGS}' cxx_fun, _ = Task.compile_fun_noshell(cxx_str) count = 70000 class batch(Task.Task): color = 'PINK' after = ['c', 'cxx'] before = ['cprogram', 'cshlib', 'cstlib', 'cxxprogram', 'cxxshlib', 'cxxstlib'] def uid(self): return Utils.h_list([Task.Task.uid(self), self.generator.idx, self.generator.path.abspath(), self.generator.target]) def __str__(self): return 'Batch compilation for %d slaves' % len(self.slaves) def __init__(self, *k, **kw): Task.Task.__init__(self, *k, **kw) self.slaves = [] self.inputs = [] self.hasrun = 0 global count count += 1 self.idx = count def add_slave(self, slave): self.slaves.append(slave) self.set_run_after(slave) def runnable_status(self): for t in self.run_after: if not t.hasrun: return Task.ASK_LATER for t in self.slaves: #if t.executed: if t.hasrun != Task.SKIPPED: return Task.RUN_ME return Task.SKIP_ME def get_cwd(self): return self.slaves[0].outputs[0].parent def batch_incpaths(self): st = self.env.CPPPATH_ST return [st % node.abspath() for node in self.generator.includes_nodes] def run(self): self.outputs = [] srclst = [] slaves = [] for t in self.slaves: if t.hasrun != Task.SKIPPED: slaves.append(t) srclst.append(t.inputs[0].abspath()) self.env.SRCLST = srclst if self.slaves[0].__class__.__name__ == 'c': ret = c_fun(self) else: ret = cxx_fun(self) if ret: return ret for t in slaves: t.old_post_run() def hook(cls_type): def n_hook(self, node): ext = '.obj' if self.env.CC_NAME == 'msvc' else '.o' name = node.name k = name.rfind('.') if k >= 0: basename = name[:k] + ext else: basename = name + ext outdir = node.parent.get_bld().make_node('%d' % self.idx) outdir.mkdir() out = outdir.find_or_declare(basename) task = self.create_task(cls_type, node, out) try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] if not getattr(self, 'masters', None): self.masters = {} self.allmasters = [] def fix_path(tsk): if self.env.CC_NAME == 'msvc': tsk.env.append_unique('CXX_TGT_F_BATCHED', '/Fo%s\\' % outdir.abspath()) if not node.parent in self.masters: m = self.masters[node.parent] = self.master = self.create_task('batch') fix_path(m) self.allmasters.append(m) else: m = self.masters[node.parent] if len(m.slaves) > MAX_BATCH: m = self.masters[node.parent] = self.master = self.create_task('batch') fix_path(m) self.allmasters.append(m) m.add_slave(task) return task return n_hook extension('.c')(hook('c')) extension('.cpp','.cc','.cxx','.C','.c++')(hook('cxx')) @feature('cprogram', 'cshlib', 'cstaticlib', 'cxxprogram', 'cxxshlib', 'cxxstlib') @after_method('apply_link') def link_after_masters(self): if getattr(self, 'allmasters', None): for m in self.allmasters: self.link_task.set_run_after(m) # Modify the c and cxx task classes - in theory it would be best to # create subclasses and to re-map the c/c++ extensions for x in ('c', 'cxx'): t = Task.classes[x] def run(self): pass def post_run(self): pass setattr(t, 'oldrun', getattr(t, 'run', None)) setattr(t, 'run', run) setattr(t, 'old_post_run', t.post_run) setattr(t, 'post_run', post_run) hamster-3.0.3/waflib/extras/biber.py000066400000000000000000000031351452646177100174060ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) """ Latex processing using "biber" """ import os from waflib import Task, Logs from waflib.Tools import tex as texmodule class tex(texmodule.tex): biber_fun, _ = Task.compile_fun('${BIBER} ${BIBERFLAGS} ${SRCFILE}',shell=False) biber_fun.__doc__ = """ Execute the program **biber** """ def bibfile(self): return None def bibunits(self): self.env.env = {} self.env.env.update(os.environ) self.env.env.update({'BIBINPUTS': self.texinputs(), 'BSTINPUTS': self.texinputs()}) self.env.SRCFILE = self.aux_nodes[0].name[:-4] if not self.env['PROMPT_LATEX']: self.env.append_unique('BIBERFLAGS', '--quiet') path = self.aux_nodes[0].abspath()[:-4] + '.bcf' if os.path.isfile(path): Logs.warn('calling biber') self.check_status('error when calling biber, check %s.blg for errors' % (self.env.SRCFILE), self.biber_fun()) else: super(tex, self).bibfile() super(tex, self).bibunits() class latex(tex): texfun, vars = Task.compile_fun('${LATEX} ${LATEXFLAGS} ${SRCFILE}', shell=False) class pdflatex(tex): texfun, vars = Task.compile_fun('${PDFLATEX} ${PDFLATEXFLAGS} ${SRCFILE}', shell=False) class xelatex(tex): texfun, vars = Task.compile_fun('${XELATEX} ${XELATEXFLAGS} ${SRCFILE}', shell=False) def configure(self): """ Almost the same as in tex.py, but try to detect 'biber' """ v = self.env for p in ' biber tex latex pdflatex xelatex bibtex dvips dvipdf ps2pdf makeindex pdf2ps'.split(): try: self.find_program(p, var=p.upper()) except self.errors.ConfigurationError: pass v['DVIPSFLAGS'] = '-Ppdf' hamster-3.0.3/waflib/extras/bjam.py000066400000000000000000000074651452646177100172460ustar00rootroot00000000000000#! /usr/bin/env python # per rosengren 2011 from os import sep, readlink from waflib import Logs from waflib.TaskGen import feature, after_method from waflib.Task import Task, always_run def options(opt): grp = opt.add_option_group('Bjam Options') grp.add_option('--bjam_src', default=None, help='You can find it in /tools/jam/src') grp.add_option('--bjam_uname', default='linuxx86_64', help='bjam is built in /bin./bjam') grp.add_option('--bjam_config', default=None) grp.add_option('--bjam_toolset', default=None) def configure(cnf): if not cnf.env.BJAM_SRC: cnf.env.BJAM_SRC = cnf.options.bjam_src if not cnf.env.BJAM_UNAME: cnf.env.BJAM_UNAME = cnf.options.bjam_uname try: cnf.find_program('bjam', path_list=[ cnf.env.BJAM_SRC + sep + 'bin.' + cnf.env.BJAM_UNAME ]) except Exception: cnf.env.BJAM = None if not cnf.env.BJAM_CONFIG: cnf.env.BJAM_CONFIG = cnf.options.bjam_config if not cnf.env.BJAM_TOOLSET: cnf.env.BJAM_TOOLSET = cnf.options.bjam_toolset @feature('bjam') @after_method('process_rule') def process_bjam(self): if not self.bld.env.BJAM: self.create_task('bjam_creator') self.create_task('bjam_build') self.create_task('bjam_installer') if getattr(self, 'always', False): always_run(bjam_creator) always_run(bjam_build) always_run(bjam_installer) class bjam_creator(Task): ext_out = 'bjam_exe' vars=['BJAM_SRC', 'BJAM_UNAME'] def run(self): env = self.env gen = self.generator bjam = gen.bld.root.find_dir(env.BJAM_SRC) if not bjam: Logs.error('Can not find bjam source') return -1 bjam_exe_relpath = 'bin.' + env.BJAM_UNAME + '/bjam' bjam_exe = bjam.find_resource(bjam_exe_relpath) if bjam_exe: env.BJAM = bjam_exe.srcpath() return 0 bjam_cmd = ['./build.sh'] Logs.debug('runner: ' + bjam.srcpath() + '> ' + str(bjam_cmd)) result = self.exec_command(bjam_cmd, cwd=bjam.srcpath()) if not result == 0: Logs.error('bjam failed') return -1 bjam_exe = bjam.find_resource(bjam_exe_relpath) if bjam_exe: env.BJAM = bjam_exe.srcpath() return 0 Logs.error('bjam failed') return -1 class bjam_build(Task): ext_in = 'bjam_exe' ext_out = 'install' vars = ['BJAM_TOOLSET'] def run(self): env = self.env gen = self.generator path = gen.path bld = gen.bld if hasattr(gen, 'root'): build_root = path.find_node(gen.root) else: build_root = path jam = bld.srcnode.find_resource(env.BJAM_CONFIG) if jam: Logs.debug('bjam: Using jam configuration from ' + jam.srcpath()) jam_rel = jam.relpath_gen(build_root) else: Logs.warn('No build configuration in build_config/user-config.jam. Using default') jam_rel = None bjam_exe = bld.srcnode.find_node(env.BJAM) if not bjam_exe: Logs.error('env.BJAM is not set') return -1 bjam_exe_rel = bjam_exe.relpath_gen(build_root) cmd = ([bjam_exe_rel] + (['--user-config=' + jam_rel] if jam_rel else []) + ['--stagedir=' + path.get_bld().path_from(build_root)] + ['--debug-configuration'] + ['--with-' + lib for lib in self.generator.target] + (['toolset=' + env.BJAM_TOOLSET] if env.BJAM_TOOLSET else []) + ['link=' + 'shared'] + ['variant=' + 'release'] ) Logs.debug('runner: ' + build_root.srcpath() + '> ' + str(cmd)) ret = self.exec_command(cmd, cwd=build_root.srcpath()) if ret != 0: return ret self.set_outputs(path.get_bld().ant_glob('lib/*') + path.get_bld().ant_glob('bin/*')) return 0 class bjam_installer(Task): ext_in = 'install' def run(self): gen = self.generator path = gen.path for idir, pat in (('${LIBDIR}', 'lib/*'), ('${BINDIR}', 'bin/*')): files = [] for n in path.get_bld().ant_glob(pat): try: t = readlink(n.srcpath()) gen.bld.symlink_as(sep.join([idir, n.name]), t, postpone=False) except OSError: files.append(n) gen.bld.install_files(idir, files, postpone=False) return 0 hamster-3.0.3/waflib/extras/blender.py000066400000000000000000000057751452646177100177520ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Michal Proszek, 2014 (poxip) """ Detect the version of Blender, path and install the extension: def options(opt): opt.load('blender') def configure(cnf): cnf.load('blender') def build(bld): bld(name='io_mesh_raw', feature='blender', files=['file1.py', 'file2.py'] ) If name variable is empty, files are installed in scripts/addons, otherwise scripts/addons/name Use ./waf configure --system to set the installation directory to system path """ import os import re from getpass import getuser from waflib import Utils from waflib.TaskGen import feature from waflib.Configure import conf def options(opt): opt.add_option( '-s', '--system', dest='directory_system', default=False, action='store_true', help='determines installation directory (default: user)' ) @conf def find_blender(ctx): '''Return version number of blender, if not exist return None''' blender = ctx.find_program('blender') output = ctx.cmd_and_log(blender + ['--version']) m = re.search(r'Blender\s*((\d+(\.|))*)', output) if not m: ctx.fatal('Could not retrieve blender version') try: blender_version = m.group(1) except IndexError: ctx.fatal('Could not retrieve blender version') ctx.env['BLENDER_VERSION'] = blender_version return blender @conf def configure_paths(ctx): """Setup blender paths""" # Get the username user = getuser() _platform = Utils.unversioned_sys_platform() config_path = {'user': '', 'system': ''} if _platform.startswith('linux'): config_path['user'] = '/home/%s/.config/blender/' % user config_path['system'] = '/usr/share/blender/' elif _platform == 'darwin': # MAC OS X config_path['user'] = \ '/Users/%s/Library/Application Support/Blender/' % user config_path['system'] = '/Library/Application Support/Blender/' elif Utils.is_win32: # Windows appdata_path = ctx.getenv('APPDATA').replace('\\', '/') homedrive = ctx.getenv('HOMEDRIVE').replace('\\', '/') config_path['user'] = '%s/Blender Foundation/Blender/' % appdata_path config_path['system'] = \ '%sAll Users/AppData/Roaming/Blender Foundation/Blender/' % homedrive else: ctx.fatal( 'Unsupported platform. ' 'Available platforms: Linux, OSX, MS-Windows.' ) blender_version = ctx.env['BLENDER_VERSION'] config_path['user'] += blender_version + '/' config_path['system'] += blender_version + '/' ctx.env['BLENDER_CONFIG_DIR'] = os.path.abspath(config_path['user']) if ctx.options.directory_system: ctx.env['BLENDER_CONFIG_DIR'] = config_path['system'] ctx.env['BLENDER_ADDONS_DIR'] = os.path.join( ctx.env['BLENDER_CONFIG_DIR'], 'scripts/addons' ) Utils.check_dir(ctx.env['BLENDER_ADDONS_DIR']) def configure(ctx): ctx.find_blender() ctx.configure_paths() @feature('blender_list') def blender(self): # Two ways to install a blender extension: as a module or just .py files dest_dir = os.path.join(self.env.BLENDER_ADDONS_DIR, self.get_name()) Utils.check_dir(dest_dir) self.add_install_files(install_to=dest_dir, install_from=getattr(self, 'files', '.')) hamster-3.0.3/waflib/extras/boo.py000066400000000000000000000043501452646177100171020ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Yannick LM 2011 """ Support for the boo programming language, for example:: bld(features = "boo", # necessary feature source = "src.boo", # list of boo files gen = "world.dll", # target type = "library", # library/exe ("-target:xyz" flag) name = "world" # necessary if the target is referenced by 'use' ) """ from waflib import Task from waflib.Configure import conf from waflib.TaskGen import feature, after_method, before_method, extension @extension('.boo') def boo_hook(self, node): # Nothing here yet ... # TODO filter the non-boo source files in 'apply_booc' and remove this method pass @feature('boo') @before_method('process_source') def apply_booc(self): """Create a booc task """ src_nodes = self.to_nodes(self.source) out_node = self.path.find_or_declare(self.gen) self.boo_task = self.create_task('booc', src_nodes, [out_node]) # Set variables used by the 'booc' task self.boo_task.env.OUT = '-o:%s' % out_node.abspath() # type is "exe" by default type = getattr(self, "type", "exe") self.boo_task.env.BOO_TARGET_TYPE = "-target:%s" % type @feature('boo') @after_method('apply_boo') def use_boo(self): """" boo applications honor the **use** keyword:: """ dep_names = self.to_list(getattr(self, 'use', [])) for dep_name in dep_names: dep_task_gen = self.bld.get_tgen_by_name(dep_name) if not dep_task_gen: continue dep_task_gen.post() dep_task = getattr(dep_task_gen, 'boo_task', None) if not dep_task: # Try a cs task: dep_task = getattr(dep_task_gen, 'cs_task', None) if not dep_task: # Try a link task: dep_task = getattr(dep_task, 'link_task', None) if not dep_task: # Abort ... continue self.boo_task.set_run_after(dep_task) # order self.boo_task.dep_nodes.extend(dep_task.outputs) # dependency self.boo_task.env.append_value('BOO_FLAGS', '-reference:%s' % dep_task.outputs[0].abspath()) class booc(Task.Task): """Compiles .boo files """ color = 'YELLOW' run_str = '${BOOC} ${BOO_FLAGS} ${BOO_TARGET_TYPE} ${OUT} ${SRC}' @conf def check_booc(self): self.find_program('booc', 'BOOC') self.env.BOO_FLAGS = ['-nologo'] def configure(self): """Check that booc is available """ self.check_booc() hamster-3.0.3/waflib/extras/boost.py000066400000000000000000000441751452646177100174620ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # # partially based on boost.py written by Gernot Vormayr # written by Ruediger Sonderfeld , 2008 # modified by Bjoern Michaelsen, 2008 # modified by Luca Fossati, 2008 # rewritten for waf 1.5.1, Thomas Nagy, 2008 # rewritten for waf 1.6.2, Sylvain Rouquette, 2011 ''' This is an extra tool, not bundled with the default waf binary. To add the boost tool to the waf file: $ ./waf-light --tools=compat15,boost or, if you have waf >= 1.6.2 $ ./waf update --files=boost When using this tool, the wscript will look like: def options(opt): opt.load('compiler_cxx boost') def configure(conf): conf.load('compiler_cxx boost') conf.check_boost(lib='system filesystem') def build(bld): bld(source='main.cpp', target='app', use='BOOST') Options are generated, in order to specify the location of boost includes/libraries. The `check_boost` configuration function allows to specify the used boost libraries. It can also provide default arguments to the --boost-mt command-line arguments. Everything will be packaged together in a BOOST component that you can use. When using MSVC, a lot of compilation flags need to match your BOOST build configuration: - you may have to add /EHsc to your CXXFLAGS or define boost::throw_exception if BOOST_NO_EXCEPTIONS is defined. Errors: C4530 - boost libraries will try to be smart and use the (pretty but often not useful) auto-linking feature of MSVC So before calling `conf.check_boost` you might want to disabling by adding conf.env.DEFINES_BOOST += ['BOOST_ALL_NO_LIB'] Errors: - boost might also be compiled with /MT, which links the runtime statically. If you have problems with redefined symbols, self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] self.env['CXXFLAGS_%s' % var] += ['/MD', '/EHsc'] Passing `--boost-linkage_autodetect` might help ensuring having a correct linkage in some basic cases. ''' import sys import re from waflib import Utils, Logs, Errors from waflib.Configure import conf from waflib.TaskGen import feature, after_method BOOST_LIBS = ['/usr/lib', '/usr/local/lib', '/opt/local/lib', '/sw/lib', '/lib'] BOOST_INCLUDES = ['/usr/include', '/usr/local/include', '/opt/local/include', '/sw/include'] BOOST_VERSION_FILE = 'boost/version.hpp' BOOST_VERSION_CODE = ''' #include #include int main() { std::cout << BOOST_LIB_VERSION << ":" << BOOST_VERSION << std::endl; } ''' BOOST_ERROR_CODE = ''' #include int main() { boost::system::error_code c; } ''' PTHREAD_CODE = ''' #include static void* f(void*) { return 0; } int main() { pthread_t th; pthread_attr_t attr; pthread_attr_init(&attr); pthread_create(&th, &attr, &f, 0); pthread_join(th, 0); pthread_cleanup_push(0, 0); pthread_cleanup_pop(0); pthread_attr_destroy(&attr); } ''' BOOST_THREAD_CODE = ''' #include int main() { boost::thread t; } ''' BOOST_LOG_CODE = ''' #include #include #include int main() { using namespace boost::log; add_common_attributes(); add_console_log(std::clog, keywords::format = "%Message%"); BOOST_LOG_TRIVIAL(debug) << "log is working" << std::endl; } ''' # toolsets from {boost_dir}/tools/build/v2/tools/common.jam PLATFORM = Utils.unversioned_sys_platform() detect_intel = lambda env: (PLATFORM == 'win32') and 'iw' or 'il' detect_clang = lambda env: (PLATFORM == 'darwin') and 'clang-darwin' or 'clang' detect_mingw = lambda env: (re.search('MinGW', env.CXX[0])) and 'mgw' or 'gcc' BOOST_TOOLSETS = { 'borland': 'bcb', 'clang': detect_clang, 'como': 'como', 'cw': 'cw', 'darwin': 'xgcc', 'edg': 'edg', 'g++': detect_mingw, 'gcc': detect_mingw, 'icpc': detect_intel, 'intel': detect_intel, 'kcc': 'kcc', 'kylix': 'bck', 'mipspro': 'mp', 'mingw': 'mgw', 'msvc': 'vc', 'qcc': 'qcc', 'sun': 'sw', 'sunc++': 'sw', 'tru64cxx': 'tru', 'vacpp': 'xlc' } def options(opt): opt = opt.add_option_group('Boost Options') opt.add_option('--boost-includes', type='string', default='', dest='boost_includes', help='''path to the directory where the boost includes are, e.g., /path/to/boost_1_55_0/stage/include''') opt.add_option('--boost-libs', type='string', default='', dest='boost_libs', help='''path to the directory where the boost libs are, e.g., path/to/boost_1_55_0/stage/lib''') opt.add_option('--boost-mt', action='store_true', default=False, dest='boost_mt', help='select multi-threaded libraries') opt.add_option('--boost-abi', type='string', default='', dest='boost_abi', help='''select libraries with tags (gd for debug, static is automatically added), see doc Boost, Getting Started, chapter 6.1''') opt.add_option('--boost-linkage_autodetect', action="store_true", dest='boost_linkage_autodetect', help="auto-detect boost linkage options (don't get used to it / might break other stuff)") opt.add_option('--boost-toolset', type='string', default='', dest='boost_toolset', help='force a toolset e.g. msvc, vc90, \ gcc, mingw, mgw45 (default: auto)') py_version = '%d%d' % (sys.version_info[0], sys.version_info[1]) opt.add_option('--boost-python', type='string', default=py_version, dest='boost_python', help='select the lib python with this version \ (default: %s)' % py_version) @conf def __boost_get_version_file(self, d): if not d: return None dnode = self.root.find_dir(d) if dnode: return dnode.find_node(BOOST_VERSION_FILE) return None @conf def boost_get_version(self, d): """silently retrieve the boost version number""" node = self.__boost_get_version_file(d) if node: try: txt = node.read() except EnvironmentError: Logs.error("Could not read the file %r", node.abspath()) else: re_but1 = re.compile('^#define\\s+BOOST_LIB_VERSION\\s+"(.+)"', re.M) m1 = re_but1.search(txt) re_but2 = re.compile('^#define\\s+BOOST_VERSION\\s+(\\d+)', re.M) m2 = re_but2.search(txt) if m1 and m2: return (m1.group(1), m2.group(1)) return self.check_cxx(fragment=BOOST_VERSION_CODE, includes=[d], execute=True, define_ret=True).split(":") @conf def boost_get_includes(self, *k, **kw): includes = k and k[0] or kw.get('includes') if includes and self.__boost_get_version_file(includes): return includes for d in self.environ.get('INCLUDE', '').split(';') + BOOST_INCLUDES: if self.__boost_get_version_file(d): return d if includes: self.end_msg('headers not found in %s' % includes) self.fatal('The configuration failed') else: self.end_msg('headers not found, please provide a --boost-includes argument (see help)') self.fatal('The configuration failed') @conf def boost_get_toolset(self, cc): toolset = cc if not cc: build_platform = Utils.unversioned_sys_platform() if build_platform in BOOST_TOOLSETS: cc = build_platform else: cc = self.env.CXX_NAME if cc in BOOST_TOOLSETS: toolset = BOOST_TOOLSETS[cc] return isinstance(toolset, str) and toolset or toolset(self.env) @conf def __boost_get_libs_path(self, *k, **kw): ''' return the lib path and all the files in it ''' if 'files' in kw: return self.root.find_dir('.'), Utils.to_list(kw['files']) libs = k and k[0] or kw.get('libs') if libs: path = self.root.find_dir(libs) files = path.ant_glob('*boost_*') if not libs or not files: for d in self.environ.get('LIB', '').split(';') + BOOST_LIBS: if not d: continue path = self.root.find_dir(d) if path: files = path.ant_glob('*boost_*') if files: break path = self.root.find_dir(d + '64') if path: files = path.ant_glob('*boost_*') if files: break if not path: if libs: self.end_msg('libs not found in %s' % libs) self.fatal('The configuration failed') else: self.end_msg('libs not found, please provide a --boost-libs argument (see help)') self.fatal('The configuration failed') self.to_log('Found the boost path in %r with the libraries:' % path) for x in files: self.to_log(' %r' % x) return path, files @conf def boost_get_libs(self, *k, **kw): ''' return the lib path and the required libs according to the parameters ''' path, files = self.__boost_get_libs_path(**kw) files = sorted(files, key=lambda f: (len(f.name), f.name), reverse=True) toolset = self.boost_get_toolset(kw.get('toolset', '')) toolset_pat = '(-%s[0-9]{0,3})' % toolset version = '-%s' % self.env.BOOST_VERSION def find_lib(re_lib, files): for file in files: if re_lib.search(file.name): self.to_log('Found boost lib %s' % file) return file return None # extensions from Tools.ccroot.lib_patterns wo_ext = re.compile(r"\.(a|so|lib|dll|dylib)(\.[0-9\.]+)?$") def format_lib_name(name): if name.startswith('lib') and self.env.CC_NAME != 'msvc': name = name[3:] return wo_ext.sub("", name) def match_libs(lib_names, is_static): libs = [] lib_names = Utils.to_list(lib_names) if not lib_names: return libs t = [] if kw.get('mt', False): t.append('-mt') if kw.get('abi'): t.append('%s%s' % (is_static and '-s' or '-', kw['abi'])) elif is_static: t.append('-s') tags_pat = t and ''.join(t) or '' ext = is_static and self.env.cxxstlib_PATTERN or self.env.cxxshlib_PATTERN ext = ext.partition('%s')[2] # remove '%s' or 'lib%s' from PATTERN for lib in lib_names: if lib == 'python': # for instance, with python='27', # accepts '-py27', '-py2', '27', '-2.7' and '2' # but will reject '-py3', '-py26', '26' and '3' tags = '({0})?((-py{2})|(-py{1}(?=[^0-9]))|({2})|(-{1}.{3})|({1}(?=[^0-9]))|(?=[^0-9])(?!-py))'.format(tags_pat, kw['python'][0], kw['python'], kw['python'][1]) else: tags = tags_pat # Trying libraries, from most strict match to least one for pattern in ['boost_%s%s%s%s%s$' % (lib, toolset_pat, tags, version, ext), 'boost_%s%s%s%s$' % (lib, tags, version, ext), # Give up trying to find the right version 'boost_%s%s%s%s$' % (lib, toolset_pat, tags, ext), 'boost_%s%s%s$' % (lib, tags, ext), 'boost_%s%s$' % (lib, ext), 'boost_%s' % lib]: self.to_log('Trying pattern %s' % pattern) file = find_lib(re.compile(pattern), files) if file: libs.append(format_lib_name(file.name)) break else: self.end_msg('lib %s not found in %s' % (lib, path.abspath())) self.fatal('The configuration failed') return libs return path.abspath(), match_libs(kw.get('lib'), False), match_libs(kw.get('stlib'), True) @conf def _check_pthread_flag(self, *k, **kw): ''' Computes which flags should be added to CXXFLAGS and LINKFLAGS to compile in multi-threading mode Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3, boost/thread.hpp will trigger a #error if -pthread isn't used: boost/config/requires_threads.hpp:47:5: #error "Compiler threading support is not turned on. Please set the correct command line options for threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)" Based on _BOOST_PTHREAD_FLAG(): https://github.com/tsuna/boost.m4/blob/master/build-aux/boost.m4 ''' var = kw.get('uselib_store', 'BOOST') self.start_msg('Checking the flags needed to use pthreads') # The ordering *is* (sometimes) important. Some notes on the # individual items follow: # (none): in case threads are in libc; should be tried before -Kthread and # other compiler flags to prevent continual compiler warnings # -lpthreads: AIX (must check this before -lpthread) # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread) # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads) # -pthreads: Solaris/GCC # -mthreads: MinGW32/GCC, Lynx/GCC # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it # doesn't hurt to check since this sometimes defines pthreads too; # also defines -D_REENTRANT) # ... -mt is also the pthreads flag for HP/aCC # -lpthread: GNU Linux, etc. # --thread-safe: KAI C++ if Utils.unversioned_sys_platform() == "sunos": # On Solaris (at least, for some versions), libc contains stubbed # (non-functional) versions of the pthreads routines, so link-based # tests will erroneously succeed. (We need to link with -pthreads/-mt/ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather # a function called by this macro, so we could check for that, but # who knows whether they'll stub that too in a future libc.) So, # we'll just look for -pthreads and -lpthread first: boost_pthread_flags = ["-pthreads", "-lpthread", "-mt", "-pthread"] else: boost_pthread_flags = ["", "-lpthreads", "-Kthread", "-kthread", "-llthread", "-pthread", "-pthreads", "-mthreads", "-lpthread", "--thread-safe", "-mt"] for boost_pthread_flag in boost_pthread_flags: try: self.env.stash() self.env.append_value('CXXFLAGS_%s' % var, boost_pthread_flag) self.env.append_value('LINKFLAGS_%s' % var, boost_pthread_flag) self.check_cxx(code=PTHREAD_CODE, msg=None, use=var, execute=False) self.end_msg(boost_pthread_flag) return except self.errors.ConfigurationError: self.env.revert() self.end_msg('None') @conf def check_boost(self, *k, **kw): """ Initialize boost libraries to be used. Keywords: you can pass the same parameters as with the command line (without "--boost-"). Note that the command line has the priority, and should preferably be used. """ if not self.env['CXX']: self.fatal('load a c++ compiler first, conf.load("compiler_cxx")') params = { 'lib': k and k[0] or kw.get('lib'), 'stlib': kw.get('stlib') } for key, value in self.options.__dict__.items(): if not key.startswith('boost_'): continue key = key[len('boost_'):] params[key] = value and value or kw.get(key, '') var = kw.get('uselib_store', 'BOOST') self.find_program('dpkg-architecture', var='DPKG_ARCHITECTURE', mandatory=False) if self.env.DPKG_ARCHITECTURE: deb_host_multiarch = self.cmd_and_log([self.env.DPKG_ARCHITECTURE[0], '-qDEB_HOST_MULTIARCH']) BOOST_LIBS.insert(0, '/usr/lib/%s' % deb_host_multiarch.strip()) self.start_msg('Checking boost includes') self.env['INCLUDES_%s' % var] = inc = self.boost_get_includes(**params) versions = self.boost_get_version(inc) self.env.BOOST_VERSION = versions[0] self.env.BOOST_VERSION_NUMBER = int(versions[1]) self.end_msg("%d.%d.%d" % (int(versions[1]) / 100000, int(versions[1]) / 100 % 1000, int(versions[1]) % 100)) if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % self.env['INCLUDES_%s' % var]) if not params['lib'] and not params['stlib']: return if 'static' in kw or 'static' in params: Logs.warn('boost: static parameter is deprecated, use stlib instead.') self.start_msg('Checking boost libs') path, libs, stlibs = self.boost_get_libs(**params) self.env['LIBPATH_%s' % var] = [path] self.env['STLIBPATH_%s' % var] = [path] self.env['LIB_%s' % var] = libs self.env['STLIB_%s' % var] = stlibs self.end_msg('ok') if Logs.verbose: Logs.pprint('CYAN', ' path : %s' % path) Logs.pprint('CYAN', ' shared libs : %s' % libs) Logs.pprint('CYAN', ' static libs : %s' % stlibs) def has_shlib(lib): return params['lib'] and lib in params['lib'] def has_stlib(lib): return params['stlib'] and lib in params['stlib'] def has_lib(lib): return has_shlib(lib) or has_stlib(lib) if has_lib('thread'): # not inside try_link to make check visible in the output self._check_pthread_flag(k, kw) def try_link(): if has_lib('system'): self.check_cxx(fragment=BOOST_ERROR_CODE, use=var, execute=False) if has_lib('thread'): self.check_cxx(fragment=BOOST_THREAD_CODE, use=var, execute=False) if has_lib('log'): if not has_lib('thread'): self.env['DEFINES_%s' % var] += ['BOOST_LOG_NO_THREADS'] if has_shlib('log'): self.env['DEFINES_%s' % var] += ['BOOST_LOG_DYN_LINK'] self.check_cxx(fragment=BOOST_LOG_CODE, use=var, execute=False) if params.get('linkage_autodetect', False): self.start_msg("Attempting to detect boost linkage flags") toolset = self.boost_get_toolset(kw.get('toolset', '')) if toolset in ('vc',): # disable auto-linking feature, causing error LNK1181 # because the code wants to be linked against self.env['DEFINES_%s' % var] += ['BOOST_ALL_NO_LIB'] # if no dlls are present, we guess the .lib files are not stubs has_dlls = False for x in Utils.listdir(path): if x.endswith(self.env.cxxshlib_PATTERN % ''): has_dlls = True break if not has_dlls: self.env['STLIBPATH_%s' % var] = [path] self.env['STLIB_%s' % var] = libs del self.env['LIB_%s' % var] del self.env['LIBPATH_%s' % var] # we attempt to play with some known-to-work CXXFLAGS combinations for cxxflags in (['/MD', '/EHsc'], []): self.env.stash() self.env["CXXFLAGS_%s" % var] += cxxflags try: try_link() except Errors.ConfigurationError as e: self.env.revert() exc = e else: self.end_msg("ok: winning cxxflags combination: %s" % (self.env["CXXFLAGS_%s" % var])) exc = None self.env.commit() break if exc is not None: self.end_msg("Could not auto-detect boost linking flags combination, you may report it to boost.py author", ex=exc) self.fatal('The configuration failed') else: self.end_msg("Boost linkage flags auto-detection not implemented (needed ?) for this toolchain") self.fatal('The configuration failed') else: self.start_msg('Checking for boost linkage') try: try_link() except Errors.ConfigurationError as e: self.end_msg("Could not link against boost libraries using supplied options") self.fatal('The configuration failed') self.end_msg('ok') @feature('cxx') @after_method('apply_link') def install_boost(self): if install_boost.done or not Utils.is_win32 or not self.bld.cmd.startswith('install'): return install_boost.done = True inst_to = getattr(self, 'install_path', '${BINDIR}') for lib in self.env.LIB_BOOST: try: file = self.bld.find_file(self.env.cxxshlib_PATTERN % lib, self.env.LIBPATH_BOOST) self.add_install_files(install_to=inst_to, install_from=self.bld.root.find_node(file)) except: continue install_boost.done = False hamster-3.0.3/waflib/extras/build_file_tracker.py000066400000000000000000000016021452646177100221310ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2015 """ Force files to depend on the timestamps of those located in the build directory. You may want to use this to force partial rebuilds, see playground/track_output_files/ for a working example. Note that there is a variety of ways to implement this, one may want use timestamps on source files too for example, or one may want to hash the files in the source directory only under certain conditions (md5_tstamp tool) or to hash the file in the build directory with its timestamp """ import os from waflib import Node, Utils def get_bld_sig(self): if not self.is_bld() or self.ctx.bldnode is self.ctx.srcnode: return Utils.h_file(self.abspath()) try: # add the creation time to the signature return self.sig + str(os.stat(self.abspath()).st_mtime) except AttributeError: return None Node.Node.get_bld_sig = get_bld_sig hamster-3.0.3/waflib/extras/build_logs.py000066400000000000000000000054101452646177100204440ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2013 (ita) """ A system for recording all outputs to a log file. Just add the following to your wscript file:: def init(ctx): ctx.load('build_logs') """ import atexit, sys, time, os, shutil, threading from waflib import ansiterm, Logs, Context # adding the logs under the build/ directory will clash with the clean/ command try: up = os.path.dirname(Context.g_module.__file__) except AttributeError: up = '.' LOGFILE = os.path.join(up, 'logs', time.strftime('%Y_%m_%d_%H_%M.log')) wlock = threading.Lock() class log_to_file(object): def __init__(self, stream, fileobj, filename): self.stream = stream self.encoding = self.stream.encoding self.fileobj = fileobj self.filename = filename self.is_valid = True def replace_colors(self, data): for x in Logs.colors_lst.values(): if isinstance(x, str): data = data.replace(x, '') return data def write(self, data): try: wlock.acquire() self.stream.write(data) self.stream.flush() if self.is_valid: self.fileobj.write(self.replace_colors(data)) finally: wlock.release() def fileno(self): return self.stream.fileno() def flush(self): self.stream.flush() if self.is_valid: self.fileobj.flush() def isatty(self): return self.stream.isatty() def init(ctx): global LOGFILE filename = os.path.abspath(LOGFILE) try: os.makedirs(os.path.dirname(os.path.abspath(filename))) except OSError: pass if hasattr(os, 'O_NOINHERIT'): fd = os.open(LOGFILE, os.O_CREAT | os.O_TRUNC | os.O_WRONLY | os.O_NOINHERIT) fileobj = os.fdopen(fd, 'w') else: fileobj = open(LOGFILE, 'w') old_stderr = sys.stderr # sys.stdout has already been replaced, so __stdout__ will be faster #sys.stdout = log_to_file(sys.stdout, fileobj, filename) #sys.stderr = log_to_file(sys.stderr, fileobj, filename) def wrap(stream): if stream.isatty(): return ansiterm.AnsiTerm(stream) return stream sys.stdout = log_to_file(wrap(sys.__stdout__), fileobj, filename) sys.stderr = log_to_file(wrap(sys.__stderr__), fileobj, filename) # now mess with the logging module... for x in Logs.log.handlers: try: stream = x.stream except AttributeError: pass else: if id(stream) == id(old_stderr): x.stream = sys.stderr def exit_cleanup(): try: fileobj = sys.stdout.fileobj except AttributeError: pass else: sys.stdout.is_valid = False sys.stderr.is_valid = False fileobj.close() filename = sys.stdout.filename Logs.info('Output logged to %r', filename) # then copy the log file to "latest.log" if possible up = os.path.dirname(os.path.abspath(filename)) try: shutil.copy(filename, os.path.join(up, 'latest.log')) except OSError: # this may fail on windows due to processes spawned pass atexit.register(exit_cleanup) hamster-3.0.3/waflib/extras/buildcopy.py000066400000000000000000000052601452646177100203160ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Calle Rosenquist, 2017 (xbreak) """ Create task that copies source files to the associated build node. This is useful to e.g. construct a complete Python package so it can be unit tested without installation. Source files to be copied can be specified either in `buildcopy_source` attribute, or `source` attribute. If both are specified `buildcopy_source` has priority. Examples:: def build(bld): bld(name = 'bar', features = 'py buildcopy', source = bld.path.ant_glob('src/bar/*.py')) bld(name = 'py baz', features = 'buildcopy', buildcopy_source = bld.path.ant_glob('src/bar/*.py') + ['src/bar/resource.txt']) """ import os, shutil from waflib import Errors, Task, TaskGen, Utils, Node, Logs @TaskGen.before_method('process_source') @TaskGen.feature('buildcopy') def make_buildcopy(self): """ Creates the buildcopy task. """ def to_src_nodes(lst): """Find file nodes only in src, TaskGen.to_nodes will not work for this since it gives preference to nodes in build. """ if isinstance(lst, Node.Node): if not lst.is_src(): raise Errors.WafError('buildcopy: node %s is not in src'%lst) if not os.path.isfile(lst.abspath()): raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%lst) return lst if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] node = self.bld.path.get_src().search_node(lst) if node: if not os.path.isfile(node.abspath()): raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%node) return node node = self.bld.path.get_src().find_node(lst) if node: if not os.path.isfile(node.abspath()): raise Errors.WafError('buildcopy: Cannot copy directory %s (unsupported action)'%node) return node raise Errors.WafError('buildcopy: File not found in src: %s'%os.path.join(*lst)) nodes = [ to_src_nodes(n) for n in getattr(self, 'buildcopy_source', getattr(self, 'source', [])) ] if not nodes: Logs.warn('buildcopy: No source files provided to buildcopy in %s (set `buildcopy_source` or `source`)', self) return node_pairs = [(n, n.get_bld()) for n in nodes] self.create_task('buildcopy', [n[0] for n in node_pairs], [n[1] for n in node_pairs], node_pairs=node_pairs) class buildcopy(Task.Task): """ Copy for each pair `n` in `node_pairs`: n[0] -> n[1]. Attribute `node_pairs` should contain a list of tuples describing source and target: node_pairs = [(in, out), ...] """ color = 'PINK' def keyword(self): return 'Copying' def run(self): for f,t in self.node_pairs: t.parent.mkdir() shutil.copy2(f.abspath(), t.abspath()) hamster-3.0.3/waflib/extras/c_bgxlc.py000066400000000000000000000013021452646177100177160ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de """ IBM XL Compiler for Blue Gene """ from waflib.Tools import ccroot,ar from waflib.Configure import conf from waflib.Tools import xlc # method xlc_common_flags from waflib.Tools.compiler_c import c_compiler c_compiler['linux'].append('c_bgxlc') @conf def find_bgxlc(conf): cc = conf.find_program(['bgxlc_r','bgxlc'], var='CC') conf.get_xlc_version(cc) conf.env.CC = cc conf.env.CC_NAME = 'bgxlc' def configure(conf): conf.find_bgxlc() conf.find_ar() conf.xlc_common_flags() conf.env.LINKFLAGS_cshlib = ['-G','-Wl,-bexpfull'] conf.env.LINKFLAGS_cprogram = [] conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/c_dumbpreproc.py000066400000000000000000000031731452646177100211510ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2010 (ita) """ Dumb C/C++ preprocessor for finding dependencies It will look at all include files it can find after removing the comments, so the following will always add the dependency on both "a.h" and "b.h":: #include "a.h" #ifdef B #include "b.h" #endif int main() { return 0; } To use:: def configure(conf): conf.load('compiler_c') conf.load('c_dumbpreproc') """ import re from waflib.Tools import c_preproc re_inc = re.compile( '^[ \t]*(#|%:)[ \t]*(include)[ \t]*[<"](.*)[>"]\r*$', re.IGNORECASE | re.MULTILINE) def lines_includes(node): code = node.read() if c_preproc.use_trigraphs: for (a, b) in c_preproc.trig_def: code = code.split(a).join(b) code = c_preproc.re_nl.sub('', code) code = c_preproc.re_cpp.sub(c_preproc.repl, code) return [(m.group(2), m.group(3)) for m in re.finditer(re_inc, code)] parser = c_preproc.c_parser class dumb_parser(parser): def addlines(self, node): if node in self.nodes[:-1]: return self.currentnode_stack.append(node.parent) # Avoid reading the same files again try: lines = self.parse_cache[node] except KeyError: lines = self.parse_cache[node] = lines_includes(node) self.lines = lines + [(c_preproc.POPFILE, '')] + self.lines def start(self, node, env): try: self.parse_cache = node.ctx.parse_cache except AttributeError: self.parse_cache = node.ctx.parse_cache = {} self.addlines(node) while self.lines: (x, y) = self.lines.pop(0) if x == c_preproc.POPFILE: self.currentnode_stack.pop() continue self.tryfind(y, env=env) c_preproc.c_parser = dumb_parser hamster-3.0.3/waflib/extras/c_emscripten.py000066400000000000000000000047401452646177100210010ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 vi:ts=4:noexpandtab import subprocess, shlex, sys from waflib.Tools import ccroot, gcc, gxx from waflib.Configure import conf from waflib.TaskGen import after_method, feature from waflib.Tools.compiler_c import c_compiler from waflib.Tools.compiler_cxx import cxx_compiler for supported_os in ('linux', 'darwin', 'gnu', 'aix'): c_compiler[supported_os].append('c_emscripten') cxx_compiler[supported_os].append('c_emscripten') @conf def get_emscripten_version(conf, cc): """ Emscripten doesn't support processing '-' like clang/gcc """ dummy = conf.cachedir.parent.make_node("waf-emscripten.c") dummy.write("") cmd = cc + ['-dM', '-E', '-x', 'c', dummy.abspath()] env = conf.env.env or None try: p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) out = p.communicate()[0] except Exception as e: conf.fatal('Could not determine emscripten version %r: %s' % (cmd, e)) if not isinstance(out, str): out = out.decode(sys.stdout.encoding or 'latin-1') k = {} out = out.splitlines() for line in out: lst = shlex.split(line) if len(lst)>2: key = lst[1] val = lst[2] k[key] = val if not ('__clang__' in k and 'EMSCRIPTEN' in k): conf.fatal('Could not determine the emscripten compiler version.') conf.env.DEST_OS = 'generic' conf.env.DEST_BINFMT = 'elf' conf.env.DEST_CPU = 'asm-js' conf.env.CC_VERSION = (k['__clang_major__'], k['__clang_minor__'], k['__clang_patchlevel__']) return k @conf def find_emscripten(conf): cc = conf.find_program(['emcc'], var='CC') conf.get_emscripten_version(cc) conf.env.CC = cc conf.env.CC_NAME = 'emscripten' cxx = conf.find_program(['em++'], var='CXX') conf.env.CXX = cxx conf.env.CXX_NAME = 'emscripten' conf.find_program(['emar'], var='AR') def configure(conf): conf.find_emscripten() conf.find_ar() conf.gcc_common_flags() conf.gxx_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() conf.env.ARFLAGS = ['rcs'] conf.env.cshlib_PATTERN = '%s.js' conf.env.cxxshlib_PATTERN = '%s.js' conf.env.cstlib_PATTERN = '%s.a' conf.env.cxxstlib_PATTERN = '%s.a' conf.env.cprogram_PATTERN = '%s.html' conf.env.cxxprogram_PATTERN = '%s.html' conf.env.CXX_TGT_F = ['-c', '-o', ''] conf.env.CC_TGT_F = ['-c', '-o', ''] conf.env.CXXLNK_TGT_F = ['-o', ''] conf.env.CCLNK_TGT_F = ['-o', ''] conf.env.append_value('LINKFLAGS',['-Wl,--enable-auto-import']) hamster-3.0.3/waflib/extras/c_nec.py000066400000000000000000000033751452646177100174000ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de """ NEC SX Compiler for SX vector systems """ import re from waflib import Utils from waflib.Tools import ccroot,ar from waflib.Configure import conf from waflib.Tools import xlc # method xlc_common_flags from waflib.Tools.compiler_c import c_compiler c_compiler['linux'].append('c_nec') @conf def find_sxc(conf): cc = conf.find_program(['sxcc'], var='CC') conf.get_sxc_version(cc) conf.env.CC = cc conf.env.CC_NAME = 'sxcc' @conf def get_sxc_version(conf, fc): version_re = re.compile(r"C\+\+/SX\s*Version\s*(?P\d*)\.(?P\d*)", re.I).search cmd = fc + ['-V'] p = Utils.subprocess.Popen(cmd, stdin=False, stdout=Utils.subprocess.PIPE, stderr=Utils.subprocess.PIPE, env=None) out, err = p.communicate() if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the NEC C compiler version.') k = match.groupdict() conf.env['C_VERSION'] = (k['major'], k['minor']) @conf def sxc_common_flags(conf): v=conf.env v['CC_SRC_F']=[] v['CC_TGT_F']=['-c','-o'] if not v['LINK_CC']: v['LINK_CC']=v['CC'] v['CCLNK_SRC_F']=[] v['CCLNK_TGT_F']=['-o'] v['CPPPATH_ST']='-I%s' v['DEFINES_ST']='-D%s' v['LIB_ST']='-l%s' v['LIBPATH_ST']='-L%s' v['STLIB_ST']='-l%s' v['STLIBPATH_ST']='-L%s' v['RPATH_ST']='' v['SONAME_ST']=[] v['SHLIB_MARKER']=[] v['STLIB_MARKER']=[] v['LINKFLAGS_cprogram']=[''] v['cprogram_PATTERN']='%s' v['CFLAGS_cshlib']=['-fPIC'] v['LINKFLAGS_cshlib']=[''] v['cshlib_PATTERN']='lib%s.so' v['LINKFLAGS_cstlib']=[] v['cstlib_PATTERN']='lib%s.a' def configure(conf): conf.find_sxc() conf.find_program('sxar',VAR='AR') conf.sxc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/cabal.py000066400000000000000000000120551452646177100173660ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Anton Feldmann, 2012 # "Base for cabal" from waflib import Task, Utils from waflib.TaskGen import extension from waflib.Utils import threading from shutil import rmtree lock = threading.Lock() registering = False def configure(self): self.find_program('cabal', var='CABAL') self.find_program('ghc-pkg', var='GHCPKG') pkgconfd = self.bldnode.abspath() + '/package.conf.d' self.env.PREFIX = self.bldnode.abspath() + '/dist' self.env.PKGCONFD = pkgconfd if self.root.find_node(pkgconfd + '/package.cache'): self.msg('Using existing package database', pkgconfd, color='CYAN') else: pkgdir = self.root.find_dir(pkgconfd) if pkgdir: self.msg('Deleting corrupt package database', pkgdir.abspath(), color ='RED') rmtree(pkgdir.abspath()) pkgdir = None self.cmd_and_log(self.env.GHCPKG + ['init', pkgconfd]) self.msg('Created package database', pkgconfd, color = 'YELLOW' if pkgdir else 'GREEN') @extension('.cabal') def process_cabal(self, node): out_dir_node = self.bld.root.find_dir(self.bld.out_dir) package_node = node.change_ext('.package') package_node = out_dir_node.find_or_declare(package_node.name) build_node = node.parent.get_bld() build_path = build_node.abspath() config_node = build_node.find_or_declare('setup-config') inplace_node = build_node.find_or_declare('package.conf.inplace') config_task = self.create_task('cabal_configure', node) config_task.cwd = node.parent.abspath() config_task.depends_on = getattr(self, 'depends_on', '') config_task.build_path = build_path config_task.set_outputs(config_node) build_task = self.create_task('cabal_build', config_node) build_task.cwd = node.parent.abspath() build_task.build_path = build_path build_task.set_outputs(inplace_node) copy_task = self.create_task('cabal_copy', inplace_node) copy_task.cwd = node.parent.abspath() copy_task.depends_on = getattr(self, 'depends_on', '') copy_task.build_path = build_path last_task = copy_task task_list = [config_task, build_task, copy_task] if (getattr(self, 'register', False)): register_task = self.create_task('cabal_register', inplace_node) register_task.cwd = node.parent.abspath() register_task.set_run_after(copy_task) register_task.build_path = build_path pkgreg_task = self.create_task('ghcpkg_register', inplace_node) pkgreg_task.cwd = node.parent.abspath() pkgreg_task.set_run_after(register_task) pkgreg_task.build_path = build_path last_task = pkgreg_task task_list += [register_task, pkgreg_task] touch_task = self.create_task('cabal_touch', inplace_node) touch_task.set_run_after(last_task) touch_task.set_outputs(package_node) touch_task.build_path = build_path task_list += [touch_task] return task_list def get_all_src_deps(node): hs_deps = node.ant_glob('**/*.hs') hsc_deps = node.ant_glob('**/*.hsc') lhs_deps = node.ant_glob('**/*.lhs') c_deps = node.ant_glob('**/*.c') cpp_deps = node.ant_glob('**/*.cpp') proto_deps = node.ant_glob('**/*.proto') return sum([hs_deps, hsc_deps, lhs_deps, c_deps, cpp_deps, proto_deps], []) class Cabal(Task.Task): def scan(self): return (get_all_src_deps(self.generator.path), ()) class cabal_configure(Cabal): run_str = '${CABAL} configure -v0 --prefix=${PREFIX} --global --user --package-db=${PKGCONFD} --builddir=${tsk.build_path}' shell = True def scan(self): out_node = self.generator.bld.root.find_dir(self.generator.bld.out_dir) deps = [out_node.find_or_declare(dep).change_ext('.package') for dep in Utils.to_list(self.depends_on)] return (deps, ()) class cabal_build(Cabal): run_str = '${CABAL} build -v1 --builddir=${tsk.build_path}/' shell = True class cabal_copy(Cabal): run_str = '${CABAL} copy -v0 --builddir=${tsk.build_path}' shell = True class cabal_register(Cabal): run_str = '${CABAL} register -v0 --gen-pkg-config=${tsk.build_path}/pkg.config --builddir=${tsk.build_path}' shell = True class ghcpkg_register(Cabal): run_str = '${GHCPKG} update -v0 --global --user --package-conf=${PKGCONFD} ${tsk.build_path}/pkg.config' shell = True def runnable_status(self): global lock, registering val = False lock.acquire() val = registering lock.release() if val: return Task.ASK_LATER ret = Task.Task.runnable_status(self) if ret == Task.RUN_ME: lock.acquire() registering = True lock.release() return ret def post_run(self): global lock, registering lock.acquire() registering = False lock.release() return Task.Task.post_run(self) class cabal_touch(Cabal): run_str = 'touch ${TGT}' hamster-3.0.3/waflib/extras/cfg_altoptions.py000066400000000000000000000054111452646177100213350ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # Tool to extend c_config.check_cfg() __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2014" """ This tool allows to work around the absence of ``*-config`` programs on systems, by keeping the same clean configuration syntax but inferring values or permitting their modification via the options interface. Note that pkg-config can also support setting ``PKG_CONFIG_PATH``, so you can put custom files in a folder containing new .pc files. This tool could also be implemented by taking advantage of this fact. Usage:: def options(opt): opt.load('c_config_alt') opt.add_package_option('package') def configure(cfg): conf.load('c_config_alt') conf.check_cfg(...) Known issues: - Behavior with different build contexts... """ import os import functools from waflib import Configure, Options, Errors def name_to_dest(x): return x.lower().replace('-', '_') def options(opt): def x(opt, param): dest = name_to_dest(param) gr = opt.get_option_group("configure options") gr.add_option('--%s-root' % dest, help="path containing include and lib subfolders for %s" \ % param, ) opt.add_package_option = functools.partial(x, opt) check_cfg_old = getattr(Configure.ConfigurationContext, 'check_cfg') @Configure.conf def check_cfg(conf, *k, **kw): if k: lst = k[0].split() kw['package'] = lst[0] kw['args'] = ' '.join(lst[1:]) if not 'package' in kw: return check_cfg_old(conf, **kw) package = kw['package'] package_lo = name_to_dest(package) package_hi = package.upper().replace('-', '_') # TODO FIXME package_hi = kw.get('uselib_store', package_hi) def check_folder(path, name): try: assert os.path.isdir(path) except AssertionError: raise Errors.ConfigurationError( "%s_%s (%s) is not a folder!" \ % (package_lo, name, path)) return path root = getattr(Options.options, '%s_root' % package_lo, None) if root is None: return check_cfg_old(conf, **kw) else: def add_manual_var(k, v): conf.start_msg('Adding for %s a manual var' % (package)) conf.env["%s_%s" % (k, package_hi)] = v conf.end_msg("%s = %s" % (k, v)) check_folder(root, 'root') pkg_inc = check_folder(os.path.join(root, "include"), 'inc') add_manual_var('INCLUDES', [pkg_inc]) pkg_lib = check_folder(os.path.join(root, "lib"), 'libpath') add_manual_var('LIBPATH', [pkg_lib]) add_manual_var('LIB', [package]) for x in kw.get('manual_deps', []): for k, v in sorted(conf.env.get_merged_dict().items()): if k.endswith('_%s' % x): k = k.replace('_%s' % x, '') conf.start_msg('Adding for %s a manual dep' \ %(package)) conf.env["%s_%s" % (k, package_hi)] += v conf.end_msg('%s += %s' % (k, v)) return True hamster-3.0.3/waflib/extras/clang_compilation_database.py000066400000000000000000000064531452646177100236370ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Christoph Koke, 2013 # Alibek Omarov, 2019 """ Writes the c and cpp compile commands into build/compile_commands.json see http://clang.llvm.org/docs/JSONCompilationDatabase.html Usage: Load this tool in `options` to be able to generate database by request in command-line and before build: $ waf clangdb def options(opt): opt.load('clang_compilation_database') Otherwise, load only in `configure` to generate it always before build. def configure(conf): conf.load('compiler_cxx') ... conf.load('clang_compilation_database') """ from waflib import Logs, TaskGen, Task, Build, Scripting Task.Task.keep_last_cmd = True class ClangDbContext(Build.BuildContext): '''generates compile_commands.json by request''' cmd = 'clangdb' def write_compilation_database(self): """ Write the clang compilation database as JSON """ database_file = self.bldnode.make_node('compile_commands.json') Logs.info('Build commands will be stored in %s', database_file.path_from(self.path)) try: root = database_file.read_json() except IOError: root = [] clang_db = dict((x['file'], x) for x in root) for task in self.clang_compilation_database_tasks: try: cmd = task.last_cmd except AttributeError: continue f_node = task.inputs[0] filename = f_node.path_from(task.get_cwd()) entry = { "directory": task.get_cwd().abspath(), "arguments": cmd, "file": filename, } clang_db[filename] = entry root = list(clang_db.values()) database_file.write_json(root) def execute(self): """ Build dry run """ self.restore() self.cur_tasks = [] self.clang_compilation_database_tasks = [] if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) self.pre_build() # we need only to generate last_cmd, so override # exec_command temporarily def exec_command(self, *k, **kw): return 0 for g in self.groups: for tg in g: try: f = tg.post except AttributeError: pass else: f() if isinstance(tg, Task.Task): lst = [tg] else: lst = tg.tasks for tsk in lst: if tsk.__class__.__name__ == "swig": tsk.runnable_status() if hasattr(tsk, 'more_tasks'): lst.extend(tsk.more_tasks) # Not all dynamic tasks can be processed, in some cases # one may have to call the method "run()" like this: #elif tsk.__class__.__name__ == 'src2c': # tsk.run() # if hasattr(tsk, 'more_tasks'): # lst.extend(tsk.more_tasks) tup = tuple(y for y in [Task.classes.get(x) for x in ('c', 'cxx')] if y) if isinstance(tsk, tup): self.clang_compilation_database_tasks.append(tsk) tsk.nocache = True old_exec = tsk.exec_command tsk.exec_command = exec_command tsk.run() tsk.exec_command = old_exec self.write_compilation_database() EXECUTE_PATCHED = False def patch_execute(): global EXECUTE_PATCHED if EXECUTE_PATCHED: return def new_execute_build(self): """ Invoke clangdb command before build """ if self.cmd.startswith('build'): Scripting.run_command(self.cmd.replace('build','clangdb')) old_execute_build(self) old_execute_build = getattr(Build.BuildContext, 'execute_build', None) setattr(Build.BuildContext, 'execute_build', new_execute_build) EXECUTE_PATCHED = True patch_execute() hamster-3.0.3/waflib/extras/clang_cross.py000066400000000000000000000047661452646177100206330ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Krzysztof Kosiński 2014 # DragoonX6 2018 """ Detect the Clang C compiler This version is an attempt at supporting the -target and -sysroot flag of Clang. """ from waflib.Tools import ccroot, ar, gcc from waflib.Configure import conf import waflib.Context import waflib.extras.clang_cross_common def options(opt): """ Target triplet for clang:: $ waf configure --clang-target-triple=x86_64-pc-linux-gnu """ cc_compiler_opts = opt.add_option_group('Configuration options') cc_compiler_opts.add_option('--clang-target-triple', default=None, help='Target triple for clang', dest='clang_target_triple') cc_compiler_opts.add_option('--clang-sysroot', default=None, help='Sysroot for clang', dest='clang_sysroot') @conf def find_clang(conf): """ Finds the program clang and executes it to ensure it really is clang """ import os cc = conf.find_program('clang', var='CC') if conf.options.clang_target_triple != None: conf.env.append_value('CC', ['-target', conf.options.clang_target_triple]) if conf.options.clang_sysroot != None: sysroot = str() if os.path.isabs(conf.options.clang_sysroot): sysroot = conf.options.clang_sysroot else: sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clang_sysroot)) conf.env.append_value('CC', ['--sysroot', sysroot]) conf.get_cc_version(cc, clang=True) conf.env.CC_NAME = 'clang' @conf def clang_modifier_x86_64_w64_mingw32(conf): conf.gcc_modifier_win32() @conf def clang_modifier_i386_w64_mingw32(conf): conf.gcc_modifier_win32() @conf def clang_modifier_x86_64_windows_msvc(conf): conf.clang_modifier_msvc() # Allow the user to override any flags if they so desire. clang_modifier_user_func = getattr(conf, 'clang_modifier_x86_64_windows_msvc_user', None) if clang_modifier_user_func: clang_modifier_user_func() @conf def clang_modifier_i386_windows_msvc(conf): conf.clang_modifier_msvc() # Allow the user to override any flags if they so desire. clang_modifier_user_func = getattr(conf, 'clang_modifier_i386_windows_msvc_user', None) if clang_modifier_user_func: clang_modifier_user_func() def configure(conf): conf.find_clang() conf.find_program(['llvm-ar', 'ar'], var='AR') conf.find_ar() conf.gcc_common_flags() # Allow the user to provide flags for the target platform. conf.gcc_modifier_platform() # And allow more fine grained control based on the compiler's triplet. conf.clang_modifier_target_triple() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/clang_cross_common.py000066400000000000000000000065421452646177100221750ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # DragoonX6 2018 """ Common routines for cross_clang.py and cross_clangxx.py """ from waflib.Configure import conf import waflib.Context def normalize_target_triple(target_triple): target_triple = target_triple[:-1] normalized_triple = target_triple.replace('--', '-unknown-') if normalized_triple.startswith('-'): normalized_triple = 'unknown' + normalized_triple if normalized_triple.endswith('-'): normalized_triple += 'unknown' # Normalize MinGW builds to *arch*-w64-mingw32 if normalized_triple.endswith('windows-gnu'): normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-w64-mingw32' # Strip the vendor when doing msvc builds, since it's unused anyway. if normalized_triple.endswith('windows-msvc'): normalized_triple = normalized_triple[:normalized_triple.index('-')] + '-windows-msvc' return normalized_triple.replace('-', '_') @conf def clang_modifier_msvc(conf): import os """ Really basic setup to use clang in msvc mode. We actually don't really want to do a lot, even though clang is msvc compatible in this mode, that doesn't mean we're actually using msvc. It's probably the best to leave it to the user, we can assume msvc mode if the user uses the clang-cl frontend, but this module only concerns itself with the gcc-like frontend. """ v = conf.env v.cprogram_PATTERN = '%s.exe' v.cshlib_PATTERN = '%s.dll' v.implib_PATTERN = '%s.lib' v.IMPLIB_ST = '-Wl,-IMPLIB:%s' v.SHLIB_MARKER = [] v.CFLAGS_cshlib = [] v.LINKFLAGS_cshlib = ['-Wl,-DLL'] v.cstlib_PATTERN = '%s.lib' v.STLIB_MARKER = [] del(v.AR) conf.find_program(['llvm-lib', 'lib'], var='AR') v.ARFLAGS = ['-nologo'] v.AR_TGT_F = ['-out:'] # Default to the linker supplied with llvm instead of link.exe or ld v.LINK_CC = v.CC + ['-fuse-ld=lld', '-nostdlib'] v.CCLNK_TGT_F = ['-o'] v.def_PATTERN = '-Wl,-def:%s' v.LINKFLAGS = [] v.LIB_ST = '-l%s' v.LIBPATH_ST = '-Wl,-LIBPATH:%s' v.STLIB_ST = '-l%s' v.STLIBPATH_ST = '-Wl,-LIBPATH:%s' CFLAGS_CRT_COMMON = [ '-Xclang', '--dependent-lib=oldnames', '-Xclang', '-fno-rtti-data', '-D_MT' ] v.CFLAGS_CRT_MULTITHREADED = CFLAGS_CRT_COMMON + [ '-Xclang', '-flto-visibility-public-std', '-Xclang', '--dependent-lib=libcmt', ] v.CXXFLAGS_CRT_MULTITHREADED = v.CFLAGS_CRT_MULTITHREADED v.CFLAGS_CRT_MULTITHREADED_DBG = CFLAGS_CRT_COMMON + [ '-D_DEBUG', '-Xclang', '-flto-visibility-public-std', '-Xclang', '--dependent-lib=libcmtd', ] v.CXXFLAGS_CRT_MULTITHREADED_DBG = v.CFLAGS_CRT_MULTITHREADED_DBG v.CFLAGS_CRT_MULTITHREADED_DLL = CFLAGS_CRT_COMMON + [ '-D_DLL', '-Xclang', '--dependent-lib=msvcrt' ] v.CXXFLAGS_CRT_MULTITHREADED_DLL = v.CFLAGS_CRT_MULTITHREADED_DLL v.CFLAGS_CRT_MULTITHREADED_DLL_DBG = CFLAGS_CRT_COMMON + [ '-D_DLL', '-D_DEBUG', '-Xclang', '--dependent-lib=msvcrtd', ] v.CXXFLAGS_CRT_MULTITHREADED_DLL_DBG = v.CFLAGS_CRT_MULTITHREADED_DLL_DBG @conf def clang_modifier_target_triple(conf, cpp=False): compiler = conf.env.CXX if cpp else conf.env.CC output = conf.cmd_and_log(compiler + ['-dumpmachine'], output=waflib.Context.STDOUT) modifier = ('clangxx' if cpp else 'clang') + '_modifier_' clang_modifier_func = getattr(conf, modifier + normalize_target_triple(output), None) if clang_modifier_func: clang_modifier_func() hamster-3.0.3/waflib/extras/clangxx_cross.py000066400000000000000000000057121452646177100212030ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy 2009-2018 (ita) # DragoonX6 2018 """ Detect the Clang++ C++ compiler This version is an attempt at supporting the -target and -sysroot flag of Clang++. """ from waflib.Tools import ccroot, ar, gxx from waflib.Configure import conf import waflib.extras.clang_cross_common def options(opt): """ Target triplet for clang++:: $ waf configure --clangxx-target-triple=x86_64-pc-linux-gnu """ cxx_compiler_opts = opt.add_option_group('Configuration options') cxx_compiler_opts.add_option('--clangxx-target-triple', default=None, help='Target triple for clang++', dest='clangxx_target_triple') cxx_compiler_opts.add_option('--clangxx-sysroot', default=None, help='Sysroot for clang++', dest='clangxx_sysroot') @conf def find_clangxx(conf): """ Finds the program clang++, and executes it to ensure it really is clang++ """ import os cxx = conf.find_program('clang++', var='CXX') if conf.options.clangxx_target_triple != None: conf.env.append_value('CXX', ['-target', conf.options.clangxx_target_triple]) if conf.options.clangxx_sysroot != None: sysroot = str() if os.path.isabs(conf.options.clangxx_sysroot): sysroot = conf.options.clangxx_sysroot else: sysroot = os.path.normpath(os.path.join(os.getcwd(), conf.options.clangxx_sysroot)) conf.env.append_value('CXX', ['--sysroot', sysroot]) conf.get_cc_version(cxx, clang=True) conf.env.CXX_NAME = 'clang' @conf def clangxx_modifier_x86_64_w64_mingw32(conf): conf.gcc_modifier_win32() @conf def clangxx_modifier_i386_w64_mingw32(conf): conf.gcc_modifier_win32() @conf def clangxx_modifier_msvc(conf): v = conf.env v.cxxprogram_PATTERN = v.cprogram_PATTERN v.cxxshlib_PATTERN = v.cshlib_PATTERN v.CXXFLAGS_cxxshlib = [] v.LINKFLAGS_cxxshlib = v.LINKFLAGS_cshlib v.cxxstlib_PATTERN = v.cstlib_PATTERN v.LINK_CXX = v.CXX + ['-fuse-ld=lld', '-nostdlib'] v.CXXLNK_TGT_F = v.CCLNK_TGT_F @conf def clangxx_modifier_x86_64_windows_msvc(conf): conf.clang_modifier_msvc() conf.clangxx_modifier_msvc() # Allow the user to override any flags if they so desire. clang_modifier_user_func = getattr(conf, 'clangxx_modifier_x86_64_windows_msvc_user', None) if clang_modifier_user_func: clang_modifier_user_func() @conf def clangxx_modifier_i386_windows_msvc(conf): conf.clang_modifier_msvc() conf.clangxx_modifier_msvc() # Allow the user to override any flags if they so desire. clang_modifier_user_func = getattr(conf, 'clangxx_modifier_i386_windows_msvc_user', None) if clang_modifier_user_func: clang_modifier_user_func() def configure(conf): conf.find_clangxx() conf.find_program(['llvm-ar', 'ar'], var='AR') conf.find_ar() conf.gxx_common_flags() # Allow the user to provide flags for the target platform. conf.gxx_modifier_platform() # And allow more fine grained control based on the compiler's triplet. conf.clang_modifier_target_triple(cpp=True) conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/classic_runner.py000066400000000000000000000030551452646177100213360ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2021 (ita) from waflib import Utils, Runner """ Re-enable the classic threading system from waf 1.x def configure(conf): conf.load('classic_runner') """ class TaskConsumer(Utils.threading.Thread): """ Task consumers belong to a pool of workers They wait for tasks in the queue and then use ``task.process(...)`` """ def __init__(self, spawner): Utils.threading.Thread.__init__(self) """ Obtain :py:class:`waflib.Task.TaskBase` instances from this queue. """ self.spawner = spawner self.daemon = True self.start() def run(self): """ Loop over the tasks to execute """ try: self.loop() except Exception: pass def loop(self): """ Obtain tasks from :py:attr:`waflib.Runner.TaskConsumer.ready` and call :py:meth:`waflib.Task.TaskBase.process`. If the object is a function, execute it. """ master = self.spawner.master while 1: if not master.stop: try: tsk = master.ready.get() if tsk: tsk.log_display(tsk.generator.bld) master.process_task(tsk) else: break finally: master.out.put(tsk) class Spawner(object): """ Daemon thread that consumes tasks from :py:class:`waflib.Runner.Parallel` producer and spawns a consuming thread :py:class:`waflib.Runner.Consumer` for each :py:class:`waflib.Task.Task` instance. """ def __init__(self, master): self.master = master """:py:class:`waflib.Runner.Parallel` producer instance""" self.pool = [TaskConsumer(self) for i in range(master.numjobs)] Runner.Spawner = Spawner hamster-3.0.3/waflib/extras/codelite.py000066400000000000000000001021401452646177100201070ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # CodeLite Project # Christian Klein (chrikle@berlios.de) # Created: Jan 2012 # As templete for this file I used the msvs.py # I hope this template will work proper """ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ """ To add this tool to your project: def options(conf): opt.load('codelite') It can be a good idea to add the sync_exec tool too. To generate solution files: $ waf configure codelite To customize the outputs, provide subclasses in your wscript files: from waflib.extras import codelite class vsnode_target(codelite.vsnode_target): def get_build_command(self, props): # likely to be required return "waf.bat build" def collect_source(self): # likely to be required ... class codelite_bar(codelite.codelite_generator): def init(self): codelite.codelite_generator.init(self) self.vsnode_target = vsnode_target The codelite class re-uses the same build() function for reading the targets (task generators), you may therefore specify codelite settings on the context object: def build(bld): bld.codelite_solution_name = 'foo.workspace' bld.waf_command = 'waf.bat' bld.projects_dir = bld.srcnode.make_node('') bld.projects_dir.mkdir() ASSUMPTIONS: * a project can be either a directory or a target, project files are written only for targets that have source files * each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path """ import os, re, sys import uuid # requires python 2.5 from waflib.Build import BuildContext from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' PROJECT_TEMPLATE = r''' ${for x in project.source} ${if (project.get_key(x)=="sourcefile")} ${endif} ${endfor} ${for x in project.source} ${if (project.get_key(x)=="headerfile")} ${endif} ${endfor} $b = project.build_properties[0]} ${xml:project.get_rebuild_command(project.build_properties[0])} ${xml:project.get_clean_command(project.build_properties[0])} ${xml:project.get_build_command(project.build_properties[0])} ${xml:project.get_install_command(project.build_properties[0])} ${xml:project.get_build_and_install_command(project.build_properties[0])} ${xml:project.get_build_all_command(project.build_properties[0])} ${xml:project.get_rebuild_all_command(project.build_properties[0])} ${xml:project.get_clean_all_command(project.build_properties[0])} ${xml:project.get_build_and_install_all_command(project.build_properties[0])} None ''' SOLUTION_TEMPLATE = ''' ${for p in project.all_projects} ${endfor} ${for p in project.all_projects} ${endfor} ''' COMPILE_TEMPLATE = '''def f(project): lst = [] def xml_escape(value): return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") %s #f = open('cmd.txt', 'w') #f.write(str(lst)) #f.close() return ''.join(lst) ''' reg_act = re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P[^}]*?)\})", re.M) def compile_template(line): """ Compile a template expression into a python function (like jsps, but way shorter) """ extr = [] def repl(match): g = match.group if g('dollar'): return "$" elif g('backslash'): return "\\" elif g('subst'): extr.append(g('code')) return "<<|@|>>" return None line2 = reg_act.sub(repl, line) params = line2.split('<<|@|>>') assert(extr) indent = 0 buf = [] app = buf.append def app(txt): buf.append(indent * '\t' + txt) for x in range(len(extr)): if params[x]: app("lst.append(%r)" % params[x]) f = extr[x] if f.startswith(('if', 'for')): app(f + ':') indent += 1 elif f.startswith('py:'): app(f[3:]) elif f.startswith(('endif', 'endfor')): indent -= 1 elif f.startswith(('else', 'elif')): indent -= 1 app(f + ':') indent += 1 elif f.startswith('xml:'): app('lst.append(xml_escape(%s))' % f[4:]) else: #app('lst.append((%s) or "cannot find %s")' % (f, f)) app('lst.append(%s)' % f) if extr: if params[-1]: app("lst.append(%r)" % params[-1]) fun = COMPILE_TEMPLATE % "\n\t".join(buf) #print(fun) return Task.funex(fun) re_blank = re.compile('(\n|\r|\\s)*\n', re.M) def rm_blank_lines(txt): txt = re_blank.sub('\r\n', txt) return txt BOM = '\xef\xbb\xbf' try: BOM = bytes(BOM, 'latin-1') # python 3 except (TypeError, NameError): pass def stealth_write(self, data, flags='wb'): try: unicode except NameError: data = data.encode('utf-8') # python 3 else: data = data.decode(sys.getfilesystemencoding(), 'replace') data = data.encode('utf-8') if self.name.endswith('.project'): data = BOM + data try: txt = self.read(flags='rb') if txt != data: raise ValueError('must write') except (IOError, ValueError): self.write(data, flags=flags) else: Logs.debug('codelite: skipping %r', self) Node.Node.stealth_write = stealth_write re_quote = re.compile("[^a-zA-Z0-9-]") def quote(s): return re_quote.sub("_", s) def xml_escape(value): return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") def make_uuid(v, prefix = None): """ simple utility function """ if isinstance(v, dict): keys = list(v.keys()) keys.sort() tmp = str([(k, v[k]) for k in keys]) else: tmp = str(v) d = Utils.md5(tmp.encode()).hexdigest().upper() if prefix: d = '%s%s' % (prefix, d[8:]) gid = uuid.UUID(d, version = 4) return str(gid).upper() def diff(node, fromnode): # difference between two nodes, but with "(..)" instead of ".." c1 = node c2 = fromnode c1h = c1.height() c2h = c2.height() lst = [] up = 0 while c1h > c2h: lst.append(c1.name) c1 = c1.parent c1h -= 1 while c2h > c1h: up += 1 c2 = c2.parent c2h -= 1 while id(c1) != id(c2): lst.append(c1.name) up += 1 c1 = c1.parent c2 = c2.parent for i in range(up): lst.append('(..)') lst.reverse() return tuple(lst) class build_property(object): pass class vsnode(object): """ Abstract class representing visual studio elements We assume that all visual studio nodes have a uuid and a parent """ def __init__(self, ctx): self.ctx = ctx # codelite context self.name = '' # string, mandatory self.vspath = '' # path in visual studio (name for dirs, absolute path for projects) self.uuid = '' # string, mandatory self.parent = None # parent node for visual studio nesting def get_waf(self): """ Override in subclasses... """ return '%s/%s' % (self.ctx.srcnode.abspath(), getattr(self.ctx, 'waf_command', 'waf')) def ptype(self): """ Return a special uuid for projects written in the solution file """ pass def write(self): """ Write the project file, by default, do nothing """ pass def make_uuid(self, val): """ Alias for creating uuid values easily (the templates cannot access global variables) """ return make_uuid(val) class vsnode_vsdir(vsnode): """ Nodes representing visual studio folders (which do not match the filesystem tree!) """ VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8" def __init__(self, ctx, uuid, name, vspath=''): vsnode.__init__(self, ctx) self.title = self.name = name self.uuid = uuid self.vspath = vspath or name def ptype(self): return self.VS_GUID_SOLUTIONFOLDER class vsnode_project(vsnode): """ Abstract class representing visual studio project elements A project is assumed to be writable, and has a node representing the file to write to """ VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" def ptype(self): return self.VS_GUID_VCPROJ def __init__(self, ctx, node): vsnode.__init__(self, ctx) self.path = node self.uuid = make_uuid(node.abspath()) self.name = node.name self.title = self.path.abspath() self.source = [] # list of node objects self.build_properties = [] # list of properties (nmake commands, output dir, etc) def dirs(self): """ Get the list of parent folders of the source files (header files included) for writing the filters """ lst = [] def add(x): if x.height() > self.tg.path.height() and x not in lst: lst.append(x) add(x.parent) for x in self.source: add(x.parent) return lst def write(self): Logs.debug('codelite: creating %r', self.path) #print "self.name:",self.name # first write the project file template1 = compile_template(PROJECT_TEMPLATE) proj_str = template1(self) proj_str = rm_blank_lines(proj_str) self.path.stealth_write(proj_str) # then write the filter #template2 = compile_template(FILTER_TEMPLATE) #filter_str = template2(self) #filter_str = rm_blank_lines(filter_str) #tmp = self.path.parent.make_node(self.path.name + '.filters') #tmp.stealth_write(filter_str) def get_key(self, node): """ required for writing the source files """ name = node.name if name.endswith(('.cpp', '.c')): return 'sourcefile' return 'headerfile' def collect_properties(self): """ Returns a list of triplet (configuration, platform, output_directory) """ ret = [] for c in self.ctx.configurations: for p in self.ctx.platforms: x = build_property() x.outdir = '' x.configuration = c x.platform = p x.preprocessor_definitions = '' x.includes_search_path = '' # can specify "deploy_dir" too ret.append(x) self.build_properties = ret def get_build_params(self, props): opt = '' return (self.get_waf(), opt) def get_build_command(self, props): return "%s build %s" % self.get_build_params(props) def get_clean_command(self, props): return "%s clean %s" % self.get_build_params(props) def get_rebuild_command(self, props): return "%s clean build %s" % self.get_build_params(props) def get_install_command(self, props): return "%s install %s" % self.get_build_params(props) def get_build_and_install_command(self, props): return "%s build install %s" % self.get_build_params(props) def get_build_and_install_all_command(self, props): return "%s build install" % self.get_build_params(props)[0] def get_clean_all_command(self, props): return "%s clean" % self.get_build_params(props)[0] def get_build_all_command(self, props): return "%s build" % self.get_build_params(props)[0] def get_rebuild_all_command(self, props): return "%s clean build" % self.get_build_params(props)[0] def get_filter_name(self, node): lst = diff(node, self.tg.path) return '\\'.join(lst) or '.' class vsnode_alias(vsnode_project): def __init__(self, ctx, node, name): vsnode_project.__init__(self, ctx, node) self.name = name self.output_file = '' class vsnode_build_all(vsnode_alias): """ Fake target used to emulate the behaviour of "make all" (starting one process by target is slow) This is the only alias enabled by default """ def __init__(self, ctx, node, name='build_all_projects'): vsnode_alias.__init__(self, ctx, node, name) self.is_active = True class vsnode_install_all(vsnode_alias): """ Fake target used to emulate the behaviour of "make install" """ def __init__(self, ctx, node, name='install_all_projects'): vsnode_alias.__init__(self, ctx, node, name) def get_build_command(self, props): return "%s build install %s" % self.get_build_params(props) def get_clean_command(self, props): return "%s clean %s" % self.get_build_params(props) def get_rebuild_command(self, props): return "%s clean build install %s" % self.get_build_params(props) class vsnode_project_view(vsnode_alias): """ Fake target used to emulate a file system view """ def __init__(self, ctx, node, name='project_view'): vsnode_alias.__init__(self, ctx, node, name) self.tg = self.ctx() # fake one, cannot remove self.exclude_files = Node.exclude_regs + ''' waf-2* waf3-2*/** .waf-2* .waf3-2*/** **/*.sdf **/*.suo **/*.ncb **/%s ''' % Options.lockfile def collect_source(self): # this is likely to be slow self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files) def get_build_command(self, props): params = self.get_build_params(props) + (self.ctx.cmd,) return "%s %s %s" % params def get_clean_command(self, props): return "" def get_rebuild_command(self, props): return self.get_build_command(props) class vsnode_target(vsnode_project): """ CodeLite project representing a targets (programs, libraries, etc) and bound to a task generator """ def __init__(self, ctx, tg): """ A project is more or less equivalent to a file/folder """ base = getattr(ctx, 'projects_dir', None) or tg.path node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node vsnode_project.__init__(self, ctx, node) self.name = quote(tg.name) self.tg = tg # task generator def get_build_params(self, props): """ Override the default to add the target name """ opt = '' if getattr(self, 'tg', None): opt += " --targets=%s" % self.tg.name return (self.get_waf(), opt) def collect_source(self): tg = self.tg source_files = tg.to_nodes(getattr(tg, 'source', [])) include_dirs = Utils.to_list(getattr(tg, 'codelite_includes', [])) include_files = [] for x in include_dirs: if isinstance(x, str): x = tg.path.find_node(x) if x: lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)] include_files.extend(lst) # remove duplicates self.source.extend(list(set(source_files + include_files))) self.source.sort(key=lambda x: x.abspath()) def collect_properties(self): """ CodeLite projects are associated with platforms and configurations (for building especially) """ super(vsnode_target, self).collect_properties() for x in self.build_properties: x.outdir = self.path.parent.abspath() x.preprocessor_definitions = '' x.includes_search_path = '' try: tsk = self.tg.link_task except AttributeError: pass else: x.output_file = tsk.outputs[0].abspath() x.preprocessor_definitions = ';'.join(tsk.env.DEFINES) x.includes_search_path = ';'.join(self.tg.env.INCPATHS) class codelite_generator(BuildContext): '''generates a CodeLite workspace''' cmd = 'codelite' fun = 'build' def init(self): """ Some data that needs to be present """ if not getattr(self, 'configurations', None): self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc if not getattr(self, 'platforms', None): self.platforms = ['Win32'] if not getattr(self, 'all_projects', None): self.all_projects = [] if not getattr(self, 'project_extension', None): self.project_extension = '.project' if not getattr(self, 'projects_dir', None): self.projects_dir = self.srcnode.make_node('') self.projects_dir.mkdir() # bind the classes to the object, so that subclass can provide custom generators if not getattr(self, 'vsnode_vsdir', None): self.vsnode_vsdir = vsnode_vsdir if not getattr(self, 'vsnode_target', None): self.vsnode_target = vsnode_target if not getattr(self, 'vsnode_build_all', None): self.vsnode_build_all = vsnode_build_all if not getattr(self, 'vsnode_install_all', None): self.vsnode_install_all = vsnode_install_all if not getattr(self, 'vsnode_project_view', None): self.vsnode_project_view = vsnode_project_view self.numver = '11.00' self.vsver = '2010' def execute(self): """ Entry point """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) # user initialization self.init() # two phases for creating the solution self.collect_projects() # add project objects into "self.all_projects" self.write_files() # write the corresponding project and solution files def collect_projects(self): """ Fill the list self.all_projects with project objects Fill the list of build targets """ self.collect_targets() #self.add_aliases() #self.collect_dirs() default_project = getattr(self, 'default_project', None) def sortfun(x): if x.name == default_project: return '' return getattr(x, 'path', None) and x.path.abspath() or x.name self.all_projects.sort(key=sortfun) def write_files(self): """ Write the project and solution files from the data collected so far. It is unlikely that you will want to change this """ for p in self.all_projects: p.write() # and finally write the solution file node = self.get_solution_node() node.parent.mkdir() Logs.warn('Creating %r', node) #a = dir(self.root) #for b in a: # print b #print self.group_names #print "Hallo2: ",self.root.listdir() #print getattr(self, 'codelite_solution_name', None) template1 = compile_template(SOLUTION_TEMPLATE) sln_str = template1(self) sln_str = rm_blank_lines(sln_str) node.stealth_write(sln_str) def get_solution_node(self): """ The solution filename is required when writing the .vcproj files return self.solution_node and if it does not exist, make one """ try: return self.solution_node except: pass codelite_solution_name = getattr(self, 'codelite_solution_name', None) if not codelite_solution_name: codelite_solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.workspace' setattr(self, 'codelite_solution_name', codelite_solution_name) if os.path.isabs(codelite_solution_name): self.solution_node = self.root.make_node(codelite_solution_name) else: self.solution_node = self.srcnode.make_node(codelite_solution_name) return self.solution_node def project_configurations(self): """ Helper that returns all the pairs (config,platform) """ ret = [] for c in self.configurations: for p in self.platforms: ret.append((c, p)) return ret def collect_targets(self): """ Process the list of task generators """ for g in self.groups: for tg in g: if not isinstance(tg, TaskGen.task_gen): continue if not hasattr(tg, 'codelite_includes'): tg.codelite_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', [])) tg.post() if not getattr(tg, 'link_task', None): continue p = self.vsnode_target(self, tg) p.collect_source() # delegate this processing p.collect_properties() self.all_projects.append(p) def add_aliases(self): """ Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7 We also add an alias for "make install" (disabled by default) """ base = getattr(self, 'projects_dir', None) or self.tg.path node_project = base.make_node('build_all_projects' + self.project_extension) # Node p_build = self.vsnode_build_all(self, node_project) p_build.collect_properties() self.all_projects.append(p_build) node_project = base.make_node('install_all_projects' + self.project_extension) # Node p_install = self.vsnode_install_all(self, node_project) p_install.collect_properties() self.all_projects.append(p_install) node_project = base.make_node('project_view' + self.project_extension) # Node p_view = self.vsnode_project_view(self, node_project) p_view.collect_source() p_view.collect_properties() self.all_projects.append(p_view) n = self.vsnode_vsdir(self, make_uuid(self.srcnode.abspath() + 'build_aliases'), "build_aliases") p_build.parent = p_install.parent = p_view.parent = n self.all_projects.append(n) def collect_dirs(self): """ Create the folder structure in the CodeLite project view """ seen = {} def make_parents(proj): # look at a project, try to make a parent if getattr(proj, 'parent', None): # aliases already have parents return x = proj.iter_path if x in seen: proj.parent = seen[x] return # There is not vsnode_vsdir for x. # So create a project representing the folder "x" n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.abspath()), x.name) n.iter_path = x.parent self.all_projects.append(n) # recurse up to the project directory if x.height() > self.srcnode.height() + 1: make_parents(n) for p in self.all_projects[:]: # iterate over a copy of all projects if not getattr(p, 'tg', None): # but only projects that have a task generator continue # make a folder for each task generator p.iter_path = p.tg.path make_parents(p) hamster-3.0.3/waflib/extras/color_gcc.py000066400000000000000000000022111452646177100202470ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Replaces the default formatter by one which understands GCC output and colorizes it. __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2012" import sys from waflib import Logs class ColorGCCFormatter(Logs.formatter): def __init__(self, colors): self.colors = colors Logs.formatter.__init__(self) def format(self, rec): frame = sys._getframe() while frame: func = frame.f_code.co_name if func == 'exec_command': cmd = frame.f_locals.get('cmd') if isinstance(cmd, list) and (len(cmd) > 0) and ('gcc' in cmd[0] or 'g++' in cmd[0]): lines = [] for line in rec.msg.splitlines(): if 'warning: ' in line: lines.append(self.colors.YELLOW + line) elif 'error: ' in line: lines.append(self.colors.RED + line) elif 'note: ' in line: lines.append(self.colors.CYAN + line) else: lines.append(line) rec.msg = "\n".join(lines) frame = frame.f_back return Logs.formatter.format(self, rec) def options(opt): Logs.log.handlers[0].setFormatter(ColorGCCFormatter(Logs.colors)) hamster-3.0.3/waflib/extras/color_msvc.py000066400000000000000000000034351452646177100204740ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Replaces the default formatter by one which understands MSVC output and colorizes it. # Modified from color_gcc.py __author__ = __maintainer__ = "Alibek Omarov " __copyright__ = "Alibek Omarov, 2019" import sys from waflib import Logs class ColorMSVCFormatter(Logs.formatter): def __init__(self, colors): self.colors = colors Logs.formatter.__init__(self) def parseMessage(self, line, color): # Split messaage from 'disk:filepath: type: message' arr = line.split(':', 3) if len(arr) < 4: return line colored = self.colors.BOLD + arr[0] + ':' + arr[1] + ':' + self.colors.NORMAL colored += color + arr[2] + ':' + self.colors.NORMAL colored += arr[3] return colored def format(self, rec): frame = sys._getframe() while frame: func = frame.f_code.co_name if func == 'exec_command': cmd = frame.f_locals.get('cmd') if isinstance(cmd, list): # Fix file case, it may be CL.EXE or cl.exe argv0 = cmd[0].lower() if 'cl.exe' in argv0: lines = [] # This will not work with "localized" versions # of MSVC for line in rec.msg.splitlines(): if ': warning ' in line: lines.append(self.parseMessage(line, self.colors.YELLOW)) elif ': error ' in line: lines.append(self.parseMessage(line, self.colors.RED)) elif ': fatal error ' in line: lines.append(self.parseMessage(line, self.colors.RED + self.colors.BOLD)) elif ': note: ' in line: lines.append(self.parseMessage(line, self.colors.CYAN)) else: lines.append(line) rec.msg = "\n".join(lines) frame = frame.f_back return Logs.formatter.format(self, rec) def options(opt): Logs.log.handlers[0].setFormatter(ColorMSVCFormatter(Logs.colors)) hamster-3.0.3/waflib/extras/color_rvct.py000066400000000000000000000024451452646177100205020ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Replaces the default formatter by one which understands RVCT output and colorizes it. __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2012" import sys import atexit from waflib import Logs errors = [] def show_errors(): for i, e in enumerate(errors): if i > 5: break print("Error: %s" % e) atexit.register(show_errors) class RcvtFormatter(Logs.formatter): def __init__(self, colors): Logs.formatter.__init__(self) self.colors = colors def format(self, rec): frame = sys._getframe() while frame: func = frame.f_code.co_name if func == 'exec_command': cmd = frame.f_locals['cmd'] if isinstance(cmd, list) and ('armcc' in cmd[0] or 'armld' in cmd[0]): lines = [] for line in rec.msg.splitlines(): if 'Warning: ' in line: lines.append(self.colors.YELLOW + line) elif 'Error: ' in line: lines.append(self.colors.RED + line) errors.append(line) elif 'note: ' in line: lines.append(self.colors.CYAN + line) else: lines.append(line) rec.msg = "\n".join(lines) frame = frame.f_back return Logs.formatter.format(self, rec) def options(opt): Logs.log.handlers[0].setFormatter(RcvtFormatter(Logs.colors)) hamster-3.0.3/waflib/extras/compat15.py000066400000000000000000000270451452646177100177620ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010 (ita) """ This file is provided to enable compatibility with waf 1.5 It was enabled by default in waf 1.6, but it is not used in waf 1.7 """ import sys from waflib import ConfigSet, Logs, Options, Scripting, Task, Build, Configure, Node, Runner, TaskGen, Utils, Errors, Context # the following is to bring some compatibility with waf 1.5 "import waflib.Configure → import Configure" sys.modules['Environment'] = ConfigSet ConfigSet.Environment = ConfigSet.ConfigSet sys.modules['Logs'] = Logs sys.modules['Options'] = Options sys.modules['Scripting'] = Scripting sys.modules['Task'] = Task sys.modules['Build'] = Build sys.modules['Configure'] = Configure sys.modules['Node'] = Node sys.modules['Runner'] = Runner sys.modules['TaskGen'] = TaskGen sys.modules['Utils'] = Utils sys.modules['Constants'] = Context Context.SRCDIR = '' Context.BLDDIR = '' from waflib.Tools import c_preproc sys.modules['preproc'] = c_preproc from waflib.Tools import c_config sys.modules['config_c'] = c_config ConfigSet.ConfigSet.copy = ConfigSet.ConfigSet.derive ConfigSet.ConfigSet.set_variant = Utils.nada Utils.pproc = Utils.subprocess Build.BuildContext.add_subdirs = Build.BuildContext.recurse Build.BuildContext.new_task_gen = Build.BuildContext.__call__ Build.BuildContext.is_install = 0 Node.Node.relpath_gen = Node.Node.path_from Utils.pproc = Utils.subprocess Utils.get_term_cols = Logs.get_term_cols def cmd_output(cmd, **kw): silent = False if 'silent' in kw: silent = kw['silent'] del(kw['silent']) if 'e' in kw: tmp = kw['e'] del(kw['e']) kw['env'] = tmp kw['shell'] = isinstance(cmd, str) kw['stdout'] = Utils.subprocess.PIPE if silent: kw['stderr'] = Utils.subprocess.PIPE try: p = Utils.subprocess.Popen(cmd, **kw) output = p.communicate()[0] except OSError as e: raise ValueError(str(e)) if p.returncode: if not silent: msg = "command execution failed: %s -> %r" % (cmd, str(output)) raise ValueError(msg) output = '' return output Utils.cmd_output = cmd_output def name_to_obj(self, s, env=None): if Logs.verbose: Logs.warn('compat: change "name_to_obj(name, env)" by "get_tgen_by_name(name)"') return self.get_tgen_by_name(s) Build.BuildContext.name_to_obj = name_to_obj def env_of_name(self, name): try: return self.all_envs[name] except KeyError: Logs.error('no such environment: '+name) return None Build.BuildContext.env_of_name = env_of_name def set_env_name(self, name, env): self.all_envs[name] = env return env Configure.ConfigurationContext.set_env_name = set_env_name def retrieve(self, name, fromenv=None): try: env = self.all_envs[name] except KeyError: env = ConfigSet.ConfigSet() self.prepare_env(env) self.all_envs[name] = env else: if fromenv: Logs.warn('The environment %s may have been configured already', name) return env Configure.ConfigurationContext.retrieve = retrieve Configure.ConfigurationContext.sub_config = Configure.ConfigurationContext.recurse Configure.ConfigurationContext.check_tool = Configure.ConfigurationContext.load Configure.conftest = Configure.conf Configure.ConfigurationError = Errors.ConfigurationError Utils.WafError = Errors.WafError Options.OptionsContext.sub_options = Options.OptionsContext.recurse Options.OptionsContext.tool_options = Context.Context.load Options.Handler = Options.OptionsContext Task.simple_task_type = Task.task_type_from_func = Task.task_factory Task.Task.classes = Task.classes def setitem(self, key, value): if key.startswith('CCFLAGS'): key = key[1:] self.table[key] = value ConfigSet.ConfigSet.__setitem__ = setitem @TaskGen.feature('d') @TaskGen.before('apply_incpaths') def old_importpaths(self): if getattr(self, 'importpaths', []): self.includes = self.importpaths from waflib import Context eld = Context.load_tool def load_tool(*k, **kw): ret = eld(*k, **kw) if 'set_options' in ret.__dict__: if Logs.verbose: Logs.warn('compat: rename "set_options" to options') ret.options = ret.set_options if 'detect' in ret.__dict__: if Logs.verbose: Logs.warn('compat: rename "detect" to "configure"') ret.configure = ret.detect return ret Context.load_tool = load_tool def get_curdir(self): return self.path.abspath() Context.Context.curdir = property(get_curdir, Utils.nada) def get_srcdir(self): return self.srcnode.abspath() Configure.ConfigurationContext.srcdir = property(get_srcdir, Utils.nada) def get_blddir(self): return self.bldnode.abspath() Configure.ConfigurationContext.blddir = property(get_blddir, Utils.nada) Configure.ConfigurationContext.check_message_1 = Configure.ConfigurationContext.start_msg Configure.ConfigurationContext.check_message_2 = Configure.ConfigurationContext.end_msg rev = Context.load_module def load_module(path, encoding=None): ret = rev(path, encoding) if 'set_options' in ret.__dict__: if Logs.verbose: Logs.warn('compat: rename "set_options" to "options" (%r)', path) ret.options = ret.set_options if 'srcdir' in ret.__dict__: if Logs.verbose: Logs.warn('compat: rename "srcdir" to "top" (%r)', path) ret.top = ret.srcdir if 'blddir' in ret.__dict__: if Logs.verbose: Logs.warn('compat: rename "blddir" to "out" (%r)', path) ret.out = ret.blddir Utils.g_module = Context.g_module Options.launch_dir = Context.launch_dir return ret Context.load_module = load_module old_post = TaskGen.task_gen.post def post(self): self.features = self.to_list(self.features) if 'cc' in self.features: if Logs.verbose: Logs.warn('compat: the feature cc does not exist anymore (use "c")') self.features.remove('cc') self.features.append('c') if 'cstaticlib' in self.features: if Logs.verbose: Logs.warn('compat: the feature cstaticlib does not exist anymore (use "cstlib" or "cxxstlib")') self.features.remove('cstaticlib') self.features.append(('cxx' in self.features) and 'cxxstlib' or 'cstlib') if getattr(self, 'ccflags', None): if Logs.verbose: Logs.warn('compat: "ccflags" was renamed to "cflags"') self.cflags = self.ccflags return old_post(self) TaskGen.task_gen.post = post def waf_version(*k, **kw): Logs.warn('wrong version (waf_version was removed in waf 1.6)') Utils.waf_version = waf_version import os @TaskGen.feature('c', 'cxx', 'd') @TaskGen.before('apply_incpaths', 'propagate_uselib_vars') @TaskGen.after('apply_link', 'process_source') def apply_uselib_local(self): """ process the uselib_local attribute execute after apply_link because of the execution order set on 'link_task' """ env = self.env from waflib.Tools.ccroot import stlink_task # 1. the case of the libs defined in the project (visit ancestors first) # the ancestors external libraries (uselib) will be prepended self.uselib = self.to_list(getattr(self, 'uselib', [])) self.includes = self.to_list(getattr(self, 'includes', [])) names = self.to_list(getattr(self, 'uselib_local', [])) get = self.bld.get_tgen_by_name seen = set() seen_uselib = set() tmp = Utils.deque(names) # consume a copy of the list of names if tmp: if Logs.verbose: Logs.warn('compat: "uselib_local" is deprecated, replace by "use"') while tmp: lib_name = tmp.popleft() # visit dependencies only once if lib_name in seen: continue y = get(lib_name) y.post() seen.add(lib_name) # object has ancestors to process (shared libraries): add them to the end of the list if getattr(y, 'uselib_local', None): for x in self.to_list(getattr(y, 'uselib_local', [])): obj = get(x) obj.post() if getattr(obj, 'link_task', None): if not isinstance(obj.link_task, stlink_task): tmp.append(x) # link task and flags if getattr(y, 'link_task', None): link_name = y.target[y.target.rfind(os.sep) + 1:] if isinstance(y.link_task, stlink_task): env.append_value('STLIB', [link_name]) else: # some linkers can link against programs env.append_value('LIB', [link_name]) # the order self.link_task.set_run_after(y.link_task) # for the recompilation self.link_task.dep_nodes += y.link_task.outputs # add the link path too tmp_path = y.link_task.outputs[0].parent.bldpath() if not tmp_path in env['LIBPATH']: env.prepend_value('LIBPATH', [tmp_path]) # add ancestors uselib too - but only propagate those that have no staticlib defined for v in self.to_list(getattr(y, 'uselib', [])): if v not in seen_uselib: seen_uselib.add(v) if not env['STLIB_' + v]: if not v in self.uselib: self.uselib.insert(0, v) # if the library task generator provides 'export_includes', add to the include path # the export_includes must be a list of paths relative to the other library if getattr(y, 'export_includes', None): self.includes.extend(y.to_incnodes(y.export_includes)) @TaskGen.feature('cprogram', 'cxxprogram', 'cstlib', 'cxxstlib', 'cshlib', 'cxxshlib', 'dprogram', 'dstlib', 'dshlib') @TaskGen.after('apply_link') def apply_objdeps(self): "add the .o files produced by some other object files in the same manner as uselib_local" names = getattr(self, 'add_objects', []) if not names: return names = self.to_list(names) get = self.bld.get_tgen_by_name seen = [] while names: x = names[0] # visit dependencies only once if x in seen: names = names[1:] continue # object does not exist ? y = get(x) # object has ancestors to process first ? update the list of names if getattr(y, 'add_objects', None): added = 0 lst = y.to_list(y.add_objects) lst.reverse() for u in lst: if u in seen: continue added = 1 names = [u]+names if added: continue # list of names modified, loop # safe to process the current object y.post() seen.append(x) for t in getattr(y, 'compiled_tasks', []): self.link_task.inputs.extend(t.outputs) @TaskGen.after('apply_link') def process_obj_files(self): if not hasattr(self, 'obj_files'): return for x in self.obj_files: node = self.path.find_resource(x) self.link_task.inputs.append(node) @TaskGen.taskgen_method def add_obj_file(self, file): """Small example on how to link object files as if they were source obj = bld.create_obj('cc') obj.add_obj_file('foo.o')""" if not hasattr(self, 'obj_files'): self.obj_files = [] if not 'process_obj_files' in self.meths: self.meths.append('process_obj_files') self.obj_files.append(file) old_define = Configure.ConfigurationContext.__dict__['define'] @Configure.conf def define(self, key, val, quote=True, comment=''): old_define(self, key, val, quote, comment) if key.startswith('HAVE_'): self.env[key] = 1 old_undefine = Configure.ConfigurationContext.__dict__['undefine'] @Configure.conf def undefine(self, key, comment=''): old_undefine(self, key, comment) if key.startswith('HAVE_'): self.env[key] = 0 # some people might want to use export_incdirs, but it was renamed def set_incdirs(self, val): Logs.warn('compat: change "export_incdirs" by "export_includes"') self.export_includes = val TaskGen.task_gen.export_incdirs = property(None, set_incdirs) def install_dir(self, path): if not path: return [] destpath = Utils.subst_vars(path, self.env) if self.is_install > 0: Logs.info('* creating %s', destpath) Utils.check_dir(destpath) elif self.is_install < 0: Logs.info('* removing %s', destpath) try: os.remove(destpath) except OSError: pass Build.BuildContext.install_dir = install_dir # before/after names repl = {'apply_core': 'process_source', 'apply_lib_vars': 'process_source', 'apply_obj_vars': 'propagate_uselib_vars', 'exec_rule': 'process_rule' } def after(*k): k = [repl.get(key, key) for key in k] return TaskGen.after_method(*k) def before(*k): k = [repl.get(key, key) for key in k] return TaskGen.before_method(*k) TaskGen.before = before hamster-3.0.3/waflib/extras/cppcheck.py000066400000000000000000000432041452646177100201040ustar00rootroot00000000000000#! /usr/bin/env python # -*- encoding: utf-8 -*- # Michel Mooij, michel.mooij7@gmail.com """ Tool Description ================ This module provides a waf wrapper (i.e. waftool) around the C/C++ source code checking tool 'cppcheck'. See http://cppcheck.sourceforge.net/ for more information on the cppcheck tool itself. Note that many linux distributions already provide a ready to install version of cppcheck. On fedora, for instance, it can be installed using yum: 'sudo yum install cppcheck' Usage ===== In order to use this waftool simply add it to the 'options' and 'configure' functions of your main waf script as shown in the example below: def options(opt): opt.load('cppcheck', tooldir='./waftools') def configure(conf): conf.load('cppcheck') Note that example shown above assumes that the cppcheck waftool is located in the sub directory named 'waftools'. When configured as shown in the example above, cppcheck will automatically perform a source code analysis on all C/C++ build tasks that have been defined in your waf build system. The example shown below for a C program will be used as input for cppcheck when building the task. def build(bld): bld.program(name='foo', src='foobar.c') The result of the source code analysis will be stored both as xml and html files in the build location for the task. Should any error be detected by cppcheck the build will be aborted and a link to the html report will be shown. By default, one index.html file is created for each task generator. A global index.html file can be obtained by setting the following variable in the configuration section: conf.env.CPPCHECK_SINGLE_HTML = False When needed source code checking by cppcheck can be disabled per task, per detected error or warning for a particular task. It can be also be disabled for all tasks. In order to exclude a task from source code checking add the skip option to the task as shown below: def build(bld): bld.program( name='foo', src='foobar.c' cppcheck_skip=True ) When needed problems detected by cppcheck may be suppressed using a file containing a list of suppression rules. The relative or absolute path to this file can be added to the build task as shown in the example below: bld.program( name='bar', src='foobar.c', cppcheck_suppress='bar.suppress' ) A cppcheck suppress file should contain one suppress rule per line. Each of these rules will be passed as an '--suppress=' argument to cppcheck. Dependencies ================ This waftool depends on the python pygments module, it is used for source code syntax highlighting when creating the html reports. see http://pygments.org/ for more information on this package. Remarks ================ The generation of the html report is originally based on the cppcheck-htmlreport.py script that comes shipped with the cppcheck tool. """ import sys import xml.etree.ElementTree as ElementTree from waflib import Task, TaskGen, Logs, Context, Options PYGMENTS_EXC_MSG= ''' The required module 'pygments' could not be found. Please install it using your platform package manager (e.g. apt-get or yum), using 'pip' or 'easy_install', see 'http://pygments.org/download/' for installation instructions. ''' try: import pygments from pygments import formatters, lexers except ImportError as e: Logs.warn(PYGMENTS_EXC_MSG) raise e def options(opt): opt.add_option('--cppcheck-skip', dest='cppcheck_skip', default=False, action='store_true', help='do not check C/C++ sources (default=False)') opt.add_option('--cppcheck-err-resume', dest='cppcheck_err_resume', default=False, action='store_true', help='continue in case of errors (default=False)') opt.add_option('--cppcheck-bin-enable', dest='cppcheck_bin_enable', default='warning,performance,portability,style,unusedFunction', action='store', help="cppcheck option '--enable=' for binaries (default=warning,performance,portability,style,unusedFunction)") opt.add_option('--cppcheck-lib-enable', dest='cppcheck_lib_enable', default='warning,performance,portability,style', action='store', help="cppcheck option '--enable=' for libraries (default=warning,performance,portability,style)") opt.add_option('--cppcheck-std-c', dest='cppcheck_std_c', default='c99', action='store', help='cppcheck standard to use when checking C (default=c99)') opt.add_option('--cppcheck-std-cxx', dest='cppcheck_std_cxx', default='c++03', action='store', help='cppcheck standard to use when checking C++ (default=c++03)') opt.add_option('--cppcheck-check-config', dest='cppcheck_check_config', default=False, action='store_true', help='forced check for missing buildin include files, e.g. stdio.h (default=False)') opt.add_option('--cppcheck-max-configs', dest='cppcheck_max_configs', default='20', action='store', help='maximum preprocessor (--max-configs) define iterations (default=20)') opt.add_option('--cppcheck-jobs', dest='cppcheck_jobs', default='1', action='store', help='number of jobs (-j) to do the checking work (default=1)') def configure(conf): if conf.options.cppcheck_skip: conf.env.CPPCHECK_SKIP = [True] conf.env.CPPCHECK_STD_C = conf.options.cppcheck_std_c conf.env.CPPCHECK_STD_CXX = conf.options.cppcheck_std_cxx conf.env.CPPCHECK_MAX_CONFIGS = conf.options.cppcheck_max_configs conf.env.CPPCHECK_BIN_ENABLE = conf.options.cppcheck_bin_enable conf.env.CPPCHECK_LIB_ENABLE = conf.options.cppcheck_lib_enable conf.env.CPPCHECK_JOBS = conf.options.cppcheck_jobs if conf.options.cppcheck_jobs != '1' and ('unusedFunction' in conf.options.cppcheck_bin_enable or 'unusedFunction' in conf.options.cppcheck_lib_enable or 'all' in conf.options.cppcheck_bin_enable or 'all' in conf.options.cppcheck_lib_enable): Logs.warn('cppcheck: unusedFunction cannot be used with multiple threads, cppcheck will disable it automatically') conf.find_program('cppcheck', var='CPPCHECK') # set to True to get a single index.html file conf.env.CPPCHECK_SINGLE_HTML = False @TaskGen.feature('c') @TaskGen.feature('cxx') def cppcheck_execute(self): if hasattr(self.bld, 'conf'): return if len(self.env.CPPCHECK_SKIP) or Options.options.cppcheck_skip: return if getattr(self, 'cppcheck_skip', False): return task = self.create_task('cppcheck') task.cmd = _tgen_create_cmd(self) task.fatal = [] if not Options.options.cppcheck_err_resume: task.fatal.append('error') def _tgen_create_cmd(self): features = getattr(self, 'features', []) std_c = self.env.CPPCHECK_STD_C std_cxx = self.env.CPPCHECK_STD_CXX max_configs = self.env.CPPCHECK_MAX_CONFIGS bin_enable = self.env.CPPCHECK_BIN_ENABLE lib_enable = self.env.CPPCHECK_LIB_ENABLE jobs = self.env.CPPCHECK_JOBS cmd = self.env.CPPCHECK args = ['--inconclusive','--report-progress','--verbose','--xml','--xml-version=2'] args.append('--max-configs=%s' % max_configs) args.append('-j %s' % jobs) if 'cxx' in features: args.append('--language=c++') args.append('--std=%s' % std_cxx) else: args.append('--language=c') args.append('--std=%s' % std_c) if Options.options.cppcheck_check_config: args.append('--check-config') if set(['cprogram','cxxprogram']) & set(features): args.append('--enable=%s' % bin_enable) else: args.append('--enable=%s' % lib_enable) for src in self.to_list(getattr(self, 'source', [])): if not isinstance(src, str): src = repr(src) args.append(src) for inc in self.to_incnodes(self.to_list(getattr(self, 'includes', []))): if not isinstance(inc, str): inc = repr(inc) args.append('-I%s' % inc) for inc in self.to_incnodes(self.to_list(self.env.INCLUDES)): if not isinstance(inc, str): inc = repr(inc) args.append('-I%s' % inc) return cmd + args class cppcheck(Task.Task): quiet = True def run(self): stderr = self.generator.bld.cmd_and_log(self.cmd, quiet=Context.STDERR, output=Context.STDERR) self._save_xml_report(stderr) defects = self._get_defects(stderr) index = self._create_html_report(defects) self._errors_evaluate(defects, index) return 0 def _save_xml_report(self, s): '''use cppcheck xml result string, add the command string used to invoke cppcheck and save as xml file. ''' header = '%s\n' % s.splitlines()[0] root = ElementTree.fromstring(s) cmd = ElementTree.SubElement(root.find('cppcheck'), 'cmd') cmd.text = str(self.cmd) body = ElementTree.tostring(root).decode('us-ascii') body_html_name = 'cppcheck-%s.xml' % self.generator.get_name() if self.env.CPPCHECK_SINGLE_HTML: body_html_name = 'cppcheck.xml' node = self.generator.path.get_bld().find_or_declare(body_html_name) node.write(header + body) def _get_defects(self, xml_string): '''evaluate the xml string returned by cppcheck (on sdterr) and use it to create a list of defects. ''' defects = [] for error in ElementTree.fromstring(xml_string).iter('error'): defect = {} defect['id'] = error.get('id') defect['severity'] = error.get('severity') defect['msg'] = str(error.get('msg')).replace('<','<') defect['verbose'] = error.get('verbose') for location in error.findall('location'): defect['file'] = location.get('file') defect['line'] = str(int(location.get('line')) - 1) defects.append(defect) return defects def _create_html_report(self, defects): files, css_style_defs = self._create_html_files(defects) index = self._create_html_index(files) self._create_css_file(css_style_defs) return index def _create_html_files(self, defects): sources = {} defects = [defect for defect in defects if 'file' in defect] for defect in defects: name = defect['file'] if not name in sources: sources[name] = [defect] else: sources[name].append(defect) files = {} css_style_defs = None bpath = self.generator.path.get_bld().abspath() names = list(sources.keys()) for i in range(0,len(names)): name = names[i] if self.env.CPPCHECK_SINGLE_HTML: htmlfile = 'cppcheck/%i.html' % (i) else: htmlfile = 'cppcheck/%s%i.html' % (self.generator.get_name(),i) errors = sources[name] files[name] = { 'htmlfile': '%s/%s' % (bpath, htmlfile), 'errors': errors } css_style_defs = self._create_html_file(name, htmlfile, errors) return files, css_style_defs def _create_html_file(self, sourcefile, htmlfile, errors): name = self.generator.get_name() root = ElementTree.fromstring(CPPCHECK_HTML_FILE) title = root.find('head/title') title.text = 'cppcheck - report - %s' % name body = root.find('body') for div in body.findall('div'): if div.get('id') == 'page': page = div break for div in page.findall('div'): if div.get('id') == 'header': h1 = div.find('h1') h1.text = 'cppcheck report - %s' % name if div.get('id') == 'menu': indexlink = div.find('a') if self.env.CPPCHECK_SINGLE_HTML: indexlink.attrib['href'] = 'index.html' else: indexlink.attrib['href'] = 'index-%s.html' % name if div.get('id') == 'content': content = div srcnode = self.generator.bld.root.find_node(sourcefile) hl_lines = [e['line'] for e in errors if 'line' in e] formatter = CppcheckHtmlFormatter(linenos=True, style='colorful', hl_lines=hl_lines, lineanchors='line') formatter.errors = [e for e in errors if 'line' in e] css_style_defs = formatter.get_style_defs('.highlight') lexer = pygments.lexers.guess_lexer_for_filename(sourcefile, "") s = pygments.highlight(srcnode.read(), lexer, formatter) table = ElementTree.fromstring(s) content.append(table) s = ElementTree.tostring(root, method='html').decode('us-ascii') s = CCPCHECK_HTML_TYPE + s node = self.generator.path.get_bld().find_or_declare(htmlfile) node.write(s) return css_style_defs def _create_html_index(self, files): name = self.generator.get_name() root = ElementTree.fromstring(CPPCHECK_HTML_FILE) title = root.find('head/title') title.text = 'cppcheck - report - %s' % name body = root.find('body') for div in body.findall('div'): if div.get('id') == 'page': page = div break for div in page.findall('div'): if div.get('id') == 'header': h1 = div.find('h1') h1.text = 'cppcheck report - %s' % name if div.get('id') == 'content': content = div self._create_html_table(content, files) if div.get('id') == 'menu': indexlink = div.find('a') if self.env.CPPCHECK_SINGLE_HTML: indexlink.attrib['href'] = 'index.html' else: indexlink.attrib['href'] = 'index-%s.html' % name s = ElementTree.tostring(root, method='html').decode('us-ascii') s = CCPCHECK_HTML_TYPE + s index_html_name = 'cppcheck/index-%s.html' % name if self.env.CPPCHECK_SINGLE_HTML: index_html_name = 'cppcheck/index.html' node = self.generator.path.get_bld().find_or_declare(index_html_name) node.write(s) return node def _create_html_table(self, content, files): table = ElementTree.fromstring(CPPCHECK_HTML_TABLE) for name, val in files.items(): f = val['htmlfile'] s = '%s\n' % (f,name) row = ElementTree.fromstring(s) table.append(row) errors = sorted(val['errors'], key=lambda e: int(e['line']) if 'line' in e else sys.maxint) for e in errors: if not 'line' in e: s = '%s%s%s\n' % (e['id'], e['severity'], e['msg']) else: attr = '' if e['severity'] == 'error': attr = 'class="error"' s = '%s' % (f, e['line'], e['line']) s+= '%s%s%s\n' % (e['id'], e['severity'], attr, e['msg']) row = ElementTree.fromstring(s) table.append(row) content.append(table) def _create_css_file(self, css_style_defs): css = str(CPPCHECK_CSS_FILE) if css_style_defs: css = "%s\n%s\n" % (css, css_style_defs) node = self.generator.path.get_bld().find_or_declare('cppcheck/style.css') node.write(css) def _errors_evaluate(self, errors, http_index): name = self.generator.get_name() fatal = self.fatal severity = [err['severity'] for err in errors] problems = [err for err in errors if err['severity'] != 'information'] if set(fatal) & set(severity): exc = "\n" exc += "\nccpcheck detected fatal error(s) in task '%s', see report for details:" % name exc += "\n file://%r" % (http_index) exc += "\n" self.generator.bld.fatal(exc) elif len(problems): msg = "\nccpcheck detected (possible) problem(s) in task '%s', see report for details:" % name msg += "\n file://%r" % http_index msg += "\n" Logs.error(msg) class CppcheckHtmlFormatter(pygments.formatters.HtmlFormatter): errors = [] def wrap(self, source, outfile): line_no = 1 for i, t in super(CppcheckHtmlFormatter, self).wrap(source, outfile): # If this is a source code line we want to add a span tag at the end. if i == 1: for error in self.errors: if int(error['line']) == line_no: t = t.replace('\n', CPPCHECK_HTML_ERROR % error['msg']) line_no += 1 yield i, t CCPCHECK_HTML_TYPE = \ '\n' CPPCHECK_HTML_FILE = """ ]> cppcheck - report - XXX
 
""" CPPCHECK_HTML_TABLE = """
Line Id Severity Message
""" CPPCHECK_HTML_ERROR = \ '<--- %s\n' CPPCHECK_CSS_FILE = """ body.body { font-family: Arial; font-size: 13px; background-color: black; padding: 0px; margin: 0px; } .error { font-family: Arial; font-size: 13px; background-color: #ffb7b7; padding: 0px; margin: 0px; } th, td { min-width: 100px; text-align: left; } #page-header { clear: both; width: 1200px; margin: 20px auto 0px auto; height: 10px; border-bottom-width: 2px; border-bottom-style: solid; border-bottom-color: #aaaaaa; } #page { width: 1160px; margin: auto; border-left-width: 2px; border-left-style: solid; border-left-color: #aaaaaa; border-right-width: 2px; border-right-style: solid; border-right-color: #aaaaaa; background-color: White; padding: 20px; } #page-footer { clear: both; width: 1200px; margin: auto; height: 10px; border-top-width: 2px; border-top-style: solid; border-top-color: #aaaaaa; } #header { width: 100%; height: 70px; background-image: url(logo.png); background-repeat: no-repeat; background-position: left top; border-bottom-style: solid; border-bottom-width: thin; border-bottom-color: #aaaaaa; } #menu { margin-top: 5px; text-align: left; float: left; width: 100px; height: 300px; } #menu > a { margin-left: 10px; display: block; } #content { float: left; width: 1020px; margin: 5px; padding: 0px 10px 10px 10px; border-left-style: solid; border-left-width: thin; border-left-color: #aaaaaa; } #footer { padding-bottom: 5px; padding-top: 5px; border-top-style: solid; border-top-width: thin; border-top-color: #aaaaaa; clear: both; font-size: 10px; } #footer > div { float: left; width: 33%; } """ hamster-3.0.3/waflib/extras/cpplint.py000066400000000000000000000165421452646177100200020ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # # written by Sylvain Rouquette, 2014 ''' This is an extra tool, not bundled with the default waf binary. To add the cpplint tool to the waf file: $ ./waf-light --tools=compat15,cpplint this tool also requires cpplint for python. If you have PIP, you can install it like this: pip install cpplint When using this tool, the wscript will look like: def options(opt): opt.load('compiler_cxx cpplint') def configure(conf): conf.load('compiler_cxx cpplint') # optional, you can also specify them on the command line conf.env.CPPLINT_FILTERS = ','.join(( '-whitespace/newline', # c++11 lambda '-readability/braces', # c++11 constructor '-whitespace/braces', # c++11 constructor '-build/storage_class', # c++11 for-range '-whitespace/blank_line', # user pref '-whitespace/labels' # user pref )) def build(bld): bld(features='cpplint', source='main.cpp', target='app') # add include files, because they aren't usually built bld(features='cpplint', source=bld.path.ant_glob('**/*.hpp')) ''' from __future__ import absolute_import import sys, re import logging from waflib import Errors, Task, TaskGen, Logs, Options, Node, Utils critical_errors = 0 CPPLINT_FORMAT = '[CPPLINT] %(filename)s:\nline %(linenum)s, severity %(confidence)s, category: %(category)s\n%(message)s\n' RE_EMACS = re.compile(r'(?P.*):(?P\d+): (?P.*) \[(?P.*)\] \[(?P\d+)\]') CPPLINT_RE = { 'waf': RE_EMACS, 'emacs': RE_EMACS, 'vs7': re.compile(r'(?P.*)\((?P\d+)\): (?P.*) \[(?P.*)\] \[(?P\d+)\]'), 'eclipse': re.compile(r'(?P.*):(?P\d+): warning: (?P.*) \[(?P.*)\] \[(?P\d+)\]'), } CPPLINT_STR = ('${CPPLINT} ' '--verbose=${CPPLINT_LEVEL} ' '--output=${CPPLINT_OUTPUT} ' '--filter=${CPPLINT_FILTERS} ' '--root=${CPPLINT_ROOT} ' '--linelength=${CPPLINT_LINE_LENGTH} ') def options(opt): opt.add_option('--cpplint-filters', type='string', default='', dest='CPPLINT_FILTERS', help='add filters to cpplint') opt.add_option('--cpplint-length', type='int', default=80, dest='CPPLINT_LINE_LENGTH', help='specify the line length (default: 80)') opt.add_option('--cpplint-level', default=1, type='int', dest='CPPLINT_LEVEL', help='specify the log level (default: 1)') opt.add_option('--cpplint-break', default=5, type='int', dest='CPPLINT_BREAK', help='break the build if error >= level (default: 5)') opt.add_option('--cpplint-root', type='string', default='', dest='CPPLINT_ROOT', help='root directory used to derive header guard') opt.add_option('--cpplint-skip', action='store_true', default=False, dest='CPPLINT_SKIP', help='skip cpplint during build') opt.add_option('--cpplint-output', type='string', default='waf', dest='CPPLINT_OUTPUT', help='select output format (waf, emacs, vs7, eclipse)') def configure(conf): try: conf.find_program('cpplint', var='CPPLINT') except Errors.ConfigurationError: conf.env.CPPLINT_SKIP = True class cpplint_formatter(Logs.formatter, object): def __init__(self, fmt): logging.Formatter.__init__(self, CPPLINT_FORMAT) self.fmt = fmt def format(self, rec): if self.fmt == 'waf': result = CPPLINT_RE[self.fmt].match(rec.msg).groupdict() rec.msg = CPPLINT_FORMAT % result if rec.levelno <= logging.INFO: rec.c1 = Logs.colors.CYAN return super(cpplint_formatter, self).format(rec) class cpplint_handler(Logs.log_handler, object): def __init__(self, stream=sys.stderr, **kw): super(cpplint_handler, self).__init__(stream, **kw) self.stream = stream def emit(self, rec): rec.stream = self.stream self.emit_override(rec) self.flush() class cpplint_wrapper(object): def __init__(self, logger, threshold, fmt): self.logger = logger self.threshold = threshold self.fmt = fmt def __enter__(self): return self def __exit__(self, exc_type, exc_value, traceback): if isinstance(exc_value, Utils.subprocess.CalledProcessError): messages = [m for m in exc_value.output.splitlines() if 'Done processing' not in m and 'Total errors found' not in m] for message in messages: self.write(message) return True def write(self, message): global critical_errors result = CPPLINT_RE[self.fmt].match(message) if not result: return level = int(result.groupdict()['confidence']) if level >= self.threshold: critical_errors += 1 if level <= 2: self.logger.info(message) elif level <= 4: self.logger.warning(message) else: self.logger.error(message) cpplint_logger = None def get_cpplint_logger(fmt): global cpplint_logger if cpplint_logger: return cpplint_logger cpplint_logger = logging.getLogger('cpplint') hdlr = cpplint_handler() hdlr.setFormatter(cpplint_formatter(fmt)) cpplint_logger.addHandler(hdlr) cpplint_logger.setLevel(logging.DEBUG) return cpplint_logger class cpplint(Task.Task): color = 'PINK' def __init__(self, *k, **kw): super(cpplint, self).__init__(*k, **kw) def run(self): global critical_errors with cpplint_wrapper(get_cpplint_logger(self.env.CPPLINT_OUTPUT), self.env.CPPLINT_BREAK, self.env.CPPLINT_OUTPUT): params = {key: str(self.env[key]) for key in self.env if 'CPPLINT_' in key} if params['CPPLINT_OUTPUT'] == 'waf': params['CPPLINT_OUTPUT'] = 'emacs' params['CPPLINT'] = self.env.get_flat('CPPLINT') cmd = Utils.subst_vars(CPPLINT_STR, params) env = self.env.env or None Utils.subprocess.check_output(cmd + self.inputs[0].abspath(), stderr=Utils.subprocess.STDOUT, env=env, shell=True) return critical_errors @TaskGen.extension('.h', '.hh', '.hpp', '.hxx') def cpplint_includes(self, node): pass @TaskGen.feature('cpplint') @TaskGen.before_method('process_source') def post_cpplint(self): if not self.env.CPPLINT_INITIALIZED: for key, value in Options.options.__dict__.items(): if not key.startswith('CPPLINT_') or self.env[key]: continue self.env[key] = value self.env.CPPLINT_INITIALIZED = True if self.env.CPPLINT_SKIP: return if not self.env.CPPLINT_OUTPUT in CPPLINT_RE: return for src in self.to_list(getattr(self, 'source', [])): if isinstance(src, Node.Node): node = src else: node = self.path.find_or_declare(src) if not node: self.bld.fatal('Could not find %r' % src) self.create_task('cpplint', node) hamster-3.0.3/waflib/extras/cross_gnu.py000066400000000000000000000137351452646177100203340ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 vi:ts=4:noexpandtab # Tool to provide dedicated variables for cross-compilation __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2014" """ This tool allows to use environment variables to define cross-compilation variables intended for build variants. The variables are obtained from the environment in 3 ways: 1. By defining CHOST, they can be derived as ${CHOST}-${TOOL} 2. By defining HOST_x 3. By defining ${CHOST//-/_}_x else one can set ``cfg.env.CHOST`` in ``wscript`` before loading ``cross_gnu``. Usage: - In your build script:: def configure(cfg): ... for variant in x_variants: setenv(variant) conf.load('cross_gnu') conf.xcheck_host_var('POUET') ... - Then:: CHOST=arm-hardfloat-linux-gnueabi waf configure env arm-hardfloat-linux-gnueabi-CC="clang -..." waf configure CFLAGS=... CHOST=arm-hardfloat-linux-gnueabi HOST_CFLAGS=-g waf configure HOST_CC="clang -..." waf configure This example ``wscript`` compiles to Microchip PIC (xc16-gcc-xyz must be in PATH): .. code:: python from waflib import Configure #from https://gist.github.com/rpuntaie/2bddfb5d7b77db26415ee14371289971 import waf_variants variants='pc fw/variant1 fw/variant2'.split() top = "." out = "../build" PIC = '33FJ128GP804' #dsPICxxx @Configure.conf def gcc_modifier_xc16(cfg): v = cfg.env v.cprogram_PATTERN = '%s.elf' v.LINKFLAGS_cprogram = ','.join(['-Wl','','','--defsym=__MPLAB_BUILD=0','','--script=p'+PIC+'.gld', '--stack=16','--check-sections','--data-init','--pack-data','--handles','--isr','--no-gc-sections', '--fill-upper=0','--stackguard=16','--no-force-link','--smart-io']) #,'--report-mem']) v.CFLAGS_cprogram=['-mcpu='+PIC,'-omf=elf','-mlarge-code','-msmart-io=1', '-msfr-warn=off','-mno-override-inline','-finline','-Winline'] def configure(cfg): if 'fw' in cfg.variant: #firmware cfg.env.DEST_OS = 'xc16' #cfg.env.CHOST = 'xc16' #works too cfg.load('c cross_gnu') #cfg.env.CHOST becomes ['xc16'] ... else: #configure for pc SW ... def build(bld): if 'fw' in bld.variant: #firmware bld.program(source='maintst.c', target='maintst'); bld(source='maintst.elf', target='maintst.hex', rule="xc16-bin2hex ${SRC} -a -omf=elf") else: #build for pc SW ... """ import os from waflib import Utils, Configure from waflib.Tools import ccroot, gcc try: from shlex import quote except ImportError: from pipes import quote def get_chost_stuff(conf): """ Get the CHOST environment variable contents """ chost = None chost_envar = None if conf.env.CHOST: chost = conf.env.CHOST[0] chost_envar = chost.replace('-', '_') return chost, chost_envar @Configure.conf def xcheck_var(conf, name, wafname=None, cross=False): wafname = wafname or name if wafname in conf.env: value = conf.env[wafname] if isinstance(value, str): value = [value] else: envar = os.environ.get(name) if not envar: return value = Utils.to_list(envar) if envar != '' else [envar] conf.env[wafname] = value if cross: pretty = 'cross-compilation %s' % wafname else: pretty = wafname conf.msg('Will use %s' % pretty, " ".join(quote(x) for x in value)) @Configure.conf def xcheck_host_prog(conf, name, tool, wafname=None): wafname = wafname or name chost, chost_envar = get_chost_stuff(conf) specific = None if chost: specific = os.environ.get('%s_%s' % (chost_envar, name)) if specific: value = Utils.to_list(specific) conf.env[wafname] += value conf.msg('Will use cross-compilation %s from %s_%s' % (name, chost_envar, name), " ".join(quote(x) for x in value)) return else: envar = os.environ.get('HOST_%s' % name) if envar is not None: value = Utils.to_list(envar) conf.env[wafname] = value conf.msg('Will use cross-compilation %s from HOST_%s' % (name, name), " ".join(quote(x) for x in value)) return if conf.env[wafname]: return value = None if chost: value = '%s-%s' % (chost, tool) if value: conf.env[wafname] = value conf.msg('Will use cross-compilation %s from CHOST' % wafname, value) @Configure.conf def xcheck_host_envar(conf, name, wafname=None): wafname = wafname or name chost, chost_envar = get_chost_stuff(conf) specific = None if chost: specific = os.environ.get('%s_%s' % (chost_envar, name)) if specific: value = Utils.to_list(specific) conf.env[wafname] += value conf.msg('Will use cross-compilation %s from %s_%s' \ % (name, chost_envar, name), " ".join(quote(x) for x in value)) return envar = os.environ.get('HOST_%s' % name) if envar is None: return value = Utils.to_list(envar) if envar != '' else [envar] conf.env[wafname] = value conf.msg('Will use cross-compilation %s from HOST_%s' % (name, name), " ".join(quote(x) for x in value)) @Configure.conf def xcheck_host(conf): conf.xcheck_var('CHOST', cross=True) conf.env.CHOST = conf.env.CHOST or [conf.env.DEST_OS] conf.env.DEST_OS = conf.env.CHOST[0].replace('-','_') conf.xcheck_host_prog('CC', 'gcc') conf.xcheck_host_prog('CXX', 'g++') conf.xcheck_host_prog('LINK_CC', 'gcc') conf.xcheck_host_prog('LINK_CXX', 'g++') conf.xcheck_host_prog('AR', 'ar') conf.xcheck_host_prog('AS', 'as') conf.xcheck_host_prog('LD', 'ld') conf.xcheck_host_envar('CFLAGS') conf.xcheck_host_envar('CXXFLAGS') conf.xcheck_host_envar('LDFLAGS', 'LINKFLAGS') conf.xcheck_host_envar('LIB') conf.xcheck_host_envar('PKG_CONFIG_LIBDIR') conf.xcheck_host_envar('PKG_CONFIG_PATH') if not conf.env.env: conf.env.env = {} conf.env.env.update(os.environ) if conf.env.PKG_CONFIG_LIBDIR: conf.env.env['PKG_CONFIG_LIBDIR'] = conf.env.PKG_CONFIG_LIBDIR[0] if conf.env.PKG_CONFIG_PATH: conf.env.env['PKG_CONFIG_PATH'] = conf.env.PKG_CONFIG_PATH[0] def configure(conf): """ Configuration example for gcc, it will not work for g++/clang/clang++ """ conf.xcheck_host() conf.gcc_common_flags() conf.gcc_modifier_platform() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/cython.py000066400000000000000000000101451452646177100176260ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010-2015 import re from waflib import Task, Logs from waflib.TaskGen import extension cy_api_pat = re.compile(r'\s*?cdef\s*?(public|api)\w*') re_cyt = re.compile(r""" ^\s* # must begin with some whitespace characters (?:from\s+(\w+)(?:\.\w+)*\s+)? # optionally match "from foo(.baz)" and capture foo c?import\s(\w+|[*]) # require "import bar" and capture bar """, re.M | re.VERBOSE) @extension('.pyx') def add_cython_file(self, node): """ Process a *.pyx* file given in the list of source files. No additional feature is required:: def build(bld): bld(features='c cshlib pyext', source='main.c foo.pyx', target='app') """ ext = '.c' if 'cxx' in self.features: self.env.append_unique('CYTHONFLAGS', '--cplus') ext = '.cc' for x in getattr(self, 'cython_includes', []): # TODO re-use these nodes in "scan" below d = self.path.find_dir(x) if d: self.env.append_unique('CYTHONFLAGS', '-I%s' % d.abspath()) tsk = self.create_task('cython', node, node.change_ext(ext)) self.source += tsk.outputs class cython(Task.Task): run_str = '${CYTHON} ${CYTHONFLAGS} -o ${TGT[0].abspath()} ${SRC}' color = 'GREEN' vars = ['INCLUDES'] """ Rebuild whenever the INCLUDES change. The variables such as CYTHONFLAGS will be appended by the metaclass. """ ext_out = ['.h'] """ The creation of a .h file is known only after the build has begun, so it is not possible to compute a build order just by looking at the task inputs/outputs. """ def runnable_status(self): """ Perform a double-check to add the headers created by cython to the output nodes. The scanner is executed only when the cython task must be executed (optimization). """ ret = super(cython, self).runnable_status() if ret == Task.ASK_LATER: return ret for x in self.generator.bld.raw_deps[self.uid()]: if x.startswith('header:'): self.outputs.append(self.inputs[0].parent.find_or_declare(x.replace('header:', ''))) return super(cython, self).runnable_status() def post_run(self): for x in self.outputs: if x.name.endswith('.h'): if not x.exists(): if Logs.verbose: Logs.warn('Expected %r', x.abspath()) x.write('') return Task.Task.post_run(self) def scan(self): """ Return the dependent files (.pxd) by looking in the include folders. Put the headers to generate in the custom list "bld.raw_deps". To inspect the scanne results use:: $ waf clean build --zones=deps """ node = self.inputs[0] txt = node.read() mods = set() for m in re_cyt.finditer(txt): if m.group(1): # matches "from foo import bar" mods.add(m.group(1)) else: mods.add(m.group(2)) Logs.debug('cython: mods %r', mods) incs = getattr(self.generator, 'cython_includes', []) incs = [self.generator.path.find_dir(x) for x in incs] incs.append(node.parent) found = [] missing = [] for x in sorted(mods): for y in incs: k = y.find_resource(x + '.pxd') if k: found.append(k) break else: missing.append(x) # the cython file implicitly depends on a pxd file that might be present implicit = node.parent.find_resource(node.name[:-3] + 'pxd') if implicit: found.append(implicit) Logs.debug('cython: found %r', found) # Now the .h created - store them in bld.raw_deps for later use has_api = False has_public = False for l in txt.splitlines(): if cy_api_pat.match(l): if ' api ' in l: has_api = True if ' public ' in l: has_public = True name = node.name.replace('.pyx', '') if has_api: missing.append('header:%s_api.h' % name) if has_public: missing.append('header:%s.h' % name) return (found, missing) def options(ctx): ctx.add_option('--cython-flags', action='store', default='', help='space separated list of flags to pass to cython') def configure(ctx): if not ctx.env.CC and not ctx.env.CXX: ctx.fatal('Load a C/C++ compiler first') if not ctx.env.PYTHON: ctx.fatal('Load the python tool first!') ctx.find_program('cython', var='CYTHON') if hasattr(ctx.options, 'cython_flags'): ctx.env.CYTHONFLAGS = ctx.options.cython_flags hamster-3.0.3/waflib/extras/dcc.py000066400000000000000000000035731452646177100170620ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Jérôme Carretero, 2011 (zougloub) from waflib import Options from waflib.Tools import ccroot from waflib.Configure import conf @conf def find_dcc(conf): conf.find_program(['dcc'], var='CC', path_list=getattr(Options.options, 'diabbindir', "")) conf.env.CC_NAME = 'dcc' @conf def find_dld(conf): conf.find_program(['dld'], var='LINK_CC', path_list=getattr(Options.options, 'diabbindir', "")) conf.env.LINK_CC_NAME = 'dld' @conf def find_dar(conf): conf.find_program(['dar'], var='AR', path_list=getattr(Options.options, 'diabbindir', "")) conf.env.AR_NAME = 'dar' conf.env.ARFLAGS = 'rcs' @conf def find_ddump(conf): conf.find_program(['ddump'], var='DDUMP', path_list=getattr(Options.options, 'diabbindir', "")) @conf def dcc_common_flags(conf): v = conf.env v['CC_SRC_F'] = [] v['CC_TGT_F'] = ['-c', '-o'] # linker if not v['LINK_CC']: v['LINK_CC'] = v['CC'] v['CCLNK_SRC_F'] = [] v['CCLNK_TGT_F'] = ['-o'] v['CPPPATH_ST'] = '-I%s' v['DEFINES_ST'] = '-D%s' v['LIB_ST'] = '-l:%s' # template for adding libs v['LIBPATH_ST'] = '-L%s' # template for adding libpaths v['STLIB_ST'] = '-l:%s' v['STLIBPATH_ST'] = '-L%s' v['RPATH_ST'] = '-Wl,-rpath,%s' #v['STLIB_MARKER'] = '-Wl,-Bstatic' # program v['cprogram_PATTERN'] = '%s.elf' # static lib v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic'] v['cstlib_PATTERN'] = 'lib%s.a' def configure(conf): conf.find_dcc() conf.find_dar() conf.find_dld() conf.find_ddump() conf.dcc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() def options(opt): """ Add the ``--with-diab-bindir`` command-line options. """ opt.add_option('--with-diab-bindir', type='string', dest='diabbindir', help = 'Specify alternate diab bin folder', default="") hamster-3.0.3/waflib/extras/distnet.py000066400000000000000000000266571452646177100200130ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ waf-powered distributed network builds, with a network cache. Caching files from a server has advantages over a NFS/Samba shared folder: - builds are much faster because they use local files - builds just continue to work in case of a network glitch - permissions are much simpler to manage """ import os, urllib, tarfile, re, shutil, tempfile, sys from collections import OrderedDict from waflib import Context, Utils, Logs try: from urllib.parse import urlencode except ImportError: urlencode = urllib.urlencode def safe_urlencode(data): x = urlencode(data) try: x = x.encode('utf-8') except Exception: pass return x try: from urllib.error import URLError except ImportError: from urllib2 import URLError try: from urllib.request import Request, urlopen except ImportError: from urllib2 import Request, urlopen DISTNETCACHE = os.environ.get('DISTNETCACHE', '/tmp/distnetcache') DISTNETSERVER = os.environ.get('DISTNETSERVER', 'http://localhost:8000/cgi-bin/') TARFORMAT = 'w:bz2' TIMEOUT = 60 REQUIRES = 'requires.txt' re_com = re.compile(r'\s*#.*', re.M) def total_version_order(num): lst = num.split('.') template = '%10s' * len(lst) ret = template % tuple(lst) return ret def get_distnet_cache(): return getattr(Context.g_module, 'DISTNETCACHE', DISTNETCACHE) def get_server_url(): return getattr(Context.g_module, 'DISTNETSERVER', DISTNETSERVER) def get_download_url(): return '%s/download.py' % get_server_url() def get_upload_url(): return '%s/upload.py' % get_server_url() def get_resolve_url(): return '%s/resolve.py' % get_server_url() def send_package_name(): out = getattr(Context.g_module, 'out', 'build') pkgfile = '%s/package_to_upload.tarfile' % out return pkgfile class package(Context.Context): fun = 'package' cmd = 'package' def execute(self): try: files = self.files except AttributeError: files = self.files = [] Context.Context.execute(self) pkgfile = send_package_name() if not pkgfile in files: if not REQUIRES in files: files.append(REQUIRES) self.make_tarfile(pkgfile, files, add_to_package=False) def make_tarfile(self, filename, files, **kw): if kw.get('add_to_package', True): self.files.append(filename) with tarfile.open(filename, TARFORMAT) as tar: endname = os.path.split(filename)[-1] endname = endname.split('.')[0] + '/' for x in files: tarinfo = tar.gettarinfo(x, x) tarinfo.uid = tarinfo.gid = 0 tarinfo.uname = tarinfo.gname = 'root' tarinfo.size = os.stat(x).st_size if os.environ.get('SOURCE_DATE_EPOCH'): tarinfo.mtime = int(os.environ.get('SOURCE_DATE_EPOCH')) # TODO - more archive creation options? if kw.get('bare', True): tarinfo.name = os.path.split(x)[1] else: tarinfo.name = endname + x # todo, if tuple, then.. Logs.debug('distnet: adding %r to %s', tarinfo.name, filename) with open(x, 'rb') as f: tar.addfile(tarinfo, f) Logs.info('Created %s', filename) class publish(Context.Context): fun = 'publish' cmd = 'publish' def execute(self): if hasattr(Context.g_module, 'publish'): Context.Context.execute(self) mod = Context.g_module rfile = getattr(self, 'rfile', send_package_name()) if not os.path.isfile(rfile): self.fatal('Create the release file with "waf release" first! %r' % rfile) fdata = Utils.readf(rfile, m='rb') data = safe_urlencode([('pkgdata', fdata), ('pkgname', mod.APPNAME), ('pkgver', mod.VERSION)]) req = Request(get_upload_url(), data) response = urlopen(req, timeout=TIMEOUT) data = response.read().strip() if sys.hexversion>0x300000f: data = data.decode('utf-8') if data != 'ok': self.fatal('Could not publish the package %r' % data) class constraint(object): def __init__(self, line=''): self.required_line = line self.info = [] line = line.strip() if not line: return lst = line.split(',') if lst: self.pkgname = lst[0] self.required_version = lst[1] for k in lst: a, b, c = k.partition('=') if a and c: self.info.append((a, c)) def __str__(self): buf = [] buf.append(self.pkgname) buf.append(self.required_version) for k in self.info: buf.append('%s=%s' % k) return ','.join(buf) def __repr__(self): return "requires %s-%s" % (self.pkgname, self.required_version) def human_display(self, pkgname, pkgver): return '%s-%s requires %s-%s' % (pkgname, pkgver, self.pkgname, self.required_version) def why(self): ret = [] for x in self.info: if x[0] == 'reason': ret.append(x[1]) return ret def add_reason(self, reason): self.info.append(('reason', reason)) def parse_constraints(text): assert(text is not None) constraints = [] text = re.sub(re_com, '', text) lines = text.splitlines() for line in lines: line = line.strip() if not line: continue constraints.append(constraint(line)) return constraints def list_package_versions(cachedir, pkgname): pkgdir = os.path.join(cachedir, pkgname) try: versions = os.listdir(pkgdir) except OSError: return [] versions.sort(key=total_version_order) versions.reverse() return versions class package_reader(Context.Context): cmd = 'solver' fun = 'solver' def __init__(self, **kw): Context.Context.__init__(self, **kw) self.myproject = getattr(Context.g_module, 'APPNAME', 'project') self.myversion = getattr(Context.g_module, 'VERSION', '1.0') self.cache_constraints = {} self.constraints = [] def compute_dependencies(self, filename=REQUIRES): text = Utils.readf(filename) data = safe_urlencode([('text', text)]) if '--offline' in sys.argv: self.constraints = self.local_resolve(text) else: req = Request(get_resolve_url(), data) try: response = urlopen(req, timeout=TIMEOUT) except URLError as e: Logs.warn('The package server is down! %r', e) self.constraints = self.local_resolve(text) else: ret = response.read() try: ret = ret.decode('utf-8') except Exception: pass self.trace(ret) self.constraints = parse_constraints(ret) self.check_errors() def check_errors(self): errors = False for c in self.constraints: if not c.required_version: errors = True reasons = c.why() if len(reasons) == 1: Logs.error('%s but no matching package could be found in this repository', reasons[0]) else: Logs.error('Conflicts on package %r:', c.pkgname) for r in reasons: Logs.error(' %s', r) if errors: self.fatal('The package requirements cannot be satisfied!') def load_constraints(self, pkgname, pkgver, requires=REQUIRES): try: return self.cache_constraints[(pkgname, pkgver)] except KeyError: text = Utils.readf(os.path.join(get_distnet_cache(), pkgname, pkgver, requires)) ret = parse_constraints(text) self.cache_constraints[(pkgname, pkgver)] = ret return ret def apply_constraint(self, domain, constraint): vname = constraint.required_version.replace('*', '.*') rev = re.compile(vname, re.M) ret = [x for x in domain if rev.match(x)] return ret def trace(self, *k): if getattr(self, 'debug', None): Logs.error(*k) def solve(self, packages_to_versions={}, packages_to_constraints={}, pkgname='', pkgver='', todo=[], done=[]): # breadth first search n_packages_to_versions = dict(packages_to_versions) n_packages_to_constraints = dict(packages_to_constraints) self.trace("calling solve with %r %r %r" % (packages_to_versions, todo, done)) done = done + [pkgname] constraints = self.load_constraints(pkgname, pkgver) self.trace("constraints %r" % constraints) for k in constraints: try: domain = n_packages_to_versions[k.pkgname] except KeyError: domain = list_package_versions(get_distnet_cache(), k.pkgname) self.trace("constraints?") if not k.pkgname in done: todo = todo + [k.pkgname] self.trace("domain before %s -> %s, %r" % (pkgname, k.pkgname, domain)) # apply the constraint domain = self.apply_constraint(domain, k) self.trace("domain after %s -> %s, %r" % (pkgname, k.pkgname, domain)) n_packages_to_versions[k.pkgname] = domain # then store the constraint applied constraints = list(packages_to_constraints.get(k.pkgname, [])) constraints.append((pkgname, pkgver, k)) n_packages_to_constraints[k.pkgname] = constraints if not domain: self.trace("no domain while processing constraint %r from %r %r" % (domain, pkgname, pkgver)) return (n_packages_to_versions, n_packages_to_constraints) # next package on the todo list if not todo: return (n_packages_to_versions, n_packages_to_constraints) n_pkgname = todo[0] n_pkgver = n_packages_to_versions[n_pkgname][0] tmp = dict(n_packages_to_versions) tmp[n_pkgname] = [n_pkgver] self.trace("fixed point %s" % n_pkgname) return self.solve(tmp, n_packages_to_constraints, n_pkgname, n_pkgver, todo[1:], done) def get_results(self): return '\n'.join([str(c) for c in self.constraints]) def solution_to_constraints(self, versions, constraints): solution = [] for p in versions: c = constraint() solution.append(c) c.pkgname = p if versions[p]: c.required_version = versions[p][0] else: c.required_version = '' for (from_pkgname, from_pkgver, c2) in constraints.get(p, ''): c.add_reason(c2.human_display(from_pkgname, from_pkgver)) return solution def local_resolve(self, text): self.cache_constraints[(self.myproject, self.myversion)] = parse_constraints(text) p2v = OrderedDict({self.myproject: [self.myversion]}) (versions, constraints) = self.solve(p2v, {}, self.myproject, self.myversion, []) return self.solution_to_constraints(versions, constraints) def download_to_file(self, pkgname, pkgver, subdir, tmp): data = safe_urlencode([('pkgname', pkgname), ('pkgver', pkgver), ('pkgfile', subdir)]) req = urlopen(get_download_url(), data, timeout=TIMEOUT) with open(tmp, 'wb') as f: while True: buf = req.read(8192) if not buf: break f.write(buf) def extract_tar(self, subdir, pkgdir, tmpfile): with tarfile.open(tmpfile) as f: temp = tempfile.mkdtemp(dir=pkgdir) try: f.extractall(temp) os.rename(temp, os.path.join(pkgdir, subdir)) finally: try: shutil.rmtree(temp) except Exception: pass def get_pkg_dir(self, pkgname, pkgver, subdir): pkgdir = os.path.join(get_distnet_cache(), pkgname, pkgver) if not os.path.isdir(pkgdir): os.makedirs(pkgdir) target = os.path.join(pkgdir, subdir) if os.path.exists(target): return target (fd, tmp) = tempfile.mkstemp(dir=pkgdir) try: os.close(fd) self.download_to_file(pkgname, pkgver, subdir, tmp) if subdir == REQUIRES: os.rename(tmp, target) else: self.extract_tar(subdir, pkgdir, tmp) finally: try: os.remove(tmp) except OSError: pass return target def __iter__(self): if not self.constraints: self.compute_dependencies() for x in self.constraints: if x.pkgname == self.myproject: continue yield x def execute(self): self.compute_dependencies() packages = package_reader() def load_tools(ctx, extra): global packages for c in packages: packages.get_pkg_dir(c.pkgname, c.required_version, extra) noarchdir = packages.get_pkg_dir(c.pkgname, c.required_version, 'noarch') for x in os.listdir(noarchdir): if x.startswith('waf_') and x.endswith('.py'): ctx.load([x.rstrip('.py')], tooldir=[noarchdir]) def options(opt): opt.add_option('--offline', action='store_true') packages.execute() load_tools(opt, REQUIRES) def configure(conf): load_tools(conf, conf.variant) def build(bld): load_tools(bld, bld.variant) hamster-3.0.3/waflib/extras/doxygen.py000066400000000000000000000164571452646177100200130ustar00rootroot00000000000000#! /usr/bin/env python # encoding: UTF-8 # Thomas Nagy 2008-2010 (ita) """ Doxygen support Variables passed to bld(): * doxyfile -- the Doxyfile to use * doxy_tar -- destination archive for generated documentation (if desired) * install_path -- where to install the documentation * pars -- dictionary overriding doxygen configuration settings When using this tool, the wscript will look like: def options(opt): opt.load('doxygen') def configure(conf): conf.load('doxygen') # check conf.env.DOXYGEN, if it is mandatory def build(bld): if bld.env.DOXYGEN: bld(features="doxygen", doxyfile='Doxyfile', ...) """ import os, os.path, re from collections import OrderedDict from waflib import Task, Utils, Node from waflib.TaskGen import feature DOXY_STR = '"${DOXYGEN}" - ' DOXY_FMTS = 'html latex man rft xml'.split() DOXY_FILE_PATTERNS = '*.' + ' *.'.join(''' c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx hpp h++ idl odl cs php php3 inc m mm py f90c cc cxx cpp c++ java ii ixx ipp i++ inl h hh hxx '''.split()) re_rl = re.compile('\\\\\r*\n', re.MULTILINE) re_nl = re.compile('\r*\n', re.M) def parse_doxy(txt): ''' Parses a doxygen file. Returns an ordered dictionary. We cannot return a default dictionary, as the order in which the entries are reported does matter, especially for the '@INCLUDE' lines. ''' tbl = OrderedDict() txt = re_rl.sub('', txt) lines = re_nl.split(txt) for x in lines: x = x.strip() if not x or x.startswith('#') or x.find('=') < 0: continue if x.find('+=') >= 0: tmp = x.split('+=') key = tmp[0].strip() if key in tbl: tbl[key] += ' ' + '+='.join(tmp[1:]).strip() else: tbl[key] = '+='.join(tmp[1:]).strip() else: tmp = x.split('=') tbl[tmp[0].strip()] = '='.join(tmp[1:]).strip() return tbl class doxygen(Task.Task): vars = ['DOXYGEN', 'DOXYFLAGS'] color = 'BLUE' ext_in = [ '.py', '.c', '.h', '.java', '.pb.cc' ] def runnable_status(self): ''' self.pars are populated in runnable_status - because this function is being run *before* both self.pars "consumers" - scan() and run() set output_dir (node) for the output ''' for x in self.run_after: if not x.hasrun: return Task.ASK_LATER if not getattr(self, 'pars', None): txt = self.inputs[0].read() self.pars = parse_doxy(txt) # Override with any parameters passed to the task generator if getattr(self.generator, 'pars', None): for k, v in self.generator.pars.items(): self.pars[k] = v if self.pars.get('OUTPUT_DIRECTORY'): # Use the path parsed from the Doxyfile as an absolute path output_node = self.inputs[0].parent.get_bld().make_node(self.pars['OUTPUT_DIRECTORY']) else: # If no OUTPUT_PATH was specified in the Doxyfile, build path from the Doxyfile name + '.doxy' output_node = self.inputs[0].parent.get_bld().make_node(self.inputs[0].name + '.doxy') output_node.mkdir() self.pars['OUTPUT_DIRECTORY'] = output_node.abspath() self.doxy_inputs = getattr(self, 'doxy_inputs', []) if not self.pars.get('INPUT'): self.doxy_inputs.append(self.inputs[0].parent) else: for i in self.pars.get('INPUT').split(): if os.path.isabs(i): node = self.generator.bld.root.find_node(i) else: node = self.inputs[0].parent.find_node(i) if not node: self.generator.bld.fatal('Could not find the doxygen input %r' % i) self.doxy_inputs.append(node) if not getattr(self, 'output_dir', None): bld = self.generator.bld # Output path is always an absolute path as it was transformed above. self.output_dir = bld.root.find_dir(self.pars['OUTPUT_DIRECTORY']) self.signature() ret = Task.Task.runnable_status(self) if ret == Task.SKIP_ME: # in case the files were removed self.add_install() return ret def scan(self): exclude_patterns = self.pars.get('EXCLUDE_PATTERNS','').split() exclude_patterns = [pattern.replace('*/', '**/') for pattern in exclude_patterns] file_patterns = self.pars.get('FILE_PATTERNS','').split() if not file_patterns: file_patterns = DOXY_FILE_PATTERNS.split() if self.pars.get('RECURSIVE') == 'YES': file_patterns = ["**/%s" % pattern for pattern in file_patterns] nodes = [] names = [] for node in self.doxy_inputs: if os.path.isdir(node.abspath()): for m in node.ant_glob(incl=file_patterns, excl=exclude_patterns): nodes.append(m) else: nodes.append(node) return (nodes, names) def run(self): dct = self.pars.copy() code = '\n'.join(['%s = %s' % (x, dct[x]) for x in self.pars]) code = code.encode() # for python 3 #fmt = DOXY_STR % (self.inputs[0].parent.abspath()) cmd = Utils.subst_vars(DOXY_STR, self.env) env = self.env.env or None proc = Utils.subprocess.Popen(cmd, shell=True, stdin=Utils.subprocess.PIPE, env=env, cwd=self.inputs[0].parent.abspath()) proc.communicate(code) return proc.returncode def post_run(self): nodes = self.output_dir.ant_glob('**/*', quiet=True) for x in nodes: self.generator.bld.node_sigs[x] = self.uid() self.add_install() return Task.Task.post_run(self) def add_install(self): nodes = self.output_dir.ant_glob('**/*', quiet=True) self.outputs += nodes if getattr(self.generator, 'install_path', None): if not getattr(self.generator, 'doxy_tar', None): self.generator.add_install_files(install_to=self.generator.install_path, install_from=self.outputs, postpone=False, cwd=self.output_dir, relative_trick=True) class tar(Task.Task): "quick tar creation" run_str = '${TAR} ${TAROPTS} ${TGT} ${SRC}' color = 'RED' after = ['doxygen'] def runnable_status(self): for x in getattr(self, 'input_tasks', []): if not x.hasrun: return Task.ASK_LATER if not getattr(self, 'tar_done_adding', None): # execute this only once self.tar_done_adding = True for x in getattr(self, 'input_tasks', []): self.set_inputs(x.outputs) if not self.inputs: return Task.SKIP_ME return Task.Task.runnable_status(self) def __str__(self): tgt_str = ' '.join([a.path_from(a.ctx.launch_node()) for a in self.outputs]) return '%s: %s\n' % (self.__class__.__name__, tgt_str) @feature('doxygen') def process_doxy(self): if not getattr(self, 'doxyfile', None): self.bld.fatal('no doxyfile variable specified??') node = self.doxyfile if not isinstance(node, Node.Node): node = self.path.find_resource(node) if not node: self.bld.fatal('doxygen file %s not found' % self.doxyfile) # the task instance dsk = self.create_task('doxygen', node, always_run=getattr(self, 'always', False)) if getattr(self, 'doxy_tar', None): tsk = self.create_task('tar', always_run=getattr(self, 'always', False)) tsk.input_tasks = [dsk] tsk.set_outputs(self.path.find_or_declare(self.doxy_tar)) if self.doxy_tar.endswith('bz2'): tsk.env['TAROPTS'] = ['cjf'] elif self.doxy_tar.endswith('gz'): tsk.env['TAROPTS'] = ['czf'] else: tsk.env['TAROPTS'] = ['cf'] if getattr(self, 'install_path', None): self.add_install_files(install_to=self.install_path, install_from=tsk.outputs) def configure(conf): ''' Check if doxygen and tar commands are present in the system If the commands are present, then conf.env.DOXYGEN and conf.env.TAR variables will be set. Detection can be controlled by setting DOXYGEN and TAR environmental variables. ''' conf.find_program('doxygen', var='DOXYGEN', mandatory=False) conf.find_program('tar', var='TAR', mandatory=False) hamster-3.0.3/waflib/extras/dpapi.py000066400000000000000000000055661452646177100174320ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Matt Clarkson, 2012 ''' DPAPI access library (http://msdn.microsoft.com/en-us/library/ms995355.aspx) This file uses code originally created by Crusher Joe: http://article.gmane.org/gmane.comp.python.ctypes/420 And modified by Wayne Koorts: http://stackoverflow.com/questions/463832/using-dpapi-with-python ''' from ctypes import windll, byref, cdll, Structure, POINTER, c_char, c_buffer from ctypes.wintypes import DWORD from waflib.Configure import conf LocalFree = windll.kernel32.LocalFree memcpy = cdll.msvcrt.memcpy CryptProtectData = windll.crypt32.CryptProtectData CryptUnprotectData = windll.crypt32.CryptUnprotectData CRYPTPROTECT_UI_FORBIDDEN = 0x01 try: extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd'.encode('ascii') except AttributeError: extra_entropy = 'cl;ad13 \0al;323kjd #(adl;k$#ajsd' class DATA_BLOB(Structure): _fields_ = [ ('cbData', DWORD), ('pbData', POINTER(c_char)) ] def get_data(blob_out): cbData = int(blob_out.cbData) pbData = blob_out.pbData buffer = c_buffer(cbData) memcpy(buffer, pbData, cbData) LocalFree(pbData) return buffer.raw @conf def dpapi_encrypt_data(self, input_bytes, entropy = extra_entropy): ''' Encrypts data and returns byte string :param input_bytes: The data to be encrypted :type input_bytes: String or Bytes :param entropy: Extra entropy to add to the encryption process (optional) :type entropy: String or Bytes ''' if not isinstance(input_bytes, bytes) or not isinstance(entropy, bytes): self.fatal('The inputs to dpapi must be bytes') buffer_in = c_buffer(input_bytes, len(input_bytes)) buffer_entropy = c_buffer(entropy, len(entropy)) blob_in = DATA_BLOB(len(input_bytes), buffer_in) blob_entropy = DATA_BLOB(len(entropy), buffer_entropy) blob_out = DATA_BLOB() if CryptProtectData(byref(blob_in), 'python_data', byref(blob_entropy), None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)): return get_data(blob_out) else: self.fatal('Failed to decrypt data') @conf def dpapi_decrypt_data(self, encrypted_bytes, entropy = extra_entropy): ''' Decrypts data and returns byte string :param encrypted_bytes: The encrypted data :type encrypted_bytes: Bytes :param entropy: Extra entropy to add to the encryption process (optional) :type entropy: String or Bytes ''' if not isinstance(encrypted_bytes, bytes) or not isinstance(entropy, bytes): self.fatal('The inputs to dpapi must be bytes') buffer_in = c_buffer(encrypted_bytes, len(encrypted_bytes)) buffer_entropy = c_buffer(entropy, len(entropy)) blob_in = DATA_BLOB(len(encrypted_bytes), buffer_in) blob_entropy = DATA_BLOB(len(entropy), buffer_entropy) blob_out = DATA_BLOB() if CryptUnprotectData(byref(blob_in), None, byref(blob_entropy), None, None, CRYPTPROTECT_UI_FORBIDDEN, byref(blob_out)): return get_data(blob_out) else: self.fatal('Failed to decrypt data') hamster-3.0.3/waflib/extras/eclipse.py000066400000000000000000000464071452646177100177600ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Eclipse CDT 5.0 generator for Waf # Richard Quirk 2009-1011 (New BSD License) # Thomas Nagy 2011 (ported to Waf 1.6) """ Usage: def options(opt): opt.load('eclipse') To add additional targets beside standard ones (configure, dist, install, check) the environment ECLIPSE_EXTRA_TARGETS can be set (ie. to ['test', 'lint', 'docs']) $ waf configure eclipse """ import sys, os from waflib import Utils, Logs, Context, Build, TaskGen, Scripting, Errors, Node from xml.dom.minidom import Document STANDARD_INCLUDES = [ '/usr/local/include', '/usr/include' ] oe_cdt = 'org.eclipse.cdt' cdt_mk = oe_cdt + '.make.core' cdt_core = oe_cdt + '.core' cdt_bld = oe_cdt + '.build.core' extbuilder_dir = '.externalToolBuilders' extbuilder_name = 'Waf_Builder.launch' settings_dir = '.settings' settings_name = 'language.settings.xml' class eclipse(Build.BuildContext): cmd = 'eclipse' fun = Scripting.default_cmd def execute(self): """ Entry point """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath())) self.create_cproject(appname, pythonpath=self.env['ECLIPSE_PYTHON_PATH']) # Helper to dump the XML document content to XML with UTF-8 encoding def write_conf_to_xml(self, filename, document): self.srcnode.make_node(filename).write(document.toprettyxml(encoding='UTF-8'), flags='wb') def create_cproject(self, appname, workspace_includes=[], pythonpath=[]): """ Create the Eclipse CDT .project and .cproject files @param appname The name that will appear in the Project Explorer @param build The BuildContext object to extract includes from @param workspace_includes Optional project includes to prevent "Unresolved Inclusion" errors in the Eclipse editor @param pythonpath Optional project specific python paths """ hasc = hasjava = haspython = False source_dirs = [] cpppath = self.env['CPPPATH'] javasrcpath = [] javalibpath = [] includes = STANDARD_INCLUDES if sys.platform != 'win32': cc = self.env.CC or self.env.CXX if cc: cmd = cc + ['-xc++', '-E', '-Wp,-v', '-'] try: gccout = self.cmd_and_log(cmd, output=Context.STDERR, quiet=Context.BOTH, input='\n'.encode()).splitlines() except Errors.WafError: pass else: includes = [] for ipath in gccout: if ipath.startswith(' /'): includes.append(ipath[1:]) cpppath += includes Logs.warn('Generating Eclipse CDT project files') for g in self.groups: for tg in g: if not isinstance(tg, TaskGen.task_gen): continue tg.post() # Add local Python modules paths to configuration so object resolving will work in IDE # This may also contain generated files (ie. pyqt5 or protoc) that get picked from build if 'py' in tg.features: pypath = tg.path.relpath() py_installfrom = getattr(tg, 'install_from', None) if isinstance(py_installfrom, Node.Node): pypath = py_installfrom.path_from(self.root.make_node(self.top_dir)) if pypath not in pythonpath: pythonpath.append(pypath) haspython = True # Add Java source directories so object resolving works in IDE # This may also contain generated files (ie. protoc) that get picked from build if 'javac' in tg.features: java_src = tg.path.relpath() java_srcdir = getattr(tg.javac_task, 'srcdir', None) if java_srcdir: if isinstance(java_srcdir, Node.Node): java_srcdir = [java_srcdir] for x in Utils.to_list(java_srcdir): x = x.path_from(self.root.make_node(self.top_dir)) if x not in javasrcpath: javasrcpath.append(x) else: if java_src not in javasrcpath: javasrcpath.append(java_src) hasjava = True # Check if there are external dependencies and add them as external jar so they will be resolved by Eclipse usedlibs=getattr(tg, 'use', []) for x in Utils.to_list(usedlibs): for cl in Utils.to_list(tg.env['CLASSPATH_'+x]): if cl not in javalibpath: javalibpath.append(cl) if not getattr(tg, 'link_task', None): continue features = Utils.to_list(getattr(tg, 'features', '')) is_cc = 'c' in features or 'cxx' in features incnodes = tg.to_incnodes(tg.to_list(getattr(tg, 'includes', [])) + tg.env['INCLUDES']) for p in incnodes: path = p.path_from(self.srcnode) if (path.startswith("/")): if path not in cpppath: cpppath.append(path) else: if path not in workspace_includes: workspace_includes.append(path) if is_cc and path not in source_dirs: source_dirs.append(path) hasc = True waf_executable = os.path.abspath(sys.argv[0]) project = self.impl_create_project(sys.executable, appname, hasc, hasjava, haspython, waf_executable) self.write_conf_to_xml('.project', project) if hasc: project = self.impl_create_cproject(sys.executable, waf_executable, appname, workspace_includes, cpppath, source_dirs) self.write_conf_to_xml('.cproject', project) if haspython: project = self.impl_create_pydevproject(sys.path, pythonpath) self.write_conf_to_xml('.pydevproject', project) if hasjava: project = self.impl_create_javaproject(javasrcpath, javalibpath) self.write_conf_to_xml('.classpath', project) # Create editor language settings to have correct standards applied in IDE, as per project configuration try: os.mkdir(settings_dir) except OSError: pass # Ignore if dir already exists lang_settings = Document() project = lang_settings.createElement('project') # Language configurations for C and C++ via cdt if hasc: configuration = self.add(lang_settings, project, 'configuration', {'id' : 'org.eclipse.cdt.core.default.config.1', 'name': 'Default'}) extension = self.add(lang_settings, configuration, 'extension', {'point': 'org.eclipse.cdt.core.LanguageSettingsProvider'}) provider = self.add(lang_settings, extension, 'provider', { 'copy-of': 'extension', 'id': 'org.eclipse.cdt.ui.UserLanguageSettingsProvider'}) provider = self.add(lang_settings, extension, 'provider-reference', { 'id': 'org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider', 'ref': 'shared-provider'}) provider = self.add(lang_settings, extension, 'provider-reference', { 'id': 'org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider', 'ref': 'shared-provider'}) # C and C++ are kept as separated providers so appropriate flags are used also in mixed projects if self.env.CC: provider = self.add(lang_settings, extension, 'provider', { 'class': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector', 'console': 'false', 'id': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector.1', 'keep-relative-paths' : 'false', 'name': 'CDT GCC Built-in Compiler Settings', 'parameter': '%s %s ${FLAGS} -E -P -v -dD "${INPUTS}"'%(self.env.CC[0],' '.join(self.env['CFLAGS'])), 'prefer-non-shared': 'true' }) self.add(lang_settings, provider, 'language-scope', { 'id': 'org.eclipse.cdt.core.gcc'}) if self.env.CXX: provider = self.add(lang_settings, extension, 'provider', { 'class': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector', 'console': 'false', 'id': 'org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector.2', 'keep-relative-paths' : 'false', 'name': 'CDT GCC Built-in Compiler Settings', 'parameter': '%s %s ${FLAGS} -E -P -v -dD "${INPUTS}"'%(self.env.CXX[0],' '.join(self.env['CXXFLAGS'])), 'prefer-non-shared': 'true' }) self.add(lang_settings, provider, 'language-scope', { 'id': 'org.eclipse.cdt.core.g++'}) lang_settings.appendChild(project) self.write_conf_to_xml('%s%s%s'%(settings_dir, os.path.sep, settings_name), lang_settings) def impl_create_project(self, executable, appname, hasc, hasjava, haspython, waf_executable): doc = Document() projectDescription = doc.createElement('projectDescription') self.add(doc, projectDescription, 'name', appname) self.add(doc, projectDescription, 'comment') self.add(doc, projectDescription, 'projects') buildSpec = self.add(doc, projectDescription, 'buildSpec') buildCommand = self.add(doc, buildSpec, 'buildCommand') self.add(doc, buildCommand, 'triggers', 'clean,full,incremental,') arguments = self.add(doc, buildCommand, 'arguments') dictionaries = {} # If CDT is present, instruct this one to call waf as it is more flexible (separate build/clean ...) if hasc: self.add(doc, buildCommand, 'name', oe_cdt + '.managedbuilder.core.genmakebuilder') # the default make-style targets are overwritten by the .cproject values dictionaries = { cdt_mk + '.contents': cdt_mk + '.activeConfigSettings', cdt_mk + '.enableAutoBuild': 'false', cdt_mk + '.enableCleanBuild': 'true', cdt_mk + '.enableFullBuild': 'true', } else: # Otherwise for Java/Python an external builder tool is created that will call waf build self.add(doc, buildCommand, 'name', 'org.eclipse.ui.externaltools.ExternalToolBuilder') dictionaries = { 'LaunchConfigHandle': '/%s/%s'%(extbuilder_dir, extbuilder_name), } # The definition is in a separate directory XML file try: os.mkdir(extbuilder_dir) except OSError: pass # Ignore error if already exists # Populate here the external builder XML calling waf builder = Document() launchConfiguration = doc.createElement('launchConfiguration') launchConfiguration.setAttribute('type', 'org.eclipse.ui.externaltools.ProgramBuilderLaunchConfigurationType') self.add(doc, launchConfiguration, 'booleanAttribute', {'key': 'org.eclipse.debug.ui.ATTR_LAUNCH_IN_BACKGROUND', 'value': 'false'}) self.add(doc, launchConfiguration, 'booleanAttribute', {'key': 'org.eclipse.ui.externaltools.ATTR_TRIGGERS_CONFIGURED', 'value': 'true'}) self.add(doc, launchConfiguration, 'stringAttribute', {'key': 'org.eclipse.ui.externaltools.ATTR_LOCATION', 'value': waf_executable}) self.add(doc, launchConfiguration, 'stringAttribute', {'key': 'org.eclipse.ui.externaltools.ATTR_RUN_BUILD_KINDS', 'value': 'full,incremental,'}) self.add(doc, launchConfiguration, 'stringAttribute', {'key': 'org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS', 'value': 'build'}) self.add(doc, launchConfiguration, 'stringAttribute', {'key': 'org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY', 'value': '${project_loc}'}) builder.appendChild(launchConfiguration) # And write the XML to the file references before self.write_conf_to_xml('%s%s%s'%(extbuilder_dir, os.path.sep, extbuilder_name), builder) for k, v in dictionaries.items(): self.addDictionary(doc, arguments, k, v) natures = self.add(doc, projectDescription, 'natures') if hasc: nature_list = """ core.ccnature managedbuilder.core.ScannerConfigNature managedbuilder.core.managedBuildNature core.cnature """.split() for n in nature_list: self.add(doc, natures, 'nature', oe_cdt + '.' + n) if haspython: self.add(doc, natures, 'nature', 'org.python.pydev.pythonNature') if hasjava: self.add(doc, natures, 'nature', 'org.eclipse.jdt.core.javanature') doc.appendChild(projectDescription) return doc def impl_create_cproject(self, executable, waf_executable, appname, workspace_includes, cpppath, source_dirs=[]): doc = Document() doc.appendChild(doc.createProcessingInstruction('fileVersion', '4.0.0')) cconf_id = cdt_core + '.default.config.1' cproject = doc.createElement('cproject') storageModule = self.add(doc, cproject, 'storageModule', {'moduleId': cdt_core + '.settings'}) cconf = self.add(doc, storageModule, 'cconfiguration', {'id':cconf_id}) storageModule = self.add(doc, cconf, 'storageModule', {'buildSystemId': oe_cdt + '.managedbuilder.core.configurationDataProvider', 'id': cconf_id, 'moduleId': cdt_core + '.settings', 'name': 'Default'}) self.add(doc, storageModule, 'externalSettings') extensions = self.add(doc, storageModule, 'extensions') extension_list = """ VCErrorParser MakeErrorParser GCCErrorParser GASErrorParser GLDErrorParser """.split() self.add(doc, extensions, 'extension', {'id': cdt_core + '.ELF', 'point':cdt_core + '.BinaryParser'}) for e in extension_list: self.add(doc, extensions, 'extension', {'id': cdt_core + '.' + e, 'point':cdt_core + '.ErrorParser'}) storageModule = self.add(doc, cconf, 'storageModule', {'moduleId': 'cdtBuildSystem', 'version': '4.0.0'}) config = self.add(doc, storageModule, 'configuration', {'artifactName': appname, 'id': cconf_id, 'name': 'Default', 'parent': cdt_bld + '.prefbase.cfg'}) folderInfo = self.add(doc, config, 'folderInfo', {'id': cconf_id+'.', 'name': '/', 'resourcePath': ''}) toolChain = self.add(doc, folderInfo, 'toolChain', {'id': cdt_bld + '.prefbase.toolchain.1', 'name': 'No ToolChain', 'resourceTypeBasedDiscovery': 'false', 'superClass': cdt_bld + '.prefbase.toolchain'}) self.add(doc, toolChain, 'targetPlatform', {'binaryParser': 'org.eclipse.cdt.core.ELF', 'id': cdt_bld + '.prefbase.toolchain.1', 'name': ''}) waf_build = '"%s" %s'%(waf_executable, eclipse.fun) waf_clean = '"%s" clean'%(waf_executable) self.add(doc, toolChain, 'builder', {'autoBuildTarget': waf_build, 'command': executable, 'enableAutoBuild': 'false', 'cleanBuildTarget': waf_clean, 'enableIncrementalBuild': 'true', 'id': cdt_bld + '.settings.default.builder.1', 'incrementalBuildTarget': waf_build, 'managedBuildOn': 'false', 'name': 'Gnu Make Builder', 'superClass': cdt_bld + '.settings.default.builder'}) tool_index = 1; for tool_name in ("Assembly", "GNU C++", "GNU C"): tool = self.add(doc, toolChain, 'tool', {'id': cdt_bld + '.settings.holder.' + str(tool_index), 'name': tool_name, 'superClass': cdt_bld + '.settings.holder'}) if cpppath or workspace_includes: incpaths = cdt_bld + '.settings.holder.incpaths' option = self.add(doc, tool, 'option', {'id': incpaths + '.' + str(tool_index), 'name': 'Include Paths', 'superClass': incpaths, 'valueType': 'includePath'}) for i in workspace_includes: self.add(doc, option, 'listOptionValue', {'builtIn': 'false', 'value': '"${workspace_loc:/%s/%s}"'%(appname, i)}) for i in cpppath: self.add(doc, option, 'listOptionValue', {'builtIn': 'false', 'value': '"%s"'%(i)}) if tool_name == "GNU C++" or tool_name == "GNU C": self.add(doc,tool,'inputType',{ 'id':'org.eclipse.cdt.build.core.settings.holder.inType.' + str(tool_index), \ 'languageId':'org.eclipse.cdt.core.gcc' if tool_name == "GNU C" else 'org.eclipse.cdt.core.g++','languageName':tool_name, \ 'sourceContentType':'org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader', \ 'superClass':'org.eclipse.cdt.build.core.settings.holder.inType' }) tool_index += 1 if source_dirs: sourceEntries = self.add(doc, config, 'sourceEntries') for i in source_dirs: self.add(doc, sourceEntries, 'entry', {'excluding': i, 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED', 'kind': 'sourcePath', 'name': ''}) self.add(doc, sourceEntries, 'entry', { 'flags': 'VALUE_WORKSPACE_PATH|RESOLVED', 'kind': 'sourcePath', 'name': i}) storageModule = self.add(doc, cconf, 'storageModule', {'moduleId': cdt_mk + '.buildtargets'}) buildTargets = self.add(doc, storageModule, 'buildTargets') def addTargetWrap(name, runAll): return self.addTarget(doc, buildTargets, executable, name, '"%s" %s'%(waf_executable, name), runAll) addTargetWrap('configure', True) addTargetWrap('dist', False) addTargetWrap('install', False) addTargetWrap('check', False) for addTgt in self.env.ECLIPSE_EXTRA_TARGETS or []: addTargetWrap(addTgt, False) storageModule = self.add(doc, cproject, 'storageModule', {'moduleId': 'cdtBuildSystem', 'version': '4.0.0'}) self.add(doc, storageModule, 'project', {'id': '%s.null.1'%appname, 'name': appname}) storageModule = self.add(doc, cproject, 'storageModule', {'moduleId': 'org.eclipse.cdt.core.LanguageSettingsProviders'}) storageModule = self.add(doc, cproject, 'storageModule', {'moduleId': 'scannerConfiguration'}) doc.appendChild(cproject) return doc def impl_create_pydevproject(self, system_path, user_path): # create a pydevproject file doc = Document() doc.appendChild(doc.createProcessingInstruction('eclipse-pydev', 'version="1.0"')) pydevproject = doc.createElement('pydev_project') prop = self.add(doc, pydevproject, 'pydev_property', 'python %d.%d'%(sys.version_info[0], sys.version_info[1])) prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_VERSION') prop = self.add(doc, pydevproject, 'pydev_property', 'Default') prop.setAttribute('name', 'org.python.pydev.PYTHON_PROJECT_INTERPRETER') # add waf's paths wafadmin = [p for p in system_path if p.find('wafadmin') != -1] if wafadmin: prop = self.add(doc, pydevproject, 'pydev_pathproperty', {'name':'org.python.pydev.PROJECT_EXTERNAL_SOURCE_PATH'}) for i in wafadmin: self.add(doc, prop, 'path', i) if user_path: prop = self.add(doc, pydevproject, 'pydev_pathproperty', {'name':'org.python.pydev.PROJECT_SOURCE_PATH'}) for i in user_path: self.add(doc, prop, 'path', '/${PROJECT_DIR_NAME}/'+i) doc.appendChild(pydevproject) return doc def impl_create_javaproject(self, javasrcpath, javalibpath): # create a .classpath file for java usage doc = Document() javaproject = doc.createElement('classpath') if javasrcpath: for i in javasrcpath: self.add(doc, javaproject, 'classpathentry', {'kind': 'src', 'path': i}) if javalibpath: for i in javalibpath: self.add(doc, javaproject, 'classpathentry', {'kind': 'lib', 'path': i}) self.add(doc, javaproject, 'classpathentry', {'kind': 'con', 'path': 'org.eclipse.jdt.launching.JRE_CONTAINER'}) self.add(doc, javaproject, 'classpathentry', {'kind': 'output', 'path': self.bldnode.name }) doc.appendChild(javaproject) return doc def addDictionary(self, doc, parent, k, v): dictionary = self.add(doc, parent, 'dictionary') self.add(doc, dictionary, 'key', k) self.add(doc, dictionary, 'value', v) return dictionary def addTarget(self, doc, buildTargets, executable, name, buildTarget, runAllBuilders=True): target = self.add(doc, buildTargets, 'target', {'name': name, 'path': '', 'targetID': oe_cdt + '.build.MakeTargetBuilder'}) self.add(doc, target, 'buildCommand', executable) self.add(doc, target, 'buildArguments', None) self.add(doc, target, 'buildTarget', buildTarget) self.add(doc, target, 'stopOnError', 'true') self.add(doc, target, 'useDefaultCommand', 'false') self.add(doc, target, 'runAllBuilders', str(runAllBuilders).lower()) def add(self, doc, parent, tag, value = None): el = doc.createElement(tag) if (value): if type(value) == type(str()): el.appendChild(doc.createTextNode(value)) elif type(value) == type(dict()): self.setAttributes(el, value) parent.appendChild(el) return el def setAttributes(self, node, attrs): for k, v in attrs.items(): node.setAttribute(k, v) hamster-3.0.3/waflib/extras/erlang.py000066400000000000000000000066731452646177100176050ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010 (ita) # Przemyslaw Rzepecki, 2016 """ Erlang support """ import re from waflib import Task, TaskGen from waflib.TaskGen import feature, after_method, before_method # to load the method "to_incnodes" below from waflib.Tools import ccroot # Those flags are required by the Erlang VM to execute/evaluate code in # non-interactive mode. It is used in this tool to create Erlang modules # documentation and run unit tests. The user can pass additional arguments to the # 'erl' command with ERL_FLAGS environment variable. EXEC_NON_INTERACTIVE = ['-noshell', '-noinput', '-eval'] def configure(conf): conf.find_program('erlc', var='ERLC') conf.find_program('erl', var='ERL') conf.add_os_flags('ERLC_FLAGS') conf.add_os_flags('ERL_FLAGS') conf.env.ERLC_DEF_PATTERN = '-D%s' conf.env.ERLC_INC_PATTERN = '-I%s' @TaskGen.extension('.erl') def process_erl_node(self, node): tsk = self.create_task('erl', node, node.change_ext('.beam')) tsk.erlc_incnodes = [tsk.outputs[0].parent] + self.to_incnodes(self.includes) tsk.env.append_value('ERLC_INCPATHS', [x.abspath() for x in tsk.erlc_incnodes]) tsk.env.append_value('ERLC_DEFINES', self.to_list(getattr(self, 'defines', []))) tsk.env.append_value('ERLC_FLAGS', self.to_list(getattr(self, 'flags', []))) tsk.cwd = tsk.outputs[0].parent class erl(Task.Task): color = 'GREEN' run_str = '${ERLC} ${ERL_FLAGS} ${ERLC_INC_PATTERN:ERLC_INCPATHS} ${ERLC_DEF_PATTERN:ERLC_DEFINES} ${SRC}' def scan(task): node = task.inputs[0] deps = [] scanned = set([]) nodes_to_scan = [node] for n in nodes_to_scan: if n.abspath() in scanned: continue for i in re.findall(r'-include\("(.*)"\)\.', n.read()): for d in task.erlc_incnodes: r = d.find_node(i) if r: deps.append(r) nodes_to_scan.append(r) break scanned.add(n.abspath()) return (deps, []) @TaskGen.extension('.beam') def process(self, node): pass class erl_test(Task.Task): color = 'BLUE' run_str = '${ERL} ${ERL_FLAGS} ${ERL_TEST_FLAGS}' @feature('eunit') @after_method('process_source') def add_erl_test_run(self): test_modules = [t.outputs[0] for t in self.tasks] test_task = self.create_task('erl_test') test_task.set_inputs(self.source + test_modules) test_task.cwd = test_modules[0].parent test_task.env.append_value('ERL_FLAGS', self.to_list(getattr(self, 'flags', []))) test_list = ", ".join([m.change_ext("").path_from(test_task.cwd)+":test()" for m in test_modules]) test_flag = 'halt(case lists:all(fun(Elem) -> Elem == ok end, [%s]) of true -> 0; false -> 1 end).' % test_list test_task.env.append_value('ERL_TEST_FLAGS', EXEC_NON_INTERACTIVE) test_task.env.append_value('ERL_TEST_FLAGS', test_flag) class edoc(Task.Task): color = 'BLUE' run_str = "${ERL} ${ERL_FLAGS} ${ERL_DOC_FLAGS}" def keyword(self): return 'Generating edoc' @feature('edoc') @before_method('process_source') def add_edoc_task(self): # do not process source, it would create double erl->beam task self.meths.remove('process_source') e = self.path.find_resource(self.source) t = e.change_ext('.html') png = t.parent.make_node('erlang.png') css = t.parent.make_node('stylesheet.css') tsk = self.create_task('edoc', e, [t, png, css]) tsk.cwd = tsk.outputs[0].parent tsk.env.append_value('ERL_DOC_FLAGS', EXEC_NON_INTERACTIVE) tsk.env.append_value('ERL_DOC_FLAGS', 'edoc:files(["%s"]), halt(0).' % tsk.inputs[0].abspath()) # TODO the above can break if a file path contains '"' hamster-3.0.3/waflib/extras/fast_partial.py000066400000000000000000000362271452646177100210040ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2017-2018 (ita) """ A system for fast partial rebuilds Creating a large amount of task objects up front can take some time. By making a few assumptions, it is possible to avoid posting creating task objects for targets that are already up-to-date. On a silly benchmark the gain observed for 1M tasks can be 5m->10s for a single file change. Usage:: def options(opt): opt.load('fast_partial') Assumptions: * Start with a clean build (run "waf distclean" after enabling) * Mostly for C/C++/Fortran targets with link tasks (object-only targets are not handled) try it in the folder generated by utils/genbench.py * For full project builds: no --targets and no pruning from subfolders * The installation phase is ignored * `use=` dependencies are specified up front even across build groups * Task generator source files are not obtained from globs Implementation details: * The first layer obtains file timestamps to recalculate file hashes only when necessary (similar to md5_tstamp); the timestamps are then stored in a dedicated pickle file * A second layer associates each task generator to a file set to help detecting changes. Task generators are to create their tasks only when the related files have been modified. A specific db file is created to store such data (5m -> 1m10) * A third layer binds build context proxies onto task generators, replacing the default context. While loading data for the full build uses more memory (4GB -> 9GB), partial builds are then much faster (1m10 -> 13s) * A fourth layer enables a 2-level cache on file signatures to reduce the size of the main pickle file (13s -> 10s) """ import os from waflib import Build, Context, Errors, Logs, Task, TaskGen, Utils from waflib.TaskGen import feature, after_method, taskgen_method import waflib.Node DONE = 0 DIRTY = 1 NEEDED = 2 SKIPPABLE = ['cshlib', 'cxxshlib', 'cstlib', 'cxxstlib', 'cprogram', 'cxxprogram'] TSTAMP_DB = '.wafpickle_tstamp_db_file' SAVED_ATTRS = 'root node_sigs task_sigs imp_sigs raw_deps node_deps'.split() class bld_proxy(object): def __init__(self, bld): object.__setattr__(self, 'bld', bld) object.__setattr__(self, 'node_class', type('Nod3', (waflib.Node.Node,), {})) self.node_class.__module__ = 'waflib.Node' self.node_class.ctx = self object.__setattr__(self, 'root', self.node_class('', None)) for x in SAVED_ATTRS: if x != 'root': object.__setattr__(self, x, {}) self.fix_nodes() def __setattr__(self, name, value): bld = object.__getattribute__(self, 'bld') setattr(bld, name, value) def __delattr__(self, name): bld = object.__getattribute__(self, 'bld') delattr(bld, name) def __getattribute__(self, name): try: return object.__getattribute__(self, name) except AttributeError: bld = object.__getattribute__(self, 'bld') return getattr(bld, name) def __call__(self, *k, **kw): return self.bld(*k, **kw) def fix_nodes(self): for x in ('srcnode', 'path', 'bldnode'): node = self.root.find_dir(getattr(self.bld, x).abspath()) object.__setattr__(self, x, node) def set_key(self, store_key): object.__setattr__(self, 'store_key', store_key) def fix_tg_path(self, *tgs): # changing Node objects on task generators is possible # yet, all Node objects must belong to the same parent for tg in tgs: tg.path = self.root.make_node(tg.path.abspath()) def restore(self): dbfn = os.path.join(self.variant_dir, Context.DBFILE + self.store_key) Logs.debug('rev_use: reading %s', dbfn) try: data = Utils.readf(dbfn, 'rb') except (EnvironmentError, EOFError): # handle missing file/empty file Logs.debug('rev_use: Could not load the build cache %s (missing)', dbfn) else: try: waflib.Node.pickle_lock.acquire() waflib.Node.Nod3 = self.node_class try: data = Build.cPickle.loads(data) except Exception as e: Logs.debug('rev_use: Could not pickle the build cache %s: %r', dbfn, e) else: for x in SAVED_ATTRS: object.__setattr__(self, x, data.get(x, {})) finally: waflib.Node.pickle_lock.release() self.fix_nodes() def store(self): data = {} for x in Build.SAVED_ATTRS: data[x] = getattr(self, x) db = os.path.join(self.variant_dir, Context.DBFILE + self.store_key) with waflib.Node.pickle_lock: waflib.Node.Nod3 = self.node_class try: x = Build.cPickle.dumps(data, Build.PROTOCOL) except Build.cPickle.PicklingError: root = data['root'] for node_deps in data['node_deps'].values(): for idx, node in enumerate(node_deps): # there may be more cross-context Node objects to fix, # but this should be the main source node_deps[idx] = root.find_node(node.abspath()) x = Build.cPickle.dumps(data, Build.PROTOCOL) Logs.debug('rev_use: storing %s', db) Utils.writef(db + '.tmp', x, m='wb') try: st = os.stat(db) os.remove(db) if not Utils.is_win32: os.chown(db + '.tmp', st.st_uid, st.st_gid) except (AttributeError, OSError): pass os.rename(db + '.tmp', db) class bld(Build.BuildContext): def __init__(self, **kw): super(bld, self).__init__(**kw) self.hashes_md5_tstamp = {} def __call__(self, *k, **kw): # this is one way of doing it, one could use a task generator method too bld = kw['bld'] = bld_proxy(self) ret = TaskGen.task_gen(*k, **kw) self.task_gen_cache_names = {} self.add_to_group(ret, group=kw.get('group')) ret.bld = bld bld.set_key(ret.path.abspath().replace(os.sep, '') + str(ret.idx)) return ret def is_dirty(self): return True def store_tstamps(self): # Called after a build is finished # For each task generator, record all files involved in task objects # optimization: done only if there was something built do_store = False try: f_deps = self.f_deps except AttributeError: f_deps = self.f_deps = {} self.f_tstamps = {} allfiles = set() for g in self.groups: for tg in g: try: staleness = tg.staleness except AttributeError: staleness = DIRTY if staleness != DIRTY: # DONE case: there was nothing built # NEEDED case: the tg was brought in because of 'use' propagation # but nothing really changed for them, there may be incomplete # tasks (object files) and in this case it is best to let the next build # figure out if an input/output file changed continue do_cache = False for tsk in tg.tasks: if tsk.hasrun == Task.SUCCESS: do_cache = True pass elif tsk.hasrun == Task.SKIPPED: pass else: # one failed task, clear the cache for this tg try: del f_deps[(tg.path.abspath(), tg.idx)] except KeyError: pass else: # just store the new state because there is a change do_store = True # skip the rest because there is no valid cache possible break else: if not do_cache: # all skipped, but is there anything in cache? try: f_deps[(tg.path.abspath(), tg.idx)] except KeyError: # probably cleared because a wscript file changed # store it do_cache = True if do_cache: # there was a rebuild, store the data structure too tg.bld.store() # all tasks skipped but no cache # or a successful task build do_store = True st = set() for tsk in tg.tasks: st.update(tsk.inputs) st.update(self.node_deps.get(tsk.uid(), [])) # TODO do last/when loading the tgs? lst = [] for k in ('wscript', 'wscript_build'): n = tg.path.find_node(k) if n: n.get_bld_sig() lst.append(n.abspath()) lst.extend(sorted(x.abspath() for x in st)) allfiles.update(lst) f_deps[(tg.path.abspath(), tg.idx)] = lst for x in allfiles: # f_tstamps has everything, while md5_tstamp can be relatively empty on partial builds self.f_tstamps[x] = self.hashes_md5_tstamp[x][0] if do_store: dbfn = os.path.join(self.variant_dir, TSTAMP_DB) Logs.debug('rev_use: storing %s', dbfn) dbfn_tmp = dbfn + '.tmp' x = Build.cPickle.dumps([self.f_tstamps, f_deps], Build.PROTOCOL) Utils.writef(dbfn_tmp, x, m='wb') os.rename(dbfn_tmp, dbfn) Logs.debug('rev_use: stored %s', dbfn) def store(self): self.store_tstamps() if self.producer.dirty: Build.BuildContext.store(self) def compute_needed_tgs(self): # assume the 'use' keys are not modified during the build phase dbfn = os.path.join(self.variant_dir, TSTAMP_DB) Logs.debug('rev_use: Loading %s', dbfn) try: data = Utils.readf(dbfn, 'rb') except (EnvironmentError, EOFError): Logs.debug('rev_use: Could not load the build cache %s (missing)', dbfn) self.f_deps = {} self.f_tstamps = {} else: try: self.f_tstamps, self.f_deps = Build.cPickle.loads(data) except Exception as e: Logs.debug('rev_use: Could not pickle the build cache %s: %r', dbfn, e) self.f_deps = {} self.f_tstamps = {} else: Logs.debug('rev_use: Loaded %s', dbfn) # 1. obtain task generators that contain rebuilds # 2. obtain the 'use' graph and its dual stales = set() reverse_use_map = Utils.defaultdict(list) use_map = Utils.defaultdict(list) for g in self.groups: for tg in g: if tg.is_stale(): stales.add(tg) try: lst = tg.use = Utils.to_list(tg.use) except AttributeError: pass else: for x in lst: try: xtg = self.get_tgen_by_name(x) except Errors.WafError: pass else: use_map[tg].append(xtg) reverse_use_map[xtg].append(tg) Logs.debug('rev_use: found %r stale tgs', len(stales)) # 3. dfs to post downstream tg as stale visited = set() def mark_down(tg): if tg in visited: return visited.add(tg) Logs.debug('rev_use: marking down %r as stale', tg.name) tg.staleness = DIRTY for x in reverse_use_map[tg]: mark_down(x) for tg in stales: mark_down(tg) # 4. dfs to find ancestors tg to mark as needed self.needed_tgs = needed_tgs = set() def mark_needed(tg): if tg in needed_tgs: return needed_tgs.add(tg) if tg.staleness == DONE: Logs.debug('rev_use: marking up %r as needed', tg.name) tg.staleness = NEEDED for x in use_map[tg]: mark_needed(x) for xx in visited: mark_needed(xx) # so we have the whole tg trees to post in the set "needed" # load their build trees for tg in needed_tgs: tg.bld.restore() tg.bld.fix_tg_path(tg) # the stale ones should be fully build, while the needed ones # may skip a few tasks, see create_compiled_task and apply_link_after below Logs.debug('rev_use: amount of needed task gens: %r', len(needed_tgs)) def post_group(self): # assumption: we can ignore the folder/subfolders cuts def tgpost(tg): try: f = tg.post except AttributeError: pass else: f() if not self.targets or self.targets == '*': for tg in self.groups[self.current_group]: # this can cut quite a lot of tg objects if tg in self.needed_tgs: tgpost(tg) else: # default implementation return Build.BuildContext.post_group() def get_build_iterator(self): if not self.targets or self.targets == '*': self.compute_needed_tgs() return Build.BuildContext.get_build_iterator(self) @taskgen_method def is_stale(self): # assume no globs self.staleness = DIRTY # 1. the case of always stale targets if getattr(self, 'always_stale', False): return True # 2. check if the db file exists db = os.path.join(self.bld.variant_dir, Context.DBFILE) try: dbstat = os.stat(db).st_mtime except OSError: Logs.debug('rev_use: must post %r because this is a clean build') return True # 3.a check if the configuration exists cache_node = self.bld.bldnode.find_node('c4che/build.config.py') if not cache_node: return True # 3.b check if the configuration changed if os.stat(cache_node.abspath()).st_mtime > dbstat: Logs.debug('rev_use: must post %r because the configuration has changed', self.name) return True # 3.c any tstamp data? try: f_deps = self.bld.f_deps except AttributeError: Logs.debug('rev_use: must post %r because there is no f_deps', self.name) return True # 4. check if this is the first build (no cache) try: lst = f_deps[(self.path.abspath(), self.idx)] except KeyError: Logs.debug('rev_use: must post %r because there it has no cached data', self.name) return True try: cache = self.bld.cache_tstamp_rev_use except AttributeError: cache = self.bld.cache_tstamp_rev_use = {} # 5. check the timestamp of each dependency files listed is unchanged f_tstamps = self.bld.f_tstamps for x in lst: try: old_ts = f_tstamps[x] except KeyError: Logs.debug('rev_use: must post %r because %r is not in cache', self.name, x) return True try: try: ts = cache[x] except KeyError: ts = cache[x] = os.stat(x).st_mtime except OSError: del f_deps[(self.path.abspath(), self.idx)] Logs.debug('rev_use: must post %r because %r does not exist anymore', self.name, x) return True else: if ts != old_ts: Logs.debug('rev_use: must post %r because the timestamp on %r changed %r %r', self.name, x, old_ts, ts) return True self.staleness = DONE return False @taskgen_method def create_compiled_task(self, name, node): # skip the creation of object files # assumption: object-only targets are not skippable if self.staleness == NEEDED: # only libraries/programs can skip object files for x in SKIPPABLE: if x in self.features: return None out = '%s.%d.o' % (node.name, self.idx) task = self.create_task(name, node, node.parent.find_or_declare(out)) try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] return task @feature(*SKIPPABLE) @after_method('apply_link') def apply_link_after(self): # cprogram/cxxprogram might be unnecessary if self.staleness != NEEDED: return for tsk in self.tasks: tsk.hasrun = Task.SKIPPED def path_from(self, node): # handle nodes of distinct types if node.ctx is not self.ctx: node = self.ctx.root.make_node(node.abspath()) return self.default_path_from(node) waflib.Node.Node.default_path_from = waflib.Node.Node.path_from waflib.Node.Node.path_from = path_from def h_file(self): # similar to md5_tstamp.py, but with 2-layer cache # global_cache for the build context common for all task generators # local_cache for the build context proxy (one by task generator) # # the global cache is not persistent # the local cache is persistent and meant for partial builds # # assume all calls are made from a single thread # filename = self.abspath() st = os.stat(filename) global_cache = self.ctx.bld.hashes_md5_tstamp local_cache = self.ctx.hashes_md5_tstamp if filename in global_cache: # value already calculated in this build cval = global_cache[filename] # the value in global cache is assumed to be calculated once # reverifying it could cause task generators # to get distinct tstamp values, thus missing rebuilds local_cache[filename] = cval return cval[1] if filename in local_cache: cval = local_cache[filename] if cval[0] == st.st_mtime: # correct value from a previous build # put it in the global cache global_cache[filename] = cval return cval[1] ret = Utils.h_file(filename) local_cache[filename] = global_cache[filename] = (st.st_mtime, ret) return ret waflib.Node.Node.h_file = h_file hamster-3.0.3/waflib/extras/fc_bgxlf.py000066400000000000000000000013261452646177100200750ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de from waflib.Tools import fc, fc_config, fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].insert(0, 'fc_bgxlf') @conf def find_bgxlf(conf): fc = conf.find_program(['bgxlf2003_r','bgxlf2003'], var='FC') conf.get_xlf_version(fc) conf.env.FC_NAME = 'BGXLF' @conf def bg_flags(self): self.env.SONAME_ST = '' self.env.FCSHLIB_MARKER = '' self.env.FCSTLIB_MARKER = '' self.env.FCFLAGS_fcshlib = ['-fPIC'] self.env.LINKFLAGS_fcshlib = ['-G', '-Wl,-bexpfull'] def configure(conf): conf.find_bgxlf() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.xlf_flags() conf.bg_flags() hamster-3.0.3/waflib/extras/fc_cray.py000066400000000000000000000026461452646177100177370ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib.Tools import fc, fc_config, fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_cray') @conf def find_crayftn(conf): """Find the Cray fortran compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['crayftn'], var='FC') conf.get_crayftn_version(fc) conf.env.FC_NAME = 'CRAY' conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod' @conf def crayftn_flags(conf): v = conf.env v['_FCMODOUTFLAGS'] = ['-em', '-J.'] # enable module files and put them in the current directory v['FCFLAGS_DEBUG'] = ['-m1'] # more verbose compiler warnings v['FCFLAGS_fcshlib'] = ['-h pic'] v['LINKFLAGS_fcshlib'] = ['-h shared'] v['FCSTLIB_MARKER'] = '-h static' v['FCSHLIB_MARKER'] = '-h dynamic' @conf def get_crayftn_version(conf, fc): version_re = re.compile(r"Cray Fortran\s*:\s*Version\s*(?P\d*)\.(?P\d*)", re.I).search cmd = fc + ['-V'] out,err = fc_config.getoutput(conf, cmd, stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the Cray Fortran compiler version.') k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) def configure(conf): conf.find_crayftn() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.crayftn_flags() hamster-3.0.3/waflib/extras/fc_fujitsu.py000066400000000000000000000024441452646177100204660ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Detection of the Fujitsu Fortran compiler for ARM64FX import re from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_fujitsu') @conf def find_fujitsu(conf): fc=conf.find_program(['frtpx'],var='FC') conf.get_fujitsu_version(fc) conf.env.FC_NAME='FUJITSU' conf.env.FC_MOD_CAPITALIZATION='lower' @conf def fujitsu_flags(conf): v=conf.env v['_FCMODOUTFLAGS']=[] v['FCFLAGS_DEBUG']=[] v['FCFLAGS_fcshlib']=[] v['LINKFLAGS_fcshlib']=[] v['FCSTLIB_MARKER']='' v['FCSHLIB_MARKER']='' @conf def get_fujitsu_version(conf,fc): version_re=re.compile(r"frtpx\s*\(FRT\)\s*(?P\d+)\.(?P\d+)\.",re.I).search cmd=fc+['--version'] out,err=fc_config.getoutput(conf,cmd,stdin=False) if out: match=version_re(out) else: match=version_re(err) if not match: return(False) conf.fatal('Could not determine the Fujitsu FRT Fortran compiler version.') else: k=match.groupdict() conf.env['FC_VERSION']=(k['major'],k['minor']) def configure(conf): conf.find_fujitsu() conf.find_program('ar',var='AR') conf.add_os_flags('ARFLAGS') if not conf.env.ARFLAGS: conf.env.ARFLAGS=['rcs'] conf.fc_flags() conf.fc_add_flags() conf.fujitsu_flags() hamster-3.0.3/waflib/extras/fc_nag.py000066400000000000000000000027601452646177100175430ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib import Utils from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].insert(0, 'fc_nag') @conf def find_nag(conf): """Find the NAG Fortran Compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['nagfor'], var='FC') conf.get_nag_version(fc) conf.env.FC_NAME = 'NAG' conf.env.FC_MOD_CAPITALIZATION = 'lower' @conf def nag_flags(conf): v = conf.env v.FCFLAGS_DEBUG = ['-C=all'] v.FCLNK_TGT_F = ['-o', ''] v.FC_TGT_F = ['-c', '-o', ''] @conf def nag_modifier_platform(conf): dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform() nag_modifier_func = getattr(conf, 'nag_modifier_' + dest_os, None) if nag_modifier_func: nag_modifier_func() @conf def get_nag_version(conf, fc): """Get the NAG compiler version""" version_re = re.compile(r"^NAG Fortran Compiler *Release *(?P\d*)\.(?P\d*)", re.M).search cmd = fc + ['-V'] out, err = fc_config.getoutput(conf,cmd,stdin=False) if out: match = version_re(out) if not match: match = version_re(err) else: match = version_re(err) if not match: conf.fatal('Could not determine the NAG version.') k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) def configure(conf): conf.find_nag() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.nag_flags() conf.nag_modifier_platform() hamster-3.0.3/waflib/extras/fc_nec.py000066400000000000000000000031731452646177100175420ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib.Tools import fc, fc_config, fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_nec') @conf def find_sxfc(conf): """Find the NEC fortran compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['sxf90','sxf03'], var='FC') conf.get_sxfc_version(fc) conf.env.FC_NAME = 'NEC' conf.env.FC_MOD_CAPITALIZATION = 'lower' @conf def sxfc_flags(conf): v = conf.env v['_FCMODOUTFLAGS'] = [] # enable module files and put them in the current directory v['FCFLAGS_DEBUG'] = [] # more verbose compiler warnings v['FCFLAGS_fcshlib'] = [] v['LINKFLAGS_fcshlib'] = [] v['FCSTLIB_MARKER'] = '' v['FCSHLIB_MARKER'] = '' @conf def get_sxfc_version(conf, fc): version_re = re.compile(r"FORTRAN90/SX\s*Version\s*(?P\d*)\.(?P\d*)", re.I).search cmd = fc + ['-V'] out,err = fc_config.getoutput(conf, cmd, stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: version_re=re.compile(r"NEC Fortran 2003 Compiler for\s*(?P\S*)\s*\(c\)\s*(?P\d*)",re.I).search if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the NEC Fortran compiler version.') k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) def configure(conf): conf.find_sxfc() conf.find_program('sxar',var='AR') conf.add_os_flags('ARFLAGS') if not conf.env.ARFLAGS: conf.env.ARFLAGS=['rcs'] conf.fc_flags() conf.fc_add_flags() conf.sxfc_flags() hamster-3.0.3/waflib/extras/fc_nfort.py000066400000000000000000000024301452646177100201200ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Detection of the NEC Fortran compiler for Aurora Tsubasa import re from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_nfort') @conf def find_nfort(conf): fc=conf.find_program(['nfort'],var='FC') conf.get_nfort_version(fc) conf.env.FC_NAME='NFORT' conf.env.FC_MOD_CAPITALIZATION='lower' @conf def nfort_flags(conf): v=conf.env v['_FCMODOUTFLAGS']=[] v['FCFLAGS_DEBUG']=[] v['FCFLAGS_fcshlib']=[] v['LINKFLAGS_fcshlib']=[] v['FCSTLIB_MARKER']='' v['FCSHLIB_MARKER']='' @conf def get_nfort_version(conf,fc): version_re=re.compile(r"nfort\s*\(NFORT\)\s*(?P\d+)\.(?P\d+)\.",re.I).search cmd=fc+['--version'] out,err=fc_config.getoutput(conf,cmd,stdin=False) if out: match=version_re(out) else: match=version_re(err) if not match: return(False) conf.fatal('Could not determine the NEC NFORT Fortran compiler version.') else: k=match.groupdict() conf.env['FC_VERSION']=(k['major'],k['minor']) def configure(conf): conf.find_nfort() conf.find_program('nar',var='AR') conf.add_os_flags('ARFLAGS') if not conf.env.ARFLAGS: conf.env.ARFLAGS=['rcs'] conf.fc_flags() conf.fc_add_flags() conf.nfort_flags() hamster-3.0.3/waflib/extras/fc_open64.py000066400000000000000000000027461452646177100201150ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib import Utils from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].insert(0, 'fc_open64') @conf def find_openf95(conf): """Find the Open64 Fortran Compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['openf95', 'openf90'], var='FC') conf.get_open64_version(fc) conf.env.FC_NAME = 'OPEN64' conf.env.FC_MOD_CAPITALIZATION = 'UPPER.mod' @conf def openf95_flags(conf): v = conf.env v['FCFLAGS_DEBUG'] = ['-fullwarn'] @conf def openf95_modifier_platform(conf): dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform() openf95_modifier_func = getattr(conf, 'openf95_modifier_' + dest_os, None) if openf95_modifier_func: openf95_modifier_func() @conf def get_open64_version(conf, fc): """Get the Open64 compiler version""" version_re = re.compile(r"Open64 Compiler Suite: *Version *(?P\d*)\.(?P\d*)", re.I).search cmd = fc + ['-version'] out, err = fc_config.getoutput(conf,cmd,stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the Open64 version.') k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) def configure(conf): conf.find_openf95() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.openf95_flags() conf.openf95_modifier_platform() hamster-3.0.3/waflib/extras/fc_pgfortran.py000066400000000000000000000033641452646177100210010ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib.Tools import fc, fc_config, fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_pgfortran') @conf def find_pgfortran(conf): """Find the PGI fortran compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['pgfortran', 'pgf95', 'pgf90'], var='FC') conf.get_pgfortran_version(fc) conf.env.FC_NAME = 'PGFC' @conf def pgfortran_flags(conf): v = conf.env v['FCFLAGS_fcshlib'] = ['-shared'] v['FCFLAGS_DEBUG'] = ['-Minform=inform', '-Mstandard'] # why not v['FCSTLIB_MARKER'] = '-Bstatic' v['FCSHLIB_MARKER'] = '-Bdynamic' v['SONAME_ST'] = '-soname %s' @conf def get_pgfortran_version(conf,fc): version_re = re.compile(r"The Portland Group", re.I).search cmd = fc + ['-V'] out,err = fc_config.getoutput(conf, cmd, stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not verify PGI signature') cmd = fc + ['-help=variable'] out,err = fc_config.getoutput(conf, cmd, stdin=False) if out.find('COMPVER')<0: conf.fatal('Could not determine the compiler type') k = {} prevk = '' out = out.splitlines() for line in out: lst = line.partition('=') if lst[1] == '=': key = lst[0].rstrip() if key == '': key = prevk val = lst[2].rstrip() k[key] = val else: prevk = line.partition(' ')[0] def isD(var): return var in k def isT(var): return var in k and k[var]!='0' conf.env['FC_VERSION'] = (k['COMPVER'].split('.')) def configure(conf): conf.find_pgfortran() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.pgfortran_flags() hamster-3.0.3/waflib/extras/fc_solstudio.py000066400000000000000000000031521452646177100210170ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib import Utils from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['linux'].append('fc_solstudio') @conf def find_solstudio(conf): """Find the Solaris Studio compiler (will look in the environment variable 'FC')""" fc = conf.find_program(['sunf95', 'f95', 'sunf90', 'f90'], var='FC') conf.get_solstudio_version(fc) conf.env.FC_NAME = 'SOL' @conf def solstudio_flags(conf): v = conf.env v['FCFLAGS_fcshlib'] = ['-Kpic'] v['FCFLAGS_DEBUG'] = ['-w3'] v['LINKFLAGS_fcshlib'] = ['-G'] v['FCSTLIB_MARKER'] = '-Bstatic' v['FCSHLIB_MARKER'] = '-Bdynamic' v['SONAME_ST'] = '-h %s' @conf def solstudio_modifier_platform(conf): dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform() solstudio_modifier_func = getattr(conf, 'solstudio_modifier_' + dest_os, None) if solstudio_modifier_func: solstudio_modifier_func() @conf def get_solstudio_version(conf, fc): """Get the compiler version""" version_re = re.compile(r"Sun Fortran 95 *(?P\d*)\.(?P\d*)", re.I).search cmd = fc + ['-V'] out, err = fc_config.getoutput(conf,cmd,stdin=False) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not determine the Sun Studio Fortran version.') k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) def configure(conf): conf.find_solstudio() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.solstudio_flags() conf.solstudio_modifier_platform() hamster-3.0.3/waflib/extras/fc_xlf.py000066400000000000000000000031171452646177100175640ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # harald at klimachs.de import re from waflib import Utils,Errors from waflib.Tools import fc,fc_config,fc_scan from waflib.Configure import conf from waflib.Tools.compiler_fc import fc_compiler fc_compiler['aix'].insert(0, 'fc_xlf') @conf def find_xlf(conf): """Find the xlf program (will look in the environment variable 'FC')""" fc = conf.find_program(['xlf2003_r', 'xlf2003', 'xlf95_r', 'xlf95', 'xlf90_r', 'xlf90', 'xlf_r', 'xlf'], var='FC') conf.get_xlf_version(fc) conf.env.FC_NAME='XLF' @conf def xlf_flags(conf): v = conf.env v['FCDEFINES_ST'] = '-WF,-D%s' v['FCFLAGS_fcshlib'] = ['-qpic=small'] v['FCFLAGS_DEBUG'] = ['-qhalt=w'] v['LINKFLAGS_fcshlib'] = ['-Wl,-shared'] @conf def xlf_modifier_platform(conf): dest_os = conf.env['DEST_OS'] or Utils.unversioned_sys_platform() xlf_modifier_func = getattr(conf, 'xlf_modifier_' + dest_os, None) if xlf_modifier_func: xlf_modifier_func() @conf def get_xlf_version(conf, fc): """Get the compiler version""" cmd = fc + ['-qversion'] try: out, err = conf.cmd_and_log(cmd, output=0) except Errors.WafError: conf.fatal('Could not find xlf %r' % cmd) for v in (r"IBM XL Fortran.* V(?P\d*)\.(?P\d*)",): version_re = re.compile(v, re.I).search match = version_re(out or err) if match: k = match.groupdict() conf.env['FC_VERSION'] = (k['major'], k['minor']) break else: conf.fatal('Could not determine the XLF version.') def configure(conf): conf.find_xlf() conf.find_ar() conf.fc_flags() conf.fc_add_flags() conf.xlf_flags() conf.xlf_modifier_platform() hamster-3.0.3/waflib/extras/file_to_object.py000066400000000000000000000066311452646177100212760ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # Tool to embed file into objects __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2014" """ This tool allows to embed file contents in object files (.o). It is not exactly portable, and the file contents are reachable using various non-portable fashions. The goal here is to provide a functional interface to the embedding of file data in objects. See the ``playground/embedded_resources`` example for an example. Usage:: bld( name='pipeline', # ^ Reference this in use="..." for things using the generated code features='file_to_object', source='some.file', # ^ Name of the file to embed in binary section. ) Known issues: - Destination is named like source, with extension renamed to .o eg. some.file -> some.o """ import os, sys from waflib import Task, TaskGen, Errors def filename_c_escape(x): return x.replace("\\", "\\\\") class file_to_object_s(Task.Task): color = 'CYAN' vars = ['DEST_CPU', 'DEST_BINFMT'] def run(self): name = [] for i, x in enumerate(self.inputs[0].name): if x.isalnum(): name.append(x) else: name.append('_') file = self.inputs[0].abspath() size = os.path.getsize(file) if self.env.DEST_CPU in ('x86_64', 'ia', 'aarch64'): unit = 'quad' align = 8 elif self.env.DEST_CPU in ('x86','arm', 'thumb', 'm68k'): unit = 'long' align = 4 else: raise Errors.WafError("Unsupported DEST_CPU, please report bug!") file = filename_c_escape(file) name = "_binary_" + "".join(name) rodata = ".section .rodata" if self.env.DEST_BINFMT == "mac-o": name = "_" + name rodata = ".section __TEXT,__const" with open(self.outputs[0].abspath(), 'w') as f: f.write(\ """ .global %(name)s_start .global %(name)s_end .global %(name)s_size %(rodata)s %(name)s_start: .incbin "%(file)s" %(name)s_end: .align %(align)d %(name)s_size: .%(unit)s 0x%(size)x """ % locals()) class file_to_object_c(Task.Task): color = 'CYAN' def run(self): name = [] for i, x in enumerate(self.inputs[0].name): if x.isalnum(): name.append(x) else: name.append('_') file = self.inputs[0].abspath() size = os.path.getsize(file) name = "_binary_" + "".join(name) def char_to_num(ch): if sys.version_info[0] < 3: return ord(ch) return ch data = self.inputs[0].read('rb') lines, line = [], [] for idx_byte, byte in enumerate(data): line.append(byte) if len(line) > 15 or idx_byte == size-1: lines.append(", ".join(("0x%02x" % char_to_num(x)) for x in line)) line = [] data = ",\n ".join(lines) self.outputs[0].write(\ """ unsigned long %(name)s_size = %(size)dL; char const %(name)s_start[] = { %(data)s }; char const %(name)s_end[] = {}; """ % locals()) @TaskGen.feature('file_to_object') @TaskGen.before_method('process_source') def tg_file_to_object(self): bld = self.bld sources = self.to_nodes(self.source) targets = [] for src in sources: if bld.env.F2O_METHOD == ["asm"]: tgt = src.parent.find_or_declare(src.name + '.f2o.s') tsk = self.create_task('file_to_object_s', src, tgt) tsk.cwd = src.parent.abspath() # verify else: tgt = src.parent.find_or_declare(src.name + '.f2o.c') tsk = self.create_task('file_to_object_c', src, tgt) tsk.cwd = src.parent.abspath() # verify targets.append(tgt) self.source = targets def configure(conf): conf.load('gas') conf.env.F2O_METHOD = ["c"] hamster-3.0.3/waflib/extras/fluid.py000066400000000000000000000015361452646177100174310ustar00rootroot00000000000000#!/usr/bin/python # encoding: utf-8 # Grygoriy Fuchedzhy 2009 """ Compile fluid files (fltk graphic library). Use the 'fluid' feature in conjunction with the 'cxx' feature. """ from waflib import Task from waflib.TaskGen import extension class fluid(Task.Task): color = 'BLUE' ext_out = ['.h'] run_str = '${FLUID} -c -o ${TGT[0].abspath()} -h ${TGT[1].abspath()} ${SRC}' @extension('.fl') def process_fluid(self, node): """add the .fl to the source list; the cxx file generated will be compiled when possible""" cpp = node.change_ext('.cpp') hpp = node.change_ext('.hpp') self.create_task('fluid', node, [cpp, hpp]) if 'cxx' in self.features: self.source.append(cpp) def configure(conf): conf.find_program('fluid', var='FLUID') conf.check_cfg(path='fltk-config', package='', args='--cxxflags --ldflags', uselib_store='FLTK', mandatory=True) hamster-3.0.3/waflib/extras/freeimage.py000066400000000000000000000041051452646177100202450ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # # written by Sylvain Rouquette, 2011 ''' To add the freeimage tool to the waf file: $ ./waf-light --tools=compat15,freeimage or, if you have waf >= 1.6.2 $ ./waf update --files=freeimage The wscript will look like: def options(opt): opt.load('compiler_cxx freeimage') def configure(conf): conf.load('compiler_cxx freeimage') # you can call check_freeimage with some parameters. # It's optional on Linux, it's 'mandatory' on Windows if # you didn't use --fi-path on the command-line # conf.check_freeimage(path='FreeImage/Dist', fip=True) def build(bld): bld(source='main.cpp', target='app', use='FREEIMAGE') ''' from waflib import Utils from waflib.Configure import conf def options(opt): opt.add_option('--fi-path', type='string', default='', dest='fi_path', help='''path to the FreeImage directory \ where the files are e.g. /FreeImage/Dist''') opt.add_option('--fip', action='store_true', default=False, dest='fip', help='link with FreeImagePlus') opt.add_option('--fi-static', action='store_true', default=False, dest='fi_static', help="link as shared libraries") @conf def check_freeimage(self, path=None, fip=False): self.start_msg('Checking FreeImage') if not self.env['CXX']: self.fatal('you must load compiler_cxx before loading freeimage') prefix = self.options.fi_static and 'ST' or '' platform = Utils.unversioned_sys_platform() if platform == 'win32': if not path: self.fatal('you must specify the path to FreeImage. \ use --fi-path=/FreeImage/Dist') else: self.env['INCLUDES_FREEIMAGE'] = path self.env['%sLIBPATH_FREEIMAGE' % prefix] = path libs = ['FreeImage'] if self.options.fip: libs.append('FreeImagePlus') if platform == 'win32': self.env['%sLIB_FREEIMAGE' % prefix] = libs else: self.env['%sLIB_FREEIMAGE' % prefix] = [i.lower() for i in libs] self.end_msg('ok') def configure(conf): platform = Utils.unversioned_sys_platform() if platform == 'win32' and not conf.options.fi_path: return conf.check_freeimage(conf.options.fi_path, conf.options.fip) hamster-3.0.3/waflib/extras/fsb.py000066400000000000000000000010741452646177100170750ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) """ Fully sequential builds The previous tasks from task generators are re-processed, and this may lead to speed issues Yet, if you are using this, speed is probably a minor concern """ from waflib import Build def options(opt): pass def configure(conf): pass class FSBContext(Build.BuildContext): def __call__(self, *k, **kw): ret = Build.BuildContext.__call__(self, *k, **kw) # evaluate the results immediately Build.BuildContext.compile(self) return ret def compile(self): pass hamster-3.0.3/waflib/extras/fsc.py000066400000000000000000000035651452646177100171050ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) """ Experimental F# stuff FSC="mono /path/to/fsc.exe" waf configure build """ from waflib import Utils, Task from waflib.TaskGen import before_method, after_method, feature from waflib.Tools import ccroot, cs ccroot.USELIB_VARS['fsc'] = set(['CSFLAGS', 'ASSEMBLIES', 'RESOURCES']) @feature('fs') @before_method('process_source') def apply_fsc(self): cs_nodes = [] no_nodes = [] for x in self.to_nodes(self.source): if x.name.endswith('.fs'): cs_nodes.append(x) else: no_nodes.append(x) self.source = no_nodes bintype = getattr(self, 'type', self.gen.endswith('.dll') and 'library' or 'exe') self.cs_task = tsk = self.create_task('fsc', cs_nodes, self.path.find_or_declare(self.gen)) tsk.env.CSTYPE = '/target:%s' % bintype tsk.env.OUT = '/out:%s' % tsk.outputs[0].abspath() inst_to = getattr(self, 'install_path', bintype=='exe' and '${BINDIR}' or '${LIBDIR}') if inst_to: # note: we are making a copy, so the files added to cs_task.outputs won't be installed automatically mod = getattr(self, 'chmod', bintype=='exe' and Utils.O755 or Utils.O644) self.install_task = self.add_install_files(install_to=inst_to, install_from=self.cs_task.outputs[:], chmod=mod) feature('fs')(cs.use_cs) after_method('apply_fsc')(cs.use_cs) feature('fs')(cs.debug_cs) after_method('apply_fsc', 'use_cs')(cs.debug_cs) class fsc(Task.Task): """ Compile F# files """ color = 'YELLOW' run_str = '${FSC} ${CSTYPE} ${CSFLAGS} ${ASS_ST:ASSEMBLIES} ${RES_ST:RESOURCES} ${OUT} ${SRC}' def configure(conf): """ Find a F# compiler, set the variable FSC for the compiler and FS_NAME (mono or fsc) """ conf.find_program(['fsc.exe', 'fsharpc'], var='FSC') conf.env.ASS_ST = '/r:%s' conf.env.RES_ST = '/resource:%s' conf.env.FS_NAME = 'fsc' if str(conf.env.FSC).lower().find('fsharpc') > -1: conf.env.FS_NAME = 'mono' hamster-3.0.3/waflib/extras/gccdeps.py000066400000000000000000000163131452646177100177350ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2008-2010 (ita) """ Execute the tasks with gcc -MD, read the dependencies from the .d file and prepare the dependency calculation for the next run. This affects the cxx class, so make sure to load Qt5 after this tool. Usage:: def options(opt): opt.load('compiler_cxx') def configure(conf): conf.load('compiler_cxx gccdeps') """ import os, re, threading from waflib import Task, Logs, Utils, Errors from waflib.Tools import asm, c, c_preproc, cxx from waflib.TaskGen import before_method, feature lock = threading.Lock() gccdeps_flags = ['-MD'] if not c_preproc.go_absolute: gccdeps_flags = ['-MMD'] # Third-party tools are allowed to add extra names in here with append() supported_compilers = ['gas', 'gcc', 'icc', 'clang'] re_o = re.compile(r"\.o$") re_splitter = re.compile(r'(?= 0: return line[sep_idx + 2:] else: return line def path_to_node(base_node, path, cached_nodes): # Take the base node and the path and return a node # Results are cached because searching the node tree is expensive # The following code is executed by threads, it is not safe, so a lock is needed... if getattr(path, '__hash__'): node_lookup_key = (base_node, path) else: # Not hashable, assume it is a list and join into a string node_lookup_key = (base_node, os.path.sep.join(path)) try: node = cached_nodes[node_lookup_key] except KeyError: # retry with lock on cache miss with lock: try: node = cached_nodes[node_lookup_key] except KeyError: node = cached_nodes[node_lookup_key] = base_node.find_resource(path) return node def post_run(self): if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: return super(self.derived_gccdeps, self).post_run() deps_filename = self.outputs[0].abspath() deps_filename = re_o.sub('.d', deps_filename) try: deps_txt = Utils.readf(deps_filename) except EnvironmentError: Logs.error('Could not find a .d dependency file, are cflags/cxxflags overwritten?') raise # Compilers have the choice to either output the file's dependencies # as one large Makefile rule: # # /path/to/file.o: /path/to/dep1.h \ # /path/to/dep2.h \ # /path/to/dep3.h \ # ... # # or as many individual rules: # # /path/to/file.o: /path/to/dep1.h # /path/to/file.o: /path/to/dep2.h # /path/to/file.o: /path/to/dep3.h # ... # # So the first step is to sanitize the input by stripping out the left- # hand side of all these lines. After that, whatever remains are the # implicit dependencies of task.outputs[0] deps_txt = '\n'.join([remove_makefile_rule_lhs(line) for line in deps_txt.splitlines()]) # Now join all the lines together deps_txt = deps_txt.replace('\\\n', '') dep_paths = deps_txt.strip() dep_paths = [x.replace('\\ ', ' ') for x in re_splitter.split(dep_paths) if x] resolved_nodes = [] unresolved_names = [] bld = self.generator.bld # Dynamically bind to the cache try: cached_nodes = bld.cached_nodes except AttributeError: cached_nodes = bld.cached_nodes = {} for path in dep_paths: node = None if os.path.isabs(path): node = path_to_node(bld.root, path, cached_nodes) else: # TODO waf 1.9 - single cwd value base_node = getattr(bld, 'cwdx', bld.bldnode) # when calling find_resource, make sure the path does not contain '..' path = [k for k in Utils.split_path(path) if k and k != '.'] while '..' in path: idx = path.index('..') if idx == 0: path = path[1:] base_node = base_node.parent else: del path[idx] del path[idx-1] node = path_to_node(base_node, path, cached_nodes) if not node: raise ValueError('could not find %r for %r' % (path, self)) if id(node) == id(self.inputs[0]): # ignore the source file, it is already in the dependencies # this way, successful config tests may be retrieved from the cache continue resolved_nodes.append(node) Logs.debug('deps: gccdeps for %s returned %s', self, resolved_nodes) bld.node_deps[self.uid()] = resolved_nodes bld.raw_deps[self.uid()] = unresolved_names try: del self.cache_sig except AttributeError: pass Task.Task.post_run(self) def scan(self): if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: return super(self.derived_gccdeps, self).scan() resolved_nodes = self.generator.bld.node_deps.get(self.uid(), []) unresolved_names = [] return (resolved_nodes, unresolved_names) def sig_implicit_deps(self): if not self.__class__.__name__ in self.env.ENABLE_GCCDEPS: return super(self.derived_gccdeps, self).sig_implicit_deps() bld = self.generator.bld try: return self.compute_sig_implicit_deps() except Errors.TaskNotReady: raise ValueError("Please specify the build order precisely with gccdeps (asm/c/c++ tasks)") except EnvironmentError: # If a file is renamed, assume the dependencies are stale and must be recalculated for x in bld.node_deps.get(self.uid(), []): if not x.is_bld() and not x.exists(): try: del x.parent.children[x.name] except KeyError: pass key = self.uid() bld.node_deps[key] = [] bld.raw_deps[key] = [] return Utils.SIG_NIL def wrap_compiled_task(classname): derived_class = type(classname, (Task.classes[classname],), {}) derived_class.derived_gccdeps = derived_class derived_class.post_run = post_run derived_class.scan = scan derived_class.sig_implicit_deps = sig_implicit_deps for k in ('asm', 'c', 'cxx'): if k in Task.classes: wrap_compiled_task(k) @before_method('process_source') @feature('force_gccdeps') def force_gccdeps(self): self.env.ENABLE_GCCDEPS = ['asm', 'c', 'cxx'] def configure(conf): # in case someone provides a --enable-gccdeps command-line option if not getattr(conf.options, 'enable_gccdeps', True): return global gccdeps_flags flags = conf.env.GCCDEPS_FLAGS or gccdeps_flags if conf.env.ASM_NAME in supported_compilers: try: conf.check(fragment='', features='asm force_gccdeps', asflags=flags, compile_filename='test.S', msg='Checking for asm flags %r' % ''.join(flags)) except Errors.ConfigurationError: pass else: conf.env.append_value('ASFLAGS', flags) conf.env.append_unique('ENABLE_GCCDEPS', 'asm') if conf.env.CC_NAME in supported_compilers: try: conf.check(fragment='int main() { return 0; }', features='c force_gccdeps', cflags=flags, msg='Checking for c flags %r' % ''.join(flags)) except Errors.ConfigurationError: pass else: conf.env.append_value('CFLAGS', flags) conf.env.append_unique('ENABLE_GCCDEPS', 'c') if conf.env.CXX_NAME in supported_compilers: try: conf.check(fragment='int main() { return 0; }', features='cxx force_gccdeps', cxxflags=flags, msg='Checking for cxx flags %r' % ''.join(flags)) except Errors.ConfigurationError: pass else: conf.env.append_value('CXXFLAGS', flags) conf.env.append_unique('ENABLE_GCCDEPS', 'cxx') def options(opt): raise ValueError('Do not load gccdeps options') hamster-3.0.3/waflib/extras/gdbus.py000066400000000000000000000055321452646177100174320ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Copyright Garmin International or its subsidiaries, 2018 # # Heavily based on dbus.py """ Compiles dbus files with **gdbus-codegen** Typical usage:: def options(opt): opt.load('compiler_c gdbus') def configure(conf): conf.load('compiler_c gdbus') def build(bld): tg = bld.program( includes = '.', source = bld.path.ant_glob('*.c'), target = 'gnome-hello') tg.add_gdbus_file('test.xml', 'com.example.example.', 'Example') """ from waflib import Task, Errors, Utils from waflib.TaskGen import taskgen_method, before_method @taskgen_method def add_gdbus_file(self, filename, prefix, namespace, export=False): """ Adds a dbus file to the list of dbus files to process. Store them in the attribute *dbus_lst*. :param filename: xml file to compile :type filename: string :param prefix: interface prefix (--interface-prefix=prefix) :type prefix: string :param mode: C namespace (--c-namespace=namespace) :type mode: string :param export: Export Headers? :type export: boolean """ if not hasattr(self, 'gdbus_lst'): self.gdbus_lst = [] if not 'process_gdbus' in self.meths: self.meths.append('process_gdbus') self.gdbus_lst.append([filename, prefix, namespace, export]) @before_method('process_source') def process_gdbus(self): """ Processes the dbus files stored in the attribute *gdbus_lst* to create :py:class:`gdbus_binding_tool` instances. """ output_node = self.path.get_bld().make_node(['gdbus', self.get_name()]) sources = [] for filename, prefix, namespace, export in getattr(self, 'gdbus_lst', []): node = self.path.find_resource(filename) if not node: raise Errors.WafError('file not found ' + filename) c_file = output_node.find_or_declare(node.change_ext('.c').name) h_file = output_node.find_or_declare(node.change_ext('.h').name) tsk = self.create_task('gdbus_binding_tool', node, [c_file, h_file]) tsk.cwd = output_node.abspath() tsk.env.GDBUS_CODEGEN_INTERFACE_PREFIX = prefix tsk.env.GDBUS_CODEGEN_NAMESPACE = namespace tsk.env.GDBUS_CODEGEN_OUTPUT = node.change_ext('').name sources.append(c_file) if sources: output_node.mkdir() self.source = Utils.to_list(self.source) + sources self.includes = [output_node] + self.to_incnodes(getattr(self, 'includes', [])) if export: self.export_includes = [output_node] + self.to_incnodes(getattr(self, 'export_includes', [])) class gdbus_binding_tool(Task.Task): """ Compiles a dbus file """ color = 'BLUE' ext_out = ['.h', '.c'] run_str = '${GDBUS_CODEGEN} --interface-prefix ${GDBUS_CODEGEN_INTERFACE_PREFIX} --generate-c-code ${GDBUS_CODEGEN_OUTPUT} --c-namespace ${GDBUS_CODEGEN_NAMESPACE} --c-generate-object-manager ${SRC[0].abspath()}' shell = True def configure(conf): """ Detects the program gdbus-codegen and sets ``conf.env.GDBUS_CODEGEN`` """ conf.find_program('gdbus-codegen', var='GDBUS_CODEGEN') hamster-3.0.3/waflib/extras/genpybind.py000066400000000000000000000155301452646177100203040ustar00rootroot00000000000000import os import pipes import subprocess import sys from waflib import Logs, Task, Context from waflib.Tools.c_preproc import scan as scan_impl # ^-- Note: waflib.extras.gccdeps.scan does not work for us, # due to its current implementation: # The -MD flag is injected into the {C,CXX}FLAGS environment variable and # dependencies are read out in a separate step after compiling by reading # the .d file saved alongside the object file. # As the genpybind task refers to a header file that is never compiled itself, # gccdeps will not be able to extract the list of dependencies. from waflib.TaskGen import feature, before_method def join_args(args): return " ".join(pipes.quote(arg) for arg in args) def configure(cfg): cfg.load("compiler_cxx") cfg.load("python") cfg.check_python_version(minver=(2, 7)) if not cfg.env.LLVM_CONFIG: cfg.find_program("llvm-config", var="LLVM_CONFIG") if not cfg.env.GENPYBIND: cfg.find_program("genpybind", var="GENPYBIND") # find clang reasource dir for builtin headers cfg.env.GENPYBIND_RESOURCE_DIR = os.path.join( cfg.cmd_and_log(cfg.env.LLVM_CONFIG + ["--libdir"]).strip(), "clang", cfg.cmd_and_log(cfg.env.LLVM_CONFIG + ["--version"]).strip()) if os.path.exists(cfg.env.GENPYBIND_RESOURCE_DIR): cfg.msg("Checking clang resource dir", cfg.env.GENPYBIND_RESOURCE_DIR) else: cfg.fatal("Clang resource dir not found") @feature("genpybind") @before_method("process_source") def generate_genpybind_source(self): """ Run genpybind on the headers provided in `source` and compile/link the generated code instead. This works by generating the code on the fly and swapping the source node before `process_source` is run. """ # name of module defaults to name of target module = getattr(self, "module", self.target) # create temporary source file in build directory to hold generated code out = "genpybind-%s.%d.cpp" % (module, self.idx) out = self.path.get_bld().find_or_declare(out) task = self.create_task("genpybind", self.to_nodes(self.source), out) # used to detect whether CFLAGS or CXXFLAGS should be passed to genpybind task.features = self.features task.module = module # can be used to select definitions to include in the current module # (when header files are shared by more than one module) task.genpybind_tags = self.to_list(getattr(self, "genpybind_tags", [])) # additional include directories task.includes = self.to_list(getattr(self, "includes", [])) task.genpybind = self.env.GENPYBIND # Tell waf to compile/link the generated code instead of the headers # originally passed-in via the `source` parameter. (see `process_source`) self.source = [out] class genpybind(Task.Task): # pylint: disable=invalid-name """ Runs genpybind on headers provided as input to this task. Generated code will be written to the first (and only) output node. """ quiet = True color = "PINK" scan = scan_impl @staticmethod def keyword(): return "Analyzing" def run(self): if not self.inputs: return args = self.find_genpybind() + self._arguments( resource_dir=self.env.GENPYBIND_RESOURCE_DIR) output = self.run_genpybind(args) # For debugging / log output pasteable_command = join_args(args) # write generated code to file in build directory # (will be compiled during process_source stage) (output_node,) = self.outputs output_node.write("// {}\n{}\n".format( pasteable_command.replace("\n", "\n// "), output)) def find_genpybind(self): return self.genpybind def run_genpybind(self, args): bld = self.generator.bld kwargs = dict(cwd=bld.variant_dir) if hasattr(bld, "log_command"): bld.log_command(args, kwargs) else: Logs.debug("runner: {!r}".format(args)) proc = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, **kwargs) stdout, stderr = proc.communicate() if not isinstance(stdout, str): stdout = stdout.decode(sys.stdout.encoding, errors="replace") if not isinstance(stderr, str): stderr = stderr.decode(sys.stderr.encoding, errors="replace") if proc.returncode != 0: bld.fatal( "genpybind returned {code} during the following call:" "\n{command}\n\n{stdout}\n\n{stderr}".format( code=proc.returncode, command=join_args(args), stdout=stdout, stderr=stderr, )) if stderr.strip(): Logs.debug("non-fatal warnings during genpybind run:\n{}".format(stderr)) return stdout def _include_paths(self): return self.generator.to_incnodes(self.includes + self.env.INCLUDES) def _inputs_as_relative_includes(self): include_paths = self._include_paths() relative_includes = [] for node in self.inputs: for inc in include_paths: if node.is_child_of(inc): relative_includes.append(node.path_from(inc)) break else: self.generator.bld.fatal("could not resolve {}".format(node)) return relative_includes def _arguments(self, genpybind_parse=None, resource_dir=None): args = [] relative_includes = self._inputs_as_relative_includes() is_cxx = "cxx" in self.features # options for genpybind args.extend(["--genpybind-module", self.module]) if self.genpybind_tags: args.extend(["--genpybind-tag"] + self.genpybind_tags) if relative_includes: args.extend(["--genpybind-include"] + relative_includes) if genpybind_parse: args.extend(["--genpybind-parse", genpybind_parse]) args.append("--") # headers to be processed by genpybind args.extend(node.abspath() for node in self.inputs) args.append("--") # options for clang/genpybind-parse args.append("-D__GENPYBIND__") args.append("-xc++" if is_cxx else "-xc") has_std_argument = False for flag in self.env["CXXFLAGS" if is_cxx else "CFLAGS"]: flag = flag.replace("-std=gnu", "-std=c") if flag.startswith("-std=c"): has_std_argument = True args.append(flag) if not has_std_argument: args.append("-std=c++14") args.extend("-I{}".format(n.abspath()) for n in self._include_paths()) args.extend("-D{}".format(p) for p in self.env.DEFINES) # point to clang resource dir, if specified if resource_dir: args.append("-resource-dir={}".format(resource_dir)) return args hamster-3.0.3/waflib/extras/gob2.py000066400000000000000000000004721452646177100171550ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Ali Sabil, 2007 from waflib import TaskGen TaskGen.declare_chain( name = 'gob2', rule = '${GOB2} -o ${TGT[0].bld_dir()} ${GOB2FLAGS} ${SRC}', ext_in = '.gob', ext_out = '.c' ) def configure(conf): conf.find_program('gob2', var='GOB2') conf.env['GOB2FLAGS'] = '' hamster-3.0.3/waflib/extras/halide.py000066400000000000000000000076231452646177100175570ustar00rootroot00000000000000#!/usr/bin/python # -*- coding: utf-8 -*- # Halide code generation tool __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2014" """ Tool to run `Halide `_ code generators. Usage:: bld( name='pipeline', # ^ Reference this in use="..." for things using the generated code #target=['pipeline.o', 'pipeline.h'] # ^ by default, name.{o,h} is added, but you can set the outputs here features='halide', halide_env="HL_TRACE=1 HL_TARGET=host-opencl-gpu_debug", # ^ Environment passed to the generator, # can be a dict, k/v list, or string. args=[], # ^ Command-line arguments to the generator (optional), # eg. to give parameters to the scheduling source='pipeline_gen', # ^ Name of the source executable ) Known issues: - Currently only supports Linux (no ".exe") - Doesn't rerun on input modification when input is part of a build chain, and has been modified externally. """ import os from waflib import Task, Utils, Options, TaskGen, Errors class run_halide_gen(Task.Task): color = 'CYAN' vars = ['HALIDE_ENV', 'HALIDE_ARGS'] run_str = "${SRC[0].abspath()} ${HALIDE_ARGS}" def __str__(self): stuff = "halide" stuff += ("[%s]" % (",".join( ('%s=%s' % (k,v)) for k, v in sorted(self.env.env.items())))) return Task.Task.__str__(self).replace(self.__class__.__name__, stuff) @TaskGen.feature('halide') @TaskGen.before_method('process_source') def halide(self): Utils.def_attrs(self, args=[], halide_env={}, ) bld = self.bld env = self.halide_env try: if isinstance(env, str): env = dict(x.split('=') for x in env.split()) elif isinstance(env, list): env = dict(x.split('=') for x in env) assert isinstance(env, dict) except Exception as e: if not isinstance(e, ValueError) \ and not isinstance(e, AssertionError): raise raise Errors.WafError( "halide_env must be under the form" \ " {'HL_x':'a', 'HL_y':'b'}" \ " or ['HL_x=y', 'HL_y=b']" \ " or 'HL_x=y HL_y=b'") src = self.to_nodes(self.source) assert len(src) == 1, "Only one source expected" src = src[0] args = Utils.to_list(self.args) def change_ext(src, ext): # Return a node with a new extension, in an appropriate folder name = src.name xpos = src.name.rfind('.') if xpos == -1: xpos = len(src.name) newname = name[:xpos] + ext if src.is_child_of(bld.bldnode): node = src.get_src().parent.find_or_declare(newname) else: node = bld.bldnode.find_or_declare(newname) return node def to_nodes(self, lst, path=None): tmp = [] path = path or self.path find = path.find_or_declare if isinstance(lst, self.path.__class__): lst = [lst] for x in Utils.to_list(lst): if isinstance(x, str): node = find(x) else: node = x tmp.append(node) return tmp tgt = to_nodes(self, self.target) if not tgt: tgt = [change_ext(src, '.o'), change_ext(src, '.h')] cwd = tgt[0].parent.abspath() task = self.create_task('run_halide_gen', src, tgt, cwd=cwd) task.env.append_unique('HALIDE_ARGS', args) if task.env.env == []: task.env.env = {} task.env.env.update(env) task.env.HALIDE_ENV = " ".join(("%s=%s" % (k,v)) for (k,v) in sorted(env.items())) task.env.HALIDE_ARGS = args try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] self.source = [] def configure(conf): if Options.options.halide_root is None: conf.check_cfg(package='Halide', args='--cflags --libs') else: halide_root = Options.options.halide_root conf.env.INCLUDES_HALIDE = [ os.path.join(halide_root, "include") ] conf.env.LIBPATH_HALIDE = [ os.path.join(halide_root, "lib") ] conf.env.LIB_HALIDE = ["Halide"] # You might want to add this, while upstream doesn't fix it #conf.env.LIB_HALIDE += ['ncurses', 'dl', 'pthread'] def options(opt): opt.add_option('--halide-root', help="path to Halide include and lib files", ) hamster-3.0.3/waflib/extras/haxe.py000066400000000000000000000125171452646177100172540ustar00rootroot00000000000000import re from waflib import Utils, Task, Errors, Logs from waflib.Configure import conf from waflib.TaskGen import extension, taskgen_method HAXE_COMPILERS = { 'JS': {'tgt': '--js', 'ext_out': ['.js']}, 'LUA': {'tgt': '--lua', 'ext_out': ['.lua']}, 'SWF': {'tgt': '--swf', 'ext_out': ['.swf']}, 'NEKO': {'tgt': '--neko', 'ext_out': ['.n']}, 'PHP': {'tgt': '--php', 'ext_out': ['.php']}, 'CPP': {'tgt': '--cpp', 'ext_out': ['.h', '.cpp']}, 'CPPIA': {'tgt': '--cppia', 'ext_out': ['.cppia']}, 'CS': {'tgt': '--cs', 'ext_out': ['.cs']}, 'JAVA': {'tgt': '--java', 'ext_out': ['.java']}, 'JVM': {'tgt': '--jvm', 'ext_out': ['.jar']}, 'PYTHON': {'tgt': '--python', 'ext_out': ['.py']}, 'HL': {'tgt': '--hl', 'ext_out': ['.hl']}, 'HLC': {'tgt': '--hl', 'ext_out': ['.h', '.c']}, } @conf def check_haxe_pkg(self, **kw): self.find_program('haxelib') libs = kw.get('libs') if not libs or not (type(libs) == str or (type(libs) == list and all(isinstance(s, str) for s in libs))): self.fatal('Specify correct libs value in ensure call') return fetch = kw.get('fetch') if not fetch is None and not type(fetch) == bool: self.fatal('Specify correct fetch value in ensure call') libs = [libs] if type(libs) == str else libs halt = False for lib in libs: try: self.start_msg('Checking for library %s' % lib) output = self.cmd_and_log(self.env.HAXELIB + ['list', lib]) except Errors.WafError: self.end_msg(False) self.fatal('Can\'t run haxelib list, ensuring halted') return if lib in output: self.end_msg(lib in output) else: if not fetch: self.end_msg(False) halt = True continue try: status = self.exec_command(self.env.HAXELIB + ['install', lib]) if status: self.end_msg(False) self.fatal('Can\'t get %s with haxelib, ensuring halted' % lib) return else: self.end_msg('downloaded', color='YELLOW') except Errors.WafError: self.end_msg(False) self.fatal('Can\'t run haxelib install, ensuring halted') return postfix = kw.get('uselib_store') or lib.upper() self.env.append_unique('LIB_' + postfix, lib) if halt: self.fatal('Can\'t find libraries in haxelib list, ensuring halted') return class haxe(Task.Task): vars = ['HAXE_VERSION', 'HAXE_FLAGS'] ext_in = ['.hx'] def run(self): cmd = self.env.HAXE + self.env.HAXE_FLAGS_DEFAULT + self.env.HAXE_FLAGS return self.exec_command(cmd) for COMP in HAXE_COMPILERS: # create runners for each compile target type("haxe_" + COMP, (haxe,), {'ext_out': HAXE_COMPILERS[COMP]['ext_out']}) @taskgen_method def init_haxe(self): errmsg = '%s not found, specify correct value' try: compiler = HAXE_COMPILERS[self.compiler] comp_tgt = compiler['tgt'] comp_mod = '/main.c' if self.compiler == 'HLC' else '' except (AttributeError, KeyError): self.bld.fatal(errmsg % 'COMPILER' + ': ' + ', '.join(HAXE_COMPILERS.keys())) return self.env.append_value( 'HAXE_FLAGS', [comp_tgt, self.path.get_bld().make_node(self.target + comp_mod).abspath()]) if hasattr(self, 'use'): if not (type(self.use) == str or type(self.use) == list): self.bld.fatal(errmsg % 'USE') return self.use = [self.use] if type(self.use) == str else self.use for dep in self.use: if self.env['LIB_' + dep]: for lib in self.env['LIB_' + dep]: self.env.append_value('HAXE_FLAGS', ['-lib', lib]) if hasattr(self, 'res'): if not type(self.res) == str: self.bld.fatal(errmsg % 'RES') return self.env.append_value('HAXE_FLAGS', ['-D', 'resourcesPath=%s' % self.res]) @extension('.hx') def haxe_hook(self, node): if len(self.source) > 1: self.bld.fatal('Use separate task generators for multiple files') return src = node tgt = self.path.get_bld().find_or_declare(self.target) self.init_haxe() self.create_task('haxe_' + self.compiler, src, tgt) @conf def check_haxe(self, mini=None, maxi=None): self.start_msg('Checking for haxe version') try: curr = re.search( r'(\d+.?)+', self.cmd_and_log(self.env.HAXE + ['-version'])).group() except Errors.WafError: self.end_msg(False) self.fatal('Can\'t get haxe version') return if mini and Utils.num2ver(curr) < Utils.num2ver(mini): self.end_msg('wrong', color='RED') self.fatal('%s is too old, need >= %s' % (curr, mini)) return if maxi and Utils.num2ver(curr) > Utils.num2ver(maxi): self.end_msg('wrong', color='RED') self.fatal('%s is too new, need <= %s' % (curr, maxi)) return self.end_msg(curr, color='GREEN') self.env.HAXE_VERSION = curr def configure(self): self.env.append_value( 'HAXE_FLAGS_DEFAULT', ['-D', 'no-compilation', '-cp', self.path.abspath()]) Logs.warn('Default flags: %s' % ' '.join(self.env.HAXE_FLAGS_DEFAULT)) self.find_program('haxe') hamster-3.0.3/waflib/extras/javatest.py000077500000000000000000000202571452646177100201530ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Federico Pellegrin, 2019 (fedepell) """ Provides Java Unit test support using :py:class:`waflib.Tools.waf_unit_test.utest` task via the **javatest** feature. This gives the possibility to run unit test and have them integrated into the standard waf unit test environment. It has been tested with TestNG and JUnit but should be easily expandable to other frameworks given the flexibility of ut_str provided by the standard waf unit test environment. The extra takes care also of managing non-java dependencies (ie. C/C++ libraries using JNI or Python modules via JEP) and setting up the environment needed to run them. Example usage: def options(opt): opt.load('java waf_unit_test javatest') def configure(conf): conf.load('java javatest') def build(bld): [ ... mainprog is built here ... ] bld(features = 'javac javatest', srcdir = 'test/', outdir = 'test', sourcepath = ['test'], classpath = [ 'src' ], basedir = 'test', use = ['JAVATEST', 'mainprog'], # mainprog is the program being tested in src/ ut_str = 'java -cp ${CLASSPATH} ${JTRUNNER} ${SRC}', jtest_source = bld.path.ant_glob('test/*.xml'), ) At command line the CLASSPATH where to find the testing environment and the test runner (default TestNG) that will then be seen in the environment as CLASSPATH_JAVATEST (then used for use) and JTRUNNER and can be used for dependencies and ut_str generation. Example configure for TestNG: waf configure --jtpath=/tmp/testng-6.12.jar:/tmp/jcommander-1.71.jar --jtrunner=org.testng.TestNG or as default runner is TestNG: waf configure --jtpath=/tmp/testng-6.12.jar:/tmp/jcommander-1.71.jar Example configure for JUnit: waf configure --jtpath=/tmp/junit.jar --jtrunner=org.junit.runner.JUnitCore The runner class presence on the system is checked for at configuration stage. """ import os from waflib import Task, TaskGen, Options, Errors, Utils, Logs from waflib.Tools import ccroot JAR_RE = '**/*' def _process_use_rec(self, name): """ Recursively process ``use`` for task generator with name ``name``.. Used by javatest_process_use. """ if name in self.javatest_use_not or name in self.javatest_use_seen: return try: tg = self.bld.get_tgen_by_name(name) except Errors.WafError: self.javatest_use_not.add(name) return self.javatest_use_seen.append(name) tg.post() for n in self.to_list(getattr(tg, 'use', [])): _process_use_rec(self, n) @TaskGen.feature('javatest') @TaskGen.after_method('process_source', 'apply_link', 'use_javac_files') def javatest_process_use(self): """ Process the ``use`` attribute which contains a list of task generator names and store paths that later is used to populate the unit test runtime environment. """ self.javatest_use_not = set() self.javatest_use_seen = [] self.javatest_libpaths = [] # strings or Nodes self.javatest_pypaths = [] # strings or Nodes self.javatest_dep_nodes = [] names = self.to_list(getattr(self, 'use', [])) for name in names: _process_use_rec(self, name) def extend_unique(lst, varlst): ext = [] for x in varlst: if x not in lst: ext.append(x) lst.extend(ext) # Collect type specific info needed to construct a valid runtime environment # for the test. for name in self.javatest_use_seen: tg = self.bld.get_tgen_by_name(name) # Python-Java embedding crosstools such as JEP if 'py' in tg.features: # Python dependencies are added to PYTHONPATH pypath = getattr(tg, 'install_from', tg.path) if 'buildcopy' in tg.features: # Since buildcopy is used we assume that PYTHONPATH in build should be used, # not source extend_unique(self.javatest_pypaths, [pypath.get_bld().abspath()]) # Add buildcopy output nodes to dependencies extend_unique(self.javatest_dep_nodes, [o for task in getattr(tg, 'tasks', []) for o in getattr(task, 'outputs', [])]) else: # If buildcopy is not used, depend on sources instead extend_unique(self.javatest_dep_nodes, tg.source) extend_unique(self.javatest_pypaths, [pypath.abspath()]) if getattr(tg, 'link_task', None): # For tasks with a link_task (C, C++, D et.c.) include their library paths: if not isinstance(tg.link_task, ccroot.stlink_task): extend_unique(self.javatest_dep_nodes, tg.link_task.outputs) extend_unique(self.javatest_libpaths, tg.link_task.env.LIBPATH) if 'pyext' in tg.features: # If the taskgen is extending Python we also want to add the interpreter libpath. extend_unique(self.javatest_libpaths, tg.link_task.env.LIBPATH_PYEXT) else: # Only add to libpath if the link task is not a Python extension extend_unique(self.javatest_libpaths, [tg.link_task.outputs[0].parent.abspath()]) if 'javac' in tg.features or 'jar' in tg.features: if hasattr(tg, 'jar_task'): # For Java JAR tasks depend on generated JAR extend_unique(self.javatest_dep_nodes, tg.jar_task.outputs) else: # For Java non-JAR ones we need to glob generated files (Java output files are not predictable) if hasattr(tg, 'outdir'): base_node = tg.outdir else: base_node = tg.path.get_bld() self.javatest_dep_nodes.extend([dx for dx in base_node.ant_glob(JAR_RE, remove=False, quiet=True)]) @TaskGen.feature('javatest') @TaskGen.after_method('apply_java', 'use_javac_files', 'set_classpath', 'javatest_process_use') def make_javatest(self): """ Creates a ``utest`` task with a populated environment for Java Unit test execution """ tsk = self.create_task('utest') tsk.set_run_after(self.javac_task) # Dependencies from recursive use analysis tsk.dep_nodes.extend(self.javatest_dep_nodes) # Put test input files as waf_unit_test relies on that for some prints and log generation # If jtest_source is there, this is specially useful for passing XML for TestNG # that contain test specification, use that as inputs, otherwise test sources if getattr(self, 'jtest_source', None): tsk.inputs = self.to_nodes(self.jtest_source) else: if self.javac_task.srcdir[0].exists(): tsk.inputs = self.javac_task.srcdir[0].ant_glob('**/*.java', remove=False) if getattr(self, 'ut_str', None): self.ut_run, lst = Task.compile_fun(self.ut_str, shell=getattr(self, 'ut_shell', False)) tsk.vars = lst + tsk.vars if getattr(self, 'ut_cwd', None): if isinstance(self.ut_cwd, str): # we want a Node instance if os.path.isabs(self.ut_cwd): self.ut_cwd = self.bld.root.make_node(self.ut_cwd) else: self.ut_cwd = self.path.make_node(self.ut_cwd) else: self.ut_cwd = self.bld.bldnode # Get parent CLASSPATH and add output dir of test, we run from wscript dir # We have to change it from list to the standard java -cp format (: separated) tsk.env.CLASSPATH = ':'.join(self.env.CLASSPATH) + ':' + self.outdir.abspath() if not self.ut_cwd.exists(): self.ut_cwd.mkdir() if not hasattr(self, 'ut_env'): self.ut_env = dict(os.environ) def add_paths(var, lst): # Add list of paths to a variable, lst can contain strings or nodes lst = [ str(n) for n in lst ] Logs.debug("ut: %s: Adding paths %s=%s", self, var, lst) self.ut_env[var] = os.pathsep.join(lst) + os.pathsep + self.ut_env.get(var, '') add_paths('PYTHONPATH', self.javatest_pypaths) if Utils.is_win32: add_paths('PATH', self.javatest_libpaths) elif Utils.unversioned_sys_platform() == 'darwin': add_paths('DYLD_LIBRARY_PATH', self.javatest_libpaths) add_paths('LD_LIBRARY_PATH', self.javatest_libpaths) else: add_paths('LD_LIBRARY_PATH', self.javatest_libpaths) def configure(ctx): cp = ctx.env.CLASSPATH or '.' if getattr(Options.options, 'jtpath', None): ctx.env.CLASSPATH_JAVATEST = getattr(Options.options, 'jtpath').split(':') cp += ':' + getattr(Options.options, 'jtpath') if getattr(Options.options, 'jtrunner', None): ctx.env.JTRUNNER = getattr(Options.options, 'jtrunner') if ctx.check_java_class(ctx.env.JTRUNNER, with_classpath=cp): ctx.fatal('Could not run test class %r' % ctx.env.JTRUNNER) def options(opt): opt.add_option('--jtpath', action='store', default='', dest='jtpath', help='Path to jar(s) needed for javatest execution, colon separated, if not in the system CLASSPATH') opt.add_option('--jtrunner', action='store', default='org.testng.TestNG', dest='jtrunner', help='Class to run javatest test [default: org.testng.TestNG]') hamster-3.0.3/waflib/extras/kde4.py000066400000000000000000000052431452646177100171540ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2010 (ita) """ Support for the KDE4 libraries and msgfmt """ import os, re from waflib import Task, Utils from waflib.TaskGen import feature @feature('msgfmt') def apply_msgfmt(self): """ Process all languages to create .mo files and to install them:: def build(bld): bld(features='msgfmt', langs='es de fr', appname='myapp', install_path='${KDE4_LOCALE_INSTALL_DIR}') """ for lang in self.to_list(self.langs): node = self.path.find_resource(lang+'.po') task = self.create_task('msgfmt', node, node.change_ext('.mo')) langname = lang.split('/') langname = langname[-1] inst = getattr(self, 'install_path', '${KDE4_LOCALE_INSTALL_DIR}') self.add_install_as( inst_to = inst + os.sep + langname + os.sep + 'LC_MESSAGES' + os.sep + getattr(self, 'appname', 'set_your_appname') + '.mo', inst_from = task.outputs[0], chmod = getattr(self, 'chmod', Utils.O644)) class msgfmt(Task.Task): """ Transform .po files into .mo files """ color = 'BLUE' run_str = '${MSGFMT} ${SRC} -o ${TGT}' def configure(self): """ Detect kde4-config and set various variables for the *use* system:: def options(opt): opt.load('compiler_cxx kde4') def configure(conf): conf.load('compiler_cxx kde4') def build(bld): bld.program(source='main.c', target='app', use='KDECORE KIO KHTML') """ kdeconfig = self.find_program('kde4-config') prefix = self.cmd_and_log(kdeconfig + ['--prefix']).strip() fname = '%s/share/apps/cmake/modules/KDELibsDependencies.cmake' % prefix try: os.stat(fname) except OSError: fname = '%s/share/kde4/apps/cmake/modules/KDELibsDependencies.cmake' % prefix try: os.stat(fname) except OSError: self.fatal('could not open %s' % fname) try: txt = Utils.readf(fname) except EnvironmentError: self.fatal('could not read %s' % fname) txt = txt.replace('\\\n', '\n') fu = re.compile('#(.*)\n') txt = fu.sub('', txt) setregexp = re.compile(r'([sS][eE][tT]\s*\()\s*([^\s]+)\s+\"([^"]+)\"\)') found = setregexp.findall(txt) for (_, key, val) in found: #print key, val self.env[key] = val # well well, i could just write an interpreter for cmake files self.env['LIB_KDECORE']= ['kdecore'] self.env['LIB_KDEUI'] = ['kdeui'] self.env['LIB_KIO'] = ['kio'] self.env['LIB_KHTML'] = ['khtml'] self.env['LIB_KPARTS'] = ['kparts'] self.env['LIBPATH_KDECORE'] = [os.path.join(self.env.KDE4_LIB_INSTALL_DIR, 'kde4', 'devel'), self.env.KDE4_LIB_INSTALL_DIR] self.env['INCLUDES_KDECORE'] = [self.env['KDE4_INCLUDE_INSTALL_DIR']] self.env.append_value('INCLUDES_KDECORE', [self.env['KDE4_INCLUDE_INSTALL_DIR']+ os.sep + 'KDE']) self.find_program('msgfmt', var='MSGFMT') hamster-3.0.3/waflib/extras/local_rpath.py000066400000000000000000000011221452646177100206050ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) import copy from waflib.TaskGen import after_method, feature @after_method('propagate_uselib_vars') @feature('cprogram', 'cshlib', 'cxxprogram', 'cxxshlib', 'fcprogram', 'fcshlib') def add_rpath_stuff(self): all = copy.copy(self.to_list(getattr(self, 'use', []))) while all: name = all.pop() try: tg = self.bld.get_tgen_by_name(name) except: continue if hasattr(tg, 'link_task'): self.env.append_value('RPATH', tg.link_task.outputs[0].parent.abspath()) all.extend(self.to_list(getattr(tg, 'use', []))) hamster-3.0.3/waflib/extras/make.py000066400000000000000000000062021452646177100172360ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 (ita) """ A make-like way of executing the build, following the relationships between inputs/outputs This algorithm will lead to slower builds, will not be as flexible as "waf build", but it might be useful for building data files (?) It is likely to break in the following cases: - files are created dynamically (no inputs or outputs) - headers - building two files from different groups """ import re from waflib import Options, Task from waflib.Build import BuildContext class MakeContext(BuildContext): '''executes tasks in a step-by-step manner, following dependencies between inputs/outputs''' cmd = 'make' fun = 'build' def __init__(self, **kw): super(MakeContext, self).__init__(**kw) self.files = Options.options.files def get_build_iterator(self): if not self.files: while 1: yield super(MakeContext, self).get_build_iterator() for g in self.groups: for tg in g: try: f = tg.post except AttributeError: pass else: f() provides = {} uses = {} all_tasks = [] tasks = [] for pat in self.files.split(','): matcher = self.get_matcher(pat) for tg in g: if isinstance(tg, Task.Task): lst = [tg] else: lst = tg.tasks for tsk in lst: all_tasks.append(tsk) do_exec = False for node in tsk.inputs: try: uses[node].append(tsk) except: uses[node] = [tsk] if matcher(node, output=False): do_exec = True break for node in tsk.outputs: try: provides[node].append(tsk) except: provides[node] = [tsk] if matcher(node, output=True): do_exec = True break if do_exec: tasks.append(tsk) # so we have the tasks that we need to process, the list of all tasks, # the map of the tasks providing nodes, and the map of tasks using nodes if not tasks: # if there are no tasks matching, return everything in the current group result = all_tasks else: # this is like a big filter... result = set() seen = set() cur = set(tasks) while cur: result |= cur tosee = set() for tsk in cur: for node in tsk.inputs: if node in seen: continue seen.add(node) tosee |= set(provides.get(node, [])) cur = tosee result = list(result) Task.set_file_constraints(result) Task.set_precedence_constraints(result) yield result while 1: yield [] def get_matcher(self, pat): # this returns a function inn = True out = True if pat.startswith('in:'): out = False pat = pat.replace('in:', '') elif pat.startswith('out:'): inn = False pat = pat.replace('out:', '') anode = self.root.find_node(pat) pattern = None if not anode: if not pat.startswith('^'): pat = '^.+?%s' % pat if not pat.endswith('$'): pat = '%s$' % pat pattern = re.compile(pat) def match(node, output): if output and not out: return False if not output and not inn: return False if anode: return anode == node else: return pattern.match(node.abspath()) return match hamster-3.0.3/waflib/extras/midl.py000066400000000000000000000032431452646177100172500ustar00rootroot00000000000000#!/usr/bin/env python # Issue 1185 ultrix gmail com """ Microsoft Interface Definition Language support. Given ComObject.idl, this tool will generate ComObject.tlb ComObject_i.h ComObject_i.c ComObject_p.c and dlldata.c To declare targets using midl:: def configure(conf): conf.load('msvc') conf.load('midl') def build(bld): bld( features='c cshlib', # Note: ComObject_i.c is generated from ComObject.idl source = 'main.c ComObject.idl ComObject_i.c', target = 'ComObject.dll') """ from waflib import Task, Utils from waflib.TaskGen import feature, before_method import os def configure(conf): conf.find_program(['midl'], var='MIDL') conf.env.MIDLFLAGS = [ '/nologo', '/D', '_DEBUG', '/W1', '/char', 'signed', '/Oicf', ] @feature('c', 'cxx') @before_method('process_source') def idl_file(self): # Do this before process_source so that the generated header can be resolved # when scanning source dependencies. idl_nodes = [] src_nodes = [] for node in Utils.to_list(self.source): if str(node).endswith('.idl'): idl_nodes.append(node) else: src_nodes.append(node) for node in self.to_nodes(idl_nodes): t = node.change_ext('.tlb') h = node.change_ext('_i.h') c = node.change_ext('_i.c') p = node.change_ext('_p.c') d = node.parent.find_or_declare('dlldata.c') self.create_task('midl', node, [t, h, c, p, d]) self.source = src_nodes class midl(Task.Task): """ Compile idl files """ color = 'YELLOW' run_str = '${MIDL} ${MIDLFLAGS} ${CPPPATH_ST:INCLUDES} /tlb ${TGT[0].bldpath()} /header ${TGT[1].bldpath()} /iid ${TGT[2].bldpath()} /proxy ${TGT[3].bldpath()} /dlldata ${TGT[4].bldpath()} ${SRC}' before = ['winrc'] hamster-3.0.3/waflib/extras/msvc_pdb.py000066400000000000000000000024731452646177100201240ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Rafaël Kooi 2019 from waflib import TaskGen @TaskGen.feature('c', 'cxx', 'fc') @TaskGen.after_method('propagate_uselib_vars') def add_pdb_per_object(self): """For msvc/fortran, specify a unique compile pdb per object, to work around LNK4099. Flags are updated with a unique /Fd flag based on the task output name. This is separate from the link pdb. """ if not hasattr(self, 'compiled_tasks'): return link_task = getattr(self, 'link_task', None) for task in self.compiled_tasks: if task.inputs and task.inputs[0].name.lower().endswith('.rc'): continue add_pdb = False for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): # several languages may be used at once for flag in task.env[flagname]: if flag[1:].lower() == 'zi': add_pdb = True break if add_pdb: node = task.outputs[0].change_ext('.pdb') pdb_flag = '/Fd:' + node.abspath() for flagname in ('CFLAGS', 'CXXFLAGS', 'FCFLAGS'): buf = [pdb_flag] for flag in task.env[flagname]: if flag[1:3] == 'Fd' or flag[1:].lower() == 'fs' or flag[1:].lower() == 'mp': continue buf.append(flag) task.env[flagname] = buf if link_task and not node in link_task.dep_nodes: link_task.dep_nodes.append(node) if not node in task.outputs: task.outputs.append(node) hamster-3.0.3/waflib/extras/msvcdeps.py000066400000000000000000000212031452646177100201430ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Copyright Garmin International or its subsidiaries, 2012-2013 ''' Off-load dependency scanning from Python code to MSVC compiler This tool is safe to load in any environment; it will only activate the MSVC exploits when it finds that a particular taskgen uses MSVC to compile. Empirical testing shows about a 10% execution time savings from using this tool as compared to c_preproc. The technique of gutting scan() and pushing the dependency calculation down to post_run() is cribbed from gccdeps.py. This affects the cxx class, so make sure to load Qt5 after this tool. Usage:: def options(opt): opt.load('compiler_cxx') def configure(conf): conf.load('compiler_cxx msvcdeps') ''' import os, sys, tempfile, threading from waflib import Context, Errors, Logs, Task, Utils from waflib.Tools import c_preproc, c, cxx, msvc from waflib.TaskGen import feature, before_method lock = threading.Lock() PREPROCESSOR_FLAG = '/showIncludes' INCLUDE_PATTERN = 'Note: including file:' # Extensible by outside tools supported_compilers = ['msvc'] @feature('c', 'cxx') @before_method('process_source') def apply_msvcdeps_flags(taskgen): if taskgen.env.CC_NAME not in supported_compilers: return for flag in ('CFLAGS', 'CXXFLAGS'): if taskgen.env.get_flat(flag).find(PREPROCESSOR_FLAG) < 0: taskgen.env.append_value(flag, PREPROCESSOR_FLAG) def get_correct_path_case(base_path, path): ''' Return a case-corrected version of ``path`` by searching the filesystem for ``path``, relative to ``base_path``, using the case returned by the filesystem. ''' components = Utils.split_path(path) corrected_path = '' if os.path.isabs(path): corrected_path = components.pop(0).upper() + os.sep for part in components: part = part.lower() search_path = os.path.join(base_path, corrected_path) if part == '..': corrected_path = os.path.join(corrected_path, part) search_path = os.path.normpath(search_path) continue for item in sorted(os.listdir(search_path)): if item.lower() == part: corrected_path = os.path.join(corrected_path, item) break else: raise ValueError("Can't find %r in %r" % (part, search_path)) return corrected_path def path_to_node(base_node, path, cached_nodes): ''' Take the base node and the path and return a node Results are cached because searching the node tree is expensive The following code is executed by threads, it is not safe, so a lock is needed... ''' # normalize the path to remove parent path components (..) path = os.path.normpath(path) # normalize the path case to increase likelihood of a cache hit node_lookup_key = (base_node, os.path.normcase(path)) try: node = cached_nodes[node_lookup_key] except KeyError: # retry with lock on cache miss with lock: try: node = cached_nodes[node_lookup_key] except KeyError: path = get_correct_path_case(base_node.abspath(), path) node = cached_nodes[node_lookup_key] = base_node.find_node(path) return node def post_run(self): if self.env.CC_NAME not in supported_compilers: return super(self.derived_msvcdeps, self).post_run() # TODO this is unlikely to work with netcache if getattr(self, 'cached', None): return Task.Task.post_run(self) resolved_nodes = [] unresolved_names = [] bld = self.generator.bld # Dynamically bind to the cache try: cached_nodes = bld.cached_nodes except AttributeError: cached_nodes = bld.cached_nodes = {} for path in self.msvcdeps_paths: node = None if os.path.isabs(path): node = path_to_node(bld.root, path, cached_nodes) else: # when calling find_resource, make sure the path does not begin with '..' base_node = bld.bldnode path = [k for k in Utils.split_path(path) if k and k != '.'] while path[0] == '..': path.pop(0) base_node = base_node.parent path = os.sep.join(path) node = path_to_node(base_node, path, cached_nodes) if not node: raise ValueError('could not find %r for %r' % (path, self)) else: if not c_preproc.go_absolute: if not (node.is_child_of(bld.srcnode) or node.is_child_of(bld.bldnode)): # System library Logs.debug('msvcdeps: Ignoring system include %r', node) continue if id(node) == id(self.inputs[0]): # ignore the source file, it is already in the dependencies # this way, successful config tests may be retrieved from the cache continue resolved_nodes.append(node) Logs.debug('deps: msvcdeps for %s returned %s', self, resolved_nodes) bld.node_deps[self.uid()] = resolved_nodes bld.raw_deps[self.uid()] = unresolved_names try: del self.cache_sig except AttributeError: pass Task.Task.post_run(self) def scan(self): if self.env.CC_NAME not in supported_compilers: return super(self.derived_msvcdeps, self).scan() resolved_nodes = self.generator.bld.node_deps.get(self.uid(), []) unresolved_names = [] return (resolved_nodes, unresolved_names) def sig_implicit_deps(self): if self.env.CC_NAME not in supported_compilers: return super(self.derived_msvcdeps, self).sig_implicit_deps() bld = self.generator.bld try: return self.compute_sig_implicit_deps() except Errors.TaskNotReady: raise ValueError("Please specify the build order precisely with msvcdeps (c/c++ tasks)") except EnvironmentError: # If a file is renamed, assume the dependencies are stale and must be recalculated for x in bld.node_deps.get(self.uid(), []): if not x.is_bld() and not x.exists(): try: del x.parent.children[x.name] except KeyError: pass key = self.uid() bld.node_deps[key] = [] bld.raw_deps[key] = [] return Utils.SIG_NIL def exec_command(self, cmd, **kw): if self.env.CC_NAME not in supported_compilers: return super(self.derived_msvcdeps, self).exec_command(cmd, **kw) if not 'cwd' in kw: kw['cwd'] = self.get_cwd() if self.env.PATH: env = kw['env'] = dict(kw.get('env') or self.env.env or os.environ) env['PATH'] = self.env.PATH if isinstance(self.env.PATH, str) else os.pathsep.join(self.env.PATH) # The Visual Studio IDE adds an environment variable that causes # the MS compiler to send its textual output directly to the # debugging window rather than normal stdout/stderr. # # This is unrecoverably bad for this tool because it will cause # all the dependency scanning to see an empty stdout stream and # assume that the file being compiled uses no headers. # # See http://blogs.msdn.com/b/freik/archive/2006/04/05/569025.aspx # # Attempting to repair the situation by deleting the offending # envvar at this point in tool execution will not be good enough-- # its presence poisons the 'waf configure' step earlier. We just # want to put a sanity check here in order to help developers # quickly diagnose the issue if an otherwise-good Waf tree # is then executed inside the MSVS IDE. assert 'VS_UNICODE_OUTPUT' not in kw['env'] cmd, args = self.split_argfile(cmd) try: (fd, tmp) = tempfile.mkstemp() os.write(fd, '\r\n'.join(args).encode()) os.close(fd) self.msvcdeps_paths = [] kw['env'] = kw.get('env', os.environ.copy()) kw['cwd'] = kw.get('cwd', os.getcwd()) kw['quiet'] = Context.STDOUT kw['output'] = Context.STDOUT out = [] if Logs.verbose: Logs.debug('argfile: @%r -> %r', tmp, args) try: raw_out = self.generator.bld.cmd_and_log(cmd + ['@' + tmp], **kw) ret = 0 except Errors.WafError as e: # Use e.msg if e.stdout is not set raw_out = getattr(e, 'stdout', e.msg) # Return non-zero error code even if we didn't # get one from the exception object ret = getattr(e, 'returncode', 1) Logs.debug('msvcdeps: Running for: %s' % self.inputs[0]) for line in raw_out.splitlines(): if line.startswith(INCLUDE_PATTERN): # Only strip whitespace after log to preserve # dependency structure in debug output inc_path = line[len(INCLUDE_PATTERN):] Logs.debug('msvcdeps: Regex matched %s', inc_path) self.msvcdeps_paths.append(inc_path.strip()) else: out.append(line) # Pipe through the remaining stdout content (not related to /showIncludes) if self.generator.bld.logger: self.generator.bld.logger.debug('out: %s' % os.linesep.join(out)) else: sys.stdout.write(os.linesep.join(out) + os.linesep) return ret finally: try: os.remove(tmp) except OSError: # anti-virus and indexers can keep files open -_- pass def wrap_compiled_task(classname): derived_class = type(classname, (Task.classes[classname],), {}) derived_class.derived_msvcdeps = derived_class derived_class.post_run = post_run derived_class.scan = scan derived_class.sig_implicit_deps = sig_implicit_deps derived_class.exec_command = exec_command for k in ('c', 'cxx'): if k in Task.classes: wrap_compiled_task(k) def options(opt): raise ValueError('Do not load msvcdeps options') hamster-3.0.3/waflib/extras/msvs.py000066400000000000000000000747421452646177100173270ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Avalanche Studios 2009-2011 # Thomas Nagy 2011 """ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. """ """ To add this tool to your project: def options(conf): opt.load('msvs') It can be a good idea to add the sync_exec tool too. To generate solution files: $ waf configure msvs To customize the outputs, provide subclasses in your wscript files:: from waflib.extras import msvs class vsnode_target(msvs.vsnode_target): def get_build_command(self, props): # likely to be required return "waf.bat build" def collect_source(self): # likely to be required ... class msvs_bar(msvs.msvs_generator): def init(self): msvs.msvs_generator.init(self) self.vsnode_target = vsnode_target The msvs class re-uses the same build() function for reading the targets (task generators), you may therefore specify msvs settings on the context object:: def build(bld): bld.solution_name = 'foo.sln' bld.waf_command = 'waf.bat' bld.projects_dir = bld.srcnode.make_node('.depproj') bld.projects_dir.mkdir() For visual studio 2008, the command is called 'msvs2008', and the classes such as vsnode_target are wrapped by a decorator class 'wrap_2008' to provide special functionality. To customize platform toolsets, pass additional parameters, for example:: class msvs_2013(msvs.msvs_generator): cmd = 'msvs2013' numver = '13.00' vsver = '2013' platform_toolset_ver = 'v120' ASSUMPTIONS: * a project can be either a directory or a target, vcxproj files are written only for targets that have source files * each project is a vcxproj file, therefore the project uuid needs only to be a hash of the absolute path """ import os, re, sys import uuid # requires python 2.5 from waflib.Build import BuildContext from waflib import Utils, TaskGen, Logs, Task, Context, Node, Options HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' PROJECT_TEMPLATE = r''' ${for b in project.build_properties} ${b.configuration} ${b.platform} ${endfor} {${project.uuid}} MakeFileProj ${project.name} ${for b in project.build_properties} Makefile ${b.outdir} ${project.platform_toolset_ver} ${endfor} ${for b in project.build_properties} ${endfor} ${for b in project.build_properties} ${xml:project.get_build_command(b)} ${xml:project.get_rebuild_command(b)} ${xml:project.get_clean_command(b)} ${xml:b.includes_search_path} ${xml:b.preprocessor_definitions};$(NMakePreprocessorDefinitions) ${xml:b.includes_search_path} $(ExecutablePath) ${if getattr(b, 'output_file', None)} ${xml:b.output_file} ${endif} ${if getattr(b, 'deploy_dir', None)} ${xml:b.deploy_dir} ${endif} ${endfor} ${for b in project.build_properties} ${if getattr(b, 'deploy_dir', None)} CopyToHardDrive ${endif} ${endfor} ${for x in project.source} <${project.get_key(x)} Include='${x.win32path()}' /> ${endfor} ''' FILTER_TEMPLATE = ''' ${for x in project.source} <${project.get_key(x)} Include="${x.win32path()}"> ${project.get_filter_name(x.parent)} ${endfor} ${for x in project.dirs()} {${project.make_uuid(x.win32path())}} ${endfor} ''' PROJECT_2008_TEMPLATE = r''' ${if project.build_properties} ${for b in project.build_properties} ${endfor} ${else} ${endif} ${if project.build_properties} ${for b in project.build_properties} ${endfor} ${else} ${endif} ${project.display_filter()} ''' SOLUTION_TEMPLATE = '''Microsoft Visual Studio Solution File, Format Version ${project.numver} # Visual Studio ${project.vsver} ${for p in project.all_projects} Project("{${p.ptype()}}") = "${p.name}", "${p.title}", "{${p.uuid}}" EndProject${endfor} Global GlobalSection(SolutionConfigurationPlatforms) = preSolution ${if project.all_projects} ${for (configuration, platform) in project.all_projects[0].ctx.project_configurations()} ${configuration}|${platform} = ${configuration}|${platform} ${endfor} ${endif} EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution ${for p in project.all_projects} ${if hasattr(p, 'source')} ${for b in p.build_properties} {${p.uuid}}.${b.configuration}|${b.platform}.ActiveCfg = ${b.configuration}|${b.platform} ${if getattr(p, 'is_active', None)} {${p.uuid}}.${b.configuration}|${b.platform}.Build.0 = ${b.configuration}|${b.platform} ${endif} ${if getattr(p, 'is_deploy', None)} {${p.uuid}}.${b.configuration}|${b.platform}.Deploy.0 = ${b.configuration}|${b.platform} ${endif} ${endfor} ${endif} ${endfor} EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution ${for p in project.all_projects} ${if p.parent} {${p.uuid}} = {${p.parent.uuid}} ${endif} ${endfor} EndGlobalSection EndGlobal ''' COMPILE_TEMPLATE = '''def f(project): lst = [] def xml_escape(value): return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") %s #f = open('cmd.txt', 'w') #f.write(str(lst)) #f.close() return ''.join(lst) ''' reg_act = re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P[^}]*?)\})", re.M) def compile_template(line): """ Compile a template expression into a python function (like jsps, but way shorter) """ extr = [] def repl(match): g = match.group if g('dollar'): return "$" elif g('backslash'): return "\\" elif g('subst'): extr.append(g('code')) return "<<|@|>>" return None line2 = reg_act.sub(repl, line) params = line2.split('<<|@|>>') assert(extr) indent = 0 buf = [] app = buf.append def app(txt): buf.append(indent * '\t' + txt) for x in range(len(extr)): if params[x]: app("lst.append(%r)" % params[x]) f = extr[x] if f.startswith(('if', 'for')): app(f + ':') indent += 1 elif f.startswith('py:'): app(f[3:]) elif f.startswith(('endif', 'endfor')): indent -= 1 elif f.startswith(('else', 'elif')): indent -= 1 app(f + ':') indent += 1 elif f.startswith('xml:'): app('lst.append(xml_escape(%s))' % f[4:]) else: #app('lst.append((%s) or "cannot find %s")' % (f, f)) app('lst.append(%s)' % f) if extr: if params[-1]: app("lst.append(%r)" % params[-1]) fun = COMPILE_TEMPLATE % "\n\t".join(buf) #print(fun) return Task.funex(fun) re_blank = re.compile('(\n|\r|\\s)*\n', re.M) def rm_blank_lines(txt): txt = re_blank.sub('\r\n', txt) return txt BOM = '\xef\xbb\xbf' try: BOM = bytes(BOM, 'latin-1') # python 3 except TypeError: pass def stealth_write(self, data, flags='wb'): try: unicode except NameError: data = data.encode('utf-8') # python 3 else: data = data.decode(sys.getfilesystemencoding(), 'replace') data = data.encode('utf-8') if self.name.endswith(('.vcproj', '.vcxproj')): data = BOM + data try: txt = self.read(flags='rb') if txt != data: raise ValueError('must write') except (IOError, ValueError): self.write(data, flags=flags) else: Logs.debug('msvs: skipping %s', self.win32path()) Node.Node.stealth_write = stealth_write re_win32 = re.compile(r'^([/\\]cygdrive)?[/\\]([a-z])([^a-z0-9_-].*)', re.I) def win32path(self): p = self.abspath() m = re_win32.match(p) if m: return "%s:%s" % (m.group(2).upper(), m.group(3)) return p Node.Node.win32path = win32path re_quote = re.compile("[^a-zA-Z0-9-]") def quote(s): return re_quote.sub("_", s) def xml_escape(value): return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") def make_uuid(v, prefix = None): """ simple utility function """ if isinstance(v, dict): keys = list(v.keys()) keys.sort() tmp = str([(k, v[k]) for k in keys]) else: tmp = str(v) d = Utils.md5(tmp.encode()).hexdigest().upper() if prefix: d = '%s%s' % (prefix, d[8:]) gid = uuid.UUID(d, version = 4) return str(gid).upper() def diff(node, fromnode): # difference between two nodes, but with "(..)" instead of ".." c1 = node c2 = fromnode c1h = c1.height() c2h = c2.height() lst = [] up = 0 while c1h > c2h: lst.append(c1.name) c1 = c1.parent c1h -= 1 while c2h > c1h: up += 1 c2 = c2.parent c2h -= 1 while id(c1) != id(c2): lst.append(c1.name) up += 1 c1 = c1.parent c2 = c2.parent for i in range(up): lst.append('(..)') lst.reverse() return tuple(lst) class build_property(object): pass class vsnode(object): """ Abstract class representing visual studio elements We assume that all visual studio nodes have a uuid and a parent """ def __init__(self, ctx): self.ctx = ctx # msvs context self.name = '' # string, mandatory self.vspath = '' # path in visual studio (name for dirs, absolute path for projects) self.uuid = '' # string, mandatory self.parent = None # parent node for visual studio nesting def get_waf(self): """ Override in subclasses... """ return 'cd /d "%s" & %s' % (self.ctx.srcnode.win32path(), getattr(self.ctx, 'waf_command', 'waf.bat')) def ptype(self): """ Return a special uuid for projects written in the solution file """ pass def write(self): """ Write the project file, by default, do nothing """ pass def make_uuid(self, val): """ Alias for creating uuid values easily (the templates cannot access global variables) """ return make_uuid(val) class vsnode_vsdir(vsnode): """ Nodes representing visual studio folders (which do not match the filesystem tree!) """ VS_GUID_SOLUTIONFOLDER = "2150E333-8FDC-42A3-9474-1A3956D46DE8" def __init__(self, ctx, uuid, name, vspath=''): vsnode.__init__(self, ctx) self.title = self.name = name self.uuid = uuid self.vspath = vspath or name def ptype(self): return self.VS_GUID_SOLUTIONFOLDER class vsnode_project(vsnode): """ Abstract class representing visual studio project elements A project is assumed to be writable, and has a node representing the file to write to """ VS_GUID_VCPROJ = "8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942" def ptype(self): return self.VS_GUID_VCPROJ def __init__(self, ctx, node): vsnode.__init__(self, ctx) self.path = node self.uuid = make_uuid(node.win32path()) self.name = node.name self.platform_toolset_ver = getattr(ctx, 'platform_toolset_ver', None) self.title = self.path.win32path() self.source = [] # list of node objects self.build_properties = [] # list of properties (nmake commands, output dir, etc) def dirs(self): """ Get the list of parent folders of the source files (header files included) for writing the filters """ lst = [] def add(x): if x.height() > self.tg.path.height() and x not in lst: lst.append(x) add(x.parent) for x in self.source: add(x.parent) return lst def write(self): Logs.debug('msvs: creating %r', self.path) # first write the project file template1 = compile_template(PROJECT_TEMPLATE) proj_str = template1(self) proj_str = rm_blank_lines(proj_str) self.path.stealth_write(proj_str) # then write the filter template2 = compile_template(FILTER_TEMPLATE) filter_str = template2(self) filter_str = rm_blank_lines(filter_str) tmp = self.path.parent.make_node(self.path.name + '.filters') tmp.stealth_write(filter_str) def get_key(self, node): """ required for writing the source files """ name = node.name if name.endswith(('.cpp', '.c')): return 'ClCompile' return 'ClInclude' def collect_properties(self): """ Returns a list of triplet (configuration, platform, output_directory) """ ret = [] for c in self.ctx.configurations: for p in self.ctx.platforms: x = build_property() x.outdir = '' x.configuration = c x.platform = p x.preprocessor_definitions = '' x.includes_search_path = '' # can specify "deploy_dir" too ret.append(x) self.build_properties = ret def get_build_params(self, props): opt = '--execsolution="%s"' % self.ctx.get_solution_node().win32path() return (self.get_waf(), opt) def get_build_command(self, props): return "%s build %s" % self.get_build_params(props) def get_clean_command(self, props): return "%s clean %s" % self.get_build_params(props) def get_rebuild_command(self, props): return "%s clean build %s" % self.get_build_params(props) def get_filter_name(self, node): lst = diff(node, self.tg.path) return '\\'.join(lst) or '.' class vsnode_alias(vsnode_project): def __init__(self, ctx, node, name): vsnode_project.__init__(self, ctx, node) self.name = name self.output_file = '' class vsnode_build_all(vsnode_alias): """ Fake target used to emulate the behaviour of "make all" (starting one process by target is slow) This is the only alias enabled by default """ def __init__(self, ctx, node, name='build_all_projects'): vsnode_alias.__init__(self, ctx, node, name) self.is_active = True class vsnode_install_all(vsnode_alias): """ Fake target used to emulate the behaviour of "make install" """ def __init__(self, ctx, node, name='install_all_projects'): vsnode_alias.__init__(self, ctx, node, name) def get_build_command(self, props): return "%s build install %s" % self.get_build_params(props) def get_clean_command(self, props): return "%s clean %s" % self.get_build_params(props) def get_rebuild_command(self, props): return "%s clean build install %s" % self.get_build_params(props) class vsnode_project_view(vsnode_alias): """ Fake target used to emulate a file system view """ def __init__(self, ctx, node, name='project_view'): vsnode_alias.__init__(self, ctx, node, name) self.tg = self.ctx() # fake one, cannot remove self.exclude_files = Node.exclude_regs + ''' waf-2* waf3-2*/** .waf-2* .waf3-2*/** **/*.sdf **/*.suo **/*.ncb **/%s ''' % Options.lockfile def collect_source(self): # this is likely to be slow self.source = self.ctx.srcnode.ant_glob('**', excl=self.exclude_files) def get_build_command(self, props): params = self.get_build_params(props) + (self.ctx.cmd,) return "%s %s %s" % params def get_clean_command(self, props): return "" def get_rebuild_command(self, props): return self.get_build_command(props) class vsnode_target(vsnode_project): """ Visual studio project representing a targets (programs, libraries, etc) and bound to a task generator """ def __init__(self, ctx, tg): """ A project is more or less equivalent to a file/folder """ base = getattr(ctx, 'projects_dir', None) or tg.path node = base.make_node(quote(tg.name) + ctx.project_extension) # the project file as a Node vsnode_project.__init__(self, ctx, node) self.name = quote(tg.name) self.tg = tg # task generator def get_build_params(self, props): """ Override the default to add the target name """ opt = '--execsolution="%s"' % self.ctx.get_solution_node().win32path() if getattr(self, 'tg', None): opt += " --targets=%s" % self.tg.name return (self.get_waf(), opt) def collect_source(self): tg = self.tg source_files = tg.to_nodes(getattr(tg, 'source', [])) include_dirs = Utils.to_list(getattr(tg, 'msvs_includes', [])) include_files = [] for x in include_dirs: if isinstance(x, str): x = tg.path.find_node(x) if x: lst = [y for y in x.ant_glob(HEADERS_GLOB, flat=False)] include_files.extend(lst) # remove duplicates self.source.extend(list(set(source_files + include_files))) self.source.sort(key=lambda x: x.win32path()) def collect_properties(self): """ Visual studio projects are associated with platforms and configurations (for building especially) """ super(vsnode_target, self).collect_properties() for x in self.build_properties: x.outdir = self.path.parent.win32path() x.preprocessor_definitions = '' x.includes_search_path = '' try: tsk = self.tg.link_task except AttributeError: pass else: x.output_file = tsk.outputs[0].win32path() x.preprocessor_definitions = ';'.join(tsk.env.DEFINES) x.includes_search_path = ';'.join(self.tg.env.INCPATHS) class msvs_generator(BuildContext): '''generates a visual studio 2010 solution''' cmd = 'msvs' fun = 'build' numver = '11.00' # Visual Studio Version Number vsver = '2010' # Visual Studio Version Year platform_toolset_ver = 'v110' # Platform Toolset Version Number def init(self): """ Some data that needs to be present """ if not getattr(self, 'configurations', None): self.configurations = ['Release'] # LocalRelease, RemoteDebug, etc if not getattr(self, 'platforms', None): self.platforms = ['Win32'] if not getattr(self, 'all_projects', None): self.all_projects = [] if not getattr(self, 'project_extension', None): self.project_extension = '.vcxproj' if not getattr(self, 'projects_dir', None): self.projects_dir = self.srcnode.make_node('.depproj') self.projects_dir.mkdir() # bind the classes to the object, so that subclass can provide custom generators if not getattr(self, 'vsnode_vsdir', None): self.vsnode_vsdir = vsnode_vsdir if not getattr(self, 'vsnode_target', None): self.vsnode_target = vsnode_target if not getattr(self, 'vsnode_build_all', None): self.vsnode_build_all = vsnode_build_all if not getattr(self, 'vsnode_install_all', None): self.vsnode_install_all = vsnode_install_all if not getattr(self, 'vsnode_project_view', None): self.vsnode_project_view = vsnode_project_view self.numver = self.__class__.numver self.vsver = self.__class__.vsver self.platform_toolset_ver = self.__class__.platform_toolset_ver def execute(self): """ Entry point """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) # user initialization self.init() # two phases for creating the solution self.collect_projects() # add project objects into "self.all_projects" self.write_files() # write the corresponding project and solution files def collect_projects(self): """ Fill the list self.all_projects with project objects Fill the list of build targets """ self.collect_targets() self.add_aliases() self.collect_dirs() default_project = getattr(self, 'default_project', None) def sortfun(x): # folders should sort to the top if getattr(x, 'VS_GUID_SOLUTIONFOLDER', None): return '' # followed by the default project elif x.name == default_project: return ' ' return getattr(x, 'path', None) and x.path.win32path() or x.name self.all_projects.sort(key=sortfun) def write_files(self): """ Write the project and solution files from the data collected so far. It is unlikely that you will want to change this """ for p in self.all_projects: p.write() # and finally write the solution file node = self.get_solution_node() node.parent.mkdir() Logs.warn('Creating %r', node) template1 = compile_template(SOLUTION_TEMPLATE) sln_str = template1(self) sln_str = rm_blank_lines(sln_str) node.stealth_write(sln_str) def get_solution_node(self): """ The solution filename is required when writing the .vcproj files return self.solution_node and if it does not exist, make one """ try: return self.solution_node except AttributeError: pass solution_name = getattr(self, 'solution_name', None) if not solution_name: solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '.sln' if os.path.isabs(solution_name): self.solution_node = self.root.make_node(solution_name) else: self.solution_node = self.srcnode.make_node(solution_name) return self.solution_node def project_configurations(self): """ Helper that returns all the pairs (config,platform) """ ret = [] for c in self.configurations: for p in self.platforms: ret.append((c, p)) return ret def collect_targets(self): """ Process the list of task generators """ for g in self.groups: for tg in g: if not isinstance(tg, TaskGen.task_gen): continue if not hasattr(tg, 'msvs_includes'): tg.msvs_includes = tg.to_list(getattr(tg, 'includes', [])) + tg.to_list(getattr(tg, 'export_includes', [])) tg.post() if not getattr(tg, 'link_task', None): continue p = self.vsnode_target(self, tg) p.collect_source() # delegate this processing p.collect_properties() self.all_projects.append(p) def add_aliases(self): """ Add a specific target that emulates the "make all" necessary for Visual studio when pressing F7 We also add an alias for "make install" (disabled by default) """ base = getattr(self, 'projects_dir', None) or self.tg.path node_project = base.make_node('build_all_projects' + self.project_extension) # Node p_build = self.vsnode_build_all(self, node_project) p_build.collect_properties() self.all_projects.append(p_build) node_project = base.make_node('install_all_projects' + self.project_extension) # Node p_install = self.vsnode_install_all(self, node_project) p_install.collect_properties() self.all_projects.append(p_install) node_project = base.make_node('project_view' + self.project_extension) # Node p_view = self.vsnode_project_view(self, node_project) p_view.collect_source() p_view.collect_properties() self.all_projects.append(p_view) n = self.vsnode_vsdir(self, make_uuid(self.srcnode.win32path() + 'build_aliases'), "build_aliases") p_build.parent = p_install.parent = p_view.parent = n self.all_projects.append(n) def collect_dirs(self): """ Create the folder structure in the Visual studio project view """ seen = {} def make_parents(proj): # look at a project, try to make a parent if getattr(proj, 'parent', None): # aliases already have parents return x = proj.iter_path if x in seen: proj.parent = seen[x] return # There is not vsnode_vsdir for x. # So create a project representing the folder "x" n = proj.parent = seen[x] = self.vsnode_vsdir(self, make_uuid(x.win32path()), x.name) n.iter_path = x.parent self.all_projects.append(n) # recurse up to the project directory if x.height() > self.srcnode.height() + 1: make_parents(n) for p in self.all_projects[:]: # iterate over a copy of all projects if not getattr(p, 'tg', None): # but only projects that have a task generator continue # make a folder for each task generator p.iter_path = p.tg.path make_parents(p) def wrap_2008(cls): class dec(cls): def __init__(self, *k, **kw): cls.__init__(self, *k, **kw) self.project_template = PROJECT_2008_TEMPLATE def display_filter(self): root = build_property() root.subfilters = [] root.sourcefiles = [] root.source = [] root.name = '' @Utils.run_once def add_path(lst): if not lst: return root child = build_property() child.subfilters = [] child.sourcefiles = [] child.source = [] child.name = lst[-1] par = add_path(lst[:-1]) par.subfilters.append(child) return child for x in self.source: # this crap is for enabling subclasses to override get_filter_name tmp = self.get_filter_name(x.parent) tmp = tmp != '.' and tuple(tmp.split('\\')) or () par = add_path(tmp) par.source.append(x) def display(n): buf = [] for x in n.source: buf.append('\n' % (xml_escape(x.win32path()), self.get_key(x))) for x in n.subfilters: buf.append('' % xml_escape(x.name)) buf.append(display(x)) buf.append('') return '\n'.join(buf) return display(root) def get_key(self, node): """ If you do not want to let visual studio use the default file extensions, override this method to return a value: 0: C/C++ Code, 1: C++ Class, 2: C++ Header File, 3: C++ Form, 4: C++ Control, 5: Text File, 6: DEF File, 7: IDL File, 8: Makefile, 9: RGS File, 10: RC File, 11: RES File, 12: XSD File, 13: XML File, 14: HTML File, 15: CSS File, 16: Bitmap, 17: Icon, 18: Resx File, 19: BSC File, 20: XSX File, 21: C++ Web Service, 22: ASAX File, 23: Asp Page, 24: Document, 25: Discovery File, 26: C# File, 27: eFileTypeClassDiagram, 28: MHTML Document, 29: Property Sheet, 30: Cursor, 31: Manifest, 32: eFileTypeRDLC """ return '' def write(self): Logs.debug('msvs: creating %r', self.path) template1 = compile_template(self.project_template) proj_str = template1(self) proj_str = rm_blank_lines(proj_str) self.path.stealth_write(proj_str) return dec class msvs_2008_generator(msvs_generator): '''generates a visual studio 2008 solution''' cmd = 'msvs2008' fun = msvs_generator.fun numver = '10.00' vsver = '2008' def init(self): if not getattr(self, 'project_extension', None): self.project_extension = '_2008.vcproj' if not getattr(self, 'solution_name', None): self.solution_name = getattr(Context.g_module, Context.APPNAME, 'project') + '_2008.sln' if not getattr(self, 'vsnode_target', None): self.vsnode_target = wrap_2008(vsnode_target) if not getattr(self, 'vsnode_build_all', None): self.vsnode_build_all = wrap_2008(vsnode_build_all) if not getattr(self, 'vsnode_install_all', None): self.vsnode_install_all = wrap_2008(vsnode_install_all) if not getattr(self, 'vsnode_project_view', None): self.vsnode_project_view = wrap_2008(vsnode_project_view) msvs_generator.init(self) def options(ctx): """ If the msvs option is used, try to detect if the build is made from visual studio """ ctx.add_option('--execsolution', action='store', help='when building with visual studio, use a build state file') old = BuildContext.execute def override_build_state(ctx): def lock(rm, add): uns = ctx.options.execsolution.replace('.sln', rm) uns = ctx.root.make_node(uns) try: uns.delete() except OSError: pass uns = ctx.options.execsolution.replace('.sln', add) uns = ctx.root.make_node(uns) try: uns.write('') except EnvironmentError: pass if ctx.options.execsolution: ctx.launch_dir = Context.top_dir # force a build for the whole project (invalid cwd when called by visual studio) lock('.lastbuildstate', '.unsuccessfulbuild') old(ctx) lock('.unsuccessfulbuild', '.lastbuildstate') else: old(ctx) BuildContext.execute = override_build_state hamster-3.0.3/waflib/extras/netcache_client.py000066400000000000000000000216071452646177100214370ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011-2015 (ita) """ A client for the network cache (playground/netcache/). Launch the server with: ./netcache_server, then use it for the builds by adding the following: def build(bld): bld.load('netcache_client') The parameters should be present in the environment in the form: NETCACHE=host:port waf configure build Or in a more detailed way: NETCACHE_PUSH=host:port NETCACHE_PULL=host:port waf configure build where: host: host where the server resides, by default localhost port: by default push on 11001 and pull on 12001 Use the server provided in playground/netcache/Netcache.java """ import os, socket, time, atexit, sys from waflib import Task, Logs, Utils, Build, Runner from waflib.Configure import conf BUF = 8192 * 16 HEADER_SIZE = 128 MODES = ['PUSH', 'PULL', 'PUSH_PULL'] STALE_TIME = 30 # seconds GET = 'GET' PUT = 'PUT' LST = 'LST' BYE = 'BYE' all_sigs_in_cache = (0.0, []) def put_data(conn, data): if sys.hexversion > 0x3000000: data = data.encode('latin-1') cnt = 0 while cnt < len(data): sent = conn.send(data[cnt:]) if sent == 0: raise RuntimeError('connection ended') cnt += sent push_connections = Runner.Queue(0) pull_connections = Runner.Queue(0) def get_connection(push=False): # return a new connection... do not forget to release it! try: if push: ret = push_connections.get(block=False) else: ret = pull_connections.get(block=False) except Exception: ret = socket.socket(socket.AF_INET, socket.SOCK_STREAM) if push: ret.connect(Task.push_addr) else: ret.connect(Task.pull_addr) return ret def release_connection(conn, msg='', push=False): if conn: if push: push_connections.put(conn) else: pull_connections.put(conn) def close_connection(conn, msg=''): if conn: data = '%s,%s' % (BYE, msg) try: put_data(conn, data.ljust(HEADER_SIZE)) except: pass try: conn.close() except: pass def close_all(): for q in (push_connections, pull_connections): while q.qsize(): conn = q.get() try: close_connection(conn) except: # ignore errors when cleaning up pass atexit.register(close_all) def read_header(conn): cnt = 0 buf = [] while cnt < HEADER_SIZE: data = conn.recv(HEADER_SIZE - cnt) if not data: #import traceback #traceback.print_stack() raise ValueError('connection ended when reading a header %r' % buf) buf.append(data) cnt += len(data) if sys.hexversion > 0x3000000: ret = ''.encode('latin-1').join(buf) ret = ret.decode('latin-1') else: ret = ''.join(buf) return ret def check_cache(conn, ssig): """ List the files on the server, this is an optimization because it assumes that concurrent builds are rare """ global all_sigs_in_cache if not STALE_TIME: return if time.time() - all_sigs_in_cache[0] > STALE_TIME: params = (LST,'') put_data(conn, ','.join(params).ljust(HEADER_SIZE)) # read what is coming back ret = read_header(conn) size = int(ret.split(',')[0]) buf = [] cnt = 0 while cnt < size: data = conn.recv(min(BUF, size-cnt)) if not data: raise ValueError('connection ended %r %r' % (cnt, size)) buf.append(data) cnt += len(data) if sys.hexversion > 0x3000000: ret = ''.encode('latin-1').join(buf) ret = ret.decode('latin-1') else: ret = ''.join(buf) all_sigs_in_cache = (time.time(), ret.splitlines()) Logs.debug('netcache: server cache has %r entries', len(all_sigs_in_cache[1])) if not ssig in all_sigs_in_cache[1]: raise ValueError('no file %s in cache' % ssig) class MissingFile(Exception): pass def recv_file(conn, ssig, count, p): check_cache(conn, ssig) params = (GET, ssig, str(count)) put_data(conn, ','.join(params).ljust(HEADER_SIZE)) data = read_header(conn) size = int(data.split(',')[0]) if size == -1: raise MissingFile('no file %s - %s in cache' % (ssig, count)) # get the file, writing immediately # TODO a tmp file would be better f = open(p, 'wb') cnt = 0 while cnt < size: data = conn.recv(min(BUF, size-cnt)) if not data: raise ValueError('connection ended %r %r' % (cnt, size)) f.write(data) cnt += len(data) f.close() def sock_send(conn, ssig, cnt, p): #print "pushing %r %r %r" % (ssig, cnt, p) size = os.stat(p).st_size params = (PUT, ssig, str(cnt), str(size)) put_data(conn, ','.join(params).ljust(HEADER_SIZE)) f = open(p, 'rb') cnt = 0 while cnt < size: r = f.read(min(BUF, size-cnt)) while r: k = conn.send(r) if not k: raise ValueError('connection ended') cnt += k r = r[k:] def can_retrieve_cache(self): if not Task.pull_addr: return False if not self.outputs: return False self.cached = False cnt = 0 sig = self.signature() ssig = Utils.to_hex(self.uid() + sig) conn = None err = False try: try: conn = get_connection() for node in self.outputs: p = node.abspath() recv_file(conn, ssig, cnt, p) cnt += 1 except MissingFile as e: Logs.debug('netcache: file is not in the cache %r', e) err = True except Exception as e: Logs.debug('netcache: could not get the files %r', self.outputs) if Logs.verbose > 1: Logs.debug('netcache: exception %r', e) err = True # broken connection? remove this one close_connection(conn) conn = None else: Logs.debug('netcache: obtained %r from cache', self.outputs) finally: release_connection(conn) if err: return False self.cached = True return True @Utils.run_once def put_files_cache(self): if not Task.push_addr: return if not self.outputs: return if getattr(self, 'cached', None): return #print "called put_files_cache", id(self) bld = self.generator.bld sig = self.signature() ssig = Utils.to_hex(self.uid() + sig) conn = None cnt = 0 try: for node in self.outputs: # We could re-create the signature of the task with the signature of the outputs # in practice, this means hashing the output files # this is unnecessary try: if not conn: conn = get_connection(push=True) sock_send(conn, ssig, cnt, node.abspath()) Logs.debug('netcache: sent %r', node) except Exception as e: Logs.debug('netcache: could not push the files %r', e) # broken connection? remove this one close_connection(conn) conn = None cnt += 1 finally: release_connection(conn, push=True) bld.task_sigs[self.uid()] = self.cache_sig def hash_env_vars(self, env, vars_lst): # reimplement so that the resulting hash does not depend on local paths if not env.table: env = env.parent if not env: return Utils.SIG_NIL idx = str(id(env)) + str(vars_lst) try: cache = self.cache_env except AttributeError: cache = self.cache_env = {} else: try: return self.cache_env[idx] except KeyError: pass v = str([env[a] for a in vars_lst]) v = v.replace(self.srcnode.abspath().__repr__()[:-1], '') m = Utils.md5() m.update(v.encode()) ret = m.digest() Logs.debug('envhash: %r %r', ret, v) cache[idx] = ret return ret def uid(self): # reimplement so that the signature does not depend on local paths try: return self.uid_ except AttributeError: m = Utils.md5() src = self.generator.bld.srcnode up = m.update up(self.__class__.__name__.encode()) for x in self.inputs + self.outputs: up(x.path_from(src).encode()) self.uid_ = m.digest() return self.uid_ def make_cached(cls): if getattr(cls, 'nocache', None): return m1 = cls.run def run(self): if getattr(self, 'nocache', False): return m1(self) if self.can_retrieve_cache(): return 0 return m1(self) cls.run = run m2 = cls.post_run def post_run(self): if getattr(self, 'nocache', False): return m2(self) bld = self.generator.bld ret = m2(self) if bld.cache_global: self.put_files_cache() if hasattr(self, 'chmod'): for node in self.outputs: os.chmod(node.abspath(), self.chmod) return ret cls.post_run = post_run @conf def setup_netcache(ctx, push_addr, pull_addr): Task.Task.can_retrieve_cache = can_retrieve_cache Task.Task.put_files_cache = put_files_cache Task.Task.uid = uid Task.push_addr = push_addr Task.pull_addr = pull_addr Build.BuildContext.hash_env_vars = hash_env_vars ctx.cache_global = True for x in Task.classes.values(): make_cached(x) def build(bld): if not 'NETCACHE' in os.environ and not 'NETCACHE_PULL' in os.environ and not 'NETCACHE_PUSH' in os.environ: Logs.warn('Setting NETCACHE_PULL=127.0.0.1:11001 and NETCACHE_PUSH=127.0.0.1:12001') os.environ['NETCACHE_PULL'] = '127.0.0.1:12001' os.environ['NETCACHE_PUSH'] = '127.0.0.1:11001' if 'NETCACHE' in os.environ: if not 'NETCACHE_PUSH' in os.environ: os.environ['NETCACHE_PUSH'] = os.environ['NETCACHE'] if not 'NETCACHE_PULL' in os.environ: os.environ['NETCACHE_PULL'] = os.environ['NETCACHE'] v = os.environ['NETCACHE_PULL'] if v: h, p = v.split(':') pull_addr = (h, int(p)) else: pull_addr = None v = os.environ['NETCACHE_PUSH'] if v: h, p = v.split(':') push_addr = (h, int(p)) else: push_addr = None setup_netcache(bld, push_addr, pull_addr) hamster-3.0.3/waflib/extras/objcopy.py000066400000000000000000000035201452646177100177660ustar00rootroot00000000000000#!/usr/bin/python # Grygoriy Fuchedzhy 2010 """ Support for converting linked targets to ihex, srec or binary files using objcopy. Use the 'objcopy' feature in conjunction with the 'cc' or 'cxx' feature. The 'objcopy' feature uses the following attributes: objcopy_bfdname Target object format name (eg. ihex, srec, binary). Defaults to ihex. objcopy_target File name used for objcopy output. This defaults to the target name with objcopy_bfdname as extension. objcopy_install_path Install path for objcopy_target file. Defaults to ${PREFIX}/fw. objcopy_flags Additional flags passed to objcopy. """ from waflib.Utils import def_attrs from waflib import Task, Options from waflib.TaskGen import feature, after_method class objcopy(Task.Task): run_str = '${OBJCOPY} -O ${TARGET_BFDNAME} ${OBJCOPYFLAGS} ${SRC} ${TGT}' color = 'CYAN' @feature('objcopy') @after_method('apply_link') def map_objcopy(self): def_attrs(self, objcopy_bfdname = 'ihex', objcopy_target = None, objcopy_install_path = "${PREFIX}/firmware", objcopy_flags = '') link_output = self.link_task.outputs[0] if not self.objcopy_target: self.objcopy_target = link_output.change_ext('.' + self.objcopy_bfdname).name task = self.create_task('objcopy', src=link_output, tgt=self.path.find_or_declare(self.objcopy_target)) task.env.append_unique('TARGET_BFDNAME', self.objcopy_bfdname) try: task.env.append_unique('OBJCOPYFLAGS', getattr(self, 'objcopy_flags')) except AttributeError: pass if self.objcopy_install_path: self.add_install_files(install_to=self.objcopy_install_path, install_from=task.outputs[0]) def configure(ctx): program_name = 'objcopy' prefix = getattr(Options.options, 'cross_prefix', None) if prefix: program_name = '{}-{}'.format(prefix, program_name) ctx.find_program(program_name, var='OBJCOPY', mandatory=True) hamster-3.0.3/waflib/extras/ocaml.py000066400000000000000000000224701452646177100174210ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2010 (ita) "ocaml support" import os, re from waflib import Utils, Task from waflib.Logs import error from waflib.TaskGen import feature, before_method, after_method, extension EXT_MLL = ['.mll'] EXT_MLY = ['.mly'] EXT_MLI = ['.mli'] EXT_MLC = ['.c'] EXT_ML = ['.ml'] open_re = re.compile(r'^\s*open\s+([a-zA-Z]+)(;;){0,1}$', re.M) foo = re.compile(r"""(\(\*)|(\*\))|("(\\.|[^"\\])*"|'(\\.|[^'\\])*'|.[^()*"'\\]*)""", re.M) def filter_comments(txt): meh = [0] def repl(m): if m.group(1): meh[0] += 1 elif m.group(2): meh[0] -= 1 elif not meh[0]: return m.group() return '' return foo.sub(repl, txt) def scan(self): node = self.inputs[0] code = filter_comments(node.read()) global open_re names = [] import_iterator = open_re.finditer(code) if import_iterator: for import_match in import_iterator: names.append(import_match.group(1)) found_lst = [] raw_lst = [] for name in names: nd = None for x in self.incpaths: nd = x.find_resource(name.lower()+'.ml') if not nd: nd = x.find_resource(name+'.ml') if nd: found_lst.append(nd) break else: raw_lst.append(name) return (found_lst, raw_lst) native_lst=['native', 'all', 'c_object'] bytecode_lst=['bytecode', 'all'] @feature('ocaml') def init_ml(self): Utils.def_attrs(self, type = 'all', incpaths_lst = [], bld_incpaths_lst = [], mlltasks = [], mlytasks = [], mlitasks = [], native_tasks = [], bytecode_tasks = [], linktasks = [], bytecode_env = None, native_env = None, compiled_tasks = [], includes = '', uselib = '', are_deps_set = 0) @feature('ocaml') @after_method('init_ml') def init_envs_ml(self): self.islibrary = getattr(self, 'islibrary', False) global native_lst, bytecode_lst self.native_env = None if self.type in native_lst: self.native_env = self.env.derive() if self.islibrary: self.native_env['OCALINKFLAGS'] = '-a' self.bytecode_env = None if self.type in bytecode_lst: self.bytecode_env = self.env.derive() if self.islibrary: self.bytecode_env['OCALINKFLAGS'] = '-a' if self.type == 'c_object': self.native_env.append_unique('OCALINKFLAGS_OPT', '-output-obj') @feature('ocaml') @before_method('apply_vars_ml') @after_method('init_envs_ml') def apply_incpaths_ml(self): inc_lst = self.includes.split() lst = self.incpaths_lst for dir in inc_lst: node = self.path.find_dir(dir) if not node: error("node not found: " + str(dir)) continue if not node in lst: lst.append(node) self.bld_incpaths_lst.append(node) # now the nodes are added to self.incpaths_lst @feature('ocaml') @before_method('process_source') def apply_vars_ml(self): for i in self.incpaths_lst: if self.bytecode_env: app = self.bytecode_env.append_value app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()]) if self.native_env: app = self.native_env.append_value app('OCAMLPATH', ['-I', i.bldpath(), '-I', i.srcpath()]) varnames = ['INCLUDES', 'OCAMLFLAGS', 'OCALINKFLAGS', 'OCALINKFLAGS_OPT'] for name in self.uselib.split(): for vname in varnames: cnt = self.env[vname+'_'+name] if cnt: if self.bytecode_env: self.bytecode_env.append_value(vname, cnt) if self.native_env: self.native_env.append_value(vname, cnt) @feature('ocaml') @after_method('process_source') def apply_link_ml(self): if self.bytecode_env: ext = self.islibrary and '.cma' or '.run' linktask = self.create_task('ocalink') linktask.bytecode = 1 linktask.set_outputs(self.path.find_or_declare(self.target + ext)) linktask.env = self.bytecode_env self.linktasks.append(linktask) if self.native_env: if self.type == 'c_object': ext = '.o' elif self.islibrary: ext = '.cmxa' else: ext = '' linktask = self.create_task('ocalinkx') linktask.set_outputs(self.path.find_or_declare(self.target + ext)) linktask.env = self.native_env self.linktasks.append(linktask) # we produce a .o file to be used by gcc self.compiled_tasks.append(linktask) @extension(*EXT_MLL) def mll_hook(self, node): mll_task = self.create_task('ocamllex', node, node.change_ext('.ml')) mll_task.env = self.native_env.derive() self.mlltasks.append(mll_task) self.source.append(mll_task.outputs[0]) @extension(*EXT_MLY) def mly_hook(self, node): mly_task = self.create_task('ocamlyacc', node, [node.change_ext('.ml'), node.change_ext('.mli')]) mly_task.env = self.native_env.derive() self.mlytasks.append(mly_task) self.source.append(mly_task.outputs[0]) task = self.create_task('ocamlcmi', mly_task.outputs[1], mly_task.outputs[1].change_ext('.cmi')) task.env = self.native_env.derive() @extension(*EXT_MLI) def mli_hook(self, node): task = self.create_task('ocamlcmi', node, node.change_ext('.cmi')) task.env = self.native_env.derive() self.mlitasks.append(task) @extension(*EXT_MLC) def mlc_hook(self, node): task = self.create_task('ocamlcc', node, node.change_ext('.o')) task.env = self.native_env.derive() self.compiled_tasks.append(task) @extension(*EXT_ML) def ml_hook(self, node): if self.native_env: task = self.create_task('ocamlx', node, node.change_ext('.cmx')) task.env = self.native_env.derive() task.incpaths = self.bld_incpaths_lst self.native_tasks.append(task) if self.bytecode_env: task = self.create_task('ocaml', node, node.change_ext('.cmo')) task.env = self.bytecode_env.derive() task.bytecode = 1 task.incpaths = self.bld_incpaths_lst self.bytecode_tasks.append(task) def compile_may_start(self): if not getattr(self, 'flag_deps', ''): self.flag_deps = 1 # the evil part is that we can only compute the dependencies after the # source files can be read (this means actually producing the source files) if getattr(self, 'bytecode', ''): alltasks = self.generator.bytecode_tasks else: alltasks = self.generator.native_tasks self.signature() # ensure that files are scanned - unfortunately tree = self.generator.bld for node in self.inputs: lst = tree.node_deps[self.uid()] for depnode in lst: for t in alltasks: if t == self: continue if depnode in t.inputs: self.set_run_after(t) # TODO necessary to get the signature right - for now delattr(self, 'cache_sig') self.signature() return Task.Task.runnable_status(self) class ocamlx(Task.Task): """native caml compilation""" color = 'GREEN' run_str = '${OCAMLOPT} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}' scan = scan runnable_status = compile_may_start class ocaml(Task.Task): """bytecode caml compilation""" color = 'GREEN' run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLFLAGS} ${OCAMLINCLUDES} -c -o ${TGT} ${SRC}' scan = scan runnable_status = compile_may_start class ocamlcmi(Task.Task): """interface generator (the .i files?)""" color = 'BLUE' run_str = '${OCAMLC} ${OCAMLPATH} ${OCAMLINCLUDES} -o ${TGT} -c ${SRC}' before = ['ocamlcc', 'ocaml', 'ocamlcc'] class ocamlcc(Task.Task): """ocaml to c interfaces""" color = 'GREEN' run_str = 'cd ${TGT[0].bld_dir()} && ${OCAMLOPT} ${OCAMLFLAGS} ${OCAMLPATH} ${OCAMLINCLUDES} -c ${SRC[0].abspath()}' class ocamllex(Task.Task): """lexical generator""" color = 'BLUE' run_str = '${OCAMLLEX} ${SRC} -o ${TGT}' before = ['ocamlcmi', 'ocaml', 'ocamlcc'] class ocamlyacc(Task.Task): """parser generator""" color = 'BLUE' run_str = '${OCAMLYACC} -b ${tsk.base()} ${SRC}' before = ['ocamlcmi', 'ocaml', 'ocamlcc'] def base(self): node = self.outputs[0] s = os.path.splitext(node.name)[0] return node.bld_dir() + os.sep + s def link_may_start(self): if getattr(self, 'bytecode', 0): alltasks = self.generator.bytecode_tasks else: alltasks = self.generator.native_tasks for x in alltasks: if not x.hasrun: return Task.ASK_LATER if not getattr(self, 'order', ''): # now reorder the inputs given the task dependencies # this part is difficult, we do not have a total order on the tasks # if the dependencies are wrong, this may not stop seen = [] pendant = []+alltasks while pendant: task = pendant.pop(0) if task in seen: continue for x in task.run_after: if not x in seen: pendant.append(task) break else: seen.append(task) self.inputs = [x.outputs[0] for x in seen] self.order = 1 return Task.Task.runnable_status(self) class ocalink(Task.Task): """bytecode caml link""" color = 'YELLOW' run_str = '${OCAMLC} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS} ${SRC}' runnable_status = link_may_start after = ['ocaml', 'ocamlcc'] class ocalinkx(Task.Task): """native caml link""" color = 'YELLOW' run_str = '${OCAMLOPT} -o ${TGT} ${OCAMLINCLUDES} ${OCALINKFLAGS_OPT} ${SRC}' runnable_status = link_may_start after = ['ocamlx', 'ocamlcc'] def configure(conf): opt = conf.find_program('ocamlopt', var='OCAMLOPT', mandatory=False) occ = conf.find_program('ocamlc', var='OCAMLC', mandatory=False) if (not opt) or (not occ): conf.fatal('The objective caml compiler was not found:\ninstall it or make it available in your PATH') v = conf.env v['OCAMLC'] = occ v['OCAMLOPT'] = opt v['OCAMLLEX'] = conf.find_program('ocamllex', var='OCAMLLEX', mandatory=False) v['OCAMLYACC'] = conf.find_program('ocamlyacc', var='OCAMLYACC', mandatory=False) v['OCAMLFLAGS'] = '' where = conf.cmd_and_log(conf.env.OCAMLC + ['-where']).strip()+os.sep v['OCAMLLIB'] = where v['LIBPATH_OCAML'] = where v['INCLUDES_OCAML'] = where v['LIB_OCAML'] = 'camlrun' hamster-3.0.3/waflib/extras/package.py000066400000000000000000000030661452646177100177210ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2011 """ Obtain packages, unpack them in a location, and add associated uselib variables (CFLAGS_pkgname, LIBPATH_pkgname, etc). The default is use a Dependencies.txt file in the source directory. This is a work in progress. Usage: def options(opt): opt.load('package') def configure(conf): conf.load_packages() """ from waflib import Logs from waflib.Configure import conf try: from urllib import request except ImportError: from urllib import urlopen else: urlopen = request.urlopen CACHEVAR = 'WAFCACHE_PACKAGE' @conf def get_package_cache_dir(self): cache = None if CACHEVAR in conf.environ: cache = conf.environ[CACHEVAR] cache = self.root.make_node(cache) elif self.env[CACHEVAR]: cache = self.env[CACHEVAR] cache = self.root.make_node(cache) else: cache = self.srcnode.make_node('.wafcache_package') cache.mkdir() return cache @conf def download_archive(self, src, dst): for x in self.env.PACKAGE_REPO: url = '/'.join((x, src)) try: web = urlopen(url) try: if web.getcode() != 200: continue except AttributeError: pass except Exception: # on python3 urlopen throws an exception # python 2.3 does not have getcode and throws an exception to fail continue else: tmp = self.root.make_node(dst) tmp.write(web.read()) Logs.warn('Downloaded %s from %s', tmp.abspath(), url) break else: self.fatal('Could not get the package %s' % src) @conf def load_packages(self): self.get_package_cache_dir() # read the dependencies, get the archives, .. hamster-3.0.3/waflib/extras/parallel_debug.py000066400000000000000000000274431452646177100212750ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2007-2010 (ita) """ Debugging helper for parallel compilation. Copy it to your project and load it with:: def options(opt): opt.load('parallel_debug', tooldir='.') def build(bld): ... The build will then output a file named pdebug.svg in the source directory. """ import re, sys, threading, time, traceback try: from Queue import Queue except: from queue import Queue from waflib import Runner, Options, Task, Logs, Errors SVG_TEMPLATE = """ ${if project.title} ${project.title} ${endif} ${for cls in project.groups} ${for rect in cls.rects} ${endfor} ${endfor} ${for info in project.infos} ${info.text} ${endfor} ${if project.tooltip} ${endif} """ COMPILE_TEMPLATE = '''def f(project): lst = [] def xml_escape(value): return value.replace("&", "&").replace('"', """).replace("'", "'").replace("<", "<").replace(">", ">") %s return ''.join(lst) ''' reg_act = re.compile(r"(?P\\)|(?P\$\$)|(?P\$\{(?P[^}]*?)\})", re.M) def compile_template(line): extr = [] def repl(match): g = match.group if g('dollar'): return "$" elif g('backslash'): return "\\" elif g('subst'): extr.append(g('code')) return "<<|@|>>" return None line2 = reg_act.sub(repl, line) params = line2.split('<<|@|>>') assert(extr) indent = 0 buf = [] app = buf.append def app(txt): buf.append(indent * '\t' + txt) for x in range(len(extr)): if params[x]: app("lst.append(%r)" % params[x]) f = extr[x] if f.startswith(('if', 'for')): app(f + ':') indent += 1 elif f.startswith('py:'): app(f[3:]) elif f.startswith(('endif', 'endfor')): indent -= 1 elif f.startswith(('else', 'elif')): indent -= 1 app(f + ':') indent += 1 elif f.startswith('xml:'): app('lst.append(xml_escape(%s))' % f[4:]) else: #app('lst.append((%s) or "cannot find %s")' % (f, f)) app('lst.append(str(%s))' % f) if extr: if params[-1]: app("lst.append(%r)" % params[-1]) fun = COMPILE_TEMPLATE % "\n\t".join(buf) # uncomment the following to debug the template #for i, x in enumerate(fun.splitlines()): # print i, x return Task.funex(fun) # red #ff4d4d # green #4da74d # lila #a751ff color2code = { 'GREEN' : '#4da74d', 'YELLOW' : '#fefe44', 'PINK' : '#a751ff', 'RED' : '#cc1d1d', 'BLUE' : '#6687bb', 'CYAN' : '#34e2e2', } mp = {} info = [] # list of (text,color) def map_to_color(name): if name in mp: return mp[name] try: cls = Task.classes[name] except KeyError: return color2code['RED'] if cls.color in mp: return mp[cls.color] if cls.color in color2code: return color2code[cls.color] return color2code['RED'] def process(self): m = self.generator.bld.producer try: # TODO another place for this? del self.generator.bld.task_sigs[self.uid()] except KeyError: pass self.generator.bld.producer.set_running(1, self) try: ret = self.run() except Exception: self.err_msg = traceback.format_exc() self.hasrun = Task.EXCEPTION # TODO cleanup m.error_handler(self) return if ret: self.err_code = ret self.hasrun = Task.CRASHED else: try: self.post_run() except Errors.WafError: pass except Exception: self.err_msg = traceback.format_exc() self.hasrun = Task.EXCEPTION else: self.hasrun = Task.SUCCESS if self.hasrun != Task.SUCCESS: m.error_handler(self) self.generator.bld.producer.set_running(-1, self) Task.Task.process_back = Task.Task.process Task.Task.process = process old_start = Runner.Parallel.start def do_start(self): try: Options.options.dband except AttributeError: self.bld.fatal('use def options(opt): opt.load("parallel_debug")!') self.taskinfo = Queue() old_start(self) if self.dirty: make_picture(self) Runner.Parallel.start = do_start lock_running = threading.Lock() def set_running(self, by, tsk): with lock_running: try: cache = self.lock_cache except AttributeError: cache = self.lock_cache = {} i = 0 if by > 0: vals = cache.values() for i in range(self.numjobs): if i not in vals: cache[tsk] = i break else: i = cache[tsk] del cache[tsk] self.taskinfo.put( (i, id(tsk), time.time(), tsk.__class__.__name__, self.processed, self.count, by, ",".join(map(str, tsk.outputs))) ) Runner.Parallel.set_running = set_running def name2class(name): return name.replace(' ', '_').replace('.', '_') def make_picture(producer): # first, cast the parameters if not hasattr(producer.bld, 'path'): return tmp = [] try: while True: tup = producer.taskinfo.get(False) tmp.append(list(tup)) except: pass try: ini = float(tmp[0][2]) except: return if not info: seen = [] for x in tmp: name = x[3] if not name in seen: seen.append(name) else: continue info.append((name, map_to_color(name))) info.sort(key=lambda x: x[0]) thread_count = 0 acc = [] for x in tmp: thread_count += x[6] acc.append("%d %d %f %r %d %d %d %s" % (x[0], x[1], x[2] - ini, x[3], x[4], x[5], thread_count, x[7])) data_node = producer.bld.path.make_node('pdebug.dat') data_node.write('\n'.join(acc)) tmp = [lst[:2] + [float(lst[2]) - ini] + lst[3:] for lst in tmp] st = {} for l in tmp: if not l[0] in st: st[l[0]] = len(st.keys()) tmp = [ [st[lst[0]]] + lst[1:] for lst in tmp ] THREAD_AMOUNT = len(st.keys()) st = {} for l in tmp: if not l[1] in st: st[l[1]] = len(st.keys()) tmp = [ [lst[0]] + [st[lst[1]]] + lst[2:] for lst in tmp ] BAND = Options.options.dband seen = {} acc = [] for x in range(len(tmp)): line = tmp[x] id = line[1] if id in seen: continue seen[id] = True begin = line[2] thread_id = line[0] for y in range(x + 1, len(tmp)): line = tmp[y] if line[1] == id: end = line[2] #print id, thread_id, begin, end #acc.append( ( 10*thread_id, 10*(thread_id+1), 10*begin, 10*end ) ) acc.append( (BAND * begin, BAND*thread_id, BAND*end - BAND*begin, BAND, line[3], line[7]) ) break if Options.options.dmaxtime < 0.1: gwidth = 1 for x in tmp: m = BAND * x[2] if m > gwidth: gwidth = m else: gwidth = BAND * Options.options.dmaxtime ratio = float(Options.options.dwidth) / gwidth gwidth = Options.options.dwidth gheight = BAND * (THREAD_AMOUNT + len(info) + 1.5) # simple data model for our template class tobject(object): pass model = tobject() model.x = 0 model.y = 0 model.width = gwidth + 4 model.height = gheight + 4 model.tooltip = not Options.options.dnotooltip model.title = Options.options.dtitle model.title_x = gwidth / 2 model.title_y = gheight + - 5 groups = {} for (x, y, w, h, clsname, name) in acc: try: groups[clsname].append((x, y, w, h, name)) except: groups[clsname] = [(x, y, w, h, name)] # groups of rectangles (else js highlighting is slow) model.groups = [] for cls in groups: g = tobject() model.groups.append(g) g.classname = name2class(cls) g.rects = [] for (x, y, w, h, name) in groups[cls]: r = tobject() g.rects.append(r) r.x = 2 + x * ratio r.y = 2 + y r.width = w * ratio r.height = h r.name = name r.color = map_to_color(cls) cnt = THREAD_AMOUNT # caption model.infos = [] for (text, color) in info: inf = tobject() model.infos.append(inf) inf.classname = name2class(text) inf.x = 2 + BAND inf.y = 5 + (cnt + 0.5) * BAND inf.width = BAND/2 inf.height = BAND/2 inf.color = color inf.text = text inf.text_x = 2 + 2 * BAND inf.text_y = 5 + (cnt + 0.5) * BAND + 10 cnt += 1 # write the file... template1 = compile_template(SVG_TEMPLATE) txt = template1(model) node = producer.bld.path.make_node('pdebug.svg') node.write(txt) Logs.warn('Created the diagram %r', node) def options(opt): opt.add_option('--dtitle', action='store', default='Parallel build representation for %r' % ' '.join(sys.argv), help='title for the svg diagram', dest='dtitle') opt.add_option('--dwidth', action='store', type='int', help='diagram width', default=800, dest='dwidth') opt.add_option('--dtime', action='store', type='float', help='recording interval in seconds', default=0.009, dest='dtime') opt.add_option('--dband', action='store', type='int', help='band width', default=22, dest='dband') opt.add_option('--dmaxtime', action='store', type='float', help='maximum time, for drawing fair comparisons', default=0, dest='dmaxtime') opt.add_option('--dnotooltip', action='store_true', help='disable tooltips', default=False, dest='dnotooltip') hamster-3.0.3/waflib/extras/pch.py000066400000000000000000000104401452646177100170720ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Alexander Afanasyev (UCLA), 2014 """ Enable precompiled C++ header support (currently only clang++ and g++ are supported) To use this tool, wscript should look like: def options(opt): opt.load('pch') # This will add `--with-pch` configure option. # Unless --with-pch during configure stage specified, the precompiled header support is disabled def configure(conf): conf.load('pch') # this will set conf.env.WITH_PCH if --with-pch is specified and the supported compiler is used # Unless conf.env.WITH_PCH is set, the precompiled header support is disabled def build(bld): bld(features='cxx pch', target='precompiled-headers', name='precompiled-headers', headers='a.h b.h c.h', # headers to pre-compile into `precompiled-headers` # Other parameters to compile precompiled headers # includes=..., # export_includes=..., # use=..., # ... # Exported parameters will be propagated even if precompiled headers are disabled ) bld( target='test', features='cxx cxxprogram', source='a.cpp b.cpp d.cpp main.cpp', use='precompiled-headers', ) # or bld( target='test', features='pch cxx cxxprogram', source='a.cpp b.cpp d.cpp main.cpp', headers='a.h b.h c.h', ) Note that precompiled header must have multiple inclusion guards. If the guards are missing, any benefit of precompiled header will be voided and compilation may fail in some cases. """ import os from waflib import Task, TaskGen, Utils from waflib.Tools import c_preproc, cxx PCH_COMPILER_OPTIONS = { 'clang++': [['-include'], '.pch', ['-x', 'c++-header']], 'g++': [['-include'], '.gch', ['-x', 'c++-header']], } def options(opt): opt.add_option('--without-pch', action='store_false', default=True, dest='with_pch', help='''Try to use precompiled header to speed up compilation (only g++ and clang++)''') def configure(conf): if (conf.options.with_pch and conf.env['COMPILER_CXX'] in PCH_COMPILER_OPTIONS.keys()): conf.env.WITH_PCH = True flags = PCH_COMPILER_OPTIONS[conf.env['COMPILER_CXX']] conf.env.CXXPCH_F = flags[0] conf.env.CXXPCH_EXT = flags[1] conf.env.CXXPCH_FLAGS = flags[2] @TaskGen.feature('pch') @TaskGen.before('process_source') def apply_pch(self): if not self.env.WITH_PCH: return if getattr(self.bld, 'pch_tasks', None) is None: self.bld.pch_tasks = {} if getattr(self, 'headers', None) is None: return self.headers = self.to_nodes(self.headers) if getattr(self, 'name', None): try: task = self.bld.pch_tasks[self.name] self.bld.fatal("Duplicated 'pch' task with name %r" % "%s.%s" % (self.name, self.idx)) except KeyError: pass out = '%s.%d%s' % (self.target, self.idx, self.env['CXXPCH_EXT']) out = self.path.find_or_declare(out) task = self.create_task('gchx', self.headers, out) # target should be an absolute path of `out`, but without precompiled header extension task.target = out.abspath()[:-len(out.suffix())] self.pch_task = task if getattr(self, 'name', None): self.bld.pch_tasks[self.name] = task @TaskGen.feature('cxx') @TaskGen.after_method('process_source', 'propagate_uselib_vars') def add_pch(self): if not (self.env['WITH_PCH'] and getattr(self, 'use', None) and getattr(self, 'compiled_tasks', None) and getattr(self.bld, 'pch_tasks', None)): return pch = None # find pch task, if any if getattr(self, 'pch_task', None): pch = self.pch_task else: for use in Utils.to_list(self.use): try: pch = self.bld.pch_tasks[use] except KeyError: pass if pch: for x in self.compiled_tasks: x.env.append_value('CXXFLAGS', self.env['CXXPCH_F'] + [pch.target]) class gchx(Task.Task): run_str = '${CXX} ${ARCH_ST:ARCH} ${CXXFLAGS} ${CXXPCH_FLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${CXXPCH_F:SRC} ${CXX_SRC_F}${SRC[0].abspath()} ${CXX_TGT_F}${TGT[0].abspath()} ${CPPFLAGS}' scan = c_preproc.scan color = 'BLUE' ext_out=['.h'] def runnable_status(self): try: node_deps = self.generator.bld.node_deps[self.uid()] except KeyError: node_deps = [] ret = Task.Task.runnable_status(self) if ret == Task.SKIP_ME and self.env.CXX_NAME == 'clang': t = os.stat(self.outputs[0].abspath()).st_mtime for n in self.inputs + node_deps: if os.stat(n.abspath()).st_mtime > t: return Task.RUN_ME return ret hamster-3.0.3/waflib/extras/pep8.py000066400000000000000000000066241452646177100172050ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # # written by Sylvain Rouquette, 2011 ''' Install pep8 module: $ easy_install pep8 or $ pip install pep8 To add the pep8 tool to the waf file: $ ./waf-light --tools=compat15,pep8 or, if you have waf >= 1.6.2 $ ./waf update --files=pep8 Then add this to your wscript: [at]extension('.py', 'wscript') def run_pep8(self, node): self.create_task('Pep8', node) ''' import threading from waflib import Task, Options pep8 = __import__('pep8') class Pep8(Task.Task): color = 'PINK' lock = threading.Lock() def check_options(self): if pep8.options: return pep8.options = Options.options pep8.options.prog = 'pep8' excl = pep8.options.exclude.split(',') pep8.options.exclude = [s.rstrip('/') for s in excl] if pep8.options.filename: pep8.options.filename = pep8.options.filename.split(',') if pep8.options.select: pep8.options.select = pep8.options.select.split(',') else: pep8.options.select = [] if pep8.options.ignore: pep8.options.ignore = pep8.options.ignore.split(',') elif pep8.options.select: # Ignore all checks which are not explicitly selected pep8.options.ignore = [''] elif pep8.options.testsuite or pep8.options.doctest: # For doctest and testsuite, all checks are required pep8.options.ignore = [] else: # The default choice: ignore controversial checks pep8.options.ignore = pep8.DEFAULT_IGNORE.split(',') pep8.options.physical_checks = pep8.find_checks('physical_line') pep8.options.logical_checks = pep8.find_checks('logical_line') pep8.options.counters = dict.fromkeys(pep8.BENCHMARK_KEYS, 0) pep8.options.messages = {} def run(self): with Pep8.lock: self.check_options() pep8.input_file(self.inputs[0].abspath()) return 0 if not pep8.get_count() else -1 def options(opt): opt.add_option('-q', '--quiet', default=0, action='count', help="report only file names, or nothing with -qq") opt.add_option('-r', '--repeat', action='store_true', help="show all occurrences of the same error") opt.add_option('--exclude', metavar='patterns', default=pep8.DEFAULT_EXCLUDE, help="exclude files or directories which match these " "comma separated patterns (default: %s)" % pep8.DEFAULT_EXCLUDE, dest='exclude') opt.add_option('--filename', metavar='patterns', default='*.py', help="when parsing directories, only check filenames " "matching these comma separated patterns (default: " "*.py)") opt.add_option('--select', metavar='errors', default='', help="select errors and warnings (e.g. E,W6)") opt.add_option('--ignore', metavar='errors', default='', help="skip errors and warnings (e.g. E4,W)") opt.add_option('--show-source', action='store_true', help="show source code for each error") opt.add_option('--show-pep8', action='store_true', help="show text of PEP 8 for each error") opt.add_option('--statistics', action='store_true', help="count errors and warnings") opt.add_option('--count', action='store_true', help="print total number of errors and warnings " "to standard error and set exit code to 1 if " "total is not null") opt.add_option('--benchmark', action='store_true', help="measure processing speed") opt.add_option('--testsuite', metavar='dir', help="run regression tests from dir") opt.add_option('--doctest', action='store_true', help="run doctest on myself") hamster-3.0.3/waflib/extras/pgicc.py000066400000000000000000000033131452646177100174060ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Antoine Dechaume 2011 """ Detect the PGI C compiler """ import sys, re from waflib import Errors from waflib.Configure import conf from waflib.Tools.compiler_c import c_compiler c_compiler['linux'].append('pgicc') @conf def find_pgi_compiler(conf, var, name): """ Find the program name, and execute it to ensure it really is itself. """ if sys.platform == 'cygwin': conf.fatal('The PGI compiler does not work on Cygwin') v = conf.env cc = None if v[var]: cc = v[var] elif var in conf.environ: cc = conf.environ[var] if not cc: cc = conf.find_program(name, var=var) if not cc: conf.fatal('PGI Compiler (%s) was not found' % name) v[var + '_VERSION'] = conf.get_pgi_version(cc) v[var] = cc v[var + '_NAME'] = 'pgi' @conf def get_pgi_version(conf, cc): """Find the version of a pgi compiler.""" version_re = re.compile(r"The Portland Group", re.I).search cmd = cc + ['-V', '-E'] # Issue 1078, prevent wrappers from linking try: out, err = conf.cmd_and_log(cmd, output=0) except Errors.WafError: conf.fatal('Could not find pgi compiler %r' % cmd) if out: match = version_re(out) else: match = version_re(err) if not match: conf.fatal('Could not verify PGI signature') cmd = cc + ['-help=variable'] try: out, err = conf.cmd_and_log(cmd, output=0) except Errors.WafError: conf.fatal('Could not find pgi compiler %r' % cmd) version = re.findall(r'^COMPVER\s*=(.*)', out, re.M) if len(version) != 1: conf.fatal('Could not determine the compiler version') return version[0] def configure(conf): conf.find_pgi_compiler('CC', 'pgcc') conf.find_ar() conf.gcc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/pgicxx.py000066400000000000000000000006131452646177100176230ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Antoine Dechaume 2011 """ Detect the PGI C++ compiler """ from waflib.Tools.compiler_cxx import cxx_compiler cxx_compiler['linux'].append('pgicxx') from waflib.extras import pgicc def configure(conf): conf.find_pgi_compiler('CXX', 'pgCC') conf.find_ar() conf.gxx_common_flags() conf.cxx_load_tools() conf.cxx_add_flags() conf.link_add_flags() hamster-3.0.3/waflib/extras/proc.py000066400000000000000000000032751452646177100172730ustar00rootroot00000000000000#! /usr/bin/env python # per rosengren 2011 from os import environ, path from waflib import TaskGen, Utils def options(opt): grp = opt.add_option_group('Oracle ProC Options') grp.add_option('--oracle_home', action='store', default=environ.get('PROC_ORACLE'), help='Path to Oracle installation home (has bin/lib)') grp.add_option('--tns_admin', action='store', default=environ.get('TNS_ADMIN'), help='Directory containing server list (TNS_NAMES.ORA)') grp.add_option('--connection', action='store', default='dummy-user/dummy-password@dummy-server', help='Format: user/password@server') def configure(cnf): env = cnf.env if not env.PROC_ORACLE: env.PROC_ORACLE = cnf.options.oracle_home if not env.PROC_TNS_ADMIN: env.PROC_TNS_ADMIN = cnf.options.tns_admin if not env.PROC_CONNECTION: env.PROC_CONNECTION = cnf.options.connection cnf.find_program('proc', var='PROC', path_list=env.PROC_ORACLE + path.sep + 'bin') def proc(tsk): env = tsk.env gen = tsk.generator inc_nodes = gen.to_incnodes(Utils.to_list(getattr(gen,'includes',[])) + env['INCLUDES']) cmd = ( [env.PROC] + ['SQLCHECK=SEMANTICS'] + (['SYS_INCLUDE=(' + ','.join(env.PROC_INCLUDES) + ')'] if env.PROC_INCLUDES else []) + ['INCLUDE=(' + ','.join( [i.bldpath() for i in inc_nodes] ) + ')'] + ['userid=' + env.PROC_CONNECTION] + ['INAME=' + tsk.inputs[0].bldpath()] + ['ONAME=' + tsk.outputs[0].bldpath()] ) exec_env = { 'ORACLE_HOME': env.PROC_ORACLE, 'LD_LIBRARY_PATH': env.PROC_ORACLE + path.sep + 'lib', } if env.PROC_TNS_ADMIN: exec_env['TNS_ADMIN'] = env.PROC_TNS_ADMIN return tsk.exec_command(cmd, env=exec_env) TaskGen.declare_chain( name = 'proc', rule = proc, ext_in = '.pc', ext_out = '.c', ) hamster-3.0.3/waflib/extras/protoc.py000066400000000000000000000153311452646177100176320ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Philipp Bender, 2012 # Matt Clarkson, 2012 import re, os from waflib.Task import Task from waflib.TaskGen import extension from waflib import Errors, Context, Logs """ A simple tool to integrate protocol buffers into your build system. Example for C++: def configure(conf): conf.load('compiler_cxx cxx protoc') def build(bld): bld( features = 'cxx cxxprogram' source = 'main.cpp file1.proto proto/file2.proto', includes = '. proto', target = 'executable') Example for Python: def configure(conf): conf.load('python protoc') def build(bld): bld( features = 'py' source = 'main.py file1.proto proto/file2.proto', protoc_includes = 'proto') Example for both Python and C++ at same time: def configure(conf): conf.load('cxx python protoc') def build(bld): bld( features = 'cxx py' source = 'file1.proto proto/file2.proto', protoc_includes = 'proto') # or includes Example for Java: def options(opt): opt.load('java') def configure(conf): conf.load('python java protoc') # Here you have to point to your protobuf-java JAR and have it in classpath conf.env.CLASSPATH_PROTOBUF = ['protobuf-java-2.5.0.jar'] def build(bld): bld( features = 'javac protoc', name = 'pbjava', srcdir = 'inc/ src', # directories used by javac source = ['inc/message_inc.proto', 'inc/message.proto'], # source is used by protoc for .proto files use = 'PROTOBUF', protoc_includes = ['inc']) # for protoc to search dependencies Protoc includes passed via protoc_includes are either relative to the taskgen or to the project and are searched in this order. Include directories external to the waf project can also be passed to the extra by using protoc_extincludes protoc_extincludes = ['/usr/include/pblib'] Notes when using this tool: - protoc command line parsing is tricky. The generated files can be put in subfolders which depend on the order of the include paths. Try to be simple when creating task generators containing protoc stuff. """ class protoc(Task): run_str = '${PROTOC} ${PROTOC_FL:PROTOC_FLAGS} ${PROTOC_ST:INCPATHS} ${PROTOC_ST:PROTOC_INCPATHS} ${PROTOC_ST:PROTOC_EXTINCPATHS} ${SRC[0].bldpath()}' color = 'BLUE' ext_out = ['.h', 'pb.cc', '.py', '.java'] def scan(self): """ Scan .proto dependencies """ node = self.inputs[0] nodes = [] names = [] seen = [] search_nodes = [] if not node: return (nodes, names) if 'cxx' in self.generator.features: search_nodes = self.generator.includes_nodes if 'py' in self.generator.features or 'javac' in self.generator.features: for incpath in getattr(self.generator, 'protoc_includes', []): incpath_node = self.generator.path.find_node(incpath) if incpath_node: search_nodes.append(incpath_node) else: # Check if relative to top-level for extra tg dependencies incpath_node = self.generator.bld.path.find_node(incpath) if incpath_node: search_nodes.append(incpath_node) else: raise Errors.WafError('protoc: include path %r does not exist' % incpath) def parse_node(node): if node in seen: return seen.append(node) code = node.read().splitlines() for line in code: m = re.search(r'^import\s+"(.*)";.*(//)?.*', line) if m: dep = m.groups()[0] for incnode in search_nodes: found = incnode.find_resource(dep) if found: nodes.append(found) parse_node(found) else: names.append(dep) parse_node(node) # Add also dependencies path to INCPATHS so protoc will find the included file for deppath in nodes: self.env.append_unique('INCPATHS', deppath.parent.bldpath()) return (nodes, names) @extension('.proto') def process_protoc(self, node): incdirs = [] out_nodes = [] protoc_flags = [] # ensure PROTOC_FLAGS is a list; a copy is used below anyway self.env.PROTOC_FLAGS = self.to_list(self.env.PROTOC_FLAGS) if 'cxx' in self.features: cpp_node = node.change_ext('.pb.cc') hpp_node = node.change_ext('.pb.h') self.source.append(cpp_node) out_nodes.append(cpp_node) out_nodes.append(hpp_node) protoc_flags.append('--cpp_out=%s' % node.parent.get_bld().bldpath()) if 'py' in self.features: py_node = node.change_ext('_pb2.py') self.source.append(py_node) out_nodes.append(py_node) protoc_flags.append('--python_out=%s' % node.parent.get_bld().bldpath()) if 'javac' in self.features: # Make javac get also pick java code generated in build if not node.parent.get_bld() in self.javac_task.srcdir: self.javac_task.srcdir.append(node.parent.get_bld()) protoc_flags.append('--java_out=%s' % node.parent.get_bld().bldpath()) node.parent.get_bld().mkdir() tsk = self.create_task('protoc', node, out_nodes) tsk.env.append_value('PROTOC_FLAGS', protoc_flags) if 'javac' in self.features: self.javac_task.set_run_after(tsk) # Instruct protoc where to search for .proto included files. # For C++ standard include files dirs are used, # but this doesn't apply to Python for example for incpath in getattr(self, 'protoc_includes', []): incpath_node = self.path.find_node(incpath) if incpath_node: incdirs.append(incpath_node.bldpath()) else: # Check if relative to top-level for extra tg dependencies incpath_node = self.bld.path.find_node(incpath) if incpath_node: incdirs.append(incpath_node.bldpath()) else: raise Errors.WafError('protoc: include path %r does not exist' % incpath) tsk.env.PROTOC_INCPATHS = incdirs # Include paths external to the waf project (ie. shared pb repositories) tsk.env.PROTOC_EXTINCPATHS = getattr(self, 'protoc_extincludes', []) # PR2115: protoc generates output of .proto files in nested # directories by canonicalizing paths. To avoid this we have to pass # as first include the full directory file of the .proto file tsk.env.prepend_value('INCPATHS', node.parent.bldpath()) use = getattr(self, 'use', '') if not 'PROTOBUF' in use: self.use = self.to_list(use) + ['PROTOBUF'] def configure(conf): conf.check_cfg(package='protobuf', uselib_store='PROTOBUF', args=['--cflags', '--libs']) conf.find_program('protoc', var='PROTOC') conf.start_msg('Checking for protoc version') protocver = conf.cmd_and_log(conf.env.PROTOC + ['--version'], output=Context.BOTH) protocver = ''.join(protocver).strip()[protocver[0].rfind(' ')+1:] conf.end_msg(protocver) conf.env.PROTOC_MAJOR = protocver[:protocver.find('.')] conf.env.PROTOC_ST = '-I%s' conf.env.PROTOC_FL = '%s' hamster-3.0.3/waflib/extras/pyqt5.py000066400000000000000000000162571452646177100174160ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Federico Pellegrin, 2016-2022 (fedepell) adapted for Python """ This tool helps with finding Python Qt5 tools and libraries, and provides translation from QT5 files to Python code. The following snippet illustrates the tool usage:: def options(opt): opt.load('py pyqt5') def configure(conf): conf.load('py pyqt5') def build(bld): bld( features = 'py pyqt5', source = 'main.py textures.qrc aboutDialog.ui', ) Here, the UI description and resource files will be processed to generate code. Usage ===== Load the "pyqt5" tool. Add into the sources list also the qrc resources files or ui5 definition files and they will be translated into python code with the system tools (PyQt5, PySide2, PyQt4 are searched in this order) and then compiled """ try: from xml.sax import make_parser from xml.sax.handler import ContentHandler except ImportError: has_xml = False ContentHandler = object else: has_xml = True import os from waflib.Tools import python from waflib import Task, Options from waflib.TaskGen import feature, extension from waflib.Configure import conf from waflib import Logs EXT_RCC = ['.qrc'] """ File extension for the resource (.qrc) files """ EXT_UI = ['.ui'] """ File extension for the user interface (.ui) files """ class XMLHandler(ContentHandler): """ Parses ``.qrc`` files """ def __init__(self): self.buf = [] self.files = [] def startElement(self, name, attrs): if name == 'file': self.buf = [] def endElement(self, name): if name == 'file': self.files.append(str(''.join(self.buf))) def characters(self, cars): self.buf.append(cars) @extension(*EXT_RCC) def create_pyrcc_task(self, node): "Creates rcc and py task for ``.qrc`` files" rcnode = node.change_ext('.py') self.create_task('pyrcc', node, rcnode) if getattr(self, 'install_from', None): self.install_from = self.install_from.get_bld() else: self.install_from = self.path.get_bld() self.install_path = getattr(self, 'install_path', '${PYTHONDIR}') self.process_py(rcnode) @extension(*EXT_UI) def create_pyuic_task(self, node): "Create uic tasks and py for user interface ``.ui`` definition files" uinode = node.change_ext('.py') self.create_task('ui5py', node, uinode) if getattr(self, 'install_from', None): self.install_from = self.install_from.get_bld() else: self.install_from = self.path.get_bld() self.install_path = getattr(self, 'install_path', '${PYTHONDIR}') self.process_py(uinode) @extension('.ts') def add_pylang(self, node): """Adds all the .ts file into ``self.lang``""" self.lang = self.to_list(getattr(self, 'lang', [])) + [node] @feature('pyqt5') def apply_pyqt5(self): """ The additional parameters are: :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): qmtasks = [] for x in self.to_list(self.lang): if isinstance(x, str): x = self.path.find_resource(x + '.ts') qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm'))) if getattr(self, 'langname', None): qmnodes = [k.outputs[0] for k in qmtasks] rcnode = self.langname if isinstance(rcnode, str): rcnode = self.path.find_or_declare(rcnode + '.qrc') t = self.create_task('qm2rcc', qmnodes, rcnode) create_pyrcc_task(self, t.outputs[0]) class pyrcc(Task.Task): """ Processes ``.qrc`` files """ color = 'BLUE' run_str = '${QT_PYRCC} ${QT_PYRCC_FLAGS} ${SRC} -o ${TGT}' ext_out = ['.py'] def rcname(self): return os.path.splitext(self.inputs[0].name)[0] def scan(self): """Parse the *.qrc* files""" if not has_xml: Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!') return ([], []) parser = make_parser() curHandler = XMLHandler() parser.setContentHandler(curHandler) fi = open(self.inputs[0].abspath(), 'r') try: parser.parse(fi) finally: fi.close() nodes = [] names = [] root = self.inputs[0].parent for x in curHandler.files: nd = root.find_resource(x) if nd: nodes.append(nd) else: names.append(x) return (nodes, names) class ui5py(Task.Task): """ Processes ``.ui`` files for python """ color = 'BLUE' run_str = '${QT_PYUIC} ${QT_PYUIC_FLAGS} ${SRC} -o ${TGT}' ext_out = ['.py'] class ts2qm(Task.Task): """ Generates ``.qm`` files from ``.ts`` files """ color = 'BLUE' run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}' class qm2rcc(Task.Task): """ Generates ``.qrc`` files from ``.qm`` files """ color = 'BLUE' after = 'ts2qm' def run(self): """Create a qrc file including the inputs""" txt = '\n'.join(['%s' % k.path_from(self.outputs[0].parent) for k in self.inputs]) code = '\n\n%s\n\n' % txt self.outputs[0].write(code) def configure(self): self.find_pyqt5_binaries() # warn about this during the configuration too if not has_xml: Logs.error('No xml.sax support was found, rcc dependencies will be incomplete!') @conf def find_pyqt5_binaries(self): """ Detects PyQt5 or PySide2 programs such as pyuic5/pyside2-uic, pyrcc5/pyside2-rcc """ env = self.env if getattr(Options.options, 'want_pyqt5', True): self.find_program(['pyuic5'], var='QT_PYUIC') self.find_program(['pyrcc5'], var='QT_PYRCC') self.find_program(['pylupdate5'], var='QT_PYLUPDATE') elif getattr(Options.options, 'want_pyside2', True): self.find_program(['pyside2-uic','uic-qt5'], var='QT_PYUIC') self.find_program(['pyside2-rcc','rcc-qt5'], var='QT_PYRCC') self.find_program(['pyside2-lupdate','lupdate-qt5'], var='QT_PYLUPDATE') elif getattr(Options.options, 'want_pyqt4', True): self.find_program(['pyuic4'], var='QT_PYUIC') self.find_program(['pyrcc4'], var='QT_PYRCC') self.find_program(['pylupdate4'], var='QT_PYLUPDATE') else: self.find_program(['pyuic5','pyside2-uic','pyuic4','uic-qt5'], var='QT_PYUIC') self.find_program(['pyrcc5','pyside2-rcc','pyrcc4','rcc-qt5'], var='QT_PYRCC') self.find_program(['pylupdate5', 'pyside2-lupdate','pylupdate4','lupdate-qt5'], var='QT_PYLUPDATE') if not env.QT_PYUIC: self.fatal('cannot find the uic compiler for python for qt5') if not env.QT_PYRCC: self.fatal('cannot find the rcc compiler for python for qt5') self.find_program(['lrelease-qt5', 'lrelease'], var='QT_LRELEASE') def options(opt): """ Command-line options """ pyqt5opt=opt.add_option_group("Python QT5 Options") pyqt5opt.add_option('--pyqt5-pyqt5', action='store_true', default=False, dest='want_pyqt5', help='use PyQt5 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)') pyqt5opt.add_option('--pyqt5-pyside2', action='store_true', default=False, dest='want_pyside2', help='use PySide2 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)') pyqt5opt.add_option('--pyqt5-pyqt4', action='store_true', default=False, dest='want_pyqt4', help='use PyQt4 bindings as python QT5 bindings (default PyQt5 is searched first, PySide2 after, PyQt4 last)') hamster-3.0.3/waflib/extras/pytest.py000066400000000000000000000212421452646177100176520ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Calle Rosenquist, 2016-2018 (xbreak) """ Provides Python unit test support using :py:class:`waflib.Tools.waf_unit_test.utest` task via the **pytest** feature. To use pytest the following is needed: 1. Load `pytest` and the dependency `waf_unit_test` tools. 2. Create a task generator with feature `pytest` (not `test`) and customize behaviour with the following attributes: - `pytest_source`: Test input files. - `ut_str`: Test runner command, e.g. ``${PYTHON} -B -m unittest discover`` or if nose is used: ``${NOSETESTS} --no-byte-compile ${SRC}``. - `ut_shell`: Determines if ``ut_str`` is executed in a shell. Default: False. - `ut_cwd`: Working directory for test runner. Defaults to directory of first ``pytest_source`` file. Additionally the following `pytest` specific attributes are used in dependent taskgens: - `pytest_path`: Node or string list of additional Python paths. - `pytest_libpath`: Node or string list of additional library paths. The `use` dependencies are used for both update calculation and to populate the following environment variables for the `pytest` test runner: 1. `PYTHONPATH` (`sys.path`) of any dependent taskgen that has the feature `py`: - `install_from` attribute is used to determine where the root of the Python sources are located. If `install_from` is not specified the default is to use the taskgen path as the root. - `pytest_path` attribute is used to manually specify additional Python paths. 2. Dynamic linker search path variable (e.g. `LD_LIBRARY_PATH`) of any dependent taskgen with non-static link_task. - `pytest_libpath` attribute is used to manually specify additional linker paths. 3. Java class search path (CLASSPATH) of any Java/Javalike dependency Note: `pytest` cannot automatically determine the correct `PYTHONPATH` for `pyext` taskgens because the extension might be part of a Python package or used standalone: - When used as part of another `py` package, the `PYTHONPATH` is provided by that taskgen so no additional action is required. - When used as a standalone module, the user needs to specify the `PYTHONPATH` explicitly via the `pytest_path` attribute on the `pyext` taskgen. For details c.f. the pytest playground examples. For example:: # A standalone Python C extension that demonstrates unit test environment population # of PYTHONPATH and LD_LIBRARY_PATH/PATH/DYLD_LIBRARY_PATH. # # Note: `pytest_path` is provided here because pytest cannot automatically determine # if the extension is part of another Python package or is used standalone. bld(name = 'foo_ext', features = 'c cshlib pyext', source = 'src/foo_ext.c', target = 'foo_ext', pytest_path = [ bld.path.get_bld() ]) # Python package under test that also depend on the Python module `foo_ext` # # Note: `install_from` is added automatically to `PYTHONPATH`. bld(name = 'foo', features = 'py', use = 'foo_ext', source = bld.path.ant_glob('src/foo/*.py'), install_from = 'src') # Unit test example using the built in module unittest and let that discover # any test cases. bld(name = 'foo_test', features = 'pytest', use = 'foo', pytest_source = bld.path.ant_glob('test/*.py'), ut_str = '${PYTHON} -B -m unittest discover') """ import os from waflib import Task, TaskGen, Errors, Utils, Logs from waflib.Tools import ccroot def _process_use_rec(self, name): """ Recursively process ``use`` for task generator with name ``name``.. Used by pytest_process_use. """ if name in self.pytest_use_not or name in self.pytest_use_seen: return try: tg = self.bld.get_tgen_by_name(name) except Errors.WafError: self.pytest_use_not.add(name) return self.pytest_use_seen.append(name) tg.post() for n in self.to_list(getattr(tg, 'use', [])): _process_use_rec(self, n) @TaskGen.feature('pytest') @TaskGen.after_method('process_source', 'apply_link') def pytest_process_use(self): """ Process the ``use`` attribute which contains a list of task generator names and store paths that later is used to populate the unit test runtime environment. """ self.pytest_use_not = set() self.pytest_use_seen = [] self.pytest_paths = [] # strings or Nodes self.pytest_libpaths = [] # strings or Nodes self.pytest_javapaths = [] # strings or Nodes self.pytest_dep_nodes = [] names = self.to_list(getattr(self, 'use', [])) for name in names: _process_use_rec(self, name) def extend_unique(lst, varlst): ext = [] for x in varlst: if x not in lst: ext.append(x) lst.extend(ext) # Collect type specific info needed to construct a valid runtime environment # for the test. for name in self.pytest_use_seen: tg = self.bld.get_tgen_by_name(name) extend_unique(self.pytest_paths, Utils.to_list(getattr(tg, 'pytest_path', []))) extend_unique(self.pytest_libpaths, Utils.to_list(getattr(tg, 'pytest_libpath', []))) if 'py' in tg.features: # Python dependencies are added to PYTHONPATH pypath = getattr(tg, 'install_from', tg.path) if 'buildcopy' in tg.features: # Since buildcopy is used we assume that PYTHONPATH in build should be used, # not source extend_unique(self.pytest_paths, [pypath.get_bld().abspath()]) # Add buildcopy output nodes to dependencies extend_unique(self.pytest_dep_nodes, [o for task in getattr(tg, 'tasks', []) \ for o in getattr(task, 'outputs', [])]) else: # If buildcopy is not used, depend on sources instead extend_unique(self.pytest_dep_nodes, tg.source) extend_unique(self.pytest_paths, [pypath.abspath()]) if 'javac' in tg.features: # If a JAR is generated point to that, otherwise to directory if getattr(tg, 'jar_task', None): extend_unique(self.pytest_javapaths, [tg.jar_task.outputs[0].abspath()]) else: extend_unique(self.pytest_javapaths, [tg.path.get_bld()]) # And add respective dependencies if present if tg.use_lst: extend_unique(self.pytest_javapaths, tg.use_lst) if getattr(tg, 'link_task', None): # For tasks with a link_task (C, C++, D et.c.) include their library paths: if not isinstance(tg.link_task, ccroot.stlink_task): extend_unique(self.pytest_dep_nodes, tg.link_task.outputs) extend_unique(self.pytest_libpaths, tg.link_task.env.LIBPATH) if 'pyext' in tg.features: # If the taskgen is extending Python we also want to add the interpreter libpath. extend_unique(self.pytest_libpaths, tg.link_task.env.LIBPATH_PYEXT) else: # Only add to libpath if the link task is not a Python extension extend_unique(self.pytest_libpaths, [tg.link_task.outputs[0].parent.abspath()]) @TaskGen.feature('pytest') @TaskGen.after_method('pytest_process_use') def make_pytest(self): """ Creates a ``utest`` task with a populated environment for Python if not specified in ``ut_env``: - Paths in `pytest_paths` attribute are used to populate PYTHONPATH - Paths in `pytest_libpaths` attribute are used to populate the system library path (e.g. LD_LIBRARY_PATH) """ nodes = self.to_nodes(self.pytest_source) tsk = self.create_task('utest', nodes) tsk.dep_nodes.extend(self.pytest_dep_nodes) if getattr(self, 'ut_str', None): self.ut_run, lst = Task.compile_fun(self.ut_str, shell=getattr(self, 'ut_shell', False)) tsk.vars = lst + tsk.vars if getattr(self, 'ut_cwd', None): if isinstance(self.ut_cwd, str): # we want a Node instance if os.path.isabs(self.ut_cwd): self.ut_cwd = self.bld.root.make_node(self.ut_cwd) else: self.ut_cwd = self.path.make_node(self.ut_cwd) else: if tsk.inputs: self.ut_cwd = tsk.inputs[0].parent else: raise Errors.WafError("no valid input files for pytest task, check pytest_source value") if not self.ut_cwd.exists(): self.ut_cwd.mkdir() if not hasattr(self, 'ut_env'): self.ut_env = dict(os.environ) def add_paths(var, lst): # Add list of paths to a variable, lst can contain strings or nodes lst = [ str(n) for n in lst ] Logs.debug("ut: %s: Adding paths %s=%s", self, var, lst) self.ut_env[var] = os.pathsep.join(lst) + os.pathsep + self.ut_env.get(var, '') # Prepend dependency paths to PYTHONPATH, CLASSPATH and LD_LIBRARY_PATH add_paths('PYTHONPATH', self.pytest_paths) add_paths('CLASSPATH', self.pytest_javapaths) if Utils.is_win32: add_paths('PATH', self.pytest_libpaths) elif Utils.unversioned_sys_platform() == 'darwin': add_paths('DYLD_LIBRARY_PATH', self.pytest_libpaths) add_paths('LD_LIBRARY_PATH', self.pytest_libpaths) else: add_paths('LD_LIBRARY_PATH', self.pytest_libpaths) hamster-3.0.3/waflib/extras/qnxnto.py000066400000000000000000000035611452646177100176550ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Jérôme Carretero 2011 (zougloub) # QNX neutrino compatibility functions import sys, os from waflib import Utils class Popen(object): """ Popen cannot work on QNX from a threaded program: Forking in threads is not implemented in neutrino. Python's os.popen / spawn / fork won't work when running in threads (they will if in the main program thread) In waf, this happens mostly in build. And the use cases can be replaced by os.system() calls. """ __slots__ = ["prog", "kw", "popen", "verbose"] verbose = 0 def __init__(self, prog, **kw): try: self.prog = prog self.kw = kw self.popen = None if Popen.verbose: sys.stdout.write("Popen created: %r, kw=%r..." % (prog, kw)) do_delegate = kw.get('stdout') == -1 and kw.get('stderr') == -1 if do_delegate: if Popen.verbose: print("Delegating to real Popen") self.popen = self.real_Popen(prog, **kw) else: if Popen.verbose: print("Emulating") except Exception as e: if Popen.verbose: print("Exception: %s" % e) raise def __getattr__(self, name): if Popen.verbose: sys.stdout.write("Getattr: %s..." % name) if name in Popen.__slots__: return object.__getattribute__(self, name) else: if self.popen is not None: if Popen.verbose: print("from Popen") return getattr(self.popen, name) else: if name == "wait": return self.emu_wait else: raise Exception("subprocess emulation: not implemented: %s" % name) def emu_wait(self): if Popen.verbose: print("emulated wait (%r kw=%r)" % (self.prog, self.kw)) if isinstance(self.prog, str): cmd = self.prog else: cmd = " ".join(self.prog) if 'cwd' in self.kw: cmd = 'cd "%s" && %s' % (self.kw['cwd'], cmd) return os.system(cmd) if sys.platform == "qnx6": Popen.real_Popen = Utils.subprocess.Popen Utils.subprocess.Popen = Popen hamster-3.0.3/waflib/extras/qt4.py000066400000000000000000000475221452646177100170430ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2006-2010 (ita) """ Tool Description ================ This tool helps with finding Qt4 tools and libraries, and also provides syntactic sugar for using Qt4 tools. The following snippet illustrates the tool usage:: def options(opt): opt.load('compiler_cxx qt4') def configure(conf): conf.load('compiler_cxx qt4') def build(bld): bld( features = 'qt4 cxx cxxprogram', uselib = 'QTCORE QTGUI QTOPENGL QTSVG', source = 'main.cpp textures.qrc aboutDialog.ui', target = 'window', ) Here, the UI description and resource files will be processed to generate code. Usage ===== Load the "qt4" tool. You also need to edit your sources accordingly: - the normal way of doing things is to have your C++ files include the .moc file. This is regarded as the best practice (and provides much faster compilations). It also implies that the include paths have beenset properly. - to have the include paths added automatically, use the following:: from waflib.TaskGen import feature, before_method, after_method @feature('cxx') @after_method('process_source') @before_method('apply_incpaths') def add_includes_paths(self): incs = set(self.to_list(getattr(self, 'includes', ''))) for x in self.compiled_tasks: incs.add(x.inputs[0].parent.path_from(self.path)) self.includes = sorted(incs) Note: another tool provides Qt processing that does not require .moc includes, see 'playground/slow_qt/'. A few options (--qt{dir,bin,...}) and environment variables (QT4_{ROOT,DIR,MOC,UIC,XCOMPILE}) allow finer tuning of the tool, tool path selection, etc; please read the source for more info. """ try: from xml.sax import make_parser from xml.sax.handler import ContentHandler except ImportError: has_xml = False ContentHandler = object else: has_xml = True import os, sys from waflib.Tools import cxx from waflib import Task, Utils, Options, Errors, Context from waflib.TaskGen import feature, after_method, extension from waflib.Configure import conf from waflib import Logs MOC_H = ['.h', '.hpp', '.hxx', '.hh'] """ File extensions associated to the .moc files """ EXT_RCC = ['.qrc'] """ File extension for the resource (.qrc) files """ EXT_UI = ['.ui'] """ File extension for the user interface (.ui) files """ EXT_QT4 = ['.cpp', '.cc', '.cxx', '.C'] """ File extensions of C++ files that may require a .moc processing """ QT4_LIBS = "QtCore QtGui QtUiTools QtNetwork QtOpenGL QtSql QtSvg QtTest QtXml QtXmlPatterns QtWebKit Qt3Support QtHelp QtScript QtDeclarative QtDesigner" class qxx(Task.classes['cxx']): """ Each C++ file can have zero or several .moc files to create. They are known only when the files are scanned (preprocessor) To avoid scanning the c++ files each time (parsing C/C++), the results are retrieved from the task cache (bld.node_deps/bld.raw_deps). The moc tasks are also created *dynamically* during the build. """ def __init__(self, *k, **kw): Task.Task.__init__(self, *k, **kw) self.moc_done = 0 def runnable_status(self): """ Compute the task signature to make sure the scanner was executed. Create the moc tasks by using :py:meth:`waflib.Tools.qt4.qxx.add_moc_tasks` (if necessary), then postpone the task execution (there is no need to recompute the task signature). """ if self.moc_done: return Task.Task.runnable_status(self) else: for t in self.run_after: if not t.hasrun: return Task.ASK_LATER self.add_moc_tasks() return Task.Task.runnable_status(self) def create_moc_task(self, h_node, m_node): """ If several libraries use the same classes, it is possible that moc will run several times (Issue 1318) It is not possible to change the file names, but we can assume that the moc transformation will be identical, and the moc tasks can be shared in a global cache. The defines passed to moc will then depend on task generator order. If this is not acceptable, then use the tool slow_qt4 instead (and enjoy the slow builds... :-( ) """ try: moc_cache = self.generator.bld.moc_cache except AttributeError: moc_cache = self.generator.bld.moc_cache = {} try: return moc_cache[h_node] except KeyError: tsk = moc_cache[h_node] = Task.classes['moc'](env=self.env, generator=self.generator) tsk.set_inputs(h_node) tsk.set_outputs(m_node) if self.generator: self.generator.tasks.append(tsk) # direct injection in the build phase (safe because called from the main thread) gen = self.generator.bld.producer gen.outstanding.append(tsk) gen.total += 1 return tsk def moc_h_ext(self): ext = [] try: ext = Options.options.qt_header_ext.split() except AttributeError: pass if not ext: ext = MOC_H return ext def add_moc_tasks(self): """ Create the moc tasks by looking in ``bld.raw_deps[self.uid()]`` """ node = self.inputs[0] bld = self.generator.bld try: # compute the signature once to know if there is a moc file to create self.signature() except KeyError: # the moc file may be referenced somewhere else pass else: # remove the signature, it must be recomputed with the moc task delattr(self, 'cache_sig') include_nodes = [node.parent] + self.generator.includes_nodes moctasks = [] mocfiles = set() for d in bld.raw_deps.get(self.uid(), []): if not d.endswith('.moc'): continue # process that base.moc only once if d in mocfiles: continue mocfiles.add(d) # find the source associated with the moc file h_node = None base2 = d[:-4] for x in include_nodes: for e in self.moc_h_ext(): h_node = x.find_node(base2 + e) if h_node: break if h_node: m_node = h_node.change_ext('.moc') break else: # foo.cpp -> foo.cpp.moc for k in EXT_QT4: if base2.endswith(k): for x in include_nodes: h_node = x.find_node(base2) if h_node: break if h_node: m_node = h_node.change_ext(k + '.moc') break if not h_node: raise Errors.WafError('No source found for %r which is a moc file' % d) # create the moc task task = self.create_moc_task(h_node, m_node) moctasks.append(task) # simple scheduler dependency: run the moc task before others self.run_after.update(set(moctasks)) self.moc_done = 1 class trans_update(Task.Task): """Update a .ts files from a list of C++ files""" run_str = '${QT_LUPDATE} ${SRC} -ts ${TGT}' color = 'BLUE' class XMLHandler(ContentHandler): """ Parser for *.qrc* files """ def __init__(self): self.buf = [] self.files = [] def startElement(self, name, attrs): if name == 'file': self.buf = [] def endElement(self, name): if name == 'file': self.files.append(str(''.join(self.buf))) def characters(self, cars): self.buf.append(cars) @extension(*EXT_RCC) def create_rcc_task(self, node): "Create rcc and cxx tasks for *.qrc* files" rcnode = node.change_ext('_rc.cpp') self.create_task('rcc', node, rcnode) cpptask = self.create_task('cxx', rcnode, rcnode.change_ext('.o')) try: self.compiled_tasks.append(cpptask) except AttributeError: self.compiled_tasks = [cpptask] return cpptask @extension(*EXT_UI) def create_uic_task(self, node): "hook for uic tasks" uictask = self.create_task('ui4', node) uictask.outputs = [self.path.find_or_declare(self.env['ui_PATTERN'] % node.name[:-3])] @extension('.ts') def add_lang(self, node): """add all the .ts file into self.lang""" self.lang = self.to_list(getattr(self, 'lang', [])) + [node] @feature('qt4') @after_method('apply_link') def apply_qt4(self): """ Add MOC_FLAGS which may be necessary for moc:: def build(bld): bld.program(features='qt4', source='main.cpp', target='app', use='QTCORE') The additional parameters are: :param lang: list of translation files (\\*.ts) to process :type lang: list of :py:class:`waflib.Node.Node` or string without the .ts extension :param update: whether to process the C++ files to update the \\*.ts files (use **waf --translate**) :type update: bool :param langname: if given, transform the \\*.ts files into a .qrc files to include in the binary file :type langname: :py:class:`waflib.Node.Node` or string without the .qrc extension """ if getattr(self, 'lang', None): qmtasks = [] for x in self.to_list(self.lang): if isinstance(x, str): x = self.path.find_resource(x + '.ts') qmtasks.append(self.create_task('ts2qm', x, x.change_ext('.qm'))) if getattr(self, 'update', None) and Options.options.trans_qt4: cxxnodes = [a.inputs[0] for a in self.compiled_tasks] + [ a.inputs[0] for a in self.tasks if getattr(a, 'inputs', None) and a.inputs[0].name.endswith('.ui')] for x in qmtasks: self.create_task('trans_update', cxxnodes, x.inputs) if getattr(self, 'langname', None): qmnodes = [x.outputs[0] for x in qmtasks] rcnode = self.langname if isinstance(rcnode, str): rcnode = self.path.find_or_declare(rcnode + '.qrc') t = self.create_task('qm2rcc', qmnodes, rcnode) k = create_rcc_task(self, t.outputs[0]) self.link_task.inputs.append(k.outputs[0]) lst = [] for flag in self.to_list(self.env['CXXFLAGS']): if len(flag) < 2: continue f = flag[0:2] if f in ('-D', '-I', '/D', '/I'): if (f[0] == '/'): lst.append('-' + flag[1:]) else: lst.append(flag) self.env.append_value('MOC_FLAGS', lst) @extension(*EXT_QT4) def cxx_hook(self, node): """ Re-map C++ file extensions to the :py:class:`waflib.Tools.qt4.qxx` task. """ return self.create_compiled_task('qxx', node) class rcc(Task.Task): """ Process *.qrc* files """ color = 'BLUE' run_str = '${QT_RCC} -name ${tsk.rcname()} ${SRC[0].abspath()} ${RCC_ST} -o ${TGT}' ext_out = ['.h'] def rcname(self): return os.path.splitext(self.inputs[0].name)[0] def scan(self): """Parse the *.qrc* files""" if not has_xml: Logs.error('no xml support was found, the rcc dependencies will be incomplete!') return ([], []) parser = make_parser() curHandler = XMLHandler() parser.setContentHandler(curHandler) fi = open(self.inputs[0].abspath(), 'r') try: parser.parse(fi) finally: fi.close() nodes = [] names = [] root = self.inputs[0].parent for x in curHandler.files: nd = root.find_resource(x) if nd: nodes.append(nd) else: names.append(x) return (nodes, names) class moc(Task.Task): """ Create *.moc* files """ color = 'BLUE' run_str = '${QT_MOC} ${MOC_FLAGS} ${MOCCPPPATH_ST:INCPATHS} ${MOCDEFINES_ST:DEFINES} ${SRC} ${MOC_ST} ${TGT}' def keyword(self): return "Creating" def __str__(self): return self.outputs[0].path_from(self.generator.bld.launch_node()) class ui4(Task.Task): """ Process *.ui* files """ color = 'BLUE' run_str = '${QT_UIC} ${SRC} -o ${TGT}' ext_out = ['.h'] class ts2qm(Task.Task): """ Create *.qm* files from *.ts* files """ color = 'BLUE' run_str = '${QT_LRELEASE} ${QT_LRELEASE_FLAGS} ${SRC} -qm ${TGT}' class qm2rcc(Task.Task): """ Transform *.qm* files into *.rc* files """ color = 'BLUE' after = 'ts2qm' def run(self): """Create a qrc file including the inputs""" txt = '\n'.join(['%s' % k.path_from(self.outputs[0].parent) for k in self.inputs]) code = '\n\n%s\n\n' % txt self.outputs[0].write(code) def configure(self): """ Besides the configuration options, the environment variable QT4_ROOT may be used to give the location of the qt4 libraries (absolute path). The detection will use the program *pkg-config* through :py:func:`waflib.Tools.config_c.check_cfg` """ self.find_qt4_binaries() self.set_qt4_libs_to_check() self.set_qt4_defines() self.find_qt4_libraries() self.add_qt4_rpath() self.simplify_qt4_libs() @conf def find_qt4_binaries(self): env = self.env opt = Options.options qtdir = getattr(opt, 'qtdir', '') qtbin = getattr(opt, 'qtbin', '') paths = [] if qtdir: qtbin = os.path.join(qtdir, 'bin') # the qt directory has been given from QT4_ROOT - deduce the qt binary path if not qtdir: qtdir = os.environ.get('QT4_ROOT', '') qtbin = os.environ.get('QT4_BIN') or os.path.join(qtdir, 'bin') if qtbin: paths = [qtbin] # no qtdir, look in the path and in /usr/local/Trolltech if not qtdir: paths = os.environ.get('PATH', '').split(os.pathsep) paths.append('/usr/share/qt4/bin/') try: lst = Utils.listdir('/usr/local/Trolltech/') except OSError: pass else: if lst: lst.sort() lst.reverse() # keep the highest version qtdir = '/usr/local/Trolltech/%s/' % lst[0] qtbin = os.path.join(qtdir, 'bin') paths.append(qtbin) # at the end, try to find qmake in the paths given # keep the one with the highest version cand = None prev_ver = ['4', '0', '0'] for qmk in ('qmake-qt4', 'qmake4', 'qmake'): try: qmake = self.find_program(qmk, path_list=paths) except self.errors.ConfigurationError: pass else: try: version = self.cmd_and_log(qmake + ['-query', 'QT_VERSION']).strip() except self.errors.WafError: pass else: if version: new_ver = version.split('.') if new_ver > prev_ver: cand = qmake prev_ver = new_ver if cand: self.env.QMAKE = cand else: self.fatal('Could not find qmake for qt4') qtbin = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_BINS']).strip() + os.sep def find_bin(lst, var): if var in env: return for f in lst: try: ret = self.find_program(f, path_list=paths) except self.errors.ConfigurationError: pass else: env[var]=ret break find_bin(['uic-qt3', 'uic3'], 'QT_UIC3') find_bin(['uic-qt4', 'uic'], 'QT_UIC') if not env.QT_UIC: self.fatal('cannot find the uic compiler for qt4') self.start_msg('Checking for uic version') uicver = self.cmd_and_log(env.QT_UIC + ["-version"], output=Context.BOTH) uicver = ''.join(uicver).strip() uicver = uicver.replace('Qt User Interface Compiler ','').replace('User Interface Compiler for Qt', '') self.end_msg(uicver) if uicver.find(' 3.') != -1: self.fatal('this uic compiler is for qt3, add uic for qt4 to your path') find_bin(['moc-qt4', 'moc'], 'QT_MOC') find_bin(['rcc-qt4', 'rcc'], 'QT_RCC') find_bin(['lrelease-qt4', 'lrelease'], 'QT_LRELEASE') find_bin(['lupdate-qt4', 'lupdate'], 'QT_LUPDATE') env['UIC3_ST']= '%s -o %s' env['UIC_ST'] = '%s -o %s' env['MOC_ST'] = '-o' env['ui_PATTERN'] = 'ui_%s.h' env['QT_LRELEASE_FLAGS'] = ['-silent'] env.MOCCPPPATH_ST = '-I%s' env.MOCDEFINES_ST = '-D%s' @conf def find_qt4_libraries(self): qtlibs = getattr(Options.options, 'qtlibs', None) or os.environ.get("QT4_LIBDIR") if not qtlibs: try: qtlibs = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_LIBS']).strip() except Errors.WafError: qtdir = self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_PREFIX']).strip() + os.sep qtlibs = os.path.join(qtdir, 'lib') self.msg('Found the Qt4 libraries in', qtlibs) qtincludes = os.environ.get("QT4_INCLUDES") or self.cmd_and_log(self.env.QMAKE + ['-query', 'QT_INSTALL_HEADERS']).strip() env = self.env if not 'PKG_CONFIG_PATH' in os.environ: os.environ['PKG_CONFIG_PATH'] = '%s:%s/pkgconfig:/usr/lib/qt4/lib/pkgconfig:/opt/qt4/lib/pkgconfig:/usr/lib/qt4/lib:/opt/qt4/lib' % (qtlibs, qtlibs) try: if os.environ.get("QT4_XCOMPILE"): raise self.errors.ConfigurationError() self.check_cfg(atleast_pkgconfig_version='0.1') except self.errors.ConfigurationError: for i in self.qt4_vars: uselib = i.upper() if Utils.unversioned_sys_platform() == "darwin": # Since at least qt 4.7.3 each library locates in separate directory frameworkName = i + ".framework" qtDynamicLib = os.path.join(qtlibs, frameworkName, i) if os.path.exists(qtDynamicLib): env.append_unique('FRAMEWORK_' + uselib, i) self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN') else: self.msg('Checking for %s' % i, False, 'YELLOW') env.append_unique('INCLUDES_' + uselib, os.path.join(qtlibs, frameworkName, 'Headers')) elif env.DEST_OS != "win32": qtDynamicLib = os.path.join(qtlibs, "lib" + i + ".so") qtStaticLib = os.path.join(qtlibs, "lib" + i + ".a") if os.path.exists(qtDynamicLib): env.append_unique('LIB_' + uselib, i) self.msg('Checking for %s' % i, qtDynamicLib, 'GREEN') elif os.path.exists(qtStaticLib): env.append_unique('LIB_' + uselib, i) self.msg('Checking for %s' % i, qtStaticLib, 'GREEN') else: self.msg('Checking for %s' % i, False, 'YELLOW') env.append_unique('LIBPATH_' + uselib, qtlibs) env.append_unique('INCLUDES_' + uselib, qtincludes) env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i)) else: # Release library names are like QtCore4 for k in ("lib%s.a", "lib%s4.a", "%s.lib", "%s4.lib"): lib = os.path.join(qtlibs, k % i) if os.path.exists(lib): env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')]) self.msg('Checking for %s' % i, lib, 'GREEN') break else: self.msg('Checking for %s' % i, False, 'YELLOW') env.append_unique('LIBPATH_' + uselib, qtlibs) env.append_unique('INCLUDES_' + uselib, qtincludes) env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i)) # Debug library names are like QtCore4d uselib = i.upper() + "_debug" for k in ("lib%sd.a", "lib%sd4.a", "%sd.lib", "%sd4.lib"): lib = os.path.join(qtlibs, k % i) if os.path.exists(lib): env.append_unique('LIB_' + uselib, i + k[k.find("%s") + 2 : k.find('.')]) self.msg('Checking for %s' % i, lib, 'GREEN') break else: self.msg('Checking for %s' % i, False, 'YELLOW') env.append_unique('LIBPATH_' + uselib, qtlibs) env.append_unique('INCLUDES_' + uselib, qtincludes) env.append_unique('INCLUDES_' + uselib, os.path.join(qtincludes, i)) else: for i in self.qt4_vars_debug + self.qt4_vars: self.check_cfg(package=i, args='--cflags --libs', mandatory=False) @conf def simplify_qt4_libs(self): # the libpaths make really long command-lines # remove the qtcore ones from qtgui, etc env = self.env def process_lib(vars_, coreval): for d in vars_: var = d.upper() if var == 'QTCORE': continue value = env['LIBPATH_'+var] if value: core = env[coreval] accu = [] for lib in value: if lib in core: continue accu.append(lib) env['LIBPATH_'+var] = accu process_lib(self.qt4_vars, 'LIBPATH_QTCORE') process_lib(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG') @conf def add_qt4_rpath(self): # rpath if wanted env = self.env if getattr(Options.options, 'want_rpath', False): def process_rpath(vars_, coreval): for d in vars_: var = d.upper() value = env['LIBPATH_'+var] if value: core = env[coreval] accu = [] for lib in value: if var != 'QTCORE': if lib in core: continue accu.append('-Wl,--rpath='+lib) env['RPATH_'+var] = accu process_rpath(self.qt4_vars, 'LIBPATH_QTCORE') process_rpath(self.qt4_vars_debug, 'LIBPATH_QTCORE_DEBUG') @conf def set_qt4_libs_to_check(self): if not hasattr(self, 'qt4_vars'): self.qt4_vars = QT4_LIBS self.qt4_vars = Utils.to_list(self.qt4_vars) if not hasattr(self, 'qt4_vars_debug'): self.qt4_vars_debug = [a + '_debug' for a in self.qt4_vars] self.qt4_vars_debug = Utils.to_list(self.qt4_vars_debug) @conf def set_qt4_defines(self): if sys.platform != 'win32': return for x in self.qt4_vars: y = x[2:].upper() self.env.append_unique('DEFINES_%s' % x.upper(), 'QT_%s_LIB' % y) self.env.append_unique('DEFINES_%s_DEBUG' % x.upper(), 'QT_%s_LIB' % y) def options(opt): """ Command-line options """ opt.add_option('--want-rpath', action='store_true', default=False, dest='want_rpath', help='enable the rpath for qt libraries') opt.add_option('--header-ext', type='string', default='', help='header extension for moc files', dest='qt_header_ext') for i in 'qtdir qtbin qtlibs'.split(): opt.add_option('--'+i, type='string', default='', dest=i) opt.add_option('--translate', action="store_true", help="collect translation strings", dest="trans_qt4", default=False) hamster-3.0.3/waflib/extras/relocation.py000066400000000000000000000043331452646177100204630ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ Waf 1.6 Try to detect if the project directory was relocated, and if it was, change the node representing the project directory. Just call: waf configure build Note that if the project directory name changes, the signatures for the tasks using files in that directory will change, causing a partial build. """ import os from waflib import Build, ConfigSet, Task, Utils, Errors from waflib.TaskGen import feature, after_method EXTRA_LOCK = '.old_srcdir' old1 = Build.BuildContext.store def store(self): old1(self) db = os.path.join(self.variant_dir, EXTRA_LOCK) env = ConfigSet.ConfigSet() env.SRCDIR = self.srcnode.abspath() env.store(db) Build.BuildContext.store = store old2 = Build.BuildContext.init_dirs def init_dirs(self): if not (os.path.isabs(self.top_dir) and os.path.isabs(self.out_dir)): raise Errors.WafError('The project was not configured: run "waf configure" first!') srcdir = None db = os.path.join(self.variant_dir, EXTRA_LOCK) env = ConfigSet.ConfigSet() try: env.load(db) srcdir = env.SRCDIR except: pass if srcdir: d = self.root.find_node(srcdir) if d and srcdir != self.top_dir and getattr(d, 'children', ''): srcnode = self.root.make_node(self.top_dir) print("relocating the source directory %r -> %r" % (srcdir, self.top_dir)) srcnode.children = {} for (k, v) in d.children.items(): srcnode.children[k] = v v.parent = srcnode d.children = {} old2(self) Build.BuildContext.init_dirs = init_dirs def uid(self): try: return self.uid_ except AttributeError: # this is not a real hot zone, but we want to avoid surprises here m = Utils.md5() up = m.update up(self.__class__.__name__.encode()) for x in self.inputs + self.outputs: up(x.path_from(x.ctx.srcnode).encode()) self.uid_ = m.digest() return self.uid_ Task.Task.uid = uid @feature('c', 'cxx', 'd', 'go', 'asm', 'fc', 'includes') @after_method('propagate_uselib_vars', 'process_source') def apply_incpaths(self): lst = self.to_incnodes(self.to_list(getattr(self, 'includes', [])) + self.env['INCLUDES']) self.includes_nodes = lst bld = self.bld self.env['INCPATHS'] = [x.is_child_of(bld.srcnode) and x.path_from(bld.bldnode) or x.abspath() for x in lst] hamster-3.0.3/waflib/extras/remote.py000066400000000000000000000230721452646177100176200ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Remote Builds tool using rsync+ssh __author__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2013" """ Simple Remote Builds ******************** This tool is an *experimental* tool (meaning, do not even try to pollute the waf bug tracker with bugs in here, contact me directly) providing simple remote builds. It uses rsync and ssh to perform the remote builds. It is intended for performing cross-compilation on platforms where a cross-compiler is either unavailable (eg. MacOS, QNX) a specific product does not exist (eg. Windows builds using Visual Studio) or simply not installed. This tool sends the sources and the waf script to the remote host, and commands the usual waf execution. There are alternatives to using this tool, such as setting up shared folders, logging on to remote machines, and building on the shared folders. Electing one method or another depends on the size of the program. Usage ===== 1. Set your wscript file so it includes a list of variants, e.g.:: from waflib import Utils top = '.' out = 'build' variants = [ 'linux_64_debug', 'linux_64_release', 'linux_32_debug', 'linux_32_release', ] from waflib.extras import remote def options(opt): # normal stuff from here on opt.load('compiler_c') def configure(conf): if not conf.variant: return # normal stuff from here on conf.load('compiler_c') def build(bld): if not bld.variant: return # normal stuff from here on bld(features='c cprogram', target='app', source='main.c') 2. Build the waf file, so it includes this tool, and put it in the current directory .. code:: bash ./waf-light --tools=remote 3. Set the host names to access the hosts: .. code:: bash export REMOTE_QNX=user@kiunix 4. Setup the ssh server and ssh keys The ssh key should not be protected by a password, or it will prompt for it every time. Create the key on the client: .. code:: bash ssh-keygen -t rsa -f foo.rsa Then copy foo.rsa.pub to the remote machine (user@kiunix:/home/user/.ssh/authorized_keys), and make sure the permissions are correct (chmod go-w ~ ~/.ssh ~/.ssh/authorized_keys) A separate key for the build processes can be set in the environment variable WAF_SSH_KEY. The tool will then use 'ssh-keyscan' to avoid prompting for remote hosts, so be warned to use this feature on internal networks only (MITM). .. code:: bash export WAF_SSH_KEY=~/foo.rsa 5. Perform the build: .. code:: bash waf configure_all build_all --remote """ import getpass, os, re, sys from collections import OrderedDict from waflib import Context, Options, Utils, ConfigSet from waflib.Build import BuildContext, CleanContext, InstallContext, UninstallContext from waflib.Configure import ConfigurationContext is_remote = False if '--remote' in sys.argv: is_remote = True sys.argv.remove('--remote') class init(Context.Context): """ Generates the *_all commands """ cmd = 'init' fun = 'init' def execute(self): for x in list(Context.g_module.variants): self.make_variant(x) lst = ['remote'] for k in Options.commands: if k.endswith('_all'): name = k.replace('_all', '') for x in Context.g_module.variants: lst.append('%s_%s' % (name, x)) else: lst.append(k) del Options.commands[:] Options.commands += lst def make_variant(self, x): for y in (BuildContext, CleanContext, InstallContext, UninstallContext): name = y.__name__.replace('Context','').lower() class tmp(y): cmd = name + '_' + x fun = 'build' variant = x class tmp(ConfigurationContext): cmd = 'configure_' + x fun = 'configure' variant = x def __init__(self, **kw): ConfigurationContext.__init__(self, **kw) self.setenv(x) class remote(BuildContext): cmd = 'remote' fun = 'build' def get_ssh_hosts(self): lst = [] for v in Context.g_module.variants: self.env.HOST = self.login_to_host(self.variant_to_login(v)) cmd = Utils.subst_vars('${SSH_KEYSCAN} -t rsa,ecdsa ${HOST}', self.env) out, err = self.cmd_and_log(cmd, output=Context.BOTH, quiet=Context.BOTH) lst.append(out.strip()) return lst def setup_private_ssh_key(self): """ When WAF_SSH_KEY points to a private key, a .ssh directory will be created in the build directory Make sure that the ssh key does not prompt for a password """ key = os.environ.get('WAF_SSH_KEY', '') if not key: return if not os.path.isfile(key): self.fatal('Key in WAF_SSH_KEY must point to a valid file') self.ssh_dir = os.path.join(self.path.abspath(), 'build', '.ssh') self.ssh_hosts = os.path.join(self.ssh_dir, 'known_hosts') self.ssh_key = os.path.join(self.ssh_dir, os.path.basename(key)) self.ssh_config = os.path.join(self.ssh_dir, 'config') for x in self.ssh_hosts, self.ssh_key, self.ssh_config: if not os.path.isfile(x): if not os.path.isdir(self.ssh_dir): os.makedirs(self.ssh_dir) Utils.writef(self.ssh_key, Utils.readf(key), 'wb') os.chmod(self.ssh_key, 448) Utils.writef(self.ssh_hosts, '\n'.join(self.get_ssh_hosts())) os.chmod(self.ssh_key, 448) Utils.writef(self.ssh_config, 'UserKnownHostsFile %s' % self.ssh_hosts, 'wb') os.chmod(self.ssh_config, 448) self.env.SSH_OPTS = ['-F', self.ssh_config, '-i', self.ssh_key] self.env.append_value('RSYNC_SEND_OPTS', '--exclude=build/.ssh') def skip_unbuildable_variant(self): # skip variants that cannot be built on this OS for k in Options.commands: a, _, b = k.partition('_') if b in Context.g_module.variants: c, _, _ = b.partition('_') if c != Utils.unversioned_sys_platform(): Options.commands.remove(k) def login_to_host(self, login): return re.sub(r'(\w+@)', '', login) def variant_to_login(self, variant): """linux_32_debug -> search env.LINUX_32 and then env.LINUX""" x = variant[:variant.rfind('_')] ret = os.environ.get('REMOTE_' + x.upper(), '') if not ret: x = x[:x.find('_')] ret = os.environ.get('REMOTE_' + x.upper(), '') if not ret: ret = '%s@localhost' % getpass.getuser() return ret def execute(self): global is_remote if not is_remote: self.skip_unbuildable_variant() else: BuildContext.execute(self) def restore(self): self.top_dir = os.path.abspath(Context.g_module.top) self.srcnode = self.root.find_node(self.top_dir) self.path = self.srcnode self.out_dir = os.path.join(self.top_dir, Context.g_module.out) self.bldnode = self.root.make_node(self.out_dir) self.bldnode.mkdir() self.env = ConfigSet.ConfigSet() def extract_groups_of_builds(self): """Return a dict mapping each variants to the commands to build""" self.vgroups = {} for x in reversed(Options.commands): _, _, variant = x.partition('_') if variant in Context.g_module.variants: try: dct = self.vgroups[variant] except KeyError: dct = self.vgroups[variant] = OrderedDict() try: dct[variant].append(x) except KeyError: dct[variant] = [x] Options.commands.remove(x) def custom_options(self, login): try: return Context.g_module.host_options[login] except (AttributeError, KeyError): return {} def recurse(self, *k, **kw): self.env.RSYNC = getattr(Context.g_module, 'rsync', 'rsync -a --chmod=u+rwx') self.env.SSH = getattr(Context.g_module, 'ssh', 'ssh') self.env.SSH_KEYSCAN = getattr(Context.g_module, 'ssh_keyscan', 'ssh-keyscan') try: self.env.WAF = getattr(Context.g_module, 'waf') except AttributeError: try: os.stat('waf') except KeyError: self.fatal('Put a waf file in the directory (./waf-light --tools=remote)') else: self.env.WAF = './waf' self.extract_groups_of_builds() self.setup_private_ssh_key() for k, v in self.vgroups.items(): task = self(rule=rsync_and_ssh, always=True) task.env.login = self.variant_to_login(k) task.env.commands = [] for opt, value in v.items(): task.env.commands += value task.env.variant = task.env.commands[0].partition('_')[2] for opt, value in self.custom_options(k): task.env[opt] = value self.jobs = len(self.vgroups) def make_mkdir_command(self, task): return Utils.subst_vars('${SSH} ${SSH_OPTS} ${login} "rm -fr ${remote_dir} && mkdir -p ${remote_dir}"', task.env) def make_send_command(self, task): return Utils.subst_vars('${RSYNC} ${RSYNC_SEND_OPTS} -e "${SSH} ${SSH_OPTS}" ${local_dir} ${login}:${remote_dir}', task.env) def make_exec_command(self, task): txt = '''${SSH} ${SSH_OPTS} ${login} "cd ${remote_dir} && ${WAF} ${commands}"''' return Utils.subst_vars(txt, task.env) def make_save_command(self, task): return Utils.subst_vars('${RSYNC} ${RSYNC_SAVE_OPTS} -e "${SSH} ${SSH_OPTS}" ${login}:${remote_dir_variant} ${build_dir}', task.env) def rsync_and_ssh(task): # remove a warning task.uid_ = id(task) bld = task.generator.bld task.env.user, _, _ = task.env.login.partition('@') task.env.hdir = Utils.to_hex(Utils.h_list((task.generator.path.abspath(), task.env.variant))) task.env.remote_dir = '~%s/wafremote/%s' % (task.env.user, task.env.hdir) task.env.local_dir = bld.srcnode.abspath() + '/' task.env.remote_dir_variant = '%s/%s/%s' % (task.env.remote_dir, Context.g_module.out, task.env.variant) task.env.build_dir = bld.bldnode.abspath() ret = task.exec_command(bld.make_mkdir_command(task)) if ret: return ret ret = task.exec_command(bld.make_send_command(task)) if ret: return ret ret = task.exec_command(bld.make_exec_command(task)) if ret: return ret ret = task.exec_command(bld.make_save_command(task)) if ret: return ret hamster-3.0.3/waflib/extras/resx.py000066400000000000000000000020321452646177100172770ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 import os from waflib import Task from waflib.TaskGen import extension def configure(conf): conf.find_program(['resgen'], var='RESGEN') conf.env.RESGENFLAGS = '/useSourcePath' @extension('.resx') def resx_file(self, node): """ Bind the .resx extension to a resgen task """ if not getattr(self, 'cs_task', None): self.bld.fatal('resx_file has no link task for use %r' % self) # Given assembly 'Foo' and file 'Sub/Dir/File.resx', create 'Foo.Sub.Dir.File.resources' assembly = getattr(self, 'namespace', os.path.splitext(self.gen)[0]) res = os.path.splitext(node.path_from(self.path))[0].replace('/', '.').replace('\\', '.') out = self.path.find_or_declare(assembly + '.' + res + '.resources') tsk = self.create_task('resgen', node, out) self.cs_task.dep_nodes.extend(tsk.outputs) # dependency self.env.append_value('RESOURCES', tsk.outputs[0].bldpath()) class resgen(Task.Task): """ Compile C# resource files """ color = 'YELLOW' run_str = '${RESGEN} ${RESGENFLAGS} ${SRC} ${TGT}' hamster-3.0.3/waflib/extras/review.py000066400000000000000000000216021452646177100176230ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Laurent Birtz, 2011 # moved the code into a separate tool (ita) """ There are several things here: - a different command-line option management making options persistent - the review command to display the options set Assumptions: - configuration options are not always added to the right group (and do not count on the users to do it...) - the options are persistent between the executions (waf options are NOT persistent by design), even for the configuration - when the options change, the build is invalidated (forcing a reconfiguration) """ import os, textwrap, shutil from waflib import Logs, Context, ConfigSet, Options, Build, Configure class Odict(dict): """Ordered dictionary""" def __init__(self, data=None): self._keys = [] dict.__init__(self) if data: # we were provided a regular dict if isinstance(data, dict): self.append_from_dict(data) # we were provided a tuple list elif type(data) == list: self.append_from_plist(data) # we were provided invalid input else: raise Exception("expected a dict or a tuple list") def append_from_dict(self, dict): map(self.__setitem__, dict.keys(), dict.values()) def append_from_plist(self, plist): for pair in plist: if len(pair) != 2: raise Exception("invalid pairs list") for (k, v) in plist: self.__setitem__(k, v) def __delitem__(self, key): if not key in self._keys: raise KeyError(key) dict.__delitem__(self, key) self._keys.remove(key) def __setitem__(self, key, item): dict.__setitem__(self, key, item) if key not in self._keys: self._keys.append(key) def clear(self): dict.clear(self) self._keys = [] def copy(self): return Odict(self.plist()) def items(self): return zip(self._keys, self.values()) def keys(self): return list(self._keys) # return a copy of the list def values(self): return map(self.get, self._keys) def plist(self): p = [] for k, v in self.items(): p.append( (k, v) ) return p def __str__(self): buf = [] buf.append("{ ") for k, v in self.items(): buf.append('%r : %r, ' % (k, v)) buf.append("}") return ''.join(buf) review_options = Odict() """ Ordered dictionary mapping configuration option names to their optparse option. """ review_defaults = {} """ Dictionary mapping configuration option names to their default value. """ old_review_set = None """ Review set containing the configuration values before parsing the command line. """ new_review_set = None """ Review set containing the configuration values after parsing the command line. """ class OptionsReview(Options.OptionsContext): def __init__(self, **kw): super(self.__class__, self).__init__(**kw) def prepare_config_review(self): """ Find the configuration options that are reviewable, detach their default value from their optparse object and store them into the review dictionaries. """ gr = self.get_option_group('configure options') for opt in gr.option_list: if opt.action != 'store' or opt.dest in ("out", "top"): continue review_options[opt.dest] = opt review_defaults[opt.dest] = opt.default if gr.defaults.has_key(opt.dest): del gr.defaults[opt.dest] opt.default = None def parse_args(self): self.prepare_config_review() self.parser.get_option('--prefix').help = 'installation prefix' super(OptionsReview, self).parse_args() Context.create_context('review').refresh_review_set() class ReviewContext(Context.Context): '''reviews the configuration values''' cmd = 'review' def __init__(self, **kw): super(self.__class__, self).__init__(**kw) out = Options.options.out if not out: out = getattr(Context.g_module, Context.OUT, None) if not out: out = Options.lockfile.replace('.lock-waf', '') self.build_path = (os.path.isabs(out) and self.root or self.path).make_node(out).abspath() """Path to the build directory""" self.cache_path = os.path.join(self.build_path, Build.CACHE_DIR) """Path to the cache directory""" self.review_path = os.path.join(self.cache_path, 'review.cache') """Path to the review cache file""" def execute(self): """ Display and store the review set. Invalidate the cache as required. """ if not self.compare_review_set(old_review_set, new_review_set): self.invalidate_cache() self.store_review_set(new_review_set) print(self.display_review_set(new_review_set)) def invalidate_cache(self): """Invalidate the cache to prevent bad builds.""" try: Logs.warn("Removing the cached configuration since the options have changed") shutil.rmtree(self.cache_path) except: pass def refresh_review_set(self): """ Obtain the old review set and the new review set, and import the new set. """ global old_review_set, new_review_set old_review_set = self.load_review_set() new_review_set = self.update_review_set(old_review_set) self.import_review_set(new_review_set) def load_review_set(self): """ Load and return the review set from the cache if it exists. Otherwise, return an empty set. """ if os.path.isfile(self.review_path): return ConfigSet.ConfigSet(self.review_path) return ConfigSet.ConfigSet() def store_review_set(self, review_set): """ Store the review set specified in the cache. """ if not os.path.isdir(self.cache_path): os.makedirs(self.cache_path) review_set.store(self.review_path) def update_review_set(self, old_set): """ Merge the options passed on the command line with those imported from the previous review set and return the corresponding preview set. """ # Convert value to string. It's important that 'None' maps to # the empty string. def val_to_str(val): if val == None or val == '': return '' return str(val) new_set = ConfigSet.ConfigSet() opt_dict = Options.options.__dict__ for name in review_options.keys(): # the option is specified explicitly on the command line if name in opt_dict: # if the option is the default, pretend it was never specified if val_to_str(opt_dict[name]) != val_to_str(review_defaults[name]): new_set[name] = opt_dict[name] # the option was explicitly specified in a previous command elif name in old_set: new_set[name] = old_set[name] return new_set def import_review_set(self, review_set): """ Import the actual value of the reviewable options in the option dictionary, given the current review set. """ for name in review_options.keys(): if name in review_set: value = review_set[name] else: value = review_defaults[name] setattr(Options.options, name, value) def compare_review_set(self, set1, set2): """ Return true if the review sets specified are equal. """ if len(set1.keys()) != len(set2.keys()): return False for key in set1.keys(): if not key in set2 or set1[key] != set2[key]: return False return True def display_review_set(self, review_set): """ Return the string representing the review set specified. """ term_width = Logs.get_term_cols() lines = [] for dest in review_options.keys(): opt = review_options[dest] name = ", ".join(opt._short_opts + opt._long_opts) help = opt.help actual = None if dest in review_set: actual = review_set[dest] default = review_defaults[dest] lines.append(self.format_option(name, help, actual, default, term_width)) return "Configuration:\n\n" + "\n\n".join(lines) + "\n" def format_option(self, name, help, actual, default, term_width): """ Return the string representing the option specified. """ def val_to_str(val): if val == None or val == '': return "(void)" return str(val) max_name_len = 20 sep_len = 2 w = textwrap.TextWrapper() w.width = term_width - 1 if w.width < 60: w.width = 60 out = "" # format the help out += w.fill(help) + "\n" # format the name name_len = len(name) out += Logs.colors.CYAN + name + Logs.colors.NORMAL # set the indentation used when the value wraps to the next line w.subsequent_indent = " ".rjust(max_name_len + sep_len) w.width -= (max_name_len + sep_len) # the name string is too long, switch to the next line if name_len > max_name_len: out += "\n" + w.subsequent_indent # fill the remaining of the line with spaces else: out += " ".rjust(max_name_len + sep_len - name_len) # format the actual value, if there is one if actual != None: out += Logs.colors.BOLD + w.fill(val_to_str(actual)) + Logs.colors.NORMAL + "\n" + w.subsequent_indent # format the default value default_fmt = val_to_str(default) if actual != None: default_fmt = "default: " + default_fmt out += Logs.colors.NORMAL + w.fill(default_fmt) + Logs.colors.NORMAL return out # Monkey-patch ConfigurationContext.execute() to have it store the review set. old_configure_execute = Configure.ConfigurationContext.execute def new_configure_execute(self): old_configure_execute(self) Context.create_context('review').store_review_set(new_review_set) Configure.ConfigurationContext.execute = new_configure_execute hamster-3.0.3/waflib/extras/rst.py000066400000000000000000000154471452646177100171440ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Jérôme Carretero, 2013 (zougloub) """ reStructuredText support (experimental) Example:: def configure(conf): conf.load('rst') if not conf.env.RST2HTML: conf.fatal('The program rst2html is required') def build(bld): bld( features = 'rst', type = 'rst2html', # rst2html, rst2pdf, ... source = 'index.rst', # mandatory, the source deps = 'image.png', # to give additional non-trivial dependencies ) By default the tool looks for a set of programs in PATH. The tools are defined in `rst_progs`. To configure with a special program use:: $ RST2HTML=/path/to/rst2html waf configure This tool is experimental; don't hesitate to contribute to it. """ import re from waflib import Node, Utils, Task, Errors, Logs from waflib.TaskGen import feature, before_method rst_progs = "rst2html rst2xetex rst2latex rst2xml rst2pdf rst2s5 rst2man rst2odt rst2rtf".split() def parse_rst_node(task, node, nodes, names, seen, dirs=None): # TODO add extensibility, to handle custom rst include tags... if dirs is None: dirs = (node.parent,node.get_bld().parent) if node in seen: return seen.append(node) code = node.read() re_rst = re.compile(r'^\s*.. ((?P\|\S+\|) )?(?Pinclude|image|figure):: (?P.*)$', re.M) for match in re_rst.finditer(code): ipath = match.group('file') itype = match.group('type') Logs.debug('rst: visiting %s: %s', itype, ipath) found = False for d in dirs: Logs.debug('rst: looking for %s in %s', ipath, d.abspath()) found = d.find_node(ipath) if found: Logs.debug('rst: found %s as %s', ipath, found.abspath()) nodes.append((itype, found)) if itype == 'include': parse_rst_node(task, found, nodes, names, seen) break if not found: names.append((itype, ipath)) class docutils(Task.Task): """ Compile a rst file. """ def scan(self): """ A recursive regex-based scanner that finds rst dependencies. """ nodes = [] names = [] seen = [] node = self.inputs[0] if not node: return (nodes, names) parse_rst_node(self, node, nodes, names, seen) Logs.debug('rst: %r: found the following file deps: %r', self, nodes) if names: Logs.warn('rst: %r: could not find the following file deps: %r', self, names) return ([v for (t,v) in nodes], [v for (t,v) in names]) def check_status(self, msg, retcode): """ Check an exit status and raise an error with a particular message :param msg: message to display if the code is non-zero :type msg: string :param retcode: condition :type retcode: boolean """ if retcode != 0: raise Errors.WafError('%r command exit status %r' % (msg, retcode)) def run(self): """ Runs the rst compilation using docutils """ raise NotImplementedError() class rst2html(docutils): color = 'BLUE' def __init__(self, *args, **kw): docutils.__init__(self, *args, **kw) self.command = self.generator.env.RST2HTML self.attributes = ['stylesheet'] def scan(self): nodes, names = docutils.scan(self) for attribute in self.attributes: stylesheet = getattr(self.generator, attribute, None) if stylesheet is not None: ssnode = self.generator.to_nodes(stylesheet)[0] nodes.append(ssnode) Logs.debug('rst: adding dep to %s %s', attribute, stylesheet) return nodes, names def run(self): cwdn = self.outputs[0].parent src = self.inputs[0].path_from(cwdn) dst = self.outputs[0].path_from(cwdn) cmd = self.command + [src, dst] cmd += Utils.to_list(getattr(self.generator, 'options', [])) for attribute in self.attributes: stylesheet = getattr(self.generator, attribute, None) if stylesheet is not None: stylesheet = self.generator.to_nodes(stylesheet)[0] cmd += ['--%s' % attribute, stylesheet.path_from(cwdn)] return self.exec_command(cmd, cwd=cwdn.abspath()) class rst2s5(rst2html): def __init__(self, *args, **kw): rst2html.__init__(self, *args, **kw) self.command = self.generator.env.RST2S5 self.attributes = ['stylesheet'] class rst2latex(rst2html): def __init__(self, *args, **kw): rst2html.__init__(self, *args, **kw) self.command = self.generator.env.RST2LATEX self.attributes = ['stylesheet'] class rst2xetex(rst2html): def __init__(self, *args, **kw): rst2html.__init__(self, *args, **kw) self.command = self.generator.env.RST2XETEX self.attributes = ['stylesheet'] class rst2pdf(docutils): color = 'BLUE' def run(self): cwdn = self.outputs[0].parent src = self.inputs[0].path_from(cwdn) dst = self.outputs[0].path_from(cwdn) cmd = self.generator.env.RST2PDF + [src, '-o', dst] cmd += Utils.to_list(getattr(self.generator, 'options', [])) return self.exec_command(cmd, cwd=cwdn.abspath()) @feature('rst') @before_method('process_source') def apply_rst(self): """ Create :py:class:`rst` or other rst-related task objects """ if self.target: if isinstance(self.target, Node.Node): tgt = self.target elif isinstance(self.target, str): tgt = self.path.get_bld().make_node(self.target) else: self.bld.fatal("rst: Don't know how to build target name %s which is not a string or Node for %s" % (self.target, self)) else: tgt = None tsk_type = getattr(self, 'type', None) src = self.to_nodes(self.source) assert len(src) == 1 src = src[0] if tsk_type is not None and tgt is None: if tsk_type.startswith('rst2'): ext = tsk_type[4:] else: self.bld.fatal("rst: Could not detect the output file extension for %s" % self) tgt = src.change_ext('.%s' % ext) elif tsk_type is None and tgt is not None: out = tgt.name ext = out[out.rfind('.')+1:] self.type = 'rst2' + ext elif tsk_type is not None and tgt is not None: # the user knows what he wants pass else: self.bld.fatal("rst: Need to indicate task type or target name for %s" % self) deps_lst = [] if getattr(self, 'deps', None): deps = self.to_list(self.deps) for filename in deps: n = self.path.find_resource(filename) if not n: self.bld.fatal('Could not find %r for %r' % (filename, self)) if not n in deps_lst: deps_lst.append(n) try: task = self.create_task(self.type, src, tgt) except KeyError: self.bld.fatal("rst: Task of type %s not implemented (created by %s)" % (self.type, self)) task.env = self.env # add the manual dependencies if deps_lst: try: lst = self.bld.node_deps[task.uid()] for n in deps_lst: if not n in lst: lst.append(n) except KeyError: self.bld.node_deps[task.uid()] = deps_lst inst_to = getattr(self, 'install_path', None) if inst_to: self.install_task = self.add_install_files(install_to=inst_to, install_from=task.outputs[:]) self.source = [] def configure(self): """ Try to find the rst programs. Do not raise any error if they are not found. You'll have to use additional code in configure() to die if programs were not found. """ for p in rst_progs: self.find_program(p, mandatory=False) hamster-3.0.3/waflib/extras/run_do_script.py000066400000000000000000000115751452646177100212040ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Hans-Martin von Gaudecker, 2012 """ Run a Stata do-script in the directory specified by **ctx.bldnode**. The first and only argument will be the name of the do-script (no extension), which can be accessed inside the do-script by the local macro `1'. Useful for keeping a log file. The tool uses the log file that is automatically kept by Stata only for error-catching purposes, it will be destroyed if the task finished without error. In case of an error in **some_script.do**, you can inspect it as **some_script.log** in the **ctx.bldnode** directory. Note that Stata will not return an error code if it exits abnormally -- catching errors relies on parsing the log file mentioned before. Should the parser behave incorrectly please send an email to hmgaudecker [at] gmail. **WARNING** The tool will not work if multiple do-scripts of the same name---but in different directories---are run at the same time! Avoid this situation. Usage:: ctx(features='run_do_script', source='some_script.do', target=['some_table.tex', 'some_figure.eps'], deps='some_data.csv') """ import os, re, sys from waflib import Task, TaskGen, Logs if sys.platform == 'darwin': STATA_COMMANDS = ['Stata64MP', 'StataMP', 'Stata64SE', 'StataSE', 'Stata64', 'Stata'] STATAFLAGS = '-e -q do' STATAENCODING = 'MacRoman' elif sys.platform.startswith('linux'): STATA_COMMANDS = ['stata-mp', 'stata-se', 'stata'] STATAFLAGS = '-b -q do' # Not sure whether this is correct... STATAENCODING = 'Latin-1' elif sys.platform.lower().startswith('win'): STATA_COMMANDS = ['StataMP-64', 'StataMP-ia', 'StataMP', 'StataSE-64', 'StataSE-ia', 'StataSE', 'Stata-64', 'Stata-ia', 'Stata.e', 'WMPSTATA', 'WSESTATA', 'WSTATA'] STATAFLAGS = '/e do' STATAENCODING = 'Latin-1' else: raise Exception("Unknown sys.platform: %s " % sys.platform) def configure(ctx): ctx.find_program(STATA_COMMANDS, var='STATACMD', errmsg="""\n No Stata executable found!\n\n If Stata is needed:\n 1) Check the settings of your system path. 2) Note we are looking for Stata executables called: %s If yours has a different name, please report to hmgaudecker [at] gmail\n Else:\n Do not load the 'run_do_script' tool in the main wscript.\n\n""" % STATA_COMMANDS) ctx.env.STATAFLAGS = STATAFLAGS ctx.env.STATAENCODING = STATAENCODING class run_do_script_base(Task.Task): """Run a Stata do-script from the bldnode directory.""" run_str = '"${STATACMD}" ${STATAFLAGS} "${SRC[0].abspath()}" "${DOFILETRUNK}"' shell = True class run_do_script(run_do_script_base): """Use the log file automatically kept by Stata for error-catching. Erase it if the task finished without error. If not, it will show up as do_script.log in the bldnode directory. """ def run(self): run_do_script_base.run(self) ret, log_tail = self.check_erase_log_file() if ret: Logs.error("""Running Stata on %r failed with code %r.\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""", self.inputs[0], ret, self.env.LOGFILEPATH, log_tail) return ret def check_erase_log_file(self): """Parse Stata's default log file and erase it if everything okay. Parser is based on Brendan Halpin's shell script found here: http://teaching.sociology.ul.ie/bhalpin/wordpress/?p=122 """ if sys.version_info.major >= 3: kwargs = {'file': self.env.LOGFILEPATH, 'mode': 'r', 'encoding': self.env.STATAENCODING} else: kwargs = {'name': self.env.LOGFILEPATH, 'mode': 'r'} with open(**kwargs) as log: log_tail = log.readlines()[-10:] for line in log_tail: error_found = re.match(r"r\(([0-9]+)\)", line) if error_found: return error_found.group(1), ''.join(log_tail) else: pass # Only end up here if the parser did not identify an error. os.remove(self.env.LOGFILEPATH) return None, None @TaskGen.feature('run_do_script') @TaskGen.before_method('process_source') def apply_run_do_script(tg): """Task generator customising the options etc. to call Stata in batch mode for running a do-script. """ # Convert sources and targets to nodes src_node = tg.path.find_resource(tg.source) tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)] tsk = tg.create_task('run_do_script', src=src_node, tgt=tgt_nodes) tsk.env.DOFILETRUNK = os.path.splitext(src_node.name)[0] tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s.log' % (tsk.env.DOFILETRUNK)) # dependencies (if the attribute 'deps' changes, trigger a recompilation) for x in tg.to_list(getattr(tg, 'deps', [])): node = tg.path.find_resource(x) if not node: tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.abspath())) tsk.dep_nodes.append(node) Logs.debug('deps: found dependencies %r for running %r', tsk.dep_nodes, src_node.abspath()) # Bypass the execution of process_source by setting the source to an empty list tg.source = [] hamster-3.0.3/waflib/extras/run_m_script.py000066400000000000000000000057721452646177100210400ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Hans-Martin von Gaudecker, 2012 """ Run a Matlab script. Note that the script is run in the directory where it lives -- Matlab won't allow it any other way. For error-catching purposes, keep an own log-file that is destroyed if the task finished without error. If not, it will show up as mscript_[index].log in the bldnode directory. Usage:: ctx(features='run_m_script', source='some_script.m', target=['some_table.tex', 'some_figure.eps'], deps='some_data.mat') """ import os, sys from waflib import Task, TaskGen, Logs MATLAB_COMMANDS = ['matlab'] def configure(ctx): ctx.find_program(MATLAB_COMMANDS, var='MATLABCMD', errmsg = """\n No Matlab executable found!\n\n If Matlab is needed:\n 1) Check the settings of your system path. 2) Note we are looking for Matlab executables called: %s If yours has a different name, please report to hmgaudecker [at] gmail\n Else:\n Do not load the 'run_m_script' tool in the main wscript.\n\n""" % MATLAB_COMMANDS) ctx.env.MATLABFLAGS = '-wait -nojvm -nosplash -minimize' class run_m_script_base(Task.Task): """Run a Matlab script.""" run_str = '"${MATLABCMD}" ${MATLABFLAGS} -logfile "${LOGFILEPATH}" -r "try, ${MSCRIPTTRUNK}, exit(0), catch err, disp(err.getReport()), exit(1), end"' shell = True class run_m_script(run_m_script_base): """Erase the Matlab overall log file if everything went okay, else raise an error and print its 10 last lines. """ def run(self): ret = run_m_script_base.run(self) logfile = self.env.LOGFILEPATH if ret: mode = 'r' if sys.version_info.major >= 3: mode = 'rb' with open(logfile, mode=mode) as f: tail = f.readlines()[-10:] Logs.error("""Running Matlab on %r returned the error %r\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""", self.inputs[0], ret, logfile, '\n'.join(tail)) else: os.remove(logfile) return ret @TaskGen.feature('run_m_script') @TaskGen.before_method('process_source') def apply_run_m_script(tg): """Task generator customising the options etc. to call Matlab in batch mode for running a m-script. """ # Convert sources and targets to nodes src_node = tg.path.find_resource(tg.source) tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)] tsk = tg.create_task('run_m_script', src=src_node, tgt=tgt_nodes) tsk.cwd = src_node.parent.abspath() tsk.env.MSCRIPTTRUNK = os.path.splitext(src_node.name)[0] tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s_%d.log' % (tsk.env.MSCRIPTTRUNK, tg.idx)) # dependencies (if the attribute 'deps' changes, trigger a recompilation) for x in tg.to_list(getattr(tg, 'deps', [])): node = tg.path.find_resource(x) if not node: tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.abspath())) tsk.dep_nodes.append(node) Logs.debug('deps: found dependencies %r for running %r', tsk.dep_nodes, src_node.abspath()) # Bypass the execution of process_source by setting the source to an empty list tg.source = [] hamster-3.0.3/waflib/extras/run_py_script.py000066400000000000000000000074141452646177100212270ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Hans-Martin von Gaudecker, 2012 """ Run a Python script in the directory specified by **ctx.bldnode**. Select a Python version by specifying the **version** keyword for the task generator instance as integer 2 or 3. Default is 3. If the build environment has an attribute "PROJECT_PATHS" with a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH. Same a string passed to the optional **add_to_pythonpath** keyword (appended after the PROJECT_ROOT). Usage:: ctx(features='run_py_script', version=3, source='some_script.py', target=['some_table.tex', 'some_figure.eps'], deps='some_data.csv', add_to_pythonpath='src/some/library') """ import os, re from waflib import Task, TaskGen, Logs def configure(conf): """TODO: Might need to be updated for Windows once "PEP 397":http://www.python.org/dev/peps/pep-0397/ is settled. """ conf.find_program('python', var='PY2CMD', mandatory=False) conf.find_program('python3', var='PY3CMD', mandatory=False) if not conf.env.PY2CMD and not conf.env.PY3CMD: conf.fatal("No Python interpreter found!") class run_py_2_script(Task.Task): """Run a Python 2 script.""" run_str = '${PY2CMD} ${SRC[0].abspath()}' shell=True class run_py_3_script(Task.Task): """Run a Python 3 script.""" run_str = '${PY3CMD} ${SRC[0].abspath()}' shell=True @TaskGen.feature('run_py_script') @TaskGen.before_method('process_source') def apply_run_py_script(tg): """Task generator for running either Python 2 or Python 3 on a single script. Attributes: * source -- A **single** source node or string. (required) * target -- A single target or list of targets (nodes or strings) * deps -- A single dependency or list of dependencies (nodes or strings) * add_to_pythonpath -- A string that will be appended to the PYTHONPATH environment variable If the build environment has an attribute "PROJECT_PATHS" with a key "PROJECT_ROOT", its value will be appended to the PYTHONPATH. """ # Set the Python version to use, default to 3. v = getattr(tg, 'version', 3) if v not in (2, 3): raise ValueError("Specify the 'version' attribute for run_py_script task generator as integer 2 or 3.\n Got: %s" %v) # Convert sources and targets to nodes src_node = tg.path.find_resource(tg.source) tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)] # Create the task. tsk = tg.create_task('run_py_%d_script' %v, src=src_node, tgt=tgt_nodes) # custom execution environment # TODO use a list and os.sep.join(lst) at the end instead of concatenating strings tsk.env.env = dict(os.environ) tsk.env.env['PYTHONPATH'] = tsk.env.env.get('PYTHONPATH', '') project_paths = getattr(tsk.env, 'PROJECT_PATHS', None) if project_paths and 'PROJECT_ROOT' in project_paths: tsk.env.env['PYTHONPATH'] += os.pathsep + project_paths['PROJECT_ROOT'].abspath() if getattr(tg, 'add_to_pythonpath', None): tsk.env.env['PYTHONPATH'] += os.pathsep + tg.add_to_pythonpath # Clean up the PYTHONPATH -- replace double occurrences of path separator tsk.env.env['PYTHONPATH'] = re.sub(os.pathsep + '+', os.pathsep, tsk.env.env['PYTHONPATH']) # Clean up the PYTHONPATH -- doesn't like starting with path separator if tsk.env.env['PYTHONPATH'].startswith(os.pathsep): tsk.env.env['PYTHONPATH'] = tsk.env.env['PYTHONPATH'][1:] # dependencies (if the attribute 'deps' changes, trigger a recompilation) for x in tg.to_list(getattr(tg, 'deps', [])): node = tg.path.find_resource(x) if not node: tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.abspath())) tsk.dep_nodes.append(node) Logs.debug('deps: found dependencies %r for running %r', tsk.dep_nodes, src_node.abspath()) # Bypass the execution of process_source by setting the source to an empty list tg.source = [] hamster-3.0.3/waflib/extras/run_r_script.py000066400000000000000000000053161452646177100210370ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Hans-Martin von Gaudecker, 2012 """ Run a R script in the directory specified by **ctx.bldnode**. For error-catching purposes, keep an own log-file that is destroyed if the task finished without error. If not, it will show up as rscript_[index].log in the bldnode directory. Usage:: ctx(features='run_r_script', source='some_script.r', target=['some_table.tex', 'some_figure.eps'], deps='some_data.csv') """ import os, sys from waflib import Task, TaskGen, Logs R_COMMANDS = ['RTerm', 'R', 'r'] def configure(ctx): ctx.find_program(R_COMMANDS, var='RCMD', errmsg = """\n No R executable found!\n\n If R is needed:\n 1) Check the settings of your system path. 2) Note we are looking for R executables called: %s If yours has a different name, please report to hmgaudecker [at] gmail\n Else:\n Do not load the 'run_r_script' tool in the main wscript.\n\n""" % R_COMMANDS) ctx.env.RFLAGS = 'CMD BATCH --slave' class run_r_script_base(Task.Task): """Run a R script.""" run_str = '"${RCMD}" ${RFLAGS} "${SRC[0].abspath()}" "${LOGFILEPATH}"' shell = True class run_r_script(run_r_script_base): """Erase the R overall log file if everything went okay, else raise an error and print its 10 last lines. """ def run(self): ret = run_r_script_base.run(self) logfile = self.env.LOGFILEPATH if ret: mode = 'r' if sys.version_info.major >= 3: mode = 'rb' with open(logfile, mode=mode) as f: tail = f.readlines()[-10:] Logs.error("""Running R on %r returned the error %r\n\nCheck the log file %s, last 10 lines\n\n%s\n\n\n""", self.inputs[0], ret, logfile, '\n'.join(tail)) else: os.remove(logfile) return ret @TaskGen.feature('run_r_script') @TaskGen.before_method('process_source') def apply_run_r_script(tg): """Task generator customising the options etc. to call R in batch mode for running a R script. """ # Convert sources and targets to nodes src_node = tg.path.find_resource(tg.source) tgt_nodes = [tg.path.find_or_declare(t) for t in tg.to_list(tg.target)] tsk = tg.create_task('run_r_script', src=src_node, tgt=tgt_nodes) tsk.env.LOGFILEPATH = os.path.join(tg.bld.bldnode.abspath(), '%s_%d.log' % (os.path.splitext(src_node.name)[0], tg.idx)) # dependencies (if the attribute 'deps' changes, trigger a recompilation) for x in tg.to_list(getattr(tg, 'deps', [])): node = tg.path.find_resource(x) if not node: tg.bld.fatal('Could not find dependency %r for running %r' % (x, src_node.abspath())) tsk.dep_nodes.append(node) Logs.debug('deps: found dependencies %r for running %r', tsk.dep_nodes, src_node.abspath()) # Bypass the execution of process_source by setting the source to an empty list tg.source = [] hamster-3.0.3/waflib/extras/sas.py000066400000000000000000000036321452646177100171130ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Mark Coggeshall, 2010 "SAS support" import os from waflib import Task, Errors, Logs from waflib.TaskGen import feature, before_method sas_fun, _ = Task.compile_fun('sas -sysin ${SRCFILE} -log ${LOGFILE} -print ${LSTFILE}', shell=False) class sas(Task.Task): vars = ['SAS', 'SASFLAGS'] def run(task): command = 'SAS' fun = sas_fun node = task.inputs[0] logfilenode = node.change_ext('.log') lstfilenode = node.change_ext('.lst') # set the cwd task.cwd = task.inputs[0].parent.get_src().abspath() Logs.debug('runner: %r on %r', command, node) SASINPUTS = node.parent.get_bld().abspath() + os.pathsep + node.parent.get_src().abspath() + os.pathsep task.env.env = {'SASINPUTS': SASINPUTS} task.env.SRCFILE = node.abspath() task.env.LOGFILE = logfilenode.abspath() task.env.LSTFILE = lstfilenode.abspath() ret = fun(task) if ret: Logs.error('Running %s on %r returned a non-zero exit', command, node) Logs.error('SRCFILE = %r', node) Logs.error('LOGFILE = %r', logfilenode) Logs.error('LSTFILE = %r', lstfilenode) return ret @feature('sas') @before_method('process_source') def apply_sas(self): if not getattr(self, 'type', None) in ('sas',): self.type = 'sas' self.env['logdir'] = getattr(self, 'logdir', 'log') self.env['lstdir'] = getattr(self, 'lstdir', 'lst') deps_lst = [] if getattr(self, 'deps', None): deps = self.to_list(self.deps) for filename in deps: n = self.path.find_resource(filename) if not n: n = self.bld.root.find_resource(filename) if not n: raise Errors.WafError('cannot find input file %s for processing' % filename) if not n in deps_lst: deps_lst.append(n) for node in self.to_nodes(self.source): if self.type == 'sas': task = self.create_task('sas', src=node) task.dep_nodes = deps_lst self.source = [] def configure(self): self.find_program('sas', var='SAS', mandatory=False) hamster-3.0.3/waflib/extras/satellite_assembly.py000066400000000000000000000041611452646177100222100ustar00rootroot00000000000000#!/usr/bin/python # encoding: utf-8 # vim: tabstop=4 noexpandtab """ Create a satellite assembly from "*.??.txt" files. ?? stands for a language code. The projects Resources subfolder contains resources.??.txt string files for several languages. The build folder will hold the satellite assemblies as ./??/ExeName.resources.dll #gen becomes template (It is called gen because it also uses resx.py). bld(source='Resources/resources.de.txt',gen=ExeName) """ import os, re from waflib import Task from waflib.TaskGen import feature,before_method class al(Task.Task): run_str = '${AL} ${ALFLAGS}' @feature('satellite_assembly') @before_method('process_source') def satellite_assembly(self): if not getattr(self, 'gen', None): self.bld.fatal('satellite_assembly needs a template assembly provided with the "gen" parameter') res_lang = re.compile(r'(.*)\.(\w\w)\.(?:resx|txt)',flags=re.I) # self.source can contain node objects, so this will break in one way or another self.source = self.to_list(self.source) for i, x in enumerate(self.source): #x = 'resources/resources.de.resx' #x = 'resources/resources.de.txt' mo = res_lang.match(x) if mo: template = os.path.splitext(self.gen)[0] templatedir, templatename = os.path.split(template) res = mo.group(1) lang = mo.group(2) #./Resources/resources.de.resources resources = self.path.find_or_declare(res+ '.' + lang + '.resources') self.create_task('resgen', self.to_nodes(x), [resources]) #./de/Exename.resources.dll satellite = self.path.find_or_declare(os.path.join(templatedir,lang,templatename) + '.resources.dll') tsk = self.create_task('al',[resources],[satellite]) tsk.env.append_value('ALFLAGS','/template:'+os.path.join(self.path.relpath(),self.gen)) tsk.env.append_value('ALFLAGS','/embed:'+resources.relpath()) tsk.env.append_value('ALFLAGS','/culture:'+lang) tsk.env.append_value('ALFLAGS','/out:'+satellite.relpath()) self.source[i] = None # remove the None elements that we just substituted self.source = list(filter(lambda x:x, self.source)) def configure(ctx): ctx.find_program('al', var='AL', mandatory=True) ctx.load('resx') hamster-3.0.3/waflib/extras/scala.py000066400000000000000000000063771452646177100174210ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010 (ita) """ Scala support scalac outputs files a bit where it wants to """ import os from waflib import Task, Utils, Node from waflib.TaskGen import feature, before_method, after_method from waflib.Tools import ccroot ccroot.USELIB_VARS['scalac'] = set(['CLASSPATH', 'SCALACFLAGS']) from waflib.Tools import javaw @feature('scalac') @before_method('process_source') def apply_scalac(self): Utils.def_attrs(self, jarname='', classpath='', sourcepath='.', srcdir='.', jar_mf_attributes={}, jar_mf_classpath=[]) outdir = getattr(self, 'outdir', None) if outdir: if not isinstance(outdir, Node.Node): outdir = self.path.get_bld().make_node(self.outdir) else: outdir = self.path.get_bld() outdir.mkdir() self.env['OUTDIR'] = outdir.abspath() self.scalac_task = tsk = self.create_task('scalac') tmp = [] srcdir = getattr(self, 'srcdir', '') if isinstance(srcdir, Node.Node): srcdir = [srcdir] for x in Utils.to_list(srcdir): if isinstance(x, Node.Node): y = x else: y = self.path.find_dir(x) if not y: self.bld.fatal('Could not find the folder %s from %s' % (x, self.path)) tmp.append(y) tsk.srcdir = tmp # reuse some code feature('scalac')(javaw.use_javac_files) after_method('apply_scalac')(javaw.use_javac_files) feature('scalac')(javaw.set_classpath) after_method('apply_scalac', 'use_scalac_files')(javaw.set_classpath) SOURCE_RE = '**/*.scala' class scalac(javaw.javac): color = 'GREEN' vars = ['CLASSPATH', 'SCALACFLAGS', 'SCALAC', 'OUTDIR'] def runnable_status(self): """ Wait for dependent tasks to be complete, then read the file system to find the input nodes. """ for t in self.run_after: if not t.hasrun: return Task.ASK_LATER if not self.inputs: global SOURCE_RE self.inputs = [] for x in self.srcdir: self.inputs.extend(x.ant_glob(SOURCE_RE, remove=False)) return super(javaw.javac, self).runnable_status() def run(self): """ Execute the scalac compiler """ env = self.env gen = self.generator bld = gen.bld wd = bld.bldnode.abspath() def to_list(xx): if isinstance(xx, str): return [xx] return xx self.last_cmd = lst = [] lst.extend(to_list(env['SCALAC'])) lst.extend(['-classpath']) lst.extend(to_list(env['CLASSPATH'])) lst.extend(['-d']) lst.extend(to_list(env['OUTDIR'])) lst.extend(to_list(env['SCALACFLAGS'])) lst.extend([a.abspath() for a in self.inputs]) lst = [x for x in lst if x] try: self.out = self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None, output=0, quiet=0)[1] except: self.generator.bld.cmd_and_log(lst, cwd=wd, env=env.env or None) def configure(self): """ Detect the scalac program """ # If SCALA_HOME is set, we prepend it to the path list java_path = self.environ['PATH'].split(os.pathsep) v = self.env if 'SCALA_HOME' in self.environ: java_path = [os.path.join(self.environ['SCALA_HOME'], 'bin')] + java_path self.env['SCALA_HOME'] = [self.environ['SCALA_HOME']] for x in 'scalac scala'.split(): self.find_program(x, var=x.upper(), path_list=java_path) if 'CLASSPATH' in self.environ: v['CLASSPATH'] = self.environ['CLASSPATH'] v.SCALACFLAGS = ['-verbose'] if not v['SCALAC']: self.fatal('scalac is required for compiling scala classes') hamster-3.0.3/waflib/extras/slow_qt4.py000066400000000000000000000053761452646177100201100ustar00rootroot00000000000000#! /usr/bin/env python # Thomas Nagy, 2011 (ita) """ Create _moc.cpp files The builds are 30-40% faster when .moc files are included, you should NOT use this tool. If you really really want it: def configure(conf): conf.load('compiler_cxx qt4') conf.load('slow_qt4') See playground/slow_qt/wscript for a complete example. """ from waflib.TaskGen import extension from waflib import Task import waflib.Tools.qt4 import waflib.Tools.cxx @extension(*waflib.Tools.qt4.EXT_QT4) def cxx_hook(self, node): return self.create_compiled_task('cxx_qt', node) class cxx_qt(Task.classes['cxx']): def runnable_status(self): ret = Task.classes['cxx'].runnable_status(self) if ret != Task.ASK_LATER and not getattr(self, 'moc_done', None): try: cache = self.generator.moc_cache except AttributeError: cache = self.generator.moc_cache = {} deps = self.generator.bld.node_deps[self.uid()] for x in [self.inputs[0]] + deps: if x.read().find('Q_OBJECT') > 0: # process "foo.h -> foo.moc" only if "foo.cpp" is in the sources for the current task generator # this code will work because it is in the main thread (runnable_status) if x.name.rfind('.') > -1: # a .h file... name = x.name[:x.name.rfind('.')] for tsk in self.generator.compiled_tasks: if tsk.inputs and tsk.inputs[0].name.startswith(name): break else: # no corresponding file, continue continue # the file foo.cpp could be compiled for a static and a shared library - hence the %number in the name cxx_node = x.parent.get_bld().make_node(x.name.replace('.', '_') + '_%d_moc.cpp' % self.generator.idx) if cxx_node in cache: continue cache[cxx_node] = self tsk = Task.classes['moc'](env=self.env, generator=self.generator) tsk.set_inputs(x) tsk.set_outputs(cxx_node) if x.name.endswith('.cpp'): # moc is trying to be too smart but it is too dumb: # why forcing the #include when Q_OBJECT is in the cpp file? gen = self.generator.bld.producer gen.outstanding.append(tsk) gen.total += 1 self.set_run_after(tsk) else: cxxtsk = Task.classes['cxx'](env=self.env, generator=self.generator) cxxtsk.set_inputs(tsk.outputs) cxxtsk.set_outputs(cxx_node.change_ext('.o')) cxxtsk.set_run_after(tsk) try: self.more_tasks.extend([tsk, cxxtsk]) except AttributeError: self.more_tasks = [tsk, cxxtsk] try: link = self.generator.link_task except AttributeError: pass else: link.set_run_after(cxxtsk) link.inputs.extend(cxxtsk.outputs) link.inputs.sort(key=lambda x: x.abspath()) self.moc_done = True for t in self.run_after: if not t.hasrun: return Task.ASK_LATER return ret hamster-3.0.3/waflib/extras/softlink_libs.py000066400000000000000000000045251452646177100211710ustar00rootroot00000000000000#! /usr/bin/env python # per rosengren 2011 from waflib.TaskGen import feature, after_method from waflib.Task import Task, always_run from os.path import basename, isabs from os import tmpfile, linesep def options(opt): grp = opt.add_option_group('Softlink Libraries Options') grp.add_option('--exclude', default='/usr/lib,/lib', help='No symbolic links are created for libs within [%default]') def configure(cnf): cnf.find_program('ldd') if not cnf.env.SOFTLINK_EXCLUDE: cnf.env.SOFTLINK_EXCLUDE = cnf.options.exclude.split(',') @feature('softlink_libs') @after_method('process_rule') def add_finder(self): tgt = self.path.find_or_declare(self.target) self.create_task('sll_finder', tgt=tgt) self.create_task('sll_installer', tgt=tgt) always_run(sll_installer) class sll_finder(Task): ext_out = 'softlink_libs' def run(self): bld = self.generator.bld linked=[] target_paths = [] for g in bld.groups: for tgen in g: # FIXME it might be better to check if there is a link_task (getattr?) target_paths += [tgen.path.get_bld().bldpath()] linked += [t.outputs[0].bldpath() for t in getattr(tgen, 'tasks', []) if t.__class__.__name__ in ['cprogram', 'cshlib', 'cxxprogram', 'cxxshlib']] lib_list = [] if len(linked): cmd = [self.env.LDD] + linked # FIXME add DYLD_LIBRARY_PATH+PATH for osx+win32 ldd_env = {'LD_LIBRARY_PATH': ':'.join(target_paths + self.env.LIBPATH)} # FIXME the with syntax will not work in python 2 with tmpfile() as result: self.exec_command(cmd, env=ldd_env, stdout=result) result.seek(0) for line in result.readlines(): words = line.split() if len(words) < 3 or words[1] != '=>': continue lib = words[2] if lib == 'not': continue if any([lib.startswith(p) for p in [bld.bldnode.abspath(), '('] + self.env.SOFTLINK_EXCLUDE]): continue if not isabs(lib): continue lib_list.append(lib) lib_list = sorted(set(lib_list)) self.outputs[0].write(linesep.join(lib_list + self.env.DYNAMIC_LIBS)) return 0 class sll_installer(Task): ext_in = 'softlink_libs' def run(self): tgt = self.outputs[0] self.generator.bld.install_files('${LIBDIR}', tgt, postpone=False) lib_list=tgt.read().split() for lib in lib_list: self.generator.bld.symlink_as('${LIBDIR}/'+basename(lib), lib, postpone=False) return 0 hamster-3.0.3/waflib/extras/sphinx.py000066400000000000000000000106261452646177100176370ustar00rootroot00000000000000"""Support for Sphinx documentation This is a wrapper for sphinx-build program. Please note that sphinx-build supports only one output format at a time, but the tool can create multiple tasks to handle more. The output formats can be passed via the sphinx_output_format, which is an array of strings. For backwards compatibility if only one output is needed, it can be passed as a single string. The default output format is html. Specific formats can be installed in different directories by specifying the install_path_ attribute. If not defined, the standard install_path will be used instead. Example wscript: def configure(cnf): conf.load('sphinx') def build(bld): bld( features='sphinx', sphinx_source='sources', # path to source directory sphinx_options='-a -v', # sphinx-build program additional options sphinx_output_format=['html', 'man'], # output format of sphinx documentation install_path_man='${DOCDIR}/man' # put man pages in a specific directory ) """ from waflib.Node import Node from waflib import Utils from waflib import Task from waflib.TaskGen import feature, after_method def configure(cnf): """Check if sphinx-build program is available and loads gnu_dirs tool.""" cnf.find_program('sphinx-build', var='SPHINX_BUILD', mandatory=False) cnf.load('gnu_dirs') @feature('sphinx') def build_sphinx(self): """Builds sphinx sources. """ if not self.env.SPHINX_BUILD: self.bld.fatal('Program SPHINX_BUILD not defined.') if not getattr(self, 'sphinx_source', None): self.bld.fatal('Attribute sphinx_source not defined.') if not isinstance(self.sphinx_source, Node): self.sphinx_source = self.path.find_node(self.sphinx_source) if not self.sphinx_source: self.bld.fatal('Can\'t find sphinx_source: %r' % self.sphinx_source) # In the taskgen we have the complete list of formats Utils.def_attrs(self, sphinx_output_format='html') self.sphinx_output_format = Utils.to_list(self.sphinx_output_format) self.env.SPHINX_OPTIONS = getattr(self, 'sphinx_options', []) for source_file in self.sphinx_source.ant_glob('**/*'): self.bld.add_manual_dependency(self.sphinx_source, source_file) for cfmt in self.sphinx_output_format: sphinx_build_task = self.create_task('SphinxBuildingTask') sphinx_build_task.set_inputs(self.sphinx_source) # In task we keep the specific format this task is generating sphinx_build_task.env.SPHINX_OUTPUT_FORMAT = cfmt # the sphinx-build results are in directory sphinx_build_task.sphinx_output_directory = self.path.get_bld().make_node(cfmt) sphinx_build_task.set_outputs(sphinx_build_task.sphinx_output_directory) sphinx_build_task.sphinx_output_directory.mkdir() Utils.def_attrs(sphinx_build_task, install_path=getattr(self, 'install_path_' + cfmt, getattr(self, 'install_path', get_install_path(sphinx_build_task)))) def get_install_path(object): if object.env.SPHINX_OUTPUT_FORMAT == 'man': return object.env.MANDIR elif object.env.SPHINX_OUTPUT_FORMAT == 'info': return object.env.INFODIR else: return object.env.DOCDIR class SphinxBuildingTask(Task.Task): color = 'BOLD' run_str = '${SPHINX_BUILD} -M ${SPHINX_OUTPUT_FORMAT} ${SRC} ${TGT} -d ${TGT[0].bld_dir()}/doctrees-${SPHINX_OUTPUT_FORMAT} ${SPHINX_OPTIONS}' def keyword(self): return 'Compiling (%s)' % self.env.SPHINX_OUTPUT_FORMAT def runnable_status(self): for x in self.run_after: if not x.hasrun: return Task.ASK_LATER self.signature() ret = Task.Task.runnable_status(self) if ret == Task.SKIP_ME: # in case the files were removed self.add_install() return ret def post_run(self): self.add_install() return Task.Task.post_run(self) def add_install(self): nodes = self.sphinx_output_directory.ant_glob('**/*', quiet=True) self.outputs += nodes self.generator.add_install_files(install_to=self.install_path, install_from=nodes, postpone=False, cwd=self.sphinx_output_directory.make_node(self.env.SPHINX_OUTPUT_FORMAT), relative_trick=True) hamster-3.0.3/waflib/extras/stale.py000066400000000000000000000043711452646177100174360ustar00rootroot00000000000000#! /usr/bin/env python # encoding: UTF-8 # Thomas Nagy, 2006-2015 (ita) """ Add a pre-build hook to remove build files (declared in the system) that do not have a corresponding target This can be used for example to remove the targets that have changed name without performing a full 'waf clean' Of course, it will only work if there are no dynamically generated nodes/tasks, in which case the method will have to be modified to exclude some folders for example. Make sure to set bld.post_mode = waflib.Build.POST_AT_ONCE """ from waflib import Logs, Build from waflib.Runner import Parallel DYNAMIC_EXT = [] # add your non-cleanable files/extensions here MOC_H_EXTS = '.cpp .cxx .hpp .hxx .h'.split() def can_delete(node): """Imperfect moc cleanup which does not look for a Q_OBJECT macro in the files""" if not node.name.endswith('.moc'): return True base = node.name[:-4] p1 = node.parent.get_src() p2 = node.parent.get_bld() for k in MOC_H_EXTS: h_name = base + k n = p1.search_node(h_name) if n: return False n = p2.search_node(h_name) if n: return False # foo.cpp.moc, foo.h.moc, etc. if base.endswith(k): return False return True # recursion over the nodes to find the stale files def stale_rec(node, nodes): if node.abspath() in node.ctx.env[Build.CFG_FILES]: return if getattr(node, 'children', []): for x in node.children.values(): if x.name != "c4che": stale_rec(x, nodes) else: for ext in DYNAMIC_EXT: if node.name.endswith(ext): break else: if not node in nodes: if can_delete(node): Logs.warn('Removing stale file -> %r', node) node.delete() old = Parallel.refill_task_list def refill_task_list(self): iit = old(self) bld = self.bld # execute this operation only once if getattr(self, 'stale_done', False): return iit self.stale_done = True # this does not work in partial builds if bld.targets != '*': return iit # this does not work in dynamic builds if getattr(bld, 'post_mode') == Build.POST_AT_ONCE: return iit # obtain the nodes to use during the build nodes = [] for tasks in bld.groups: for x in tasks: try: nodes.extend(x.outputs) except AttributeError: pass stale_rec(bld.bldnode, nodes) return iit Parallel.refill_task_list = refill_task_list hamster-3.0.3/waflib/extras/stracedeps.py000066400000000000000000000100061452646177100204530ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2015 (ita) """ Execute tasks through strace to obtain dependencies after the process is run. This scheme is similar to that of the Fabricate script. To use:: def configure(conf): conf.load('strace') WARNING: * This will not work when advanced scanners are needed (qt4/qt5) * The overhead of running 'strace' is significant (56s -> 1m29s) * It will not work on Windows :-) """ import os, re, threading from waflib import Task, Logs, Utils #TRACECALLS = 'trace=access,chdir,clone,creat,execve,exit_group,fork,lstat,lstat64,mkdir,open,rename,stat,stat64,symlink,vfork' TRACECALLS = 'trace=process,file' BANNED = ('/tmp', '/proc', '/sys', '/dev') s_process = r'(?:clone|fork|vfork)\(.*?(?P\d+)' s_file = r'(?P\w+)\("(?P([^"\\]|\\.)*)"(.*)' re_lines = re.compile(r'^(?P\d+)\s+(?:(?:%s)|(?:%s))\r*$' % (s_file, s_process), re.IGNORECASE | re.MULTILINE) strace_lock = threading.Lock() def configure(conf): conf.find_program('strace') def task_method(func): # Decorator function to bind/replace methods on the base Task class # # The methods Task.exec_command and Task.sig_implicit_deps already exists and are rarely overridden # we thus expect that we are the only ones doing this try: setattr(Task.Task, 'nostrace_%s' % func.__name__, getattr(Task.Task, func.__name__)) except AttributeError: pass setattr(Task.Task, func.__name__, func) return func @task_method def get_strace_file(self): try: return self.strace_file except AttributeError: pass if self.outputs: ret = self.outputs[0].abspath() + '.strace' else: ret = '%s%s%d%s' % (self.generator.bld.bldnode.abspath(), os.sep, id(self), '.strace') self.strace_file = ret return ret @task_method def get_strace_args(self): return (self.env.STRACE or ['strace']) + ['-e', TRACECALLS, '-f', '-o', self.get_strace_file()] @task_method def exec_command(self, cmd, **kw): bld = self.generator.bld if not 'cwd' in kw: kw['cwd'] = self.get_cwd() args = self.get_strace_args() fname = self.get_strace_file() if isinstance(cmd, list): cmd = args + cmd else: cmd = '%s %s' % (' '.join(args), cmd) try: ret = bld.exec_command(cmd, **kw) finally: if not ret: self.parse_strace_deps(fname, kw['cwd']) return ret @task_method def sig_implicit_deps(self): # bypass the scanner functions return @task_method def parse_strace_deps(self, path, cwd): # uncomment the following line to disable the dependencies and force a file scan # return try: cnt = Utils.readf(path) finally: try: os.remove(path) except OSError: pass if not isinstance(cwd, str): cwd = cwd.abspath() nodes = [] bld = self.generator.bld try: cache = bld.strace_cache except AttributeError: cache = bld.strace_cache = {} # chdir and relative paths pid_to_cwd = {} global BANNED done = set() for m in re.finditer(re_lines, cnt): # scraping the output of strace pid = m.group('pid') if m.group('npid'): npid = m.group('npid') pid_to_cwd[npid] = pid_to_cwd.get(pid, cwd) continue p = m.group('path').replace('\\"', '"') if p == '.' or m.group().find('= -1 ENOENT') > -1: # just to speed it up a bit continue if not os.path.isabs(p): p = os.path.join(pid_to_cwd.get(pid, cwd), p) call = m.group('call') if call == 'chdir': pid_to_cwd[pid] = p continue if p in done: continue done.add(p) for x in BANNED: if p.startswith(x): break else: if p.endswith('/') or os.path.isdir(p): continue try: node = cache[p] except KeyError: strace_lock.acquire() try: cache[p] = node = bld.root.find_node(p) if not node: continue finally: strace_lock.release() nodes.append(node) # record the dependencies then force the task signature recalculation for next time if Logs.verbose: Logs.debug('deps: real scanner for %r returned %r', self, nodes) bld = self.generator.bld bld.node_deps[self.uid()] = nodes bld.raw_deps[self.uid()] = [] try: del self.cache_sig except AttributeError: pass self.signature() hamster-3.0.3/waflib/extras/swig.py000066400000000000000000000141621452646177100172760ustar00rootroot00000000000000#! /usr/bin/env python # encoding: UTF-8 # Petar Forai # Thomas Nagy 2008-2010 (ita) import re from waflib import Task, Logs from waflib.TaskGen import extension, feature, after_method from waflib.Configure import conf from waflib.Tools import c_preproc """ tasks have to be added dynamically: - swig interface files may be created at runtime - the module name may be unknown in advance """ SWIG_EXTS = ['.swig', '.i'] re_module = re.compile(r'%module(?:\s*\(.*\))?\s+([^\r\n]+)', re.M) re_1 = re.compile(r'^%module.*?\s+([\w]+)\s*?$', re.M) re_2 = re.compile(r'[#%](?:include|import(?:\(module=".*"\))+|python(?:begin|code)) [<"](.*)[">]', re.M) class swig(Task.Task): color = 'BLUE' run_str = '${SWIG} ${SWIGFLAGS} ${SWIGPATH_ST:INCPATHS} ${SWIGDEF_ST:DEFINES} ${SRC}' ext_out = ['.h'] # might produce .h files although it is not mandatory vars = ['SWIG_VERSION', 'SWIGDEPS'] def runnable_status(self): for t in self.run_after: if not t.hasrun: return Task.ASK_LATER if not getattr(self, 'init_outputs', None): self.init_outputs = True if not getattr(self, 'module', None): # search the module name txt = self.inputs[0].read() m = re_module.search(txt) if not m: raise ValueError("could not find the swig module name") self.module = m.group(1) swig_c(self) # add the language-specific output files as nodes # call funs in the dict swig_langs for x in self.env['SWIGFLAGS']: # obtain the language x = x[1:] try: fun = swig_langs[x] except KeyError: pass else: fun(self) return super(swig, self).runnable_status() def scan(self): "scan for swig dependencies, climb the .i files" lst_src = [] seen = [] missing = [] to_see = [self.inputs[0]] while to_see: node = to_see.pop(0) if node in seen: continue seen.append(node) lst_src.append(node) # read the file code = node.read() code = c_preproc.re_nl.sub('', code) code = c_preproc.re_cpp.sub(c_preproc.repl, code) # find .i files and project headers names = re_2.findall(code) for n in names: for d in self.generator.includes_nodes + [node.parent]: u = d.find_resource(n) if u: to_see.append(u) break else: missing.append(n) return (lst_src, missing) # provide additional language processing swig_langs = {} def swigf(fun): swig_langs[fun.__name__.replace('swig_', '')] = fun return fun swig.swigf = swigf def swig_c(self): ext = '.swigwrap_%d.c' % self.generator.idx flags = self.env['SWIGFLAGS'] if '-c++' in flags: ext += 'xx' out_node = self.inputs[0].parent.find_or_declare(self.module + ext) if '-c++' in flags: c_tsk = self.generator.cxx_hook(out_node) else: c_tsk = self.generator.c_hook(out_node) c_tsk.set_run_after(self) # transfer weights from swig task to c task if getattr(self, 'weight', None): c_tsk.weight = self.weight if getattr(self, 'tree_weight', None): c_tsk.tree_weight = self.tree_weight try: self.more_tasks.append(c_tsk) except AttributeError: self.more_tasks = [c_tsk] try: ltask = self.generator.link_task except AttributeError: pass else: ltask.set_run_after(c_tsk) # setting input nodes does not declare the build order # because the build already started, but it sets # the dependency to enable rebuilds ltask.inputs.append(c_tsk.outputs[0]) self.outputs.append(out_node) if not '-o' in self.env['SWIGFLAGS']: self.env.append_value('SWIGFLAGS', ['-o', self.outputs[0].abspath()]) @swigf def swig_python(tsk): node = tsk.inputs[0].parent if tsk.outdir: node = tsk.outdir tsk.set_outputs(node.find_or_declare(tsk.module+'.py')) @swigf def swig_ocaml(tsk): node = tsk.inputs[0].parent if tsk.outdir: node = tsk.outdir tsk.set_outputs(node.find_or_declare(tsk.module+'.ml')) tsk.set_outputs(node.find_or_declare(tsk.module+'.mli')) @extension(*SWIG_EXTS) def i_file(self, node): # the task instance tsk = self.create_task('swig') tsk.set_inputs(node) tsk.module = getattr(self, 'swig_module', None) flags = self.to_list(getattr(self, 'swig_flags', [])) tsk.env.append_value('SWIGFLAGS', flags) tsk.outdir = None if '-outdir' in flags: outdir = flags[flags.index('-outdir')+1] outdir = tsk.generator.bld.bldnode.make_node(outdir) outdir.mkdir() tsk.outdir = outdir @feature('c', 'cxx', 'd', 'fc', 'asm') @after_method('apply_link', 'process_source') def enforce_swig_before_link(self): try: link_task = self.link_task except AttributeError: pass else: for x in self.tasks: if x.__class__.__name__ == 'swig': link_task.run_after.add(x) @conf def check_swig_version(conf, minver=None): """ Check if the swig tool is found matching a given minimum version. minver should be a tuple, eg. to check for swig >= 1.3.28 pass (1,3,28) as minver. If successful, SWIG_VERSION is defined as 'MAJOR.MINOR' (eg. '1.3') of the actual swig version found. :param minver: minimum version :type minver: tuple of int :return: swig version :rtype: tuple of int """ assert minver is None or isinstance(minver, tuple) swigbin = conf.env['SWIG'] if not swigbin: conf.fatal('could not find the swig executable') # Get swig version string cmd = swigbin + ['-version'] Logs.debug('swig: Running swig command %r', cmd) reg_swig = re.compile(r'SWIG Version\s(.*)', re.M) swig_out = conf.cmd_and_log(cmd) swigver_tuple = tuple([int(s) for s in reg_swig.findall(swig_out)[0].split('.')]) # Compare swig version with the minimum required result = (minver is None) or (swigver_tuple >= minver) if result: # Define useful environment variables swigver = '.'.join([str(x) for x in swigver_tuple[:2]]) conf.env['SWIG_VERSION'] = swigver # Feedback swigver_full = '.'.join(map(str, swigver_tuple[:3])) if minver is None: conf.msg('Checking for swig version', swigver_full) else: minver_str = '.'.join(map(str, minver)) conf.msg('Checking for swig version >= %s' % (minver_str,), swigver_full, color=result and 'GREEN' or 'YELLOW') if not result: conf.fatal('The swig version is too old, expecting %r' % (minver,)) return swigver_tuple def configure(conf): conf.find_program('swig', var='SWIG') conf.env.SWIGPATH_ST = '-I%s' conf.env.SWIGDEF_ST = '-D%s' hamster-3.0.3/waflib/extras/syms.py000066400000000000000000000062101452646177100173130ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ This tool supports the export_symbols_regex to export the symbols in a shared library. by default, all symbols are exported by gcc, and nothing by msvc. to use the tool, do something like: def build(ctx): ctx(features='c cshlib syms', source='a.c b.c', export_symbols_regex='mylib_.*', target='testlib') only the symbols starting with 'mylib_' will be exported. """ import re from waflib.Context import STDOUT from waflib.Task import Task from waflib.Errors import WafError from waflib.TaskGen import feature, after_method class gen_sym(Task): def run(self): obj = self.inputs[0] kw = {} reg = getattr(self.generator, 'export_symbols_regex', '.+?') if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME): re_nm = re.compile(r'External\s+\|\s+_(?P%s)\b' % reg) cmd = (self.env.DUMPBIN or ['dumpbin']) + ['/symbols', obj.abspath()] else: if self.env.DEST_BINFMT == 'pe': #gcc uses nm, and has a preceding _ on windows re_nm = re.compile(r'(T|D)\s+_(?P%s)\b' % reg) elif self.env.DEST_BINFMT=='mac-o': re_nm=re.compile(r'(T|D)\s+(?P_?(%s))\b' % reg) else: re_nm = re.compile(r'(T|D)\s+(?P%s)\b' % reg) cmd = (self.env.NM or ['nm']) + ['-g', obj.abspath()] syms = [m.group('symbol') for m in re_nm.finditer(self.generator.bld.cmd_and_log(cmd, quiet=STDOUT, **kw))] self.outputs[0].write('%r' % syms) class compile_sym(Task): def run(self): syms = {} for x in self.inputs: slist = eval(x.read()) for s in slist: syms[s] = 1 lsyms = list(syms.keys()) lsyms.sort() if self.env.DEST_BINFMT == 'pe': self.outputs[0].write('EXPORTS\n' + '\n'.join(lsyms)) elif self.env.DEST_BINFMT == 'elf': self.outputs[0].write('{ global:\n' + ';\n'.join(lsyms) + ";\nlocal: *; };\n") elif self.env.DEST_BINFMT=='mac-o': self.outputs[0].write('\n'.join(lsyms) + '\n') else: raise WafError('NotImplemented') @feature('syms') @after_method('process_source', 'process_use', 'apply_link', 'process_uselib_local', 'propagate_uselib_vars') def do_the_symbol_stuff(self): def_node = self.path.find_or_declare(getattr(self, 'sym_file', self.target + '.def')) compiled_tasks = getattr(self, 'compiled_tasks', None) if compiled_tasks: ins = [x.outputs[0] for x in compiled_tasks] self.gen_sym_tasks = [self.create_task('gen_sym', x, x.change_ext('.%d.sym' % self.idx)) for x in ins] self.create_task('compile_sym', [x.outputs[0] for x in self.gen_sym_tasks], def_node) link_task = getattr(self, 'link_task', None) if link_task: self.link_task.dep_nodes.append(def_node) if 'msvc' in (self.env.CC_NAME, self.env.CXX_NAME): self.link_task.env.append_value('LINKFLAGS', ['/def:' + def_node.bldpath()]) elif self.env.DEST_BINFMT == 'pe': # gcc on windows takes *.def as an additional input self.link_task.inputs.append(def_node) elif self.env.DEST_BINFMT == 'elf': self.link_task.env.append_value('LINKFLAGS', ['-Wl,-version-script', '-Wl,' + def_node.bldpath()]) elif self.env.DEST_BINFMT=='mac-o': self.link_task.env.append_value('LINKFLAGS',['-Wl,-exported_symbols_list,' + def_node.bldpath()]) else: raise WafError('NotImplemented') hamster-3.0.3/waflib/extras/ticgt.py000066400000000000000000000224021452646177100174330ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Texas Instruments code generator support (experimental) # When reporting issues, please directly assign the bug to the maintainer. __author__ = __maintainer__ = "Jérôme Carretero " __copyright__ = "Jérôme Carretero, 2012" """ TI cgt6x is a compiler suite for TI DSPs. The toolchain does pretty weird things, and I'm sure I'm missing some of them. But still, the tool saves time. What this tool does is: - create a TI compiler environment - create TI compiler features, to handle some specifics about this compiler It has a few idiosyncracies, such as not giving the liberty of the .o file names - automatically activate them when using the TI compiler - handle the tconf tool The tool TODO: - the set_platform_flags() function is not nice - more tests - broaden tool scope, if needed """ import os, re from waflib import Options, Utils, Task, TaskGen from waflib.Tools import c, ccroot, c_preproc from waflib.Configure import conf from waflib.TaskGen import feature, before_method from waflib.Tools.c import cprogram opj = os.path.join @conf def find_ticc(conf): conf.find_program(['cl6x'], var='CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin')) conf.env.CC_NAME = 'ticc' @conf def find_tild(conf): conf.find_program(['lnk6x'], var='LINK_CC', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin')) conf.env.LINK_CC_NAME = 'tild' @conf def find_tiar(conf): conf.find_program(['ar6x'], var='AR', path_list=opj(getattr(Options.options, 'ti-cgt-dir', ""), 'bin')) conf.env.AR_NAME = 'tiar' conf.env.ARFLAGS = 'qru' @conf def ticc_common_flags(conf): v = conf.env if not v['LINK_CC']: v['LINK_CC'] = v['CC'] v['CCLNK_SRC_F'] = [] v['CCLNK_TGT_F'] = ['-o'] v['CPPPATH_ST'] = '-I%s' v['DEFINES_ST'] = '-d%s' v['LIB_ST'] = '-l%s' # template for adding libs v['LIBPATH_ST'] = '-i%s' # template for adding libpaths v['STLIB_ST'] = '-l=%s.lib' v['STLIBPATH_ST'] = '-i%s' # program v['cprogram_PATTERN'] = '%s.out' # static lib #v['LINKFLAGS_cstlib'] = ['-Wl,-Bstatic'] v['cstlib_PATTERN'] = '%s.lib' def configure(conf): v = conf.env v.TI_CGT_DIR = getattr(Options.options, 'ti-cgt-dir', "") v.TI_DSPLINK_DIR = getattr(Options.options, 'ti-dsplink-dir', "") v.TI_BIOSUTILS_DIR = getattr(Options.options, 'ti-biosutils-dir', "") v.TI_DSPBIOS_DIR = getattr(Options.options, 'ti-dspbios-dir', "") v.TI_XDCTOOLS_DIR = getattr(Options.options, 'ti-xdctools-dir', "") conf.find_ticc() conf.find_tiar() conf.find_tild() conf.ticc_common_flags() conf.cc_load_tools() conf.cc_add_flags() conf.link_add_flags() conf.find_program(['tconf'], var='TCONF', path_list=v.TI_XDCTOOLS_DIR) conf.env.TCONF_INCLUDES += [ opj(conf.env.TI_DSPBIOS_DIR, 'packages'), ] conf.env.INCLUDES += [ opj(conf.env.TI_CGT_DIR, 'include'), ] conf.env.LIBPATH += [ opj(conf.env.TI_CGT_DIR, "lib"), ] conf.env.INCLUDES_DSPBIOS += [ opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'include'), ] conf.env.LIBPATH_DSPBIOS += [ opj(conf.env.TI_DSPBIOS_DIR, 'packages', 'ti', 'bios', 'lib'), ] conf.env.INCLUDES_DSPLINK += [ opj(conf.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc'), ] @conf def ti_set_debug(cfg, debug=1): """ Sets debug flags for the compiler. TODO: - for each TI CFLAG/INCLUDES/LINKFLAGS/LIBPATH replace RELEASE by DEBUG - -g --no_compress """ if debug: cfg.env.CFLAGS += "-d_DEBUG -dDEBUG -dDDSP_DEBUG".split() @conf def ti_dsplink_set_platform_flags(cfg, splat, dsp, dspbios_ver, board): """ Sets the INCLUDES, LINKFLAGS for DSPLINK and TCONF_INCLUDES For the specific hardware. Assumes that DSPLINK was built in its own folder. :param splat: short platform name (eg. OMAPL138) :param dsp: DSP name (eg. 674X) :param dspbios_ver: string identifying DspBios version (eg. 5.XX) :param board: board name (eg. OMAPL138GEM) """ d1 = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver) d = opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', 'DspBios', dspbios_ver, board) cfg.env.TCONF_INCLUDES += [d1, d] cfg.env.INCLUDES_DSPLINK += [ opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'inc', dsp), d, ] cfg.env.LINKFLAGS_DSPLINK += [ opj(cfg.env.TI_DSPLINK_DIR, 'dsplink', 'dsp', 'export', 'BIN', 'DspBios', splat, board+'_0', 'RELEASE', 'dsplink%s.lib' % x) for x in ('', 'pool', 'mpcs', 'mplist', 'msg', 'data', 'notify', 'ringio') ] def options(opt): opt.add_option('--with-ti-cgt', type='string', dest='ti-cgt-dir', help = 'Specify alternate cgt root folder', default="") opt.add_option('--with-ti-biosutils', type='string', dest='ti-biosutils-dir', help = 'Specify alternate biosutils folder', default="") opt.add_option('--with-ti-dspbios', type='string', dest='ti-dspbios-dir', help = 'Specify alternate dspbios folder', default="") opt.add_option('--with-ti-dsplink', type='string', dest='ti-dsplink-dir', help = 'Specify alternate dsplink folder', default="") opt.add_option('--with-ti-xdctools', type='string', dest='ti-xdctools-dir', help = 'Specify alternate xdctools folder', default="") class ti_cprogram(cprogram): """ Link object files into a c program Changes: - the linked executable to have a relative path (because we can) - put the LIBPATH first """ run_str = '${LINK_CC} ${LIBPATH_ST:LIBPATH} ${LIB_ST:LIB} ${LINKFLAGS} ${CCLNK_SRC_F}${SRC} ${CCLNK_TGT_F}${TGT[0].bldpath()} ${RPATH_ST:RPATH} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${FRAMEWORK_ST:FRAMEWORK} ${ARCH_ST:ARCH} ${STLIB_MARKER} ${STLIBPATH_ST:STLIBPATH} ${STLIB_ST:STLIB} ${SHLIB_MARKER} ' @feature("c") @before_method('apply_link') def use_ti_cprogram(self): """ Automatically uses ti_cprogram link process """ if 'cprogram' in self.features and self.env.CC_NAME == 'ticc': self.features.insert(0, "ti_cprogram") class ti_c(Task.Task): """ Compile task for the TI codegen compiler This compiler does not allow specifying the output file name, only the output path. """ "Compile C files into object files" run_str = '${CC} ${ARCH_ST:ARCH} ${CFLAGS} ${FRAMEWORKPATH_ST:FRAMEWORKPATH} ${CPPPATH_ST:INCPATHS} ${DEFINES_ST:DEFINES} ${SRC} -c ${OUT} ${CPPFLAGS}' vars = ['CCDEPS'] # unused variable to depend on, just in case ext_in = ['.h'] # set the build order easily by using ext_out=['.h'] scan = c_preproc.scan def create_compiled_task(self, name, node): """ Overrides ccroot.create_compiled_task to support ti_c """ out = '%s' % (node.change_ext('.obj').name) if self.env.CC_NAME == 'ticc': name = 'ti_c' task = self.create_task(name, node, node.parent.find_or_declare(out)) self.env.OUT = '-fr%s' % (node.parent.get_bld().abspath()) try: self.compiled_tasks.append(task) except AttributeError: self.compiled_tasks = [task] return task @TaskGen.extension('.c') def c_hook(self, node): "Bind the c file extension to the creation of a :py:class:`waflib.Tools.c.c` instance" if self.env.CC_NAME == 'ticc': return create_compiled_task(self, 'ti_c', node) else: return self.create_compiled_task('c', node) @feature("ti-tconf") @before_method('process_source') def apply_tconf(self): sources = [x.get_src() for x in self.to_nodes(self.source, path=self.path.get_src())] node = sources[0] assert(sources[0].name.endswith(".tcf")) if len(sources) > 1: assert(sources[1].name.endswith(".cmd")) target = getattr(self, 'target', self.source) target_node = node.get_bld().parent.find_or_declare(node.name) procid = "%d" % int(getattr(self, 'procid', 0)) importpaths = [] includes = Utils.to_list(getattr(self, 'includes', [])) for x in includes + self.env.TCONF_INCLUDES: if x == os.path.abspath(x): importpaths.append(x) else: relpath = self.path.find_node(x).path_from(target_node.parent) importpaths.append(relpath) task = self.create_task('ti_tconf', sources, target_node.change_ext('.cdb')) task.path = self.path task.includes = includes task.cwd = target_node.parent.abspath() task.env = self.env.derive() task.env["TCONFSRC"] = node.path_from(target_node.parent) task.env["TCONFINC"] = '-Dconfig.importPath=%s' % ";".join(importpaths) task.env['TCONFPROGNAME'] = '-Dconfig.programName=%s' % target task.env['PROCID'] = procid task.outputs = [ target_node.change_ext("cfg_c.c"), target_node.change_ext("cfg.s62"), target_node.change_ext("cfg.cmd"), ] create_compiled_task(self, 'ti_c', task.outputs[1]) ctask = create_compiled_task(self, 'ti_c', task.outputs[0]) ctask.env = self.env.derive() self.add_those_o_files(target_node.change_ext("cfg.cmd")) if len(sources) > 1: self.add_those_o_files(sources[1]) self.source = [] re_tconf_include = re.compile(r'(?Putils\.importFile)\("(?P.*)"\)',re.M) class ti_tconf(Task.Task): run_str = '${TCONF} ${TCONFINC} ${TCONFPROGNAME} ${TCONFSRC} ${PROCID}' color = 'PINK' def scan(self): includes = Utils.to_list(getattr(self, 'includes', [])) def deps(node): nodes, names = [], [] if node: code = Utils.readf(node.abspath()) for match in re_tconf_include.finditer(code): path = match.group('file') if path: for x in includes: filename = opj(x, path) fi = self.path.find_resource(filename) if fi: subnodes, subnames = deps(fi) nodes += subnodes names += subnames nodes.append(fi) names.append(path) break return nodes, names return deps(self.inputs[0]) hamster-3.0.3/waflib/extras/unity.py000066400000000000000000000054701452646177100174770ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ Compile whole groups of C/C++ files at once (C and C++ files are processed independently though). To enable globally:: def options(opt): opt.load('compiler_cxx') def build(bld): bld.load('compiler_cxx unity') To enable for specific task generators only:: def build(bld): bld(features='c cprogram unity', source='main.c', ...) The file order is often significant in such builds, so it can be necessary to adjust the order of source files and the batch sizes. To control the amount of files processed in a batch per target (the default is 50):: def build(bld): bld(features='c cprogram', unity_size=20) """ from waflib import Task, Options from waflib.Tools import c_preproc from waflib import TaskGen MAX_BATCH = 50 EXTS_C = ('.c',) EXTS_CXX = ('.cpp','.cc','.cxx','.C','.c++') def options(opt): global MAX_BATCH opt.add_option('--batchsize', action='store', dest='batchsize', type='int', default=MAX_BATCH, help='default unity batch size (0 disables unity builds)') @TaskGen.taskgen_method def batch_size(self): default = getattr(Options.options, 'batchsize', MAX_BATCH) if default < 1: return 0 return getattr(self, 'unity_size', default) class unity(Task.Task): color = 'BLUE' scan = c_preproc.scan def to_include(self, node): ret = node.path_from(self.outputs[0].parent) ret = ret.replace('\\', '\\\\').replace('"', '\\"') return ret def run(self): lst = ['#include "%s"\n' % self.to_include(node) for node in self.inputs] txt = ''.join(lst) self.outputs[0].write(txt) def __str__(self): node = self.outputs[0] return node.path_from(node.ctx.launch_node()) def bind_unity(obj, cls_name, exts): if not 'mappings' in obj.__dict__: obj.mappings = dict(obj.mappings) for j in exts: fun = obj.mappings[j] if fun.__name__ == 'unity_fun': raise ValueError('Attempt to bind unity mappings multiple times %r' % j) def unity_fun(self, node): cnt = self.batch_size() if cnt <= 1: return fun(self, node) x = getattr(self, 'master_%s' % cls_name, None) if not x or len(x.inputs) >= cnt: x = self.create_task('unity') setattr(self, 'master_%s' % cls_name, x) cnt_cur = getattr(self, 'cnt_%s' % cls_name, 0) c_node = node.parent.find_or_declare('unity_%s_%d_%d.%s' % (self.idx, cnt_cur, cnt, cls_name)) x.outputs = [c_node] setattr(self, 'cnt_%s' % cls_name, cnt_cur + 1) fun(self, c_node) x.inputs.append(node) obj.mappings[j] = unity_fun @TaskGen.feature('unity') @TaskGen.before('process_source') def single_unity(self): lst = self.to_list(self.features) if 'c' in lst: bind_unity(self, 'c', EXTS_C) if 'cxx' in lst: bind_unity(self, 'cxx', EXTS_CXX) def build(bld): if bld.env.CC_NAME: bind_unity(TaskGen.task_gen, 'c', EXTS_C) if bld.env.CXX_NAME: bind_unity(TaskGen.task_gen, 'cxx', EXTS_CXX) hamster-3.0.3/waflib/extras/use_config.py000066400000000000000000000130311452646177100204400ustar00rootroot00000000000000#!/usr/bin/env python # coding=utf-8 # Mathieu Courtois - EDF R&D, 2013 - http://www.code-aster.org """ When a project has a lot of options the 'waf configure' command line can be very long and it becomes a cause of error. This tool provides a convenient way to load a set of configuration parameters from a local file or from a remote url. The configuration parameters are stored in a Python file that is imported as an extra waf tool can be. Example: $ waf configure --use-config-dir=http://www.anywhere.org --use-config=myconf1 ... The file 'myconf1' will be downloaded from 'http://www.anywhere.org' (or 'http://www.anywhere.org/wafcfg'). If the files are available locally, it could be: $ waf configure --use-config-dir=/somewhere/myconfigurations --use-config=myconf1 ... The configuration of 'myconf1.py' is automatically loaded by calling its 'configure' function. In this example, it defines environment variables and set options: def configure(self): self.env['CC'] = 'gcc-4.8' self.env.append_value('LIBPATH', [...]) self.options.perlbinary = '/usr/local/bin/perl' self.options.pyc = False The corresponding command line should have been: $ CC=gcc-4.8 LIBPATH=... waf configure --nopyc --with-perl-binary=/usr/local/bin/perl This is an extra tool, not bundled with the default waf binary. To add the use_config tool to the waf file: $ ./waf-light --tools=use_config When using this tool, the wscript will look like: def options(opt): opt.load('use_config') def configure(conf): conf.load('use_config') """ import sys import os.path as osp import os local_repo = '' """Local repository containing additional Waf tools (plugins)""" remote_repo = 'https://gitlab.com/ita1024/waf/raw/master/' """ Remote directory containing downloadable waf tools. The missing tools can be downloaded by using:: $ waf configure --download """ remote_locs = ['waflib/extras', 'waflib/Tools'] """ Remote directories for use with :py:const:`waflib.extras.use_config.remote_repo` """ try: from urllib import request except ImportError: from urllib import urlopen else: urlopen = request.urlopen from waflib import Errors, Context, Logs, Utils, Options, Configure try: from urllib.parse import urlparse except ImportError: from urlparse import urlparse DEFAULT_DIR = 'wafcfg' # add first the current wafcfg subdirectory sys.path.append(osp.abspath(DEFAULT_DIR)) def options(self): group = self.add_option_group('configure options') group.add_option('--download', dest='download', default=False, action='store_true', help='try to download the tools if missing') group.add_option('--use-config', action='store', default=None, metavar='CFG', dest='use_config', help='force the configuration parameters by importing ' 'CFG.py. Several modules may be provided (comma ' 'separated).') group.add_option('--use-config-dir', action='store', default=DEFAULT_DIR, metavar='CFG_DIR', dest='use_config_dir', help='path or url where to find the configuration file') def download_check(node): """ Hook to check for the tools which are downloaded. Replace with your function if necessary. """ pass def download_tool(tool, force=False, ctx=None): """ Download a Waf tool from the remote repository defined in :py:const:`waflib.extras.use_config.remote_repo`:: $ waf configure --download """ for x in Utils.to_list(remote_repo): for sub in Utils.to_list(remote_locs): url = '/'.join((x, sub, tool + '.py')) try: web = urlopen(url) try: if web.getcode() != 200: continue except AttributeError: pass except Exception: # on python3 urlopen throws an exception # python 2.3 does not have getcode and throws an exception to fail continue else: tmp = ctx.root.make_node(os.sep.join((Context.waf_dir, 'waflib', 'extras', tool + '.py'))) tmp.write(web.read(), 'wb') Logs.warn('Downloaded %s from %s', tool, url) download_check(tmp) try: module = Context.load_tool(tool) except Exception: Logs.warn('The tool %s from %s is unusable', tool, url) try: tmp.delete() except Exception: pass continue return module raise Errors.WafError('Could not load the Waf tool') def load_tool(tool, tooldir=None, ctx=None, with_sys_path=True): try: module = Context.load_tool_default(tool, tooldir, ctx, with_sys_path) except ImportError as e: if not ctx or not hasattr(Options.options, 'download'): Logs.error('Could not load %r during options phase (download unavailable at this point)' % tool) raise if Options.options.download: module = download_tool(tool, ctx=ctx) if not module: ctx.fatal('Could not load the Waf tool %r or download a suitable replacement from the repository (sys.path %r)\n%s' % (tool, sys.path, e)) else: ctx.fatal('Could not load the Waf tool %r from %r (try the --download option?):\n%s' % (tool, sys.path, e)) return module Context.load_tool_default = Context.load_tool Context.load_tool = load_tool Configure.download_tool = download_tool def configure(self): opts = self.options use_cfg = opts.use_config if use_cfg is None: return url = urlparse(opts.use_config_dir) kwargs = {} if url.scheme: kwargs['download'] = True kwargs['remote_url'] = url.geturl() # search first with the exact url, else try with +'/wafcfg' kwargs['remote_locs'] = ['', DEFAULT_DIR] tooldir = url.geturl() + ' ' + DEFAULT_DIR for cfg in use_cfg.split(','): Logs.pprint('NORMAL', "Searching configuration '%s'..." % cfg) self.load(cfg, tooldir=tooldir, **kwargs) self.start_msg('Checking for configuration') self.end_msg(use_cfg) hamster-3.0.3/waflib/extras/valadoc.py000066400000000000000000000105351452646177100177360ustar00rootroot00000000000000#! /usr/bin/env python # encoding: UTF-8 # Nicolas Joseph 2009 """ ported from waf 1.5: TODO: tabs vs spaces """ from waflib import Task, Utils, Errors, Logs from waflib.TaskGen import feature VALADOC_STR = '${VALADOC}' class valadoc(Task.Task): vars = ['VALADOC', 'VALADOCFLAGS'] color = 'BLUE' after = ['cprogram', 'cstlib', 'cshlib', 'cxxprogram', 'cxxstlib', 'cxxshlib'] quiet = True # no outputs .. this is weird def __init__(self, *k, **kw): Task.Task.__init__(self, *k, **kw) self.output_dir = '' self.doclet = '' self.package_name = '' self.package_version = '' self.files = [] self.vapi_dirs = [] self.protected = True self.private = False self.inherit = False self.deps = False self.vala_defines = [] self.vala_target_glib = None self.enable_non_null_experimental = False self.force = False def run(self): if not self.env['VALADOCFLAGS']: self.env['VALADOCFLAGS'] = '' cmd = [Utils.subst_vars(VALADOC_STR, self.env)] cmd.append ('-o %s' % self.output_dir) if getattr(self, 'doclet', None): cmd.append ('--doclet %s' % self.doclet) cmd.append ('--package-name %s' % self.package_name) if getattr(self, 'package_version', None): cmd.append ('--package-version %s' % self.package_version) if getattr(self, 'packages', None): for package in self.packages: cmd.append ('--pkg %s' % package) if getattr(self, 'vapi_dirs', None): for vapi_dir in self.vapi_dirs: cmd.append ('--vapidir %s' % vapi_dir) if not getattr(self, 'protected', None): cmd.append ('--no-protected') if getattr(self, 'private', None): cmd.append ('--private') if getattr(self, 'inherit', None): cmd.append ('--inherit') if getattr(self, 'deps', None): cmd.append ('--deps') if getattr(self, 'vala_defines', None): for define in self.vala_defines: cmd.append ('--define %s' % define) if getattr(self, 'vala_target_glib', None): cmd.append ('--target-glib=%s' % self.vala_target_glib) if getattr(self, 'enable_non_null_experimental', None): cmd.append ('--enable-non-null-experimental') if getattr(self, 'force', None): cmd.append ('--force') cmd.append (' '.join ([x.abspath() for x in self.files])) return self.generator.bld.exec_command(' '.join(cmd)) @feature('valadoc') def process_valadoc(self): """ Generate API documentation from Vala source code with valadoc doc = bld( features = 'valadoc', output_dir = '../doc/html', package_name = 'vala-gtk-example', package_version = '1.0.0', packages = 'gtk+-2.0', vapi_dirs = '../vapi', force = True ) path = bld.path.find_dir ('../src') doc.files = path.ant_glob (incl='**/*.vala') """ task = self.create_task('valadoc') if getattr(self, 'output_dir', None): task.output_dir = self.path.find_or_declare(self.output_dir).abspath() else: Errors.WafError('no output directory') if getattr(self, 'doclet', None): task.doclet = self.doclet else: Errors.WafError('no doclet directory') if getattr(self, 'package_name', None): task.package_name = self.package_name else: Errors.WafError('no package name') if getattr(self, 'package_version', None): task.package_version = self.package_version if getattr(self, 'packages', None): task.packages = Utils.to_list(self.packages) if getattr(self, 'vapi_dirs', None): vapi_dirs = Utils.to_list(self.vapi_dirs) for vapi_dir in vapi_dirs: try: task.vapi_dirs.append(self.path.find_dir(vapi_dir).abspath()) except AttributeError: Logs.warn('Unable to locate Vala API directory: %r', vapi_dir) if getattr(self, 'files', None): task.files = self.files else: Errors.WafError('no input file') if getattr(self, 'protected', None): task.protected = self.protected if getattr(self, 'private', None): task.private = self.private if getattr(self, 'inherit', None): task.inherit = self.inherit if getattr(self, 'deps', None): task.deps = self.deps if getattr(self, 'vala_defines', None): task.vala_defines = Utils.to_list(self.vala_defines) if getattr(self, 'vala_target_glib', None): task.vala_target_glib = self.vala_target_glib if getattr(self, 'enable_non_null_experimental', None): task.enable_non_null_experimental = self.enable_non_null_experimental if getattr(self, 'force', None): task.force = self.force def configure(conf): conf.find_program('valadoc', errmsg='You must install valadoc for generate the API documentation') hamster-3.0.3/waflib/extras/waf_xattr.py000066400000000000000000000100601452646177100203150ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ Use extended attributes instead of database files 1. Input files will be made writable 2. This is only for systems providing extended filesystem attributes 3. By default, hashes are calculated only if timestamp/size change (HASH_CACHE below) 4. The module enables "deep_inputs" on all tasks by propagating task signatures 5. This module also skips task signature comparisons for task code changes due to point 4. 6. This module is for Python3/Linux only, but it could be extended to Python2/other systems using the xattr library 7. For projects in which tasks always declare output files, it should be possible to store the rest of build context attributes on output files (imp_sigs, raw_deps and node_deps) but this is not done here On a simple C++ project benchmark, the variations before and after adding waf_xattr.py were observed: total build time: 20s -> 22s no-op build time: 2.4s -> 1.8s pickle file size: 2.9MB -> 2.6MB """ import os from waflib import Logs, Node, Task, Utils, Errors from waflib.Task import SKIP_ME, RUN_ME, CANCEL_ME, ASK_LATER, SKIPPED, MISSING HASH_CACHE = True SIG_VAR = 'user.waf.sig' SEP = ','.encode() TEMPLATE = '%b%d,%d'.encode() try: PermissionError except NameError: PermissionError = IOError def getxattr(self): return os.getxattr(self.abspath(), SIG_VAR) def setxattr(self, val): os.setxattr(self.abspath(), SIG_VAR, val) def h_file(self): try: ret = getxattr(self) except OSError: if HASH_CACHE: st = os.stat(self.abspath()) mtime = st.st_mtime size = st.st_size else: if len(ret) == 16: # for build directory files return ret if HASH_CACHE: # check if timestamp and mtime match to avoid re-hashing st = os.stat(self.abspath()) mtime, size = ret[16:].split(SEP) if int(1000 * st.st_mtime) == int(mtime) and st.st_size == int(size): return ret[:16] ret = Utils.h_file(self.abspath()) if HASH_CACHE: val = TEMPLATE % (ret, int(1000 * st.st_mtime), int(st.st_size)) try: setxattr(self, val) except PermissionError: os.chmod(self.abspath(), st.st_mode | 128) setxattr(self, val) return ret def runnable_status(self): bld = self.generator.bld if bld.is_install < 0: return SKIP_ME for t in self.run_after: if not t.hasrun: return ASK_LATER elif t.hasrun < SKIPPED: # a dependency has an error return CANCEL_ME # first compute the signature try: new_sig = self.signature() except Errors.TaskNotReady: return ASK_LATER if not self.outputs: # compare the signature to a signature computed previously # this part is only for tasks with no output files key = self.uid() try: prev_sig = bld.task_sigs[key] except KeyError: Logs.debug('task: task %r must run: it was never run before or the task code changed', self) return RUN_ME if new_sig != prev_sig: Logs.debug('task: task %r must run: the task signature changed', self) return RUN_ME # compare the signatures of the outputs to make a decision for node in self.outputs: try: sig = node.h_file() except EnvironmentError: Logs.debug('task: task %r must run: an output node does not exist', self) return RUN_ME if sig != new_sig: Logs.debug('task: task %r must run: an output node is stale', self) return RUN_ME return (self.always_run and RUN_ME) or SKIP_ME def post_run(self): bld = self.generator.bld sig = self.signature() for node in self.outputs: if not node.exists(): self.hasrun = MISSING self.err_msg = '-> missing file: %r' % node.abspath() raise Errors.WafError(self.err_msg) os.setxattr(node.abspath(), 'user.waf.sig', sig) if not self.outputs: # only for task with no outputs bld.task_sigs[self.uid()] = sig if not self.keep_last_cmd: try: del self.last_cmd except AttributeError: pass try: os.getxattr except AttributeError: pass else: h_file.__doc__ = Node.Node.h_file.__doc__ # keep file hashes as file attributes Node.Node.h_file = h_file # enable "deep_inputs" on all tasks Task.Task.runnable_status = runnable_status Task.Task.post_run = post_run Task.Task.sig_deep_inputs = Utils.nada hamster-3.0.3/waflib/extras/wafcache.py000066400000000000000000000445751452646177100201010ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2019 (ita) """ Filesystem-based cache system to share and re-use build artifacts Cache access operations (copy to and from) are delegated to independent pre-forked worker subprocesses. The following environment variables may be set: * WAFCACHE: several possibilities: - File cache: absolute path of the waf cache (~/.cache/wafcache_user, where `user` represents the currently logged-in user) - URL to a cache server, for example: export WAFCACHE=http://localhost:8080/files/ in that case, GET/POST requests are made to urls of the form http://localhost:8080/files/000000000/0 (cache management is delegated to the server) - GCS, S3 or MINIO bucket gs://my-bucket/ (uses gsutil command line tool or WAFCACHE_CMD) s3://my-bucket/ (uses aws command line tool or WAFCACHE_CMD) minio://my-bucket/ (uses mc command line tool or WAFCACHE_CMD) * WAFCACHE_CMD: bucket upload/download command, for example: WAFCACHE_CMD="gsutil cp %{SRC} %{TGT}" Note that the WAFCACHE bucket value is used for the source or destination depending on the operation (upload or download). For example, with: WAFCACHE="gs://mybucket/" the following commands may be run: gsutil cp build/myprogram gs://mybucket/aa/aaaaa/1 gsutil cp gs://mybucket/bb/bbbbb/2 build/somefile * WAFCACHE_NO_PUSH: if set, disables pushing to the cache * WAFCACHE_VERBOSITY: if set, displays more detailed cache operations * WAFCACHE_STATS: if set, displays cache usage statistics on exit File cache specific options: Files are copied using hard links by default; if the cache is located onto another partition, the system switches to file copies instead. * WAFCACHE_TRIM_MAX_FOLDER: maximum amount of tasks to cache (1M) * WAFCACHE_EVICT_MAX_BYTES: maximum amount of cache size in bytes (10GB) * WAFCACHE_EVICT_INTERVAL_MINUTES: minimum time interval to try and trim the cache (3 minutes) Upload specific options: * WAFCACHE_ASYNC_WORKERS: define a number of workers to upload results asynchronously this may improve build performance with many/long file uploads the default is unset (synchronous uploads) * WAFCACHE_ASYNC_NOWAIT: do not wait for uploads to complete (default: False) this requires asynchonous uploads to have an effect Usage:: def build(bld): bld.load('wafcache') ... To troubleshoot:: waf clean build --zone=wafcache """ import atexit, base64, errno, fcntl, getpass, os, re, shutil, sys, time, threading, traceback, urllib3, shlex try: import subprocess32 as subprocess except ImportError: import subprocess base_cache = os.path.expanduser('~/.cache/') if not os.path.isdir(base_cache): base_cache = '/tmp/' default_wafcache_dir = os.path.join(base_cache, 'wafcache_' + getpass.getuser()) CACHE_DIR = os.environ.get('WAFCACHE', default_wafcache_dir) WAFCACHE_CMD = os.environ.get('WAFCACHE_CMD') TRIM_MAX_FOLDERS = int(os.environ.get('WAFCACHE_TRIM_MAX_FOLDER', 1000000)) EVICT_INTERVAL_MINUTES = int(os.environ.get('WAFCACHE_EVICT_INTERVAL_MINUTES', 3)) EVICT_MAX_BYTES = int(os.environ.get('WAFCACHE_EVICT_MAX_BYTES', 10**10)) WAFCACHE_NO_PUSH = 1 if os.environ.get('WAFCACHE_NO_PUSH') else 0 WAFCACHE_VERBOSITY = 1 if os.environ.get('WAFCACHE_VERBOSITY') else 0 WAFCACHE_STATS = 1 if os.environ.get('WAFCACHE_STATS') else 0 WAFCACHE_ASYNC_WORKERS = os.environ.get('WAFCACHE_ASYNC_WORKERS') WAFCACHE_ASYNC_NOWAIT = os.environ.get('WAFCACHE_ASYNC_NOWAIT') OK = "ok" re_waf_cmd = re.compile('(?P%{SRC})|(?P%{TGT})') try: import cPickle except ImportError: import pickle as cPickle if __name__ != '__main__': from waflib import Task, Logs, Utils, Build def can_retrieve_cache(self): """ New method for waf Task classes """ if not self.outputs: return False self.cached = False sig = self.signature() ssig = Utils.to_hex(self.uid() + sig) if WAFCACHE_STATS: self.generator.bld.cache_reqs += 1 files_to = [node.abspath() for node in self.outputs] proc = get_process() err = cache_command(proc, ssig, [], files_to) process_pool.append(proc) if err.startswith(OK): if WAFCACHE_VERBOSITY: Logs.pprint('CYAN', ' Fetched %r from cache' % files_to) else: Logs.debug('wafcache: fetched %r from cache', files_to) if WAFCACHE_STATS: self.generator.bld.cache_hits += 1 else: if WAFCACHE_VERBOSITY: Logs.pprint('YELLOW', ' No cache entry %s' % files_to) else: Logs.debug('wafcache: No cache entry %s: %s', files_to, err) return False self.cached = True return True def put_files_cache(self): """ New method for waf Task classes """ if WAFCACHE_NO_PUSH or getattr(self, 'cached', None) or not self.outputs: return files_from = [] for node in self.outputs: path = node.abspath() if not os.path.isfile(path): return files_from.append(path) bld = self.generator.bld old_sig = self.signature() for node in self.inputs: try: del node.ctx.cache_sig[node] except KeyError: pass delattr(self, 'cache_sig') sig = self.signature() def _async_put_files_cache(bld, ssig, files_from): proc = get_process() if WAFCACHE_ASYNC_WORKERS: with bld.wafcache_lock: if bld.wafcache_stop: process_pool.append(proc) return bld.wafcache_procs.add(proc) err = cache_command(proc, ssig, files_from, []) process_pool.append(proc) if err.startswith(OK): if WAFCACHE_VERBOSITY: Logs.pprint('CYAN', ' Successfully uploaded %s to cache' % files_from) else: Logs.debug('wafcache: Successfully uploaded %r to cache', files_from) if WAFCACHE_STATS: bld.cache_puts += 1 else: if WAFCACHE_VERBOSITY: Logs.pprint('RED', ' Error caching step results %s: %s' % (files_from, err)) else: Logs.debug('wafcache: Error caching results %s: %s', files_from, err) if old_sig == sig: ssig = Utils.to_hex(self.uid() + sig) if WAFCACHE_ASYNC_WORKERS: fut = bld.wafcache_executor.submit(_async_put_files_cache, bld, ssig, files_from) bld.wafcache_uploads.append(fut) else: _async_put_files_cache(bld, ssig, files_from) else: Logs.debug('wafcache: skipped %r upload due to late input modifications %r', self.outputs, self.inputs) bld.task_sigs[self.uid()] = self.cache_sig def hash_env_vars(self, env, vars_lst): """ Reimplement BuildContext.hash_env_vars so that the resulting hash does not depend on local paths """ if not env.table: env = env.parent if not env: return Utils.SIG_NIL idx = str(id(env)) + str(vars_lst) try: cache = self.cache_env except AttributeError: cache = self.cache_env = {} else: try: return self.cache_env[idx] except KeyError: pass v = str([env[a] for a in vars_lst]) v = v.replace(self.srcnode.abspath().__repr__()[:-1], '') m = Utils.md5() m.update(v.encode()) ret = m.digest() Logs.debug('envhash: %r %r', ret, v) cache[idx] = ret return ret def uid(self): """ Reimplement Task.uid() so that the signature does not depend on local paths """ try: return self.uid_ except AttributeError: m = Utils.md5() src = self.generator.bld.srcnode up = m.update up(self.__class__.__name__.encode()) for x in self.inputs + self.outputs: up(x.path_from(src).encode()) self.uid_ = m.digest() return self.uid_ def make_cached(cls): """ Enable the waf cache for a given task class """ if getattr(cls, 'nocache', None) or getattr(cls, 'has_cache', False): return full_name = "%s.%s" % (cls.__module__, cls.__name__) if full_name in ('waflib.Tools.ccroot.vnum', 'waflib.Build.inst'): return m1 = getattr(cls, 'run', None) def run(self): if getattr(self, 'nocache', False): return m1(self) if self.can_retrieve_cache(): return 0 return m1(self) cls.run = run m2 = getattr(cls, 'post_run', None) def post_run(self): if getattr(self, 'nocache', False): return m2(self) ret = m2(self) self.put_files_cache() return ret cls.post_run = post_run cls.has_cache = True process_pool = [] def get_process(): """ Returns a worker process that can process waf cache commands The worker process is assumed to be returned to the process pool when unused """ try: return process_pool.pop() except IndexError: filepath = os.path.dirname(os.path.abspath(__file__)) + os.sep + 'wafcache.py' cmd = [sys.executable, '-c', Utils.readf(filepath)] return subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, bufsize=0) def atexit_pool(): for proc in process_pool: proc.kill() atexit.register(atexit_pool) def build(bld): """ Called during the build process to enable file caching """ if WAFCACHE_ASYNC_WORKERS: try: num_workers = int(WAFCACHE_ASYNC_WORKERS) except ValueError: Logs.warn('Invalid WAFCACHE_ASYNC_WORKERS specified: %r' % WAFCACHE_ASYNC_WORKERS) else: from concurrent.futures import ThreadPoolExecutor bld.wafcache_executor = ThreadPoolExecutor(max_workers=num_workers) bld.wafcache_uploads = [] bld.wafcache_procs = set([]) bld.wafcache_stop = False bld.wafcache_lock = threading.Lock() def finalize_upload_async(bld): if WAFCACHE_ASYNC_NOWAIT: with bld.wafcache_lock: bld.wafcache_stop = True for fut in reversed(bld.wafcache_uploads): fut.cancel() for proc in bld.wafcache_procs: proc.kill() bld.wafcache_procs.clear() else: Logs.pprint('CYAN', '... waiting for wafcache uploads to complete (%s uploads)' % len(bld.wafcache_uploads)) bld.wafcache_executor.shutdown(wait=True) bld.add_post_fun(finalize_upload_async) if WAFCACHE_STATS: # Init counter for statistics and hook to print results at the end bld.cache_reqs = bld.cache_hits = bld.cache_puts = 0 def printstats(bld): hit_ratio = 0 if bld.cache_reqs > 0: hit_ratio = (bld.cache_hits / bld.cache_reqs) * 100 Logs.pprint('CYAN', ' wafcache stats: %s requests, %s hits (ratio: %.2f%%), %s writes' % (bld.cache_reqs, bld.cache_hits, hit_ratio, bld.cache_puts) ) bld.add_post_fun(printstats) if process_pool: # already called once return # pre-allocation processes = [get_process() for x in range(bld.jobs)] process_pool.extend(processes) Task.Task.can_retrieve_cache = can_retrieve_cache Task.Task.put_files_cache = put_files_cache Task.Task.uid = uid Build.BuildContext.hash_env_vars = hash_env_vars for x in reversed(list(Task.classes.values())): make_cached(x) def cache_command(proc, sig, files_from, files_to): """ Create a command for cache worker processes, returns a pickled base64-encoded tuple containing the task signature, a list of files to cache and a list of files files to get from cache (one of the lists is assumed to be empty) """ obj = base64.b64encode(cPickle.dumps([sig, files_from, files_to])) proc.stdin.write(obj) proc.stdin.write('\n'.encode()) proc.stdin.flush() obj = proc.stdout.readline() if not obj: raise OSError('Preforked sub-process %r died' % proc.pid) return cPickle.loads(base64.b64decode(obj)) try: copyfun = os.link except NameError: copyfun = shutil.copy2 def atomic_copy(orig, dest): """ Copy files to the cache, the operation is atomic for a given file """ global copyfun tmp = dest + '.tmp' up = os.path.dirname(dest) try: os.makedirs(up) except OSError: pass try: copyfun(orig, tmp) except OSError as e: if e.errno == errno.EXDEV: copyfun = shutil.copy2 copyfun(orig, tmp) else: raise os.rename(tmp, dest) def lru_trim(): """ the cache folders take the form: `CACHE_DIR/0b/0b180f82246d726ece37c8ccd0fb1cde2650d7bfcf122ec1f169079a3bfc0ab9` they are listed in order of last access, and then removed until the amount of folders is within TRIM_MAX_FOLDERS and the total space taken by files is less than EVICT_MAX_BYTES """ lst = [] for up in os.listdir(CACHE_DIR): if len(up) == 2: sub = os.path.join(CACHE_DIR, up) for hval in os.listdir(sub): path = os.path.join(sub, hval) size = 0 for fname in os.listdir(path): try: size += os.lstat(os.path.join(path, fname)).st_size except OSError: pass lst.append((os.stat(path).st_mtime, size, path)) lst.sort(key=lambda x: x[0]) lst.reverse() tot = sum(x[1] for x in lst) while tot > EVICT_MAX_BYTES or len(lst) > TRIM_MAX_FOLDERS: _, tmp_size, path = lst.pop() tot -= tmp_size tmp = path + '.remove' try: shutil.rmtree(tmp) except OSError: pass try: os.rename(path, tmp) except OSError: sys.stderr.write('Could not rename %r to %r\n' % (path, tmp)) else: try: shutil.rmtree(tmp) except OSError: sys.stderr.write('Could not remove %r\n' % tmp) sys.stderr.write("Cache trimmed: %r bytes in %r folders left\n" % (tot, len(lst))) def lru_evict(): """ Reduce the cache size """ lockfile = os.path.join(CACHE_DIR, 'all.lock') try: st = os.stat(lockfile) except EnvironmentError as e: if e.errno == errno.ENOENT: with open(lockfile, 'w') as f: f.write('') return else: raise if st.st_mtime < time.time() - EVICT_INTERVAL_MINUTES * 60: # check every EVICT_INTERVAL_MINUTES minutes if the cache is too big # OCLOEXEC is unnecessary because no processes are spawned fd = os.open(lockfile, os.O_RDWR | os.O_CREAT, 0o755) try: try: fcntl.flock(fd, fcntl.LOCK_EX | fcntl.LOCK_NB) except EnvironmentError: if WAFCACHE_VERBOSITY: sys.stderr.write('wafcache: another cleaning process is running\n') else: # now dow the actual cleanup lru_trim() os.utime(lockfile, None) finally: os.close(fd) class netcache(object): def __init__(self): self.http = urllib3.PoolManager() def url_of(self, sig, i): return "%s/%s/%s" % (CACHE_DIR, sig, i) def upload(self, file_path, sig, i): url = self.url_of(sig, i) with open(file_path, 'rb') as f: file_data = f.read() r = self.http.request('POST', url, timeout=60, fields={ 'file': ('%s/%s' % (sig, i), file_data), }) if r.status >= 400: raise OSError("Invalid status %r %r" % (url, r.status)) def download(self, file_path, sig, i): url = self.url_of(sig, i) with self.http.request('GET', url, preload_content=False, timeout=60) as inf: if inf.status >= 400: raise OSError("Invalid status %r %r" % (url, inf.status)) with open(file_path, 'wb') as out: shutil.copyfileobj(inf, out) def copy_to_cache(self, sig, files_from, files_to): try: for i, x in enumerate(files_from): if not os.path.islink(x): self.upload(x, sig, i) except Exception: return traceback.format_exc() return OK def copy_from_cache(self, sig, files_from, files_to): try: for i, x in enumerate(files_to): self.download(x, sig, i) except Exception: return traceback.format_exc() return OK class fcache(object): def __init__(self): if not os.path.exists(CACHE_DIR): try: os.makedirs(CACHE_DIR) except OSError: pass if not os.path.exists(CACHE_DIR): raise ValueError('Could not initialize the cache directory') def copy_to_cache(self, sig, files_from, files_to): """ Copy files to the cache, existing files are overwritten, and the copy is atomic only for a given file, not for all files that belong to a given task object """ try: for i, x in enumerate(files_from): dest = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) atomic_copy(x, dest) except Exception: return traceback.format_exc() else: # attempt trimming if caching was successful: # we may have things to trim! try: lru_evict() except Exception: return traceback.format_exc() return OK def copy_from_cache(self, sig, files_from, files_to): """ Copy files from the cache """ try: for i, x in enumerate(files_to): orig = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) atomic_copy(orig, x) # success! update the cache time os.utime(os.path.join(CACHE_DIR, sig[:2], sig), None) except Exception: return traceback.format_exc() return OK class bucket_cache(object): def bucket_copy(self, source, target): if WAFCACHE_CMD: def replacer(match): if match.group('src'): return source elif match.group('tgt'): return target cmd = [re_waf_cmd.sub(replacer, x) for x in shlex.split(WAFCACHE_CMD)] elif CACHE_DIR.startswith('s3://'): cmd = ['aws', 's3', 'cp', source, target] elif CACHE_DIR.startswith('gs://'): cmd = ['gsutil', 'cp', source, target] else: cmd = ['mc', 'cp', source, target] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() if proc.returncode: raise OSError('Error copy %r to %r using: %r (exit %r):\n out:%s\n err:%s' % ( source, target, cmd, proc.returncode, out.decode(errors='replace'), err.decode(errors='replace'))) def copy_to_cache(self, sig, files_from, files_to): try: for i, x in enumerate(files_from): dest = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) self.bucket_copy(x, dest) except Exception: return traceback.format_exc() return OK def copy_from_cache(self, sig, files_from, files_to): try: for i, x in enumerate(files_to): orig = os.path.join(CACHE_DIR, sig[:2], sig, str(i)) self.bucket_copy(orig, x) except EnvironmentError: return traceback.format_exc() return OK def loop(service): """ This function is run when this file is run as a standalone python script, it assumes a parent process that will communicate the commands to it as pickled-encoded tuples (one line per command) The commands are to copy files to the cache or copy files from the cache to a target destination """ # one operation is performed at a single time by a single process # therefore stdin never has more than one line txt = sys.stdin.readline().strip() if not txt: # parent process probably ended sys.exit(1) ret = OK [sig, files_from, files_to] = cPickle.loads(base64.b64decode(txt)) if files_from: # TODO return early when pushing files upstream ret = service.copy_to_cache(sig, files_from, files_to) elif files_to: # the build process waits for workers to (possibly) obtain files from the cache ret = service.copy_from_cache(sig, files_from, files_to) else: ret = "Invalid command" obj = base64.b64encode(cPickle.dumps(ret)) sys.stdout.write(obj.decode()) sys.stdout.write('\n') sys.stdout.flush() if __name__ == '__main__': if CACHE_DIR.startswith('s3://') or CACHE_DIR.startswith('gs://') or CACHE_DIR.startswith('minio://'): if CACHE_DIR.startswith('minio://'): CACHE_DIR = CACHE_DIR[8:] # minio doesn't need the protocol part, uses config aliases service = bucket_cache() elif CACHE_DIR.startswith('http'): service = netcache() else: service = fcache() while 1: try: loop(service) except KeyboardInterrupt: break hamster-3.0.3/waflib/extras/why.py000066400000000000000000000035431452646177100171350ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010 (ita) """ This tool modifies the task signature scheme to store and obtain information about the task execution (why it must run, etc):: def configure(conf): conf.load('why') After adding the tool, a full rebuild is necessary: waf clean build --zones=task """ from waflib import Task, Utils, Logs, Errors def signature(self): # compute the result one time, and suppose the scan_signature will give the good result try: return self.cache_sig except AttributeError: pass self.m = Utils.md5() self.m.update(self.hcode) id_sig = self.m.digest() # explicit deps self.m = Utils.md5() self.sig_explicit_deps() exp_sig = self.m.digest() # env vars self.m = Utils.md5() self.sig_vars() var_sig = self.m.digest() # implicit deps / scanner results self.m = Utils.md5() if self.scan: try: self.sig_implicit_deps() except Errors.TaskRescan: return self.signature() impl_sig = self.m.digest() ret = self.cache_sig = impl_sig + id_sig + exp_sig + var_sig return ret Task.Task.signature = signature old = Task.Task.runnable_status def runnable_status(self): ret = old(self) if ret == Task.RUN_ME: try: old_sigs = self.generator.bld.task_sigs[self.uid()] except (KeyError, AttributeError): Logs.debug("task: task must run as no previous signature exists") else: new_sigs = self.cache_sig def v(x): return Utils.to_hex(x) Logs.debug('Task %r', self) msgs = ['* Implicit or scanner dependency', '* Task code', '* Source file, explicit or manual dependency', '* Configuration data variable'] tmp = 'task: -> %s: %s %s' for x in range(len(msgs)): l = len(Utils.SIG_NIL) a = new_sigs[x*l : (x+1)*l] b = old_sigs[x*l : (x+1)*l] if (a != b): Logs.debug(tmp, msgs[x].ljust(35), v(a), v(b)) return ret Task.Task.runnable_status = runnable_status hamster-3.0.3/waflib/extras/win32_opts.py000066400000000000000000000111441452646177100203310ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 """ Windows-specific optimizations This module can help reducing the overhead of listing files on windows (more than 10000 files). Python 3.5 already provides the listdir optimization though. """ import os from waflib import Utils, Build, Node, Logs try: TP = '%s\\*'.decode('ascii') except AttributeError: TP = '%s\\*' if Utils.is_win32: from waflib.Tools import md5_tstamp import ctypes, ctypes.wintypes FindFirstFile = ctypes.windll.kernel32.FindFirstFileW FindNextFile = ctypes.windll.kernel32.FindNextFileW FindClose = ctypes.windll.kernel32.FindClose FILE_ATTRIBUTE_DIRECTORY = 0x10 INVALID_HANDLE_VALUE = -1 UPPER_FOLDERS = ('.', '..') try: UPPER_FOLDERS = [unicode(x) for x in UPPER_FOLDERS] except NameError: pass def cached_hash_file(self): try: cache = self.ctx.cache_listdir_cache_hash_file except AttributeError: cache = self.ctx.cache_listdir_cache_hash_file = {} if id(self.parent) in cache: try: t = cache[id(self.parent)][self.name] except KeyError: raise IOError('Not a file') else: # an opportunity to list the files and the timestamps at once findData = ctypes.wintypes.WIN32_FIND_DATAW() find = FindFirstFile(TP % self.parent.abspath(), ctypes.byref(findData)) if find == INVALID_HANDLE_VALUE: cache[id(self.parent)] = {} raise IOError('Not a file') cache[id(self.parent)] = lst_files = {} try: while True: if findData.cFileName not in UPPER_FOLDERS: thatsadir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY if not thatsadir: ts = findData.ftLastWriteTime d = (ts.dwLowDateTime << 32) | ts.dwHighDateTime lst_files[str(findData.cFileName)] = d if not FindNextFile(find, ctypes.byref(findData)): break except Exception: cache[id(self.parent)] = {} raise IOError('Not a file') finally: FindClose(find) t = lst_files[self.name] fname = self.abspath() if fname in Build.hashes_md5_tstamp: if Build.hashes_md5_tstamp[fname][0] == t: return Build.hashes_md5_tstamp[fname][1] try: fd = os.open(fname, os.O_BINARY | os.O_RDONLY | os.O_NOINHERIT) except OSError: raise IOError('Cannot read from %r' % fname) f = os.fdopen(fd, 'rb') m = Utils.md5() rb = 1 try: while rb: rb = f.read(200000) m.update(rb) finally: f.close() # ensure that the cache is overwritten Build.hashes_md5_tstamp[fname] = (t, m.digest()) return m.digest() Node.Node.cached_hash_file = cached_hash_file def get_bld_sig_win32(self): try: return self.ctx.hash_cache[id(self)] except KeyError: pass except AttributeError: self.ctx.hash_cache = {} self.ctx.hash_cache[id(self)] = ret = Utils.h_file(self.abspath()) return ret Node.Node.get_bld_sig = get_bld_sig_win32 def isfile_cached(self): # optimize for nt.stat calls, assuming there are many files for few folders try: cache = self.__class__.cache_isfile_cache except AttributeError: cache = self.__class__.cache_isfile_cache = {} try: c1 = cache[id(self.parent)] except KeyError: c1 = cache[id(self.parent)] = [] curpath = self.parent.abspath() findData = ctypes.wintypes.WIN32_FIND_DATAW() find = FindFirstFile(TP % curpath, ctypes.byref(findData)) if find == INVALID_HANDLE_VALUE: Logs.error("invalid win32 handle isfile_cached %r", self.abspath()) return os.path.isfile(self.abspath()) try: while True: if findData.cFileName not in UPPER_FOLDERS: thatsadir = findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY if not thatsadir: c1.append(str(findData.cFileName)) if not FindNextFile(find, ctypes.byref(findData)): break except Exception as e: Logs.error('exception while listing a folder %r %r', self.abspath(), e) return os.path.isfile(self.abspath()) finally: FindClose(find) return self.name in c1 Node.Node.isfile_cached = isfile_cached def find_or_declare_win32(self, lst): # assuming that "find_or_declare" is called before the build starts, remove the calls to os.path.isfile if isinstance(lst, str): lst = [x for x in Utils.split_path(lst) if x and x != '.'] node = self.get_bld().search_node(lst) if node: if not node.isfile_cached(): try: node.parent.mkdir() except OSError: pass return node self = self.get_src() node = self.find_node(lst) if node: if not node.isfile_cached(): try: node.parent.mkdir() except OSError: pass return node node = self.get_bld().make_node(lst) node.parent.mkdir() return node Node.Node.find_or_declare = find_or_declare_win32 hamster-3.0.3/waflib/extras/wix.py000066400000000000000000000051431452646177100171330ustar00rootroot00000000000000#!/usr/bin/python # encoding: utf-8 # vim: tabstop=4 noexpandtab """ Windows Installer XML Tool (WiX) .wxs --- candle ---> .wxobj --- light ---> .msi bld(features='wix', some.wxs, gen='some.msi', candleflags=[..], lightflags=[..]) bld(features='wix', source=['bundle.wxs','WixBalExtension'], gen='setup.exe', candleflags=[..]) """ import os, copy from waflib import TaskGen from waflib import Task from waflib.Utils import winreg class candle(Task.Task): run_str = '${CANDLE} -nologo ${CANDLEFLAGS} -out ${TGT} ${SRC[0].abspath()}', class light(Task.Task): run_str = "${LIGHT} -nologo -b ${SRC[0].parent.abspath()} ${LIGHTFLAGS} -out ${TGT} ${SRC[0].abspath()}" @TaskGen.feature('wix') @TaskGen.before_method('process_source') def wix(self): #X.wxs -> ${SRC} for CANDLE #X.wxobj -> ${SRC} for LIGHT #X.dll -> -ext X in ${LIGHTFLAGS} #X.wxl -> wixui.wixlib -loc X.wxl in ${LIGHTFLAGS} wxobj = [] wxs = [] exts = [] wxl = [] rest = [] for x in self.source: if x.endswith('.wxobj'): wxobj.append(x) elif x.endswith('.wxs'): wxobj.append(self.path.find_or_declare(x[:-4]+'.wxobj')) wxs.append(x) elif x.endswith('.dll'): exts.append(x[:-4]) elif '.' not in x: exts.append(x) elif x.endswith('.wxl'): wxl.append(x) else: rest.append(x) self.source = self.to_nodes(rest) #.wxs cndl = self.create_task('candle', self.to_nodes(wxs), self.to_nodes(wxobj)) lght = self.create_task('light', self.to_nodes(wxobj), self.path.find_or_declare(self.gen)) cndl.env.CANDLEFLAGS = copy.copy(getattr(self,'candleflags',[])) lght.env.LIGHTFLAGS = copy.copy(getattr(self,'lightflags',[])) for x in wxl: lght.env.append_value('LIGHTFLAGS','wixui.wixlib') lght.env.append_value('LIGHTFLAGS','-loc') lght.env.append_value('LIGHTFLAGS',x) for x in exts: cndl.env.append_value('CANDLEFLAGS','-ext') cndl.env.append_value('CANDLEFLAGS',x) lght.env.append_value('LIGHTFLAGS','-ext') lght.env.append_value('LIGHTFLAGS',x) #wix_bin_path() def wix_bin_path(): basekey = r"SOFTWARE\Microsoft\.NETFramework\AssemblyFolders" query = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, basekey) cnt=winreg.QueryInfoKey(query)[0] thiskey = r'C:\Program Files (x86)\WiX Toolset v3.10\SDK' for i in range(cnt-1,-1,-1): thiskey = winreg.EnumKey(query,i) if 'WiX' in thiskey: break winreg.CloseKey(query) return os.path.normpath(winreg.QueryValue(winreg.HKEY_LOCAL_MACHINE, basekey+r'\\'+thiskey)+'..\\bin') def configure(ctx): path_list=[wix_bin_path()] ctx.find_program('candle', var='CANDLE', mandatory=True, path_list = path_list) ctx.find_program('light', var='LIGHT', mandatory=True, path_list = path_list) hamster-3.0.3/waflib/extras/xcode6.py000066400000000000000000000572271452646177100175260ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # XCode 3/XCode 4/XCode 6/Xcode 7 generator for Waf # Based on work by Nicolas Mercier 2011 # Extended by Simon Warg 2015, https://github.com/mimon # XCode project file format based on http://www.monobjc.net/xcode-project-file-format.html """ See playground/xcode6/ for usage examples. """ from waflib import Context, TaskGen, Build, Utils, Errors, Logs import os, sys # FIXME too few extensions XCODE_EXTS = ['.c', '.cpp', '.m', '.mm'] HEADERS_GLOB = '**/(*.h|*.hpp|*.H|*.inl)' MAP_EXT = { '': "folder", '.h' : "sourcecode.c.h", '.hh': "sourcecode.cpp.h", '.inl': "sourcecode.cpp.h", '.hpp': "sourcecode.cpp.h", '.c': "sourcecode.c.c", '.m': "sourcecode.c.objc", '.mm': "sourcecode.cpp.objcpp", '.cc': "sourcecode.cpp.cpp", '.cpp': "sourcecode.cpp.cpp", '.C': "sourcecode.cpp.cpp", '.cxx': "sourcecode.cpp.cpp", '.c++': "sourcecode.cpp.cpp", '.l': "sourcecode.lex", # luthor '.ll': "sourcecode.lex", '.y': "sourcecode.yacc", '.yy': "sourcecode.yacc", '.plist': "text.plist.xml", ".nib": "wrapper.nib", ".xib": "text.xib", } # Used in PBXNativeTarget elements PRODUCT_TYPE_APPLICATION = 'com.apple.product-type.application' PRODUCT_TYPE_FRAMEWORK = 'com.apple.product-type.framework' PRODUCT_TYPE_EXECUTABLE = 'com.apple.product-type.tool' PRODUCT_TYPE_LIB_STATIC = 'com.apple.product-type.library.static' PRODUCT_TYPE_LIB_DYNAMIC = 'com.apple.product-type.library.dynamic' PRODUCT_TYPE_EXTENSION = 'com.apple.product-type.kernel-extension' PRODUCT_TYPE_IOKIT = 'com.apple.product-type.kernel-extension.iokit' # Used in PBXFileReference elements FILE_TYPE_APPLICATION = 'wrapper.cfbundle' FILE_TYPE_FRAMEWORK = 'wrapper.framework' FILE_TYPE_LIB_DYNAMIC = 'compiled.mach-o.dylib' FILE_TYPE_LIB_STATIC = 'archive.ar' FILE_TYPE_EXECUTABLE = 'compiled.mach-o.executable' # Tuple packs of the above TARGET_TYPE_FRAMEWORK = (PRODUCT_TYPE_FRAMEWORK, FILE_TYPE_FRAMEWORK, '.framework') TARGET_TYPE_APPLICATION = (PRODUCT_TYPE_APPLICATION, FILE_TYPE_APPLICATION, '.app') TARGET_TYPE_DYNAMIC_LIB = (PRODUCT_TYPE_LIB_DYNAMIC, FILE_TYPE_LIB_DYNAMIC, '.dylib') TARGET_TYPE_STATIC_LIB = (PRODUCT_TYPE_LIB_STATIC, FILE_TYPE_LIB_STATIC, '.a') TARGET_TYPE_EXECUTABLE = (PRODUCT_TYPE_EXECUTABLE, FILE_TYPE_EXECUTABLE, '') # Maps target type string to its data TARGET_TYPES = { 'framework': TARGET_TYPE_FRAMEWORK, 'app': TARGET_TYPE_APPLICATION, 'dylib': TARGET_TYPE_DYNAMIC_LIB, 'stlib': TARGET_TYPE_STATIC_LIB, 'exe' :TARGET_TYPE_EXECUTABLE, } def delete_invalid_values(dct): """ Deletes entries that are dictionaries or sets """ for k, v in list(dct.items()): if isinstance(v, dict) or isinstance(v, set): del dct[k] return dct """ Configuration of the global project settings. Sets an environment variable 'PROJ_CONFIGURATION' which is a dictionary of configuration name and buildsettings pair. E.g.: env.PROJ_CONFIGURATION = { 'Debug': { 'ARCHS': 'x86', ... } 'Release': { 'ARCHS': x86_64' ... } } The user can define a completely customized dictionary in configure() stage. Otherwise a default Debug/Release will be created based on env variable """ def configure(self): if not self.env.PROJ_CONFIGURATION: self.to_log("A default project configuration was created since no custom one was given in the configure(conf) stage. Define your custom project settings by adding PROJ_CONFIGURATION to env. The env.PROJ_CONFIGURATION must be a dictionary with at least one key, where each key is the configuration name, and the value is a dictionary of key/value settings.\n") # Check for any added config files added by the tool 'c_config'. if 'cfg_files' in self.env: self.env.INCLUDES = Utils.to_list(self.env.INCLUDES) + [os.path.abspath(os.path.dirname(f)) for f in self.env.cfg_files] # Create default project configuration? if 'PROJ_CONFIGURATION' not in self.env: defaults = delete_invalid_values(self.env.get_merged_dict()) self.env.PROJ_CONFIGURATION = { "Debug": defaults, "Release": defaults, } # Some build settings are required to be present by XCode. We will supply default values # if user hasn't defined any. defaults_required = [('PRODUCT_NAME', '$(TARGET_NAME)')] for cfgname,settings in self.env.PROJ_CONFIGURATION.items(): for default_var, default_val in defaults_required: if default_var not in settings: settings[default_var] = default_val # Error check customization if not isinstance(self.env.PROJ_CONFIGURATION, dict): raise Errors.ConfigurationError("The env.PROJ_CONFIGURATION must be a dictionary with at least one key, where each key is the configuration name, and the value is a dictionary of key/value settings.") part1 = 0 part2 = 10000 part3 = 0 id = 562000999 def newid(): global id id += 1 return "%04X%04X%04X%012d" % (0, 10000, 0, id) """ Represents a tree node in the XCode project plist file format. When written to a file, all attributes of XCodeNode are stringified together with its value. However, attributes starting with an underscore _ are ignored during that process and allows you to store arbitrary values that are not supposed to be written out. """ class XCodeNode(object): def __init__(self): self._id = newid() self._been_written = False def tostring(self, value): if isinstance(value, dict): result = "{\n" for k,v in value.items(): result = result + "\t\t\t%s = %s;\n" % (k, self.tostring(v)) result = result + "\t\t}" return result elif isinstance(value, str): return '"%s"' % value.replace('"', '\\\\\\"') elif isinstance(value, list): result = "(\n" for i in value: result = result + "\t\t\t\t%s,\n" % self.tostring(i) result = result + "\t\t\t)" return result elif isinstance(value, XCodeNode): return value._id else: return str(value) def write_recursive(self, value, file): if isinstance(value, dict): for k,v in value.items(): self.write_recursive(v, file) elif isinstance(value, list): for i in value: self.write_recursive(i, file) elif isinstance(value, XCodeNode): value.write(file) def write(self, file): if not self._been_written: self._been_written = True for attribute,value in self.__dict__.items(): if attribute[0] != '_': self.write_recursive(value, file) w = file.write w("\t%s = {\n" % self._id) w("\t\tisa = %s;\n" % self.__class__.__name__) for attribute,value in self.__dict__.items(): if attribute[0] != '_': w("\t\t%s = %s;\n" % (attribute, self.tostring(value))) w("\t};\n\n") # Configurations class XCBuildConfiguration(XCodeNode): def __init__(self, name, settings = {}, env=None): XCodeNode.__init__(self) self.baseConfigurationReference = "" self.buildSettings = settings self.name = name if env and env.ARCH: settings['ARCHS'] = " ".join(env.ARCH) class XCConfigurationList(XCodeNode): def __init__(self, configlst): """ :param configlst: list of XCConfigurationList """ XCodeNode.__init__(self) self.buildConfigurations = configlst self.defaultConfigurationIsVisible = 0 self.defaultConfigurationName = configlst and configlst[0].name or "" # Group/Files class PBXFileReference(XCodeNode): def __init__(self, name, path, filetype = '', sourcetree = "SOURCE_ROOT"): XCodeNode.__init__(self) self.fileEncoding = 4 if not filetype: _, ext = os.path.splitext(name) filetype = MAP_EXT.get(ext, 'text') self.lastKnownFileType = filetype self.explicitFileType = filetype self.name = name self.path = path self.sourceTree = sourcetree def __hash__(self): return (self.path+self.name).__hash__() def __eq__(self, other): return (self.path, self.name) == (other.path, other.name) class PBXBuildFile(XCodeNode): """ This element indicate a file reference that is used in a PBXBuildPhase (either as an include or resource). """ def __init__(self, fileRef, settings={}): XCodeNode.__init__(self) # fileRef is a reference to a PBXFileReference object self.fileRef = fileRef # A map of key/value pairs for additional settings. self.settings = settings def __hash__(self): return (self.fileRef).__hash__() def __eq__(self, other): return self.fileRef == other.fileRef class PBXGroup(XCodeNode): def __init__(self, name, sourcetree = 'SOURCE_TREE'): XCodeNode.__init__(self) self.children = [] self.name = name self.sourceTree = sourcetree # Maintain a lookup table for all PBXFileReferences # that are contained in this group. self._filerefs = {} def add(self, sources): """ Add a list of PBXFileReferences to this group :param sources: list of PBXFileReferences objects """ self._filerefs.update(dict(zip(sources, sources))) self.children.extend(sources) def get_sub_groups(self): """ Returns all child PBXGroup objects contained in this group """ return list(filter(lambda x: isinstance(x, PBXGroup), self.children)) def find_fileref(self, fileref): """ Recursively search this group for an existing PBXFileReference. Returns None if none were found. The reason you'd want to reuse existing PBXFileReferences from a PBXGroup is that XCode doesn't like PBXFileReferences that aren't part of a PBXGroup hierarchy. If it isn't, the consequence is that certain UI features like 'Reveal in Finder' stops working. """ if fileref in self._filerefs: return self._filerefs[fileref] elif self.children: for childgroup in self.get_sub_groups(): f = childgroup.find_fileref(fileref) if f: return f return None class PBXContainerItemProxy(XCodeNode): """ This is the element for to decorate a target item. """ def __init__(self, containerPortal, remoteGlobalIDString, remoteInfo='', proxyType=1): XCodeNode.__init__(self) self.containerPortal = containerPortal # PBXProject self.remoteGlobalIDString = remoteGlobalIDString # PBXNativeTarget self.remoteInfo = remoteInfo # Target name self.proxyType = proxyType class PBXTargetDependency(XCodeNode): """ This is the element for referencing other target through content proxies. """ def __init__(self, native_target, proxy): XCodeNode.__init__(self) self.target = native_target self.targetProxy = proxy class PBXFrameworksBuildPhase(XCodeNode): """ This is the element for the framework link build phase, i.e. linking to frameworks """ def __init__(self, pbxbuildfiles): XCodeNode.__init__(self) self.buildActionMask = 2147483647 self.runOnlyForDeploymentPostprocessing = 0 self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib) class PBXHeadersBuildPhase(XCodeNode): """ This is the element for adding header files to be packaged into the .framework """ def __init__(self, pbxbuildfiles): XCodeNode.__init__(self) self.buildActionMask = 2147483647 self.runOnlyForDeploymentPostprocessing = 0 self.files = pbxbuildfiles #List of PBXBuildFile (.o, .framework, .dylib) class PBXCopyFilesBuildPhase(XCodeNode): """ Represents the PBXCopyFilesBuildPhase section. PBXBuildFile can be added to this node to copy files after build is done. """ def __init__(self, pbxbuildfiles, dstpath, dstSubpathSpec=0, *args, **kwargs): XCodeNode.__init__(self) self.files = pbxbuildfiles self.dstPath = dstpath self.dstSubfolderSpec = dstSubpathSpec class PBXSourcesBuildPhase(XCodeNode): """ Represents the 'Compile Sources' build phase in a Xcode target """ def __init__(self, buildfiles): XCodeNode.__init__(self) self.files = buildfiles # List of PBXBuildFile objects class PBXLegacyTarget(XCodeNode): def __init__(self, action, target=''): XCodeNode.__init__(self) self.buildConfigurationList = XCConfigurationList([XCBuildConfiguration('waf', {})]) if not target: self.buildArgumentsString = "%s %s" % (sys.argv[0], action) else: self.buildArgumentsString = "%s %s --targets=%s" % (sys.argv[0], action, target) self.buildPhases = [] self.buildToolPath = sys.executable self.buildWorkingDirectory = "" self.dependencies = [] self.name = target or action self.productName = target or action self.passBuildSettingsInEnvironment = 0 class PBXShellScriptBuildPhase(XCodeNode): def __init__(self, action, target): XCodeNode.__init__(self) self.buildActionMask = 2147483647 self.files = [] self.inputPaths = [] self.outputPaths = [] self.runOnlyForDeploymentPostProcessing = 0 self.shellPath = "/bin/sh" self.shellScript = "%s %s %s --targets=%s" % (sys.executable, sys.argv[0], action, target) class PBXNativeTarget(XCodeNode): """ Represents a target in XCode, e.g. App, DyLib, Framework etc. """ def __init__(self, target, node, target_type=TARGET_TYPE_APPLICATION, configlist=[], buildphases=[]): XCodeNode.__init__(self) product_type = target_type[0] file_type = target_type[1] self.buildConfigurationList = XCConfigurationList(configlist) self.buildPhases = buildphases self.buildRules = [] self.dependencies = [] self.name = target self.productName = target self.productType = product_type # See TARGET_TYPE_ tuples constants self.productReference = PBXFileReference(node.name, node.abspath(), file_type, '') def add_configuration(self, cf): """ :type cf: XCBuildConfiguration """ self.buildConfigurationList.buildConfigurations.append(cf) def add_build_phase(self, phase): # Some build phase types may appear only once. If a phase type already exists, then merge them. if ( (phase.__class__ == PBXFrameworksBuildPhase) or (phase.__class__ == PBXSourcesBuildPhase) ): for b in self.buildPhases: if b.__class__ == phase.__class__: b.files.extend(phase.files) return self.buildPhases.append(phase) def add_dependency(self, depnd): self.dependencies.append(depnd) # Root project object class PBXProject(XCodeNode): def __init__(self, name, version, env): XCodeNode.__init__(self) if not isinstance(env.PROJ_CONFIGURATION, dict): raise Errors.WafError("Error: env.PROJ_CONFIGURATION must be a dictionary. This is done for you if you do not define one yourself. However, did you load the xcode module at the end of your wscript configure() ?") # Retrieve project configuration configurations = [] for config_name, settings in env.PROJ_CONFIGURATION.items(): cf = XCBuildConfiguration(config_name, settings) configurations.append(cf) self.buildConfigurationList = XCConfigurationList(configurations) self.compatibilityVersion = version[0] self.hasScannedForEncodings = 1 self.mainGroup = PBXGroup(name) self.projectRoot = "" self.projectDirPath = "" self.targets = [] self._objectVersion = version[1] def create_target_dependency(self, target, name): """ : param target : PXBNativeTarget """ proxy = PBXContainerItemProxy(self, target, name) dependency = PBXTargetDependency(target, proxy) return dependency def write(self, file): # Make sure this is written only once if self._been_written: return w = file.write w("// !$*UTF8*$!\n") w("{\n") w("\tarchiveVersion = 1;\n") w("\tclasses = {\n") w("\t};\n") w("\tobjectVersion = %d;\n" % self._objectVersion) w("\tobjects = {\n\n") XCodeNode.write(self, file) w("\t};\n") w("\trootObject = %s;\n" % self._id) w("}\n") def add_target(self, target): self.targets.append(target) def get_target(self, name): """ Get a reference to PBXNativeTarget if it exists """ for t in self.targets: if t.name == name: return t return None @TaskGen.feature('c', 'cxx') @TaskGen.after('propagate_uselib_vars', 'apply_incpaths') def process_xcode(self): bld = self.bld try: p = bld.project except AttributeError: return if not hasattr(self, 'target_type'): return products_group = bld.products_group target_group = PBXGroup(self.name) p.mainGroup.children.append(target_group) # Determine what type to build - framework, app bundle etc. target_type = getattr(self, 'target_type', 'app') if target_type not in TARGET_TYPES: raise Errors.WafError("Target type '%s' does not exists. Available options are '%s'. In target '%s'" % (target_type, "', '".join(TARGET_TYPES.keys()), self.name)) else: target_type = TARGET_TYPES[target_type] file_ext = target_type[2] # Create the output node target_node = self.path.find_or_declare(self.name+file_ext) target = PBXNativeTarget(self.name, target_node, target_type, [], []) products_group.children.append(target.productReference) # Pull source files from the 'source' attribute and assign them to a UI group. # Use a default UI group named 'Source' unless the user # provides a 'group_files' dictionary to customize the UI grouping. sources = getattr(self, 'source', []) if hasattr(self, 'group_files'): group_files = getattr(self, 'group_files', []) for grpname,files in group_files.items(): group = bld.create_group(grpname, files) target_group.children.append(group) else: group = bld.create_group('Source', sources) target_group.children.append(group) # Create a PBXFileReference for each source file. # If the source file already exists as a PBXFileReference in any of the UI groups, then # reuse that PBXFileReference object (XCode does not like it if we don't reuse) for idx, path in enumerate(sources): fileref = PBXFileReference(path.name, path.abspath()) existing_fileref = target_group.find_fileref(fileref) if existing_fileref: sources[idx] = existing_fileref else: sources[idx] = fileref # If the 'source' attribute contains any file extension that XCode can't work with, # then remove it. The allowed file extensions are defined in XCODE_EXTS. is_valid_file_extension = lambda file: os.path.splitext(file.path)[1] in XCODE_EXTS sources = list(filter(is_valid_file_extension, sources)) buildfiles = [bld.unique_buildfile(PBXBuildFile(x)) for x in sources] target.add_build_phase(PBXSourcesBuildPhase(buildfiles)) # Check if any framework to link against is some other target we've made libs = getattr(self, 'tmp_use_seen', []) for lib in libs: use_target = p.get_target(lib) if use_target: # Create an XCode dependency so that XCode knows to build the other target before this target dependency = p.create_target_dependency(use_target, use_target.name) target.add_dependency(dependency) buildphase = PBXFrameworksBuildPhase([PBXBuildFile(use_target.productReference)]) target.add_build_phase(buildphase) if lib in self.env.LIB: self.env.LIB = list(filter(lambda x: x != lib, self.env.LIB)) # If 'export_headers' is present, add files to the Headers build phase in xcode. # These are files that'll get packed into the Framework for instance. exp_hdrs = getattr(self, 'export_headers', []) hdrs = bld.as_nodes(Utils.to_list(exp_hdrs)) files = [p.mainGroup.find_fileref(PBXFileReference(n.name, n.abspath())) for n in hdrs] files = [PBXBuildFile(f, {'ATTRIBUTES': ('Public',)}) for f in files] buildphase = PBXHeadersBuildPhase(files) target.add_build_phase(buildphase) # Merge frameworks and libs into one list, and prefix the frameworks frameworks = Utils.to_list(self.env.FRAMEWORK) frameworks = ' '.join(['-framework %s' % (f.split('.framework')[0]) for f in frameworks]) libs = Utils.to_list(self.env.STLIB) + Utils.to_list(self.env.LIB) libs = ' '.join(bld.env['STLIB_ST'] % t for t in libs) # Override target specific build settings bldsettings = { 'HEADER_SEARCH_PATHS': ['$(inherited)'] + self.env['INCPATHS'], 'LIBRARY_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.LIBPATH) + Utils.to_list(self.env.STLIBPATH) + Utils.to_list(self.env.LIBDIR), 'FRAMEWORK_SEARCH_PATHS': ['$(inherited)'] + Utils.to_list(self.env.FRAMEWORKPATH), 'OTHER_LDFLAGS': libs + ' ' + frameworks + ' ' + ' '.join(bld.env['LINKFLAGS']), 'OTHER_CPLUSPLUSFLAGS': Utils.to_list(self.env['CXXFLAGS']), 'OTHER_CFLAGS': Utils.to_list(self.env['CFLAGS']), 'INSTALL_PATH': [], 'GCC_PREPROCESSOR_DEFINITIONS': self.env['DEFINES'] } # Install path installpaths = Utils.to_list(getattr(self, 'install', [])) prodbuildfile = PBXBuildFile(target.productReference) for instpath in installpaths: bldsettings['INSTALL_PATH'].append(instpath) target.add_build_phase(PBXCopyFilesBuildPhase([prodbuildfile], instpath)) if not bldsettings['INSTALL_PATH']: del bldsettings['INSTALL_PATH'] # Create build settings which can override the project settings. Defaults to none if user # did not pass argument. This will be filled up with target specific # search paths, libs to link etc. settings = getattr(self, 'settings', {}) # The keys represents different build configuration, e.g. Debug, Release and so on.. # Insert our generated build settings to all configuration names keys = set(settings.keys()) | set(bld.env.PROJ_CONFIGURATION.keys()) for k in keys: if k in settings: settings[k].update(bldsettings) else: settings[k] = bldsettings for k,v in settings.items(): target.add_configuration(XCBuildConfiguration(k, v)) p.add_target(target) class xcode(Build.BuildContext): cmd = 'xcode6' fun = 'build' def as_nodes(self, files): """ Returns a list of waflib.Nodes from a list of string of file paths """ nodes = [] for x in files: if not isinstance(x, str): d = x else: d = self.srcnode.find_node(x) if not d: raise Errors.WafError('File \'%s\' was not found' % x) nodes.append(d) return nodes def create_group(self, name, files): """ Returns a new PBXGroup containing the files (paths) passed in the files arg :type files: string """ group = PBXGroup(name) """ Do not use unique file reference here, since XCode seem to allow only one file reference to be referenced by a group. """ files_ = [] for d in self.as_nodes(Utils.to_list(files)): fileref = PBXFileReference(d.name, d.abspath()) files_.append(fileref) group.add(files_) return group def unique_buildfile(self, buildfile): """ Returns a unique buildfile, possibly an existing one. Use this after you've constructed a PBXBuildFile to make sure there is only one PBXBuildFile for the same file in the same project. """ try: build_files = self.build_files except AttributeError: build_files = self.build_files = {} if buildfile not in build_files: build_files[buildfile] = buildfile return build_files[buildfile] def execute(self): """ Entry point """ self.restore() if not self.all_envs: self.load_envs() self.recurse([self.run_dir]) appname = getattr(Context.g_module, Context.APPNAME, os.path.basename(self.srcnode.abspath())) p = PBXProject(appname, ('Xcode 3.2', 46), self.env) # If we don't create a Products group, then # XCode will create one, which entails that # we'll start to see duplicate files in the UI # for some reason. products_group = PBXGroup('Products') p.mainGroup.children.append(products_group) self.project = p self.products_group = products_group # post all task generators # the process_xcode method above will be called for each target if self.targets and self.targets != '*': (self._min_grp, self._exact_tg) = self.get_targets() self.current_group = 0 while self.current_group < len(self.groups): self.post_group() self.current_group += 1 node = self.bldnode.make_node('%s.xcodeproj' % appname) node.mkdir() node = node.make_node('project.pbxproj') with open(node.abspath(), 'w') as f: p.write(f) Logs.pprint('GREEN', 'Wrote %r' % node.abspath()) def bind_fun(tgtype): def fun(self, *k, **kw): tgtype = fun.__name__ if tgtype == 'shlib' or tgtype == 'dylib': features = 'cxx cxxshlib' tgtype = 'dylib' elif tgtype == 'framework': features = 'cxx cxxshlib' tgtype = 'framework' elif tgtype == 'program': features = 'cxx cxxprogram' tgtype = 'exe' elif tgtype == 'app': features = 'cxx cxxprogram' tgtype = 'app' elif tgtype == 'stlib': features = 'cxx cxxstlib' tgtype = 'stlib' lst = kw['features'] = Utils.to_list(kw.get('features', [])) for x in features.split(): if not x in kw['features']: lst.append(x) kw['target_type'] = tgtype return self(*k, **kw) fun.__name__ = tgtype setattr(Build.BuildContext, tgtype, fun) return fun for xx in 'app framework dylib shlib stlib program'.split(): bind_fun(xx) hamster-3.0.3/waflib/fixpy2.py000066400000000000000000000027201452646177100162350ustar00rootroot00000000000000#!/usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2010-2018 (ita) from __future__ import with_statement import os all_modifs = {} def fixdir(dir): """Call all substitution functions on Waf folders""" for k in all_modifs: for v in all_modifs[k]: modif(os.path.join(dir, 'waflib'), k, v) def modif(dir, name, fun): """Call a substitution function""" if name == '*': lst = [] for y in '. Tools extras'.split(): for x in os.listdir(os.path.join(dir, y)): if x.endswith('.py'): lst.append(y + os.sep + x) for x in lst: modif(dir, x, fun) return filename = os.path.join(dir, name) with open(filename, 'r') as f: txt = f.read() txt = fun(txt) with open(filename, 'w') as f: f.write(txt) def subst(*k): """register a substitution function""" def do_subst(fun): for x in k: try: all_modifs[x].append(fun) except KeyError: all_modifs[x] = [fun] return fun return do_subst @subst('*') def r1(code): "utf-8 fixes for python < 2.6" code = code.replace('as e:', ',e:') code = code.replace(".decode(sys.stdout.encoding or'latin-1',errors='replace')", '') return code.replace('.encode()', '') @subst('Runner.py') def r4(code): "generator syntax" return code.replace('next(self.biter)', 'self.biter.next()').replace('self.daemon = True', 'self.setDaemon(1)') @subst('Context.py') def r5(code): return code.replace("('Execution failure: %s'%str(e),ex=e)", "('Execution failure: %s'%str(e),ex=e),None,sys.exc_info()[2]") hamster-3.0.3/waflib/processor.py000077500000000000000000000031011452646177100170300ustar00rootroot00000000000000#! /usr/bin/env python # encoding: utf-8 # Thomas Nagy, 2016-2018 (ita) import os, sys, traceback, base64, signal try: import cPickle except ImportError: import pickle as cPickle try: import subprocess32 as subprocess except ImportError: import subprocess try: TimeoutExpired = subprocess.TimeoutExpired except AttributeError: class TimeoutExpired(Exception): pass def run(): txt = sys.stdin.readline().strip() if not txt: # parent process probably ended sys.exit(1) [cmd, kwargs, cargs] = cPickle.loads(base64.b64decode(txt)) cargs = cargs or {} if not 'close_fds' in kwargs: # workers have no fds kwargs['close_fds'] = False ret = 1 out, err, ex, trace = (None, None, None, None) try: proc = subprocess.Popen(cmd, **kwargs) try: out, err = proc.communicate(**cargs) except TimeoutExpired: if kwargs.get('start_new_session') and hasattr(os, 'killpg'): os.killpg(proc.pid, signal.SIGKILL) else: proc.kill() out, err = proc.communicate() exc = TimeoutExpired(proc.args, timeout=cargs['timeout'], output=out) exc.stderr = err raise exc ret = proc.returncode except Exception as e: exc_type, exc_value, tb = sys.exc_info() exc_lines = traceback.format_exception(exc_type, exc_value, tb) trace = str(cmd) + '\n' + ''.join(exc_lines) ex = e.__class__.__name__ # it is just text so maybe we do not need to pickle() tmp = [ret, out, err, ex, trace] obj = base64.b64encode(cPickle.dumps(tmp)) sys.stdout.write(obj.decode()) sys.stdout.write('\n') sys.stdout.flush() while 1: try: run() except KeyboardInterrupt: break hamster-3.0.3/wscript000066400000000000000000000067461452646177100146300ustar00rootroot00000000000000# -*- python -*- import subprocess from waflib import Utils # Reuse code from hamster to figure out the version number to use process = subprocess.run(["python3", "src/hamster/version.py"], check=True, stdout=subprocess.PIPE, text=True) VERSION = process.stdout APPNAME = 'hamster' top = '.' out = 'build' def options(ctx): ctx.load('gnu_dirs') # the waf default value is /usr/local, which causes issues (e.g. #309) # ctx.parser.set_defaults(prefix='/usr') did not update the help string, # hence need to replace the whole option ctx.parser.remove_option('--prefix') default_prefix = '/usr' ctx.add_option('--prefix', dest='prefix', default=default_prefix, help='installation prefix [default: {}]'.format(default_prefix)) ctx.add_option('--skip-gsettings', dest='skip_gsettings', action='store_true', help='skip gsettings schemas build and installation (for packagers)') ctx.add_option('--skip-icon-cache-update', dest='skip_icon_cache_update', action='store_true', help='skip icon cache update (for packagers)') def configure(ctx): ctx.load('gnu_dirs') # for DATADIR if not ctx.options.skip_gsettings: ctx.load('glib2') # for GSettings support ctx.load('python') ctx.check_python_version(minver=(3,4,0)) ctx.load('intltool') ctx.env.ENABLE_NLS = 1 ctx.env.HAVE_BIND_TEXTDOMAIN_CODESET = 1 ctx.env.VERSION = VERSION ctx.env.GETTEXT_PACKAGE = "hamster" ctx.env.PACKAGE = "hamster" ctx.recurse("help") # options are tied to a specific ./waf invocation (one terminal line), # and woud have to be given again at any other ./waf invocation # that is trouble when one wants to ./waf uninstall much later; # it can be hard to remember the exact options used at the install step. # So from now on, options have to be given at the configure step only. # copy the options to the persistent env: for name in ('prefix', 'skip_gsettings', 'skip_icon_cache_update'): value = getattr(ctx.options, name) setattr(ctx.env, name, value) def build(ctx): ctx.install_as('${LIBEXECDIR}/hamster/hamster-service', "src/hamster-service.py", chmod=Utils.O755) ctx.install_as('${LIBEXECDIR}/hamster/hamster-windows-service', "src/hamster-windows-service.py", chmod=Utils.O755) ctx.install_as('${BINDIR}/hamster', "src/hamster-cli.py", chmod=Utils.O755) ctx.install_files('${PREFIX}/share/bash-completion/completions', 'src/hamster.bash') ctx(features='py', source=ctx.path.ant_glob('src/hamster/**/*.py'), install_from='src') # set correct flags in defs.py ctx(features="subst", source="src/hamster/defs.py.in", target="src/hamster/defs.py", install_path="${PYTHONDIR}/hamster" ) ctx(features="subst", source= "org.gnome.Hamster.service.in", target= "org.gnome.Hamster.service", install_path="${DATADIR}/dbus-1/services", ) ctx(features="subst", source= "org.gnome.Hamster.GUI.service.in", target= "org.gnome.Hamster.GUI.service", install_path="${DATADIR}/dbus-1/services", ) ctx(features="subst", source= "org.gnome.Hamster.WindowServer.service.in", target= "org.gnome.Hamster.WindowServer.service", install_path="${DATADIR}/dbus-1/services", ) # look for wscript into further directories ctx.recurse("po data help")