tryton-5.0.17/0000755000175000017500000000000013571264253012463 5ustar cedced00000000000000tryton-5.0.17/CHANGELOG0000644000175000017500000003211013571264252013671 0ustar cedced00000000000000Version 5.0.17 - 2019-12-02 * Bug fixes (see mercurial logs for details) Version 5.0.16 - 2019-11-08 * Bug fixes (see mercurial logs for details) Version 5.0.15 - 2019-09-15 * Bug fixes (see mercurial logs for details) Version 5.0.14 - 2019-09-01 * Bug fixes (see mercurial logs for details) Version 5.0.13 - 2019-08-17 * Bug fixes (see mercurial logs for details) Version 5.0.12 - 2019-07-01 * Bug fixes (see mercurial logs for details) Version 5.0.11 - 2019-06-10 * Bug fixes (see mercurial logs for details) Version 5.0.10 - 2019-05-16 * Bug fixes (see mercurial logs for details) Version 5.0.9 - 2019-04-22 * Bug fixes (see mercurial logs for details) Version 5.0.8 - 2019-04-02 * Bug fixes (see mercurial logs for details) Version 5.0.7 - 2019-03-15 * Bug fixes (see mercurial logs for details) Version 5.0.6 - 2019-02-19 * Bug fixes (see mercurial logs for details) Version 5.0.5 - 2019-01-22 * Bug fixes (see mercurial logs for details) Version 5.0.4 - 2019-01-05 * Bug fixes (see mercurial logs for details) Version 5.0.3 - 2018-12-02 * Bug fixes (see mercurial logs for details) Version 5.0.2 - 2018-11-12 * Bug fixes (see mercurial logs for details) Version 5.0.1 - 2018-10-31 * Bug fixes (see mercurial logs for details) * Ensure URL scheme of bus (issue7792) Version 5.0.0 - 2018-10-01 * Bug fixes (see mercurial logs for details) * Use dropdown for attachment * Apply factor on domain parser * Use tab name in CSV Export/Import * Add bus management * Use CSS to style label * New icons * Support timestamp field * Add support for Python 3.7 * Use GtkApplication * Validate dictionary items * Add (i)like support to domain inversion * Use Python 3 * Improve loading strategy by using views * Use non conflicting keyboard shortcuts in sync with sao * Use the context to get the suffix of window name * Call on_change methods after setting default dtstart on calendar view Version 4.8.0 - 2018-04-23 * Bug fixes (see mercurial logs for details) * Manage active field on search widget * Reset record to its original state when discarding the popup window * Add support of expand attribute on group tag * Add the context model name in the screen context * Use limit to expand tree * Add keyword attribute to button tag * Support field name on image tag * Add option to check new version * Show related record names for all windows * Remove support of GTK+ 2.0 * Add icons on Many2One in editable tree * Use translated values when exporting Reference and Selection fields Version 4.6.0 - 2017-10-30 * Bug fixes (see mercurial logs for details) * Allow to export model and record name of Reference fields * Re-position buttons on Binary/Image widget * Improve treeview headers * Update states of both toolbar and menu * Improve toolbar order * Make readonly, required and invalid widget themable * Load user CSS theme * Use profile name or login details in title Version 4.4.0 - 2017-05-01 * Bug fixes (see mercurial logs for details) * Verify certificate with default CA * Replace URL entry by a toolbar button Version 4.2.0 - 2016-11-28 * Bug fixes (see mercurial logs for details) * Add support for GTK+ 3.0 * Add PYSON Widget * Show records names in wizard title * Add support for datetime_field to Reference * Show non editable widget as insensitive * Move info-bar at the bottom * Manage readonly on fields translation dialog * Restore tab default order when no manual change * Call autocompletion when setting record value * Remove database management * Limit readonly state for xxx2Many * Show records names in relate window title * Add support for count on Action Window Domains * Manage custom login process * Add clear icon on Many2One * Re-position icons on Many2One widget Version 4.0.0 - 2016-05-02 * Bug fixes (see mercurial logs for details) * Improvement of charts design * Timedelta uses 30 days for month * Add all available encoding for import/export * Add CSV parameters to export window * Add DnD on import window * Manage context model of ir.action.act_window * Add Note * Manage view_ids on tree view * Use Apple key for copy/past of list Version 3.8.0 - 2015-11-02 * Bug fixes (see mercurial logs for details) * Use italic labels for editable fields * Escape '_' in button string and page string * Export selected records only * Use HTML for RichText widget * Change Progressbar to work with float between 0 and 1 * Add Fast Tabbing option * Remove colors on widgets * Bold label of required fields * Explicit error message for invalid record * Add reversed operators to PYSON expressions Version 3.6.0 - 2015-04-20 * Bug fixes (see mercurial logs for details) * Hide columns containing always the same value * Remove Tabs Position option * Manage product attribute * Remove float_time widget * Add TimeDelta field * Improve date/time widgets * Remove datetime widget on list/tree view * Allow to put many times the same field on tree view * Add search completion on dictionary widget * Merge host and port field in profile editor * New color scheme for graph * Replace img_{width,height} by width and height attributes Version 3.4.0 - 2014-10-20 * Bug fixes (see mercurial logs for details) * Add DnD on export window * Allow to overide predefined export * Prefill export window with current view fields * Manage field context on Group value * Add export of selection string * Load plugins from local user directory * Manage tree_state attribute * Add simple tree_state support on form view * Change range operator of search widget to be included * Explicitly set value of parent field Version 3.2.0 - 2014-04-21 * Bug fixes (see mercurial logs for details) * Add option to show revisions * Add a multi selection widget for many2many * Remove auto-refresh * Add support of domain for non-relation field * Allow drag & drop on the attachment button * Replace sha widget by password * Add Len to PYSON * Use a pool of connection * Manage client actions from button and wizard * Add tree_invisible attribute to button in tree view * Add buttons of the view in actions menu * Don't evaluate anymore relate action with the record * Paste on editable list create new records if needed * Drop support of Python 2.6 * Allow to search on rec_name of Reference fields * Use local timezone * Sanitize report file extension Version 3.0.0 - 2013-10-21 * Bug fixes (see mercurial logs for details) * Add factor on number widgets * Add calendar view * Add URL entry * Remove request Version 2.8.0 - 2013-04-22 * Bug fixes (see mercurial logs for details) * Manage dynamic label * Manage prefix, suffix on tree view * Manage selection_change_with on Selection and Reference fields * Add Dict fields on form * Remove Goto * Add global search * Add toggle button for menu * Replace shortcuts by menu favorites * Move Plugins into toolbar Actions * Add url to list view * Add dynamic icon for url * Add completion on Many2One, Many2Many and One2Many * Add bookmark on search widget * Manage domains on Action Window * Use range for Date/Time fields in filter box * Allow multi-selection for Selection field in filter box Version 2.6.0 - 2012-10-22 * Bug fixes (see mercurial logs for details) * Allow to paste in editable list view * Manage readonly state on group * Remove "Please wait" box * Refactorize date widgets * Manage tuple on Reference * Add constant interpolation on line graph * Make Import/Export Data no-modal * Deactivate switch view button when there is only 1 view * Manage create/delete field access * Add dynamic size limit on the One2Many, Many2Many and Char * Search only on fields in XML view * Cache action keyword * Always use cached views * Manage model access * Manage time format * Deactivate attachment button when record is not created Version 2.4.0 - 2012-04-23 * Bug fixes (see mercurial logs for details) * Remove workflow * Improve contextual menu: - Actions for all relation fields on list view - Use icons - Add attachments entry * Use RPCProgress almost everywhere * Add a simple search box * New domain parser using shlex * Better translation dialog box * Add the richtext widget for WYSIWYG Editor on text fields * Add a record pool to prefetch more records * Add Time widget * Add support for fuzzy_translation * Activate save button on editing * Refactor set/get and set/get_client of fields * Display binary size alongside the buttons in treeview * Set correctly the focus on tab switching * Add shortcut to focus search entry * Add binary field to tree views * Improve board view: - use the same search widget as form - link double click to open popup Version 2.2.0 - 2011-10-24 * Bug fixes (see mercurial logs for details) * New search widget * Improve memory management of Binary fields * Support buffer for Binary fields * Remove delete on Escape in editable tree * Use JSON-RPC * Limit size of field when possible * Add xalign and yalign as fields attributes * Convert many popup to be no-modal * Add window manager for: - replace current window - prevent simmilar window * Merge and review toolbars in form and board * Drop support of Python 2.5 * Use the same design for Many2Many than One2Many * Allow resize columns smaller than the header Version 2.0.0 - 2011-04-26 * Bug fixes (see mercurial logs for details) * Popup form dialog has 3 buttons (close, ok, new) * New UI layout * Add DnD on tree view * Merge tree and list views * Remove generic default value on right-click * Made numpad locale aware * Selection widget used for many2one dynamically change their content following the domain specification * Add open button on binary and image widgets * Hide buttons on image widget if readonly * Added a connection manager à la gajim * Fix warning in wizards * Added possibility to use server-side icons * Added additional gtk.Entry for filename on BinaryField * Display deleted lines in One2Many and Many2Many * Handle URL * Add communication between boards * Added domain inversion feature * Handle loading attribute on fields * Use default format for value in wizard form * Add One2One field Version 1.8.0 - 2010-11-01 * Bug fixes (see mercurial logs for details) * More fully integrate GTK menubar for Mac OS * Allow to configure search limit * Add Previous/Next on list view * Set non-applicable form controls in one2many view to be insensitive Version 1.6.0 - 2010-05-08 * Bug fixes (see mercurial logs for details) * Don't stop wizard execution when exception occurs * Use ir.attachment view instead of a custom one * Add fingerprint and CA check for SSL connection * Use lazy load in Import/Export windows * Validate record before switching view * Refactoring: * Better naming in model * Group extends list * Add an index to Group * New common windows for dialog of many2one, one2many and many2many * one2many and many2many dialog use the same screen than the widget * Reduce the number of option in Screen * Remove RPCProxy to handle logout exception on every server call * Better naming of event signals * Fix on_change detection for many2many for issue1400 * Add PySON to replace python string evaluation * Don't show "Spell Checking" option if gtkspell is not present * Use the same internal model for many2many and one2many fields * Remove egenix-mx-base and replace it by python-dateutil * Add cache to safe_eval * Use versioned configuration directory * Next and Previous scroll per page on list and don't loop * Add AccelGroup on search windows (CTRL+Return) * Use same keyboard shortcut for xxx2many than for other fields Version 1.4.0 - 2009-10-19 * Bug fixes (see mercurial logs for details) * Handle datetime_field in xxx2Many * Add new safe_eval * Ask previous password for set_preferences on password change * Add "Statusbar" option * Add default filename for database backup * Add checkbox on restore to update database * Add 'login.host' options to hide server connection * Handle required attribute with local domains * Allow to run wizard in tabs * Remove statusbar on form for more space * Add "Change Accelerators" option * Use gzip in pysocket * Use the report name to create the temporary file to open it * Allow to store wizard size * Add reset default on fields * Store in config default width and height of main window * Added arrow navigation if supported by gtk * Add 'starts with' and 'ends with' on char search * Handle domain with '=' or '!=' as operator on selection * Extend fields domain with local domains * Improve float time widget to handle year, month, week and day and handle float_time attribute for contextual time convertion Version 1.2.0 - 2009-04-20 * Bug fixes (see mercurial logs for details) * Make graph works also with datetime * Add edition on Many2Many * Fix open in csv export to use file actions * Update client labels at language change * Handle datetime_field in Many2One * Set readonly on records with _datetime in the context * Display values of reference fields even if there is no model * Allow to directly print or create email with reports * Handle invisible states on list view * Add user warnings * Add Model in logs * Allow to duplicate many records at once * Improve netrpc communication speed * Improve date widget to display mask only when having focus * Fix for host with IPv6 enable but without default IPv6 route * Add desktop entry * Add win32 single executable * Allow egg installation Version 1.0.0 - 2008-11-17 * Initial release tryton-5.0.17/make-win32-installer.sh0000644000175000017500000000030113463252531016655 0ustar cedced00000000000000#!/bin/sh set -e version=`./setup.py --version` series=${version%.*} ./setup.py compile_catalog ./setup-freeze.py install_exe -d dist makensis -DVERSION=${version} -DSERIES=${series} setup.nsi tryton-5.0.17/spanish.nsh0000644000175000017500000000210713463252531014636 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_SPANISH} LangString LicenseText ${CURLANG} "Tryton está liberado bajo la licencia «GNU General Public License» publicada por la Free Software Foundation, o bien la versión 3 de la licencia, o (a su elección) cualquier versión posterior. Lea cuidadosamente la licencia. Pulse «Siguiente» para continuar." LangString LicenseNext ${CURLANG} "&Siguiente" LangString PreviousInstall ${CURLANG} "Tryton ya está instalado.$\n$\nPulse `OK` para eliminar la versión anterior o `Cancelar` para cancelar la actualización." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Instalar tryton.exe y otros archivos necesarios" LangString SecStartMenuName ${CURLANG} "Accesos directos en el menú de inicio y en el escritorio" LangString SecStartMenuDesc ${CURLANG} "Crear accesos directos en el menú de inicio y en el escritorio" tryton-5.0.17/make-darwin-installer.sh0000644000175000017500000000057713463252531017216 0ustar cedced00000000000000#!/bin/sh set -e version=`./setup.py --version` ./setup.py compile_catalog ./setup-freeze.py bdist_mac rm -rf dist mkdir dist mv build/Tryton.app dist/ for f in CHANGELOG COPYRIGHT LICENSE README; do cp ${f} dist/${f}.txt done cp -r doc dist/ rm -f "tryton-${version}.dmg" hdiutil create "tryton-${version}.dmg" -volname "Tryton Client ${version}" \ -fs HFS+ -srcfolder dist tryton-5.0.17/COPYRIGHT0000644000175000017500000000201213571264251013747 0ustar cedced00000000000000Copyright (C) 2004-2008 Tiny SPRL. Copyright (C) 2007-2009 Lorenzo Gil Sanchez. Copyright (C) 2007-2013 Bertrand Chenal. Copyright (C) 2007-2019 Cédric Krier. Copyright (C) 2008-2011 Udo Spallek. Copyright (C) 2008-2011 virtual things - Preisler & Spallek GbR. Copyright (C) 2008-2019 B2CK SPRL. Copyright (C) 2010-2019 Nicolas Évrard. Copyright (C) 2011-2012 Rodrigo Hübner. Copyright (C) 2012-2013 Antoine Smolders. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . tryton-5.0.17/portuguese.nsh0000644000175000017500000000203413463252531015372 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_ENGLISH} LangString LicenseText ${CURLANG} "Tryton é licenciado sob a General Public License conforme publicada pela Free Software Foundation, conforme a versão 3 da licença, ou (segundo sua escolha) qualquer versão posterior. Favor ler a licença cuidadosamente. Clique em Seguinte para continuar." LangString LicenseNext ${CURLANG} "&Seguinte" LangString PreviousInstall ${CURLANG} "O Tryton já está instalado.$\n$\nClique em 'OK' para remover a versão anterior ou 'Cancelar' para cancelar esta atualização." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Instala tryton.exe e outros arquivos necessários" LangString SecStartMenuName ${CURLANG} "Menu Iniciar e Atalhos da Área de Trabalho" LangString SecStartMenuDesc ${CURLANG} "Criar atalhos no menu iniciar e na área de trabalho" tryton-5.0.17/english.nsh0000644000175000017500000000173013463252531014623 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_ENGLISH} LangString LicenseText ${CURLANG} "Tryton is released under 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. Please carefully read the license. Click Next to continue." LangString LicenseNext ${CURLANG} "&Next" LangString PreviousInstall ${CURLANG} "Tryton is already installed.$\n$\nClick `OK` to remove the previous version or `Cancel` to cancel this upgrade." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Install tryton.exe and other required files" LangString SecStartMenuName ${CURLANG} "Start Menu and Desktop Shortcuts" LangString SecStartMenuDesc ${CURLANG} "Create shortcuts in the start menu and on desktop" tryton-5.0.17/setup.cfg0000644000175000017500000000073613571264253014312 0ustar cedced00000000000000[extract_messages] copyright_holder = Tryton msgid_bugs_address = issue_tracker@tryton.org output_file = tryton/data/locale/tryton.pot keywords = _, gettext [init_catalog] domain = tryton input_file = tryton/data/locale/tryton.pot output_dir = tryton/data/locale [compile_catalog] domain = tryton directory = tryton/data/locale [update_catalog] domain = tryton input_file = tryton/data/locale/tryton.pot output_dir = tryton/data/locale [egg_info] tag_build = tag_date = 0 tryton-5.0.17/PKG-INFO0000644000175000017500000000563313571264253013567 0ustar cedced00000000000000Metadata-Version: 2.1 Name: tryton Version: 5.0.17 Summary: Tryton client Home-page: http://www.tryton.org/ Author: Tryton Author-email: issue_tracker@tryton.org License: GPL-3 Download-URL: http://downloads.tryton.org/5.0/ Description: tryton ====== The client of the Tryton application platform. A three-tiers high-level general purpose application platform written in Python and use Postgresql as database engine. It is the core base of an Open Source ERP. It provides modularity, scalability and security. Installing ---------- See INSTALL Package Contents ---------------- bin/ Script for startup. doc/ sphinx documentation in reStructuredText. To generate the HTML: python doc/build.py tryton/ tryton sources. Support ------- If you encounter any problems with Tryton, please don't hesitate to ask questions on the Tryton bug tracker, mailing list, wiki or IRC channel: http://bugs.tryton.org/ http://groups.tryton.org/ http://wiki.tryton.org/ irc://irc.freenode.net/tryton License ------- See LICENSE Copyright --------- See COPYRIGHT For more information please visit the Tryton web site: http://www.tryton.org/ Keywords: business application ERP Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: X11 Applications :: GTK Classifier: Framework :: Tryton Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: Bulgarian Classifier: Natural Language :: Catalan Classifier: Natural Language :: Chinese (Simplified) Classifier: Natural Language :: Czech Classifier: Natural Language :: Dutch Classifier: Natural Language :: English Classifier: Natural Language :: French Classifier: Natural Language :: German Classifier: Natural Language :: Hungarian Classifier: Natural Language :: Italian Classifier: Natural Language :: Persian Classifier: Natural Language :: Polish Classifier: Natural Language :: Portuguese (Brazilian) Classifier: Natural Language :: Russian Classifier: Natural Language :: Slovenian Classifier: Natural Language :: Spanish Classifier: Natural Language :: Japanese Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Office/Business Requires-Python: >=3.4 Provides-Extra: calendar tryton-5.0.17/setup-freeze.py0000644000175000017500000001002213463252531015442 0ustar cedced00000000000000#!/usr/bin/env python3 # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os import re import sys import tempfile from subprocess import Popen, PIPE, check_call from cx_Freeze import setup, Executable home = os.path.expanduser('~/') pythonrc = os.path.join(home, '.pythonrc.py') try: with open(pythonrc) as fp: exec(fp.read()) except IOError: pass include_files = [ (os.path.join('tryton', 'data'), 'data'), (os.path.join('tryton', 'plugins'), 'plugins'), (os.path.join(sys.prefix, 'share', 'glib-2.0', 'schemas'), os.path.join('share', 'glib-2.0', 'schemas')), (os.path.join(sys.prefix, 'lib', 'gtk-3.0'), os.path.join('lib', 'gtk-3.0')), (os.path.join(sys.prefix, 'lib', 'gdk-pixbuf-2.0'), os.path.join('lib', 'gdk-pixbuf-2.0')), (os.path.join(sys.prefix, 'share', 'locale'), os.path.join('share', 'locale')), (os.path.join(sys.prefix, 'share', 'icons', 'Adwaita'), os.path.join('share', 'icons', 'Adwaita')), (os.path.join(sys.platform, 'gtk-3.0', 'gtk.immodules'), os.path.join('etc', 'gtk-3.0', 'gtk.immodules')), (os.path.join(sys.platform, 'gtk-3.0', 'gdk-pixbuf.loaders'), os.path.join('etc', 'gtk-3.0', 'gdk-pixbuf.loaders')), ] required_gi_namespaces = [ 'Atk-1.0', 'GLib-2.0', 'GModule-2.0', 'GObject-2.0', 'Gdk-3.0', 'GdkPixbuf-2.0', 'Gio-2.0', 'GooCanvas-2.0', 'Gtk-3.0', 'Pango-1.0', 'PangoCairo-1.0', 'PangoFT2-1.0', 'Rsvg-2.0', 'cairo-1.0', 'fontconfig-2.0', 'freetype2-2.0', ] def replace_path(match): libs = [os.path.basename(p) for p in match.group(1).split(',')] required_libs.update(libs) if sys.platform == 'darwin': libs = [os.path.join('@executable_path', l) for l in libs] return 'shared-library="%s"' % ','.join(libs) lib_re = re.compile(r'shared-library="([^\"]*)"') required_libs = set() temp = tempfile.mkdtemp() for ns in required_gi_namespaces: gir_name = '%s.gir' % ns gir_file = os.path.join(sys.prefix, 'share', 'gir-1.0', gir_name) gir_tmp = os.path.join(temp, gir_name) with open(gir_file, 'r', encoding='utf-8') as src: with open(gir_tmp, 'w', encoding='utf-8') as dst: for line in src: dst.write(lib_re.sub(replace_path, line)) typefile_name = '%s.typelib' % ns typefile_file = os.path.join('lib', 'girepository-1.0', typefile_name) typefile_tmp = os.path.join(temp, typefile_name) check_call(['g-ir-compiler', '--output=' + typefile_tmp, gir_tmp]) include_files.append((typefile_tmp, typefile_file)) if sys.platform == 'win32': required_libs.update([ 'libcroco-0.6-3.dll', 'libepoxy-0.dll', ]) include_files.append( (os.path.join(sys.prefix, 'ssl'), os.path.join('etc', 'ssl'))) lib_path = os.getenv('PATH', os.defpath).split(os.pathsep) else: lib_path = [os.path.join(sys.prefix, 'lib')] for lib in required_libs: for path in lib_path: path = os.path.join(path, lib) if os.path.isfile(path): break else: raise Exception('%s not found' % lib) include_files.append((path, lib)) version = Popen( 'python setup.py --version', stdout=PIPE, shell=True).stdout.read() version = version.strip() setup(name='tryton', version=version, options={ 'build_exe': { 'no_compress': True, 'include_files': include_files, 'silent': True, 'packages': ['gi'], 'include_msvcr': True, }, 'bdist_mac': { 'iconfile': os.path.join( 'tryton', 'data', 'pixmaps', 'tryton', 'tryton.icns'), 'bundle_name': 'Tryton', } }, executables=[Executable( 'bin/tryton', base='Win32GUI' if sys.platform == 'win32' else None, icon=os.path.join( 'tryton', 'data', 'pixmaps', 'tryton', 'tryton.ico'), )]) tryton-5.0.17/tryton.egg-info/0000755000175000017500000000000013571264253015514 5ustar cedced00000000000000tryton-5.0.17/tryton.egg-info/dependency_links.txt0000644000175000017500000000000113571264253021562 0ustar cedced00000000000000 tryton-5.0.17/tryton.egg-info/PKG-INFO0000644000175000017500000000563313571264253016620 0ustar cedced00000000000000Metadata-Version: 2.1 Name: tryton Version: 5.0.17 Summary: Tryton client Home-page: http://www.tryton.org/ Author: Tryton Author-email: issue_tracker@tryton.org License: GPL-3 Download-URL: http://downloads.tryton.org/5.0/ Description: tryton ====== The client of the Tryton application platform. A three-tiers high-level general purpose application platform written in Python and use Postgresql as database engine. It is the core base of an Open Source ERP. It provides modularity, scalability and security. Installing ---------- See INSTALL Package Contents ---------------- bin/ Script for startup. doc/ sphinx documentation in reStructuredText. To generate the HTML: python doc/build.py tryton/ tryton sources. Support ------- If you encounter any problems with Tryton, please don't hesitate to ask questions on the Tryton bug tracker, mailing list, wiki or IRC channel: http://bugs.tryton.org/ http://groups.tryton.org/ http://wiki.tryton.org/ irc://irc.freenode.net/tryton License ------- See LICENSE Copyright --------- See COPYRIGHT For more information please visit the Tryton web site: http://www.tryton.org/ Keywords: business application ERP Platform: any Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: X11 Applications :: GTK Classifier: Framework :: Tryton Classifier: Intended Audience :: End Users/Desktop Classifier: License :: OSI Approved :: GNU General Public License (GPL) Classifier: Natural Language :: Bulgarian Classifier: Natural Language :: Catalan Classifier: Natural Language :: Chinese (Simplified) Classifier: Natural Language :: Czech Classifier: Natural Language :: Dutch Classifier: Natural Language :: English Classifier: Natural Language :: French Classifier: Natural Language :: German Classifier: Natural Language :: Hungarian Classifier: Natural Language :: Italian Classifier: Natural Language :: Persian Classifier: Natural Language :: Polish Classifier: Natural Language :: Portuguese (Brazilian) Classifier: Natural Language :: Russian Classifier: Natural Language :: Slovenian Classifier: Natural Language :: Spanish Classifier: Natural Language :: Japanese Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Topic :: Office/Business Requires-Python: >=3.4 Provides-Extra: calendar tryton-5.0.17/tryton.egg-info/top_level.txt0000644000175000017500000000000713571264253020243 0ustar cedced00000000000000tryton tryton-5.0.17/tryton.egg-info/not-zip-safe0000644000175000017500000000000113366255714017746 0ustar cedced00000000000000 tryton-5.0.17/tryton.egg-info/SOURCES.txt0000644000175000017500000002241513571264253017404 0ustar cedced00000000000000.hgtags CHANGELOG COPYRIGHT INSTALL LICENSE MANIFEST.in README catalan.nsh english.nsh farsi.nsh french.nsh german.nsh make-darwin-installer.sh make-win32-installer.sh portuguese.nsh setup-freeze.py setup.cfg setup.nsi setup.py slovenian.nsh spanish.nsh tryton.desktop bin/tryton darwin/gtk-3.0/gdk-pixbuf.loaders darwin/gtk-3.0/gtk.immodules doc/Makefile doc/build.py doc/conf.py doc/glossary.rst doc/index.rst doc/installation.rst doc/introduction.rst doc/make.bat doc/usage.rst tryton/__init__.py tryton/bus.py tryton/client.py tryton/config.py tryton/exceptions.py tryton/fingerprints.py tryton/jsonrpc.py tryton/pyson.py tryton/rpc.py tryton/signal_event.py tryton/translate.py tryton.egg-info/PKG-INFO tryton.egg-info/SOURCES.txt tryton.egg-info/dependency_links.txt tryton.egg-info/not-zip-safe tryton.egg-info/requires.txt tryton.egg-info/top_level.txt tryton/action/__init__.py tryton/action/main.py tryton/common/__init__.py tryton/common/button.py tryton/common/cellrendererbinary.py tryton/common/cellrendererbutton.py tryton/common/cellrendererclickablepixbuf.py tryton/common/cellrenderercombo.py tryton/common/cellrendererfloat.py tryton/common/cellrendererinteger.py tryton/common/cellrenderertext.py tryton/common/cellrenderertoggle.py tryton/common/common.py tryton/common/completion.py tryton/common/datetime_.py tryton/common/datetime_strftime.py tryton/common/domain_inversion.py tryton/common/domain_parser.py tryton/common/entry_position.py tryton/common/environment.py tryton/common/focus.py tryton/common/htmltextbuffer.py tryton/common/popup_menu.py tryton/common/selection.py tryton/common/timedelta.py tryton/common/treeviewcontrol.py tryton/common/underline.py tryton/common/widget_style.py tryton/data/locale/tryton.pot tryton/data/locale/bg/LC_MESSAGES/tryton.mo tryton/data/locale/bg/LC_MESSAGES/tryton.po tryton/data/locale/ca/LC_MESSAGES/tryton.mo tryton/data/locale/ca/LC_MESSAGES/tryton.po tryton/data/locale/cs/LC_MESSAGES/tryton.mo tryton/data/locale/cs/LC_MESSAGES/tryton.po tryton/data/locale/de/LC_MESSAGES/tryton.mo tryton/data/locale/de/LC_MESSAGES/tryton.po tryton/data/locale/es/LC_MESSAGES/tryton.mo tryton/data/locale/es/LC_MESSAGES/tryton.po tryton/data/locale/es_419/LC_MESSAGES/tryton.mo tryton/data/locale/es_419/LC_MESSAGES/tryton.po tryton/data/locale/fa/LC_MESSAGES/tryton.mo tryton/data/locale/fa/LC_MESSAGES/tryton.po tryton/data/locale/fr/LC_MESSAGES/tryton.mo tryton/data/locale/fr/LC_MESSAGES/tryton.po tryton/data/locale/hu_HU/LC_MESSAGES/tryton.mo tryton/data/locale/hu_HU/LC_MESSAGES/tryton.po tryton/data/locale/it_IT/LC_MESSAGES/tryton.mo tryton/data/locale/it_IT/LC_MESSAGES/tryton.po tryton/data/locale/ja_JP/LC_MESSAGES/tryton.mo tryton/data/locale/ja_JP/LC_MESSAGES/tryton.po tryton/data/locale/lo/LC_MESSAGES/tryton.mo tryton/data/locale/lo/LC_MESSAGES/tryton.po tryton/data/locale/lt/LC_MESSAGES/tryton.mo tryton/data/locale/lt/LC_MESSAGES/tryton.po tryton/data/locale/nl/LC_MESSAGES/tryton.mo tryton/data/locale/nl/LC_MESSAGES/tryton.po tryton/data/locale/pl/LC_MESSAGES/tryton.mo tryton/data/locale/pl/LC_MESSAGES/tryton.po tryton/data/locale/pt_BR/LC_MESSAGES/tryton.mo tryton/data/locale/pt_BR/LC_MESSAGES/tryton.po tryton/data/locale/ru/LC_MESSAGES/tryton.mo tryton/data/locale/ru/LC_MESSAGES/tryton.po tryton/data/locale/sl/LC_MESSAGES/tryton.mo tryton/data/locale/sl/LC_MESSAGES/tryton.po tryton/data/locale/zh_CN/LC_MESSAGES/tryton.mo tryton/data/locale/zh_CN/LC_MESSAGES/tryton.po tryton/data/pixmaps/tryton/LICENSE tryton/data/pixmaps/tryton/tryton-add.svg tryton/data/pixmaps/tryton/tryton-archive.svg tryton/data/pixmaps/tryton/tryton-attach.svg tryton/data/pixmaps/tryton/tryton-back.svg tryton/data/pixmaps/tryton/tryton-bookmark-border.svg tryton/data/pixmaps/tryton/tryton-bookmark.svg tryton/data/pixmaps/tryton/tryton-bookmarks.svg tryton/data/pixmaps/tryton/tryton-cancel.svg tryton/data/pixmaps/tryton/tryton-clear.svg tryton/data/pixmaps/tryton/tryton-close.svg tryton/data/pixmaps/tryton/tryton-copy.svg tryton/data/pixmaps/tryton/tryton-create.svg tryton/data/pixmaps/tryton/tryton-date.svg tryton/data/pixmaps/tryton/tryton-delete.svg tryton/data/pixmaps/tryton/tryton-email.svg tryton/data/pixmaps/tryton/tryton-error.svg tryton/data/pixmaps/tryton/tryton-exit.svg tryton/data/pixmaps/tryton/tryton-export.svg tryton/data/pixmaps/tryton/tryton-filter.svg tryton/data/pixmaps/tryton/tryton-format-align-center.svg tryton/data/pixmaps/tryton/tryton-format-align-justify.svg tryton/data/pixmaps/tryton/tryton-format-align-left.svg tryton/data/pixmaps/tryton/tryton-format-align-right.svg tryton/data/pixmaps/tryton/tryton-format-bold.svg tryton/data/pixmaps/tryton/tryton-format-color-text.svg tryton/data/pixmaps/tryton/tryton-format-italic.svg tryton/data/pixmaps/tryton/tryton-format-underline.svg tryton/data/pixmaps/tryton/tryton-forward.svg tryton/data/pixmaps/tryton/tryton-history.svg tryton/data/pixmaps/tryton/tryton-icon.png tryton/data/pixmaps/tryton/tryton-import.svg tryton/data/pixmaps/tryton/tryton-info.svg tryton/data/pixmaps/tryton/tryton-launch.svg tryton/data/pixmaps/tryton/tryton-link.svg tryton/data/pixmaps/tryton/tryton-log.svg tryton/data/pixmaps/tryton/tryton-menu.svg tryton/data/pixmaps/tryton/tryton-note.svg tryton/data/pixmaps/tryton/tryton-ok.svg tryton/data/pixmaps/tryton/tryton-open.svg tryton/data/pixmaps/tryton/tryton-print.svg tryton/data/pixmaps/tryton/tryton-public.svg tryton/data/pixmaps/tryton/tryton-refresh.svg tryton/data/pixmaps/tryton/tryton-remove.svg tryton/data/pixmaps/tryton/tryton-save.svg tryton/data/pixmaps/tryton/tryton-search.svg tryton/data/pixmaps/tryton/tryton-star-border.svg tryton/data/pixmaps/tryton/tryton-star.svg tryton/data/pixmaps/tryton/tryton-switch.svg tryton/data/pixmaps/tryton/tryton-translate.svg tryton/data/pixmaps/tryton/tryton-unarchive.svg tryton/data/pixmaps/tryton/tryton-undo.svg tryton/data/pixmaps/tryton/tryton-warning.svg tryton/data/pixmaps/tryton/tryton.icns tryton/data/pixmaps/tryton/tryton.ico tryton/data/pixmaps/tryton/tryton.png tryton/gui/__init__.py tryton/gui/main.py tryton/gui/window/__init__.py tryton/gui/window/about.py tryton/gui/window/attachment.py tryton/gui/window/board.py tryton/gui/window/dblogin.py tryton/gui/window/email.py tryton/gui/window/form.py tryton/gui/window/infobar.py tryton/gui/window/limit.py tryton/gui/window/nomodal.py tryton/gui/window/note.py tryton/gui/window/preference.py tryton/gui/window/revision.py tryton/gui/window/shortcuts.py tryton/gui/window/tabcontent.py tryton/gui/window/win_csv.py tryton/gui/window/win_export.py tryton/gui/window/win_form.py tryton/gui/window/win_import.py tryton/gui/window/win_search.py tryton/gui/window/window.py tryton/gui/window/wizard.py tryton/gui/window/view_board/__init__.py tryton/gui/window/view_board/action.py tryton/gui/window/view_board/view_board.py tryton/gui/window/view_form/__init__.py tryton/gui/window/view_form/model/__init__.py tryton/gui/window/view_form/model/field.py tryton/gui/window/view_form/model/group.py tryton/gui/window/view_form/model/record.py tryton/gui/window/view_form/screen/__init__.py tryton/gui/window/view_form/screen/screen.py tryton/gui/window/view_form/view/__init__.py tryton/gui/window/view_form/view/calendar_.py tryton/gui/window/view_form/view/form.py tryton/gui/window/view_form/view/graph.py tryton/gui/window/view_form/view/list.py tryton/gui/window/view_form/view/screen_container.py tryton/gui/window/view_form/view/calendar_gtk/__init__.py tryton/gui/window/view_form/view/calendar_gtk/calendar_.py tryton/gui/window/view_form/view/calendar_gtk/dates_period.py tryton/gui/window/view_form/view/calendar_gtk/toolbar.py tryton/gui/window/view_form/view/form_gtk/__init__.py tryton/gui/window/view_form/view/form_gtk/binary.py tryton/gui/window/view_form/view/form_gtk/calendar.py tryton/gui/window/view_form/view/form_gtk/char.py tryton/gui/window/view_form/view/form_gtk/checkbox.py tryton/gui/window/view_form/view/form_gtk/dictionary.py tryton/gui/window/view_form/view/form_gtk/float.py tryton/gui/window/view_form/view/form_gtk/image.py tryton/gui/window/view_form/view/form_gtk/integer.py tryton/gui/window/view_form/view/form_gtk/many2many.py tryton/gui/window/view_form/view/form_gtk/many2one.py tryton/gui/window/view_form/view/form_gtk/multiselection.py tryton/gui/window/view_form/view/form_gtk/one2many.py tryton/gui/window/view_form/view/form_gtk/one2one.py tryton/gui/window/view_form/view/form_gtk/progressbar.py tryton/gui/window/view_form/view/form_gtk/pyson.py tryton/gui/window/view_form/view/form_gtk/reference.py tryton/gui/window/view_form/view/form_gtk/richtextbox.py tryton/gui/window/view_form/view/form_gtk/selection.py tryton/gui/window/view_form/view/form_gtk/state_widget.py tryton/gui/window/view_form/view/form_gtk/textbox.py tryton/gui/window/view_form/view/form_gtk/timedelta.py tryton/gui/window/view_form/view/form_gtk/url.py tryton/gui/window/view_form/view/form_gtk/widget.py tryton/gui/window/view_form/view/graph_gtk/__init__.py tryton/gui/window/view_form/view/graph_gtk/bar.py tryton/gui/window/view_form/view/graph_gtk/graph.py tryton/gui/window/view_form/view/graph_gtk/line.py tryton/gui/window/view_form/view/graph_gtk/pie.py tryton/gui/window/view_form/view/list_gtk/__init__.py tryton/gui/window/view_form/view/list_gtk/editabletree.py tryton/gui/window/view_form/view/list_gtk/widget.py tryton/plugins/__init__.py tryton/plugins/translation/__init__.py win32/gtk-3.0/gdk-pixbuf.loaders win32/gtk-3.0/gtk.immodulestryton-5.0.17/tryton.egg-info/requires.txt0000644000175000017500000000007713571264253020120 0ustar cedced00000000000000pycairo python-dateutil PyGObject [calendar] GooCalendar>=0.4 tryton-5.0.17/README0000644000175000017500000000166613354423127013350 0ustar cedced00000000000000tryton ====== The client of the Tryton application platform. A three-tiers high-level general purpose application platform written in Python and use Postgresql as database engine. It is the core base of an Open Source ERP. It provides modularity, scalability and security. Installing ---------- See INSTALL Package Contents ---------------- bin/ Script for startup. doc/ sphinx documentation in reStructuredText. To generate the HTML: python doc/build.py tryton/ tryton sources. Support ------- If you encounter any problems with Tryton, please don't hesitate to ask questions on the Tryton bug tracker, mailing list, wiki or IRC channel: http://bugs.tryton.org/ http://groups.tryton.org/ http://wiki.tryton.org/ irc://irc.freenode.net/tryton License ------- See LICENSE Copyright --------- See COPYRIGHT For more information please visit the Tryton web site: http://www.tryton.org/ tryton-5.0.17/french.nsh0000644000175000017500000000210113463252531014430 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_FRENCH} LangString LicenseText ${CURLANG} "Tryton est publié sous la GNU General Public License comme publiée par la Free Software Foundation, soit la version 3 de la License, ou (à votre choix) toute version ultérieure. S'il vous plaît lisez attentivement la license. Cliquez sur Suivant pour continuer." LangString LicenseNext ${CURLANG} "&Suivant" LangString PreviousInstall ${CURLANG} "Tryton est déjà installé.$\n$\nCliquez `OK` pour supprimer la précédente version ou `Annuler` pour annuler cette mis à jour." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Installe tryton.exe et d'autres fichiers requis" LangString SecStartMenuName ${CURLANG} "Raccourcis dans le menu Démarrer et sur le bureau" LangString SecStartMenuDesc ${CURLANG} "Crée les raccourcis dans le menu Démarrer et sur le bureau" tryton-5.0.17/farsi.nsh0000644000175000017500000000340413463252531014276 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_FARSI} LangString LicenseText ${CURLANG} "*1'*HF *-* E,H2 , ~ 'D 3 (F'/ F1E 'A2'1G' "2'/EF*41 4/G '3*  D7A' EA'/ E,H2 1' (' /B* E7'D9G A1E'&/. (1' '/'EG (9/ 1' D F/." LangString LicenseNext ${CURLANG} "&(9/" LangString PreviousInstall ${CURLANG} "Tryton /1 -'D -'61 F5( 4/G '3*.$\n$\n (1' -0A F3.G B(D ' D:H (1' D:H 'F '1*B'!  OK 1' D F/." LangString SecTrytonName ${CURLANG} "*1'*HF" LangString SecTrytonDesc ${CURLANG} "F5( A'D *1'*HF ',1' H 3'1 ED2HE'* F1E 'A2'1" LangString SecStartMenuName ${CURLANG} "EFH 41H9 H E'F(1G' /3*'~" LangString SecStartMenuDesc ${CURLANG} "D7A'K E'F(1 G' EFH 41H9 H /3*'~ 1' ','/ F/" tryton-5.0.17/german.nsh0000644000175000017500000000207213463252531014443 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_GERMAN} LangString LicenseText ${CURLANG} "Tryton wird unter der GNU General Public License wie von der Free Software Foundation veröffentlicht freigegeben, entweder Version 3 der Lizenz oder (nach Ihrer Wahl) jeder späteren Version. Bitte lesen Sie die Lizenz aufmerksam. Klicken Sie auf Weiter, um fortzufahren." LangString LicenseNext ${CURLANG} "&Weiter" LangString PreviousInstall ${CURLANG} "Tryton ist bereits installiert.$\n$\nWählen Sie `OK`, um die bisherige Version zu entfernen oder `Abbrechen` um die Aktualisierung abzubrechen." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "tryton.exe und andere benötigte Dateien installieren" LangString SecStartMenuName ${CURLANG} "Startmenü und Desktop-Verknüpfungen" LangString SecStartMenuDesc ${CURLANG} "Verknüpfungen im Startmenü und auf dem Desktop erstellen" tryton-5.0.17/slovenian.nsh0000644000175000017500000000201713463252531015167 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_SLOVENIAN} LangString LicenseText ${CURLANG} "Tryton je izdan pod licenco GNU General Public License, kot jo je objavila Free Software Foundation, bodisi pod razlièico 3 ali (po va¹i izbiri) katerokoli poznej¹o razlièico. Licenco pozorno preberite. Kliknite Naprej za nadaljevanje." LangString LicenseNext ${CURLANG} "&Naprej" LangString PreviousInstall ${CURLANG} "Tryton je že nameščen.$\n$\nKliknite »V redu«, da odstranite prejšnjo različico ali »Prekliči«, da prekličete to nadgradnjo." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Namestitev tryton.exe in ostalih potrebnih datotek" LangString SecStartMenuName ${CURLANG} "Bli¾njici v zaèetnem meniju in na namizju" LangString SecStartMenuDesc ${CURLANG} "Ustvari bli¾njici v zaèetnem meniju in na namizju" tryton-5.0.17/bin/0000755000175000017500000000000013571264253013233 5ustar cedced00000000000000tryton-5.0.17/bin/tryton0000755000175000017500000000345613463252531014524 0ustar cedced00000000000000#!/usr/bin/env python3 import sys import os try: DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..', '..', 'tryton'))) if os.path.isdir(DIR): sys.path.insert(0, os.path.dirname(DIR)) except NameError: pass if hasattr(sys, 'frozen'): if not ('-v' in sys.argv or '--verbose' in sys.argv or '-l' in sys.argv or '--log-level' in sys.argv): sys.stdout = open(os.devnull, 'w') sys.stderr = open(os.devnull, 'w') prefix = os.path.dirname(sys.executable) os.environ['GTK_EXE_PREFIX'] = prefix os.environ['GTK_DATA_PREFIX'] = prefix os.environ['XDG_DATA_DIRS'] = os.path.join(prefix, 'share') etc = os.path.join(prefix, 'etc') os.environ['GDK_PIXBUF_MODULE_FILE'] = os.path.join( etc, 'gtk-3.0', 'gdk-pixbuf.loaders') os.environ['GTK_IM_MODULE_FILE'] = os.path.join( etc, 'gtk-3.0', 'gtk.immodules') os.environ['GI_TYPELIB_PATH'] = os.path.join( prefix, 'lib', 'girepository-1.0') if sys.platform == 'win32': # cx_freeze >= 5 put python modules under lib directory sys.path.append(os.path.join(prefix, 'lib')) os.environ.setdefault('SSL_CERT_FILE', os.path.join(etc, 'ssl', 'cert.pem')) os.environ.setdefault('SSL_CERT_DIR', os.path.join(etc, 'ssl', 'certs')) # On first launch the MacOSX app launcher may append an extra unique # argument starting with -psn_. This must be filtered to not crash the # option parser. if sys.platform == 'darwin': sys.argv = [a for a in sys.argv if not a.startswith('-psn_')] # Disable dbusmenu to show second menu in tabs os.environ['UBUNTU_MENUPROXY'] = '0' # overlay-scrollbar breaks treeview height os.environ['LIBOVERLAY_SCROLLBAR'] = '0' from tryton.client import main main() tryton-5.0.17/MANIFEST.in0000644000175000017500000000061713563614150014221 0ustar cedced00000000000000include LICENSE include COPYRIGHT include README include INSTALL include CHANGELOG include setup.nsi include setup-single.nsi include setup-bundle.sh include tryton.desktop include *.nsh include setup-freeze.py include make-*-installer.sh include */gtk-3.0/* include doc/* recursive-include doc *.rst recursive-include doc *.po recursive-include doc *.pot include tryton/data/pixmaps/tryton/LICENSE tryton-5.0.17/doc/0000755000175000017500000000000013571264253013230 5ustar cedced00000000000000tryton-5.0.17/doc/installation.rst0000644000175000017500000000176013463252531016463 0ustar cedced00000000000000Installing tryton ================= Prerequisites ------------- * Python 3.4 or later (http://www.python.org/) * gtk+ 3.20 or later and py-gobject3 (http://www.gtk.org/) * librsvg (http://librsvg.sourceforge.net/) * python-dateutil (http://labix.org/python-dateutil) * Optional: GooCalendar 0.4 or later (https://pypi.python.org/pypi/GooCalendar) Installation ------------ Once you've downloaded and unpacked a tryton source release, enter the directory where the archive was unpacked, and run: ``python setup.py install`` Note that you may need administrator/root privileges for this step, as this command will by default attempt to install tryton to the Python site-packages directory on your system. For advanced options, please refer to the easy_install__ and/or the distutils__ documentation: __ http://setuptools.readthedocs.io/en/latest/easy_install.html __ http://docs.python.org/inst/inst.html To use without installation, run ``bin/tryton`` from where the archive was unpacked. tryton-5.0.17/doc/glossary.rst0000644000175000017500000001354713354423127015633 0ustar cedced00000000000000Glossary ######## .. glossary:: :sorted: Actions An *action* is a function which is triggered by a user intervention. *Actions* are called from activating menu items or pushing buttons. Actions often provide :term:`wizards`. Board The *board* is a type of :term:`views` able to handle other views. This view type is not documented or not used for now. Character Encoding See [WP-ENCOD]_ CSV File format for Comma Separated Values. See [WP-CSV]_ Data *Data* means information content produced by users. Dialog A *dialog* is a :term:`popup` window, which overlays other windows and request user interaction. *Dialogs* are used to set up special :term:`actions`. Fields *Fields* are attributes of a *data object*. *Fields* are represented as table fields in relational databases. Form View The *form* is a mode of :term:`views`, which displays single :term:`records` of data. Form The *form* is the general type of :term:`views` used in Tryton. The *form* provides several modes for presenting :term:`data`: * :term:`Form View` * :term:`Tree View` * :term:`Graph View` Graph View *Graph view* is a mode of :term:`views` to show sets of data in a diagram. *Graph views* can be pie-charts or bar-charts. Main Frame The *main frame* is a huge part arranged in the center of the :term:`Tryton client`. *Using the Tryton client* means mainly using the *main frame* part. It contains :term:`tabs` to organize and to show different :term:`views`. Model A *model* describes how data is represented and accessed. Models formally define records and relationships for a certain domain of interest. Modules *Modules* are enclosed file packages for the :term:`Tryton server`. A *Module* defines the :term:`Model`, the presentation of the information (:term:`views`), functions, :term:`actions` and default presets. Additionally *modules* may provide standardized data like ISO names for countries. *Modules* in Tryton are build up generically. That is, they are constructed as simple as possible to provide the desired functionality. Plugins A *plugin* is an add-on module for the :term:`Tryton client`. Popup A small window which pops up the main window. Records A *record* is a singular dataset in a :term:`Model`. *Records* are represented as lines or *records* in a relational database table. Tabs *Tabs* are :term:`widgets` to arrange different contents side by side. They are used to switch quickly between different domains of interest. Tryton uses *tabs* in two layer: * A tabbed :term:`Main Frame`. * Tabs inside :term:`Views`. The main frame consists of *tabs* that embed the main menu and all views to an appropriate :term:`model`. The other type of *tabs* is used inside of :term:`views` to split them into visual domains of the same model. These *tabs* are used for structuring contents of one model to different sub headings. Three-Tiers A *three-tiers* application framework like Tryton, is build up of three different software components: 1. The storage or data tier. 2. The logic or application tier. 3. The presentation tier. The storage tier in the Tryton framework is provided by the PostgreSQL database engine. The application logic tier is provided by :term:`Tryton server` and its :term:`modules`. The presentation tier is mainly provided by the :term:`Tryton client`. In a *three tiers* framework, the presentation tier (client) never connects directly to the storage tier. All communication is controlled by the application tier. Tree View *Tree view* is a mode of :term:`views` showing sets of :term:`data`. *Tree views* can be flat lists or tables as well as tree-like nested lists. Tryton Server The *Tryton server* is the application or logic tier in the :term:`three-tiers` application platform *Tryton*. The *Tryton server* connects the underlying application logic of the different :term:`modules` with corresponding database records. The *Tryton server* provides different interfaces to present the generated information: * :term:`Tryton client`: (graphical user interface GUI) * XMLRPC see [WP-XMLRPC]_ * WebDAV see [WP-WebDAV]_ * OpenOffice Tryton Client The *Tryton client* application is the graphical user interface (GUI) of the :term:`Tryton server`. Views A *view* is the visual presentation of :term:`data`. *Views* resides inside :term:`tabs` in the :term:`main frame` of the :term:`Tryton client`. There are two general types of *views* in Tryton: 1. :term:`Form` 2. :term:`Board` Each of the view types has different modes to show data. *Views* are built of several :term:`widgets` and provide often additional :term:`actions`. It is also possible to present the same data in different view modes alternately. Widgets A *Widget* is a visual element of a graphical user interface (GUI). Some *Widgets* solely show informations, others allow manipulation from user side. Example *Widgets* are buttons, check-boxes, entry-boxes, selection lists, tables, lists, trees, ... Wizards *Wizards* define stateful sequences of interaction to proceed complex :term:`actions`. A *wizard* divides the complexity of some actions into several user guided steps. References ********** .. [WP-XMLRPC] http://en.wikipedia.org/wiki/Xmlrpc .. [WP-WebDAV] http://en.wikipedia.org/wiki/Webdav .. [WP-CSV] http://en.wikipedia.org/wiki/Comma-separated_values .. [WP-ENCOD] http://en.wikipedia.org/wiki/Character_encoding tryton-5.0.17/doc/make.bat0000644000175000017500000000577713354423127014651 0ustar cedced00000000000000@ECHO OFF REM Command file for Sphinx documentation set SPHINXBUILD=sphinx-build set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. changes to make an overview over all changed/added/deprecated items echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Tryton.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Tryton.ghc goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) :end tryton-5.0.17/doc/conf.py0000644000175000017500000001503013561331112014512 0ustar cedced00000000000000# -*- coding: utf-8 -*- # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # # Tryton documentation build configuration file, created by # sphinx-quickstart on Tue Mar 23 13:25:32 2010. # # This file is execfile()d with the current directory set to its containing dir # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. from __future__ import unicode_literals # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # sys.path.append(os.path.abspath('.')) # -- General configuration ---------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. # source_encoding = 'utf-8' # The master toctree document. master_doc = 'index' # General information about the project. project = 'tryton' copyright = '2008-2011, Anne Krings, Bertrand Chenal, Cédric Krier, \ Mathias Behrle, Tobias Paepke, Udo Spallek' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '5.0' # The full version, including alpha/beta/rc tags. release = '5.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. # unused_docs = [] # List of directories, relative to source directory, that shouldn't be searched # for source files. exclude_trees = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # -- Options for HTML output -------------------------------------------------- # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. # html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_use_modindex = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = '' # Output file base name for HTML help builder. htmlhelp_basename = 'trytonddoc' # -- Options for LaTeX output ------------------------------------------------- # The paper size ('letter' or 'a4'). # latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). # latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]) latex_documents = [ ('index', 'tryton.tex', 'tryton Documentation', 'Anne Krings, Bertrand Chenal, Cédric Krier, Mathias Behrle, ' 'Tobias Paepke, Udo Spallek', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # Additional stuff for the LaTeX preamble. # latex_preamble = '' # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_use_modindex = True tryton-5.0.17/doc/Makefile0000644000175000017500000000606613354423127014674 0ustar cedced00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Tryton.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Tryton.qhc" latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ "run these through (pdf)latex." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." tryton-5.0.17/doc/usage.rst0000644000175000017500000004422513524765775015112 0ustar cedced00000000000000 :tocdepth: 2 Client Usage ############ This document is the reference about the concepts of the graphical user interface (also known as *Tryton client* ) of the Tryton application framework. Name **** tryton - Graphical user client of the Tryton application framework Synopsis ******** :: tryton [options] [url] On startup the login dialog is displayed. Options ******* --version Show program version number and exit -h, --help Show help message and exit -c FILE, --config=FILE Specify alternate `configuration file`_ -d, --dev Enable development mode, which deactivates client side caching -v, --verbose Enable basic debugging -l LOG_LEVEL, --log-level=LOG_LEVEL Specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL -u LOGIN, --user=LOGIN Specify the login user -s SERVER, --server=SERVER Specify the server hostname:port URL *** When an url is passed, the client will try to find already running client that could handle it and send to this one to open the url. If it doesn't find one then it will start the GUI and open the url itself. The url schemes are: `tryton://[:]//model/[/][;parameters]` `tryton://[:]//wizard/[;parameters]` `tryton://[:]//report/[;parameters]` where `parameters` are the corresponding fields of actions encoded in `JSON`_. .. _JSON: http://en.wikipedia.org/wiki/Json .. Note:: `model` is for `act_window` .. Note:: `report` must have at least a data parameter with `ids`, `id` and `model name` Overview ******** On startup the login dialog is displayed. It allows to select a existing profile (or to manage them) or to enter the host and database information. The following schematic illustration of the Tryton client shows the names of all important visual parts. Figure: Tryton client application:: Client Window ________________________________________________________________ |T| Search | Favorites Tryton _ o x| |----------------------------------------------------------------| | + | ______ | Tabs | |-+ | [Tab1] |[Tab2]| [Tab3]... | | | |- | +-------+ +--------------------------------+| | + | | Menu Tab2 || | |-+ | |-----------------------------------------------|| Tool bar | | |- | | New Save Switch Reload | Prev Next | Attach v || | | |- | |-----------------------------------------------|| | + | | _______________________ || Search widget | |-+ | | Filter | *| Bookmark <- -> || | | |- | |-----------------------------------------------|| | | |- | | || | + | | || View | |-+ | | || | |- | | || | |- | | || | | | || | | | || | | | || | | | || |_____________| |_______________________________________________|| |________________________________________________________________| Tabbed Main Frame ^^^^^^^^^^^^^^^^^ This part of the client contains all the related contents and functions provided by the :term:`Tryton server` :term:`modules`. All aspects inside the *main frame* depend at least on the individual set of installed modules. The main frame provides a `tabbed document interface`__ to arrange different views side by side. New :term:`tabs` are opened by special :term:`actions`, like choosing a menu item or clicking some action buttons. All tabs include titles which show the name of the provided view. :term:`Tabs` can be arranged by Drag and Drop. __ TDI_ .. _TDI: http://en.wikipedia.org/wiki/Tabbed_document_interface .. Note:: Inside :term:`views` there can be tabs, too. Menu ++++ The *menu* does not contain fixed menu items. All of them are dynamically provided by the actual set of the installed :term:`modules` depending on the access rules of the current user. If a menu item is clicked, the appropriate action will open in a new tab. A search field allows to quickly filter the menu items by name and to search in models for which the global search is enabled. Application Menu **************** The following section describes the action of the application menu. A rule of thumb: All items of the menu bar that are suffixed by three dots (...) will open an intermediate :term:`dialog` for setting up the provided menu action. Most dialog provide a *Cancel* button, used to stop the complete dialog process. .. _Menu-Preferences: Preferences: A preference dialog opens, where the actual user can show and edit his personal settings. All user preferences are stored server side. I.e. logging in with the same credentials from different computers always restores the same preferences. Options ^^^^^^^ The Options menu sets up several visual and context depending preferences. .. _Menu-Options-Toolbar: Toolbar: * Default: Shows labels and icons as defaulted in the GTK configuration. * Text and Icons: Shows labels and icons in the tool bar. * Icons: Shows icons only in the tool bar. * Text: Shows labels only in the tool bar. .. _Menu-Options-Form: Form: * Save Width/Height: Check box to enable saving of manually adjusted widths of columns in lists and trees. Additionally saving of manually adjusted widths and heights of dialog and popup windows. * Save Tree Expanded State: Check box to enable saving of expanded and selected nodes in trees/lists. * Fast Tabbing: Check box to enable fast tabbing navigation by skipping readonly entries. * Spell Checking: Check box to enable spell checking in fields. .. _Menu-Options-PDA-Mode: PDA Mode: When activated, the client display in a condensed mode. .. _Menu-Options-Search-Limit: Search Limit: Open a dialog to set up the maximum number of records displayed on a list. .. _Menu-Options-Email: Email: Open a dialog to set up an email reader. * Command Line: The command line calling the email reader. * Placeholders: - ``${to}``: the destination email address - ``${cc}``: the carbon copy email address - ``${subject}``: the subject of the email - ``${body}``: the body of the email - ``${attachment}``: the attachment of the email * Examples: - Thunderbird 2 on Linux: ``thunderbird -compose "to='${to}',cc='${cc}',subject='${subject}',body='${body}',attachment='file://${attachment}'"`` - Thunderbird 2 on Windows XP SP3: ``"C:\\Program Files\\Mozilla Thunderbird\\thunderbird.exe" -compose to="${to}",cc="${cc}",subject="${subject}",body="${body}",attachment="${attachment}"`` .. note:: The path of *Program Files* may vary dependent on the localization of your Windows version. .. _Menu-Options-Check_Version: Check Version: Check box to enable the check of new bug-fix version. Help ^^^^ .. _Menu-Help-Keyboard_Shortcuts: Keyboard Shortcuts...: Shows the information dialog of the predefined keyboard shortcut map. * Edition Widgets: Shows shortcuts working on text entries, relation entries and date/time entries. .. _Menu-Help-About: About...: License, Contributors, Authors of Tryton Tool Bar ******** The tool bar contains the functionalities linked to the current tab. Some operations are working with one record or with a selection of :term:`records`. In :term:`form view` the actual record is selected for operations. In :term:`tree view` all selected records are used for operations. .. _Toolbar-New: New: Creates a new record. .. _Toolbar-Save: Save: Saves the actual record. .. _Toolbar-Switch_View: Switch View: Switches the actual view aspect to: * :term:`Form view` * :term:`Tree view` * :term:`Graph view` Not all views provide all aspects. .. _Toolbar-Reload_Undo: Reload/Undo: Reloads the content of the actual tab. Undoes changes, if save request for the current record is denied. .. _Toolbar-Duplicate: Duplicate: Duplicates the content of the actual record in a newly created record. .. _Toolbar-Delete: Delete: Deletes the selected or actual record. .. _Toolbar-Previous: Previous: Goes to the last record in a list (sequence). .. _Toolbar-Next: Next: Goes to the next record in a list (sequence). .. _Toolbar-Search: Search: Goes to the search widget. .. _Toolbar-View_Logs: View Logs...: Shows generic information of the current record. .. _Toolbar-Show revisions: Show revisions...: Reload the current view/record at a specific revision. .. _Toolbar-Close: Close Tab: Closes the current tab. A Request :term:`Dialog` opens in case of unsaved changes. .. _Toolbar-Attachment: Attachment: The attachment item handles the document management system of Tryton which is able to attach files to any arbitrary :term:`model`. On click it opens the attachments :term:`dialog`. The default dialog shows a list view of the attached files and links. .. _Toolbar-Actions: Actions...: Shows all actions for the actual view, model and record. .. _Toolbar-Relate: Relate...: Shows all relate view for the actual view, model and record. .. _Toolbar-Report: Report...: Shows all reports for the actual view, model and record. .. _Toolbar-Email: E-Mail...: Shows all email reports for the actual view, model and record. .. _Toolbar-Print: Print...: Shows all print actions for the actual view, model and record. .. _Toolbar-Copy-URL: Copy URL: Copy the URL of the form into the clipboard. .. _Toolbar-Export_Data: Export Data...: Export of current/selected records into :term:`CSV`-file or open it in Excel. * Predefined exports - Choose preferences of already saved exports. * All Fields: Fields available from the model. * Fields to export: Defines the specific fields to export. * Options: - Save: Save export as a CSV file. - Open: Open export in spread sheet application. * Add field names: Add a header row with field names to the export data. * Actions: - Add: Adds selected fields to *Fields to export*. - Remove: Removes selected fields from *Fields to export*. - Clear: Removes all fields from *Fields to export*. - Save Export: Saves field mapping to a *Predefined export* with a name. - Delete Export: Deletes a selected *Predefined export*. - OK: Exports the data (action depending on *Options*). - Cancel .. _Toolbar-Import_Data: Import Data...: Import records from :term:`CSV`-file. * All Fields: Fields available in the model (required fields are marked up). * Fields to Import: Exact sequence of all columns in the CSV file. * File to Import: File :term:`dialog` for choosing a CSV file to import. * CSV Parameters: Setup specific parameters for chosen CSV file. - Field Separator: Character which separates CSV fields. - Text Delimiter: Character which encloses text in CSV. - Encoding: :term:`Character encoding` of CSV file. - Lines to Skip: Count of lines to skip a headline or another offset. * Actions: - Add: Adds fields to *Fields to Import*. - Remove: Deletes fields from *Fields to Import*. - Clear: Removes all fields from *Fields to Import*. - Auto-Detect: Tries to auto detect fields in the CSV *File to Import*. - OK: Proceeds the data import. - Cancel Widgets ******* There are a several widgets used on Tryton in client side. The follow sections will explains some of them. Date/DateTime/Time Widgets ^^^^^^^^^^^^^^^^^^^^^^^^^^ These widgets have several key shortcuts to quickly modify the value. Each key increases if lower case or decreases if upper case: - `y`: by one year - `m`: by one month - `w`: by one week - `d`: by one day - `h`: by one hour - `i`: by one minute - `s`: by one second Search Widget ^^^^^^^^^^^^^ The search widget adds the ability to easily search for records on the current tab. This widget is visible only on :term:`tree view`. The Syntax ++++++++++ A query is composed of search clauses. A clause is composed of a field name (with `:` at the end), an operator and a value. The field name is optional and defaults to the record name. The operator is also optional and defaults to `like` or `equal` depending on the type of the field. The default operator is `=` except for fields of type `char`, `text` and `many2one` which is `ilike`. Field Names +++++++++++ All field names shown in the :term:`tree view` can be searched. Field names must be followed by a `:` For example: ``Name:`` If the field name contains spaces, it is possible to escape it using double quotes. For example: ``"Receivable Today":`` Operators +++++++++ The following operators can be used: * `=`: equal to * `<`: less then * `<=`: less then or equal to * `>`: greater then * `>=`: greater then or equal to * `!=`: not equal * `!`: not equal or not like (depending of the type of field) For example: ``Name: != Dwight`` .. note:: The `ilike` operator is never explicit and `%` is appended to the value to make it behaves like `starts with` Values ++++++ The format of the value depends on the type of the field. A list of values can be set using `;` as separator. For example: ``Name: Michael; Pam`` It will find all records having the `Name` starting with `Michael` or `Pam`. A range of number values can be set using `..`. For example: ``Amount: 100..500`` It will find all records with `Amount` between `100` and `500` included. There are two wildcards: * `%`: matches any string of zero or more characters. * `_`: matches any single character. It is possible to escape special characters in values by using double quotes. For example: ``Name: "Michael:Scott"`` Here it will search with the value `Michael:Scott`. Clause composition ++++++++++++++++++ The clauses can be composed using the two boolean operators `and` and `or`. By default, there is an implicit `and` between each clause if no operator is specified. For example: ``Name: Michael Amount: 100`` is the same as ``Name: Michael and Amount: 100`` The `and` operator has a highest precedence than `or` but you can change it by using parenthesis. For example: ``(Name: Michael or Name: Pam) and Amount: 100`` is different than ``Name: Michael or Name: Pam and Amount: 100`` which is evaluated as ``Name: Michael or (Name: Pam and Amount: 100)`` RichText Editor ^^^^^^^^^^^^^^^ This feature create a rich text editor with various features that allow for text formatting. The features are: * Bold: On/off style of bold text * Italic: On/off style of italic text * Underline: On/off style of underline text * Choose font family: Choice from a combo box the desired font family * Choose font size: Choice from a combo box the desired size font * Text justify: Choice between four options for alignment of the line (left, right, center, fill) * Background color: Choose the background color of text from a color palette * Foreground color: Choose the foreground color of text from a color palette Besides these features, it can change and edit text markup. The text markup feature has a similar HTML tags and is used to describe the format specified by the user and is a way of storing this format for future opening of a correct formatted text. The tags are explain follows: * Bold: Tag `b` is used, i.e. text * Italic: Tag `i` is used, i.e. text * Underline: Tag `u` is used, i.e. text * Font family: It is a attribute `font-family` for `span` tag, i.e. text * Font size: It is a attribute `size` for `span` tag, i.e. text * Text Justify: For justification text is used paragraph tag `p`. The paragraph tag is used to create new lines and the alignment is applied across the board. Example:

some text

* Background color: It is a attribute `background` for `span` tag, i.e. text * Foreground color: It is a attribute `foreground` for `span` tag, i.e. text CSS *** The client can be styled using the file `theme.css`. Here are the list of custom selectors: * `.readonly`: readonly widget or label * `.required`: widget or label of required field * `.invalid`: widget for which the field value is not valid * `headerbar.profile-`: the name of the connection profile is set on the main window For more information about style option see `GTK+ CSS`_ .. _GTK+ CSS: https://developer.gnome.org/gtk3/stable/chap-css-overview.html Appendix ******** Configuration File ^^^^^^^^^^^^^^^^^^ :: ~/.config/tryton/x.y/tryton.conf # General configuration ~/.config/tryton/x.y/accel.map # Accelerators configuration ~/.config/tryton/x.y/known_hosts # Fingerprints ~/.config/tryton/x.y/ca_certs # Certification Authority (http://docs.python.org/library/ssl.html#ssl-certificates) ~/.config/tryton/x.y/profiles.cfg # Profile configuration ~/.config/tryton/x.y/plugins # Local user plugins directory ~/.config.tryton/x.y/theme.css # Custom CSS theme .. note:: `~` means the home directory of the user. But on Windows system it is the `APPDATA` directory. tryton-5.0.17/doc/build.py0000644000175000017500000000146513354423127014703 0ustar cedced00000000000000# -*- coding: utf-8 -*- # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import sys import os from os import path from sphinx.util.console import nocolor from sphinx.application import Sphinx srcdir = confdir = path.abspath(path.normpath(path.dirname(__file__))) outdir = os.path.join(srcdir, 'html') static_dir = os.path.join(srcdir, 'static') doctreedir = path.join(outdir, '.doctrees') status = sys.stdout confoverrides = {} freshenv = True buildername = 'html' if not path.isdir(outdir): os.mkdir(outdir) if not path.isdir(static_dir): os.mkdir(static_dir) nocolor() app = Sphinx(srcdir, confdir, outdir, doctreedir, buildername, confoverrides, status, sys.stderr, freshenv) app.builder.build_all() tryton-5.0.17/doc/index.rst0000755000175000017500000000043113354423127015066 0ustar cedced00000000000000.. Tryton documentation master file. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Tryton Client ############# Contents: .. toctree:: :maxdepth: 2 introduction installation usage glossary tryton-5.0.17/doc/introduction.rst0000644000175000017500000000024613354423127016501 0ustar cedced00000000000000Introduction ############ Tryton is a Graphical User Interface to the Tryton Framework based on GTK__ and Python__. __ http://www.gtk.org __ http://www.python.org tryton-5.0.17/tryton.desktop0000644000175000017500000000230613367164774015430 0ustar cedced00000000000000[Desktop Entry] Version=1.0 Type=Application Name=Tryton GenericName=Client for the Tryton Application Platform GenericName[ca_ES]=Client per l'aplicació Tryton GenericName[de]=Client für die Tryton Applikationsplattform GenericName[es_AR]=Cliente para la aplicación Tryton GenericName[es_EC]=Cliente para la aplicación Tryton GenericName[es_ES]=Cliente para la aplicación Tryton GenericName[es_CO]=Cliente para la Aplicación Tryton GenericName[fr]=Client de la plate-forme applicative Tryton GenericName[ru]=Клиент для платформы приложений Tryton GenericName[sl]=Odjemalec za Tryton programsko platformo Comment=Access Tryton server Comment[de]=Verbindet zu einem Tryton Server Comment[es_AR]=Acceso al servidor Tryton Comment[es_EC]=Acceso al servidor Tryton Comment[ca_ES]=Accés al servidor Tryton Comment[es_ES]=Acceso al servidor Tryton Comment[es_CO]=Acceso al servidor Tryton Comment[fr]=Accéder au serveur Tryton Comment[ru]=Подключение к серверу Tryton Comment[sl]=Dostop do Tryton strežnika Keywords=Business;Management;Enterprise;ERP;Framework;Client; Exec=tryton %u Icon=tryton-icon Terminal=false MimeType=application/tryton; Categories=Office;Finance; tryton-5.0.17/catalan.nsh0000644000175000017500000000211513463252531014573 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. !verbose 3 !ifdef CURLANG !undef CURLANG !endif !define CURLANG ${LANG_CATALAN} LangString LicenseText ${CURLANG} "Tryton està alliberat sota la llicència «GNU General Public License» publicada per la Free Software Foundation, o bé la versió 3 de la llicència, o (sota la vostra elecció) qualsevol versió posterior. Llegiu detingudament la llicència. Premeu «Següent» per continuar." LangString LicenseNext ${CURLANG} "&Següent" LangString PreviousInstall ${CURLANG} "Tryton ja està instal·lat.$\n$\nPremeu `OK` per eliminar la versió anterior o `Cancel·la` per cancel·lar l'actualització." LangString SecTrytonName ${CURLANG} "Tryton" LangString SecTrytonDesc ${CURLANG} "Instal·la tryton.exe i altres fitxers necessaris" LangString SecStartMenuName ${CURLANG} "Accessos directes al menú d'inici i a l'escriptori" LangString SecStartMenuDesc ${CURLANG} "Crea accessos directes al menú d'inici i a l'escriptori" tryton-5.0.17/setup.nsi0000644000175000017500000001255613463252531014343 0ustar cedced00000000000000;This file is part of Tryton. The COPYRIGHT file at the top level of ;this repository contains the full copyright notices and license terms. ;Check version !ifndef VERSION !error "Missing VERSION! Specify it with '/DVERSION='" !endif ;Check series !ifndef SERIES !error "Missing SERIES! Specify if with '/DSERIES='" !endif ;Include Modern UI !include "MUI.nsh" ;General Name "Tryton ${VERSION}" OutFile "tryton-${VERSION}.exe" SetCompressor lzma SetCompress auto Unicode true ;Default installation folder InstallDir "$PROGRAMFILES\Tryton-${SERIES}" ;Get installation folder from registry if available InstallDirRegKey HKCU "Software\Tryton-${SERIES}" "" BrandingText "Tryton ${SERIES}" ;Vista redirects $SMPROGRAMS to all users without this RequestExecutionLevel admin ;Variables Var MUI_TEMP Var STARTMENU_FOLDER ;Interface Settings !define MUI_ABORTWARNING ;Language Selection Dialog Settings ;Remember the installer language !define MUI_LANGDLL_REGISTRY_ROOT "HKCU" !define MUI_LANGDLL_REGISTRY_KEY "Software\Modern UI Test" !define MUI_LANGDLL_REGISTRY_VALUENAME "Installer Language" ;Pages !define MUI_ICON "tryton\data\pixmaps\tryton\tryton.ico" !define MUI_LICENSEPAGE_TEXT_BOTTOM "$(LicenseText)" !define MUI_LICENSEPAGE_BUTTON "$(LicenseNext)" !insertmacro MUI_PAGE_LICENSE "LICENSE" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_STARTMENU Application $STARTMENU_FOLDER !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_CONFIRM !insertmacro MUI_UNPAGE_INSTFILES ;Languages !insertmacro MUI_LANGUAGE "English" ; First is the default !include "english.nsh" !insertmacro MUI_LANGUAGE "Catalan" !include "catalan.nsh" !insertmacro MUI_LANGUAGE "French" !include "french.nsh" !insertmacro MUI_LANGUAGE "German" !include "german.nsh" !insertmacro MUI_LANGUAGE "Farsi" !include "farsi.nsh" !insertmacro MUI_LANGUAGE "Slovenian" !include "slovenian.nsh" !insertmacro MUI_LANGUAGE "Spanish" !include "spanish.nsh" ;Reserve Files ;If you are using solid compression, files that are required before ;the actual installation should be stored first in the data block, ;because this will make your installer start faster. !insertmacro MUI_RESERVEFILE_LANGDLL ;Installer Sections Function .onInit ClearErrors ReadRegStr $0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" "UninstallString" StrCmp $0 "" DoInstall MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION "$(PreviousInstall)" /SD IDOK IDOK Uninstall Quit Uninstall: ReadRegStr $1 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" "InstallLocation" ClearErrors StrCpy $2 "/S" IfSilent +2 StrCpy $2 "" ExecWait '$0 $2 _?=$1' IfErrors 0 DoInstall Quit DoInstall: FunctionEnd Section $(SecTrytonName) SecTryton SectionIn 1 2 RO ;Set output path to the installation directory SetOutPath "$INSTDIR" ;Put file File /r "dist\*" File "COPYRIGHT" File "INSTALL" File "LICENSE" File "README" File "CHANGELOG" SetOutPath "$INSTDIR\doc" File /r "doc\*" ;Register URL protocol WriteRegStr HKCR "tryton" "" "URL:Tryton Protocol" WriteRegStr HKCR "tryton" "URL Protocol" "" WriteRegStr HKCR "tryton\DefaultIcon" "" "$INSTDIR\tryton.exe,1" WriteRegStr HKCR "tryton\shell\open\command" "" '$INSTDIR\tryton.exe "%1"' ;Write the installation path into the registry WriteRegStr HKLM "Software\Tryton-${SERIES}" "" $INSTDIR ;Write the uninstall keys for Windows WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" "DisplayName" "Tryton ${VERSION} (remove only)" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" "InstallLocation" "$INSTDIR" ;Create the uninstaller WriteUninstaller uninstall.exe SectionEnd Section $(SecStartMenuName) SecStartMenu SectionIn 1 2 !insertmacro MUI_STARTMENU_WRITE_BEGIN Application SetShellVarContext all CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER" CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0 CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Tryton-${SERIES}.lnk" "$INSTDIR\tryton.exe" "" "$INSTDIR\tryton.exe" 0 CreateShortCut "$DESKTOP\Tryton-${SERIES}.lnk" "$INSTDIR\tryton.exe" "" "$INSTDIR\tryton.exe" 0 !insertmacro MUI_STARTMENU_WRITE_END SectionEnd ;Descriptions !insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN !insertmacro MUI_DESCRIPTION_TEXT ${SecTryton} $(SecTrytonDesc) !insertmacro MUI_DESCRIPTION_TEXT ${SecStartMenu} $(SecStartMenuDesc) !insertmacro MUI_FUNCTION_DESCRIPTION_END Section "Uninstall" ;Add your stuff here RMDIR /r "$INSTDIR" ;remove registry keys DeleteRegKey HKLM "Software\Tryton-${SERIES}" DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\tryton-${SERIES}" SetShellVarContext all Delete "$DESKTOP\Tryton-${SERIES}.lnk" !insertmacro MUI_STARTMENU_GETFOLDER Application $MUI_TEMP StrCmp $MUI_TEMP "" noshortcuts Delete "$SMPROGRAMS\$MUI_TEMP\Uninstall.lnk" Delete "$SMPROGRAMS\$MUI_TEMP\Tryton-${SERIES}.lnk" RMDir "$SMPROGRAMS\$MUI_TEMP" noshortcuts: SectionEnd tryton-5.0.17/win32/0000755000175000017500000000000013571264253013425 5ustar cedced00000000000000tryton-5.0.17/win32/gtk-3.0/0000755000175000017500000000000013571264253014510 5ustar cedced00000000000000tryton-5.0.17/win32/gtk-3.0/gtk.immodules0000644000175000017500000000000013463252532017200 0ustar cedced00000000000000tryton-5.0.17/win32/gtk-3.0/gdk-pixbuf.loaders0000644000175000017500000000653513463252532020131 0ustar cedced00000000000000# GdkPixbuf Image Loader Modules file # Automatically generated file, do not edit # Created by gdk-pixbuf-query-loaders.exe from gdk-pixbuf-2.36.12 # # LoaderDir = lib\gdk-pixbuf-2.0\2.10.0\loaders # "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-ani.dll" "ani" 4 "gdk-pixbuf" "Windows animated cursor" "LGPL" "application/x-navi-animation" "" "ani" "" "RIFF ACON" " xxxx " 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-bmp.dll" "bmp" 5 "gdk-pixbuf" "BMP" "LGPL" "image/bmp" "image/x-bmp" "image/x-MS-bmp" "" "bmp" "" "BM" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-gif.dll" "gif" 4 "gdk-pixbuf" "GIF" "LGPL" "image/gif" "" "gif" "" "GIF8" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-icns.dll" "icns" 4 "gdk-pixbuf" "MacOS X icon" "GPL" "image/x-icns" "" "icns" "" "icns" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-ico.dll" "ico" 5 "gdk-pixbuf" "Windows icon" "LGPL" "image/x-icon" "image/x-ico" "image/x-win-bitmap" "image/vnd.microsoft.icon" "application/ico" "image/ico" "image/icon" "text/ico" "" "ico" "cur" "" " \001 " "zz znz" 100 " \002 " "zz znz" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-jasper.dll" "jpeg2000" 4 "gdk-pixbuf" "JPEG 2000" "LGPL" "image/jp2" "image/jpeg2000" "image/jpx" "" "jp2" "jpc" "jpx" "j2k" "jpf" "" " jP" "!!!! " 100 "\377O\377Q" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-jpeg.dll" "jpeg" 5 "gdk-pixbuf" "JPEG" "LGPL" "image/jpeg" "" "jpeg" "jpe" "jpg" "" "\377\330" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-png.dll" "png" 5 "gdk-pixbuf" "PNG" "LGPL" "image/png" "" "png" "" "\211PNG\r\n\032\n" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-pnm.dll" "pnm" 4 "gdk-pixbuf" "PNM/PBM/PGM/PPM" "LGPL" "image/x-portable-anymap" "image/x-portable-bitmap" "image/x-portable-graymap" "image/x-portable-pixmap" "" "pnm" "pbm" "pgm" "ppm" "" "P1" "" 100 "P2" "" 100 "P3" "" 100 "P4" "" 100 "P5" "" 100 "P6" "" 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-qtif.dll" "qtif" 4 "gdk-pixbuf" "QuickTime" "LGPL" "image/x-quicktime" "image/qtif" "" "qtif" "qif" "" "abcdidsc" "xxxx " 100 "abcdidat" "xxxx " 100 "lib\\gdk-pixbuf-2.0\\2.10.0\\loaders\\libpixbufloader-svg.dll" "svg" 6 "gdk-pixbuf" "Scalable Vector Graphics" "LGPL" "image/svg+xml" "image/svg" "image/svg-xml" "image/vnd.adobe.svg+xml" "text/xml-svg" "image/svg+xml-compressed" "" "svg" "svgz" "svg.gz" "" " =0.4'], }, zip_safe=False, **args ) tryton-5.0.17/.hgtags0000644000175000017500000000340213571264252013737 0ustar cedced00000000000000923b3073b686c6dc5a921d0561c934adf3eeb879 1.0.0 9a6434d63616f46520b6fa1b2be31906ff6f4f6a 1.2.0 de84c1443d4bad908eabb99c381578b988c2117f 1.4.0 3976912b23dfc5db2525d4c2e55d17f099d9492d 1.6.0 8aa050da53cbdfabe1353a37da91c011b7fff549 1.8.0 1876747b3f963ba6011b4bcf6968e681624c6e24 2.0.0 5364f8ca6cd2cccfb5f7f39c69bb20bae2b5f495 2.2.0 fe15da23f7333e0e90d2693aadddf6bed53ed602 2.4.0 d069f9f1cdc3fea39e71415268582abb2b333ea1 2.6.0 21fbf8bd36096d926c472acfecd3963369204af8 2.8.0 9197d90b0257ec7c4576a38092fd592b3e87f7a4 3.0.0 9721289ee2fdaab8b990de9327c3eab87363c88c 3.2.0 8e5cba59137f9d0a063fa6d7855e09a51bc5889c 3.4.0 1ac658605d42d82988cfb232afebfe359aba7776 3.6.0 f4b9c8a84cf61935afec788c3c639982731452ef 3.8.0 44d8ed92ff90cf98c4c01d37f12d344d9d66e7f1 4.0.0 94037cff031ef897c9533a579356977c8a3cf695 4.2.0 763dc5d8e1d7e483edbf9977dd96afc114555555 4.4.0 d7ed5002e47249d019fbc546f6ac562db44c54f2 4.6.0 2a2b48ea60fbb5201ea12443000d3a106a2fa27c 4.8.0 70ade9d1fe04c734fe2dd7d35dd75b13f1af902a 5.0.0 a2075027e959021a8c136382b5c5889844209f28 5.0.1 7a5d9d95f996a921fbea902280721554cfc218a9 5.0.2 454b9a53cd9103e921a68ae3baae55a97b050302 5.0.3 825b1e3a4b9cd921666ac4e4022107d259530560 5.0.4 b14cb2de66470550c9c9bce8fa9a0946370c9095 5.0.5 6ffc2d4111797291085d921e149814010f001913 5.0.6 a747cbf966071288c512983f397e443fb6a1f022 5.0.7 9a37e8ac8ac5e1c9ba7ade4fd3a38f9493d59d68 5.0.8 36dc2828d66a90a8ce8767fbbab9969ad4438ca1 5.0.9 ddcba59ec82183435dda70d03b034fd2874031f0 5.0.10 9de7d859f0c09d99e947fb0e580b49c84256a7cc 5.0.11 3be8de6331a706fad1b81acaed2199f06d3587e4 5.0.12 cee881bbf448513425ed481cc9b09f8c97d0f7d5 5.0.13 7666c44bdfed7110053edb81e19ac5a10088c862 5.0.14 f70d4e23827dd29a2a9c195709adb490d4f3696d 5.0.15 56ed6650c38418af2b539d2e9f2a6a0b273b00fe 5.0.16 a8e8b3955a0cace8bd03996e7f0525dbdaef4a75 5.0.17 tryton-5.0.17/darwin/0000755000175000017500000000000013571264253013747 5ustar cedced00000000000000tryton-5.0.17/darwin/gtk-3.0/0000755000175000017500000000000013571264253015032 5ustar cedced00000000000000tryton-5.0.17/darwin/gtk-3.0/gtk.immodules0000644000175000017500000000350713463252531017540 0ustar cedced00000000000000# GTK+ Input Method Modules file # Automatically generated file, do not edit # Created by gtk-query-immodules-3.0 from gtk+-3.22.26 # # ModulesPath = @executable_path/lib/gtk-3.0/3.0.0/x86_64-apple-darwin16.7.0/immodules:@executable_path/lib/gtk-3.0/3.0.0/immodules:@executable_path/lib/gtk-3.0/x86_64-apple-darwin16.7.0/immodules:@executable_path/lib/gtk-3.0/immodules # "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-am-et.so" "am_et" "Amharic (EZ+)" "gtk30" "@executable_path/share/locale" "am" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-cedilla.so" "cedilla" "Cedilla" "gtk30" "@executable_path/share/locale" "az:ca:co:fr:gv:oc:pt:sq:tr:wa" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-cyrillic-translit.so" "cyrillic_translit" "Cyrillic (Transliterated)" "gtk30" "@executable_path/share/locale" "" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-inuktitut.so" "inuktitut" "Inuktitut (Transliterated)" "gtk30" "@executable_path/share/locale" "iu" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-ipa.so" "ipa" "IPA" "gtk30" "@executable_path/share/locale" "" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-multipress.so" "multipress" "Multipress" "gtk30" "" "" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-quartz.so" "quartz" "Mac OS X Quartz" "gtk30" "@executable_path/share/locale" "ja:ko:zh:*" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-thai.so" "thai" "Thai-Lao" "gtk30" "@executable_path/share/locale" "lo:th" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-ti-er.so" "ti_er" "Tigrigna-Eritrean (EZ+)" "gtk30" "@executable_path/share/locale" "ti" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-ti-et.so" "ti_et" "Tigrigna-Ethiopian (EZ+)" "gtk30" "@executable_path/share/locale" "ti" "@executable_path/lib/gtk-3.0/3.0.0/immodules/im-viqr.so" "viqr" "Vietnamese (VIQR)" "gtk30" "@executable_path/share/locale" "vi" tryton-5.0.17/darwin/gtk-3.0/gdk-pixbuf.loaders0000644000175000017500000000626713463252531020454 0ustar cedced00000000000000# GdkPixbuf Image Loader Modules file # Automatically generated file, do not edit # Created by gdk-pixbuf-query-loaders from gdk-pixbuf-2.34.0 # # LoaderDir = @executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders # "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-ani.so" "ani" 4 "gdk-pixbuf" "Windows animated cursor" "LGPL" "application/x-navi-animation" "" "ani" "" "RIFF ACON" " xxxx " 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-bmp.so" "bmp" 5 "gdk-pixbuf" "BMP" "LGPL" "image/bmp" "image/x-bmp" "image/x-MS-bmp" "" "bmp" "" "BM" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-gif.so" "gif" 4 "gdk-pixbuf" "GIF" "LGPL" "image/gif" "" "gif" "" "GIF8" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-icns.so" "icns" 4 "gdk-pixbuf" "MacOS X icon" "GPL" "image/x-icns" "" "icns" "" "icns" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-ico.so" "ico" 5 "gdk-pixbuf" "Windows icon" "LGPL" "image/x-icon" "image/x-ico" "image/x-win-bitmap" "image/vnd.microsoft.icon" "application/ico" "image/ico" "image/icon" "text/ico" "" "ico" "cur" "" " \001 " "zz znz" 100 " \002 " "zz znz" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-jpeg.so" "jpeg" 5 "gdk-pixbuf" "JPEG" "LGPL" "image/jpeg" "" "jpeg" "jpe" "jpg" "" "\377\330" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-png.so" "png" 5 "gdk-pixbuf" "PNG" "LGPL" "image/png" "" "png" "" "\211PNG\r\n\032\n" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-pnm.so" "pnm" 4 "gdk-pixbuf" "PNM/PBM/PGM/PPM" "LGPL" "image/x-portable-anymap" "image/x-portable-bitmap" "image/x-portable-graymap" "image/x-portable-pixmap" "" "pnm" "pbm" "pgm" "ppm" "" "P1" "" 100 "P2" "" 100 "P3" "" 100 "P4" "" 100 "P5" "" 100 "P6" "" 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-qtif.so" "qtif" 4 "gdk-pixbuf" "QuickTime" "LGPL" "image/x-quicktime" "image/qtif" "" "qtif" "qif" "" "abcdidsc" "xxxx " 100 "abcdidat" "xxxx " 100 "@executable_path/lib/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-svg.so" "svg" 6 "gdk-pixbuf" "Scalable Vector Graphics" "LGPL" "image/svg+xml" "image/svg" "image/svg-xml" "image/vnd.adobe.svg+xml" "text/xml-svg" "image/svg+xml-compressed" "" "svg" "svgz" "svg.gz" "" " = 24: break time = datetime.time(hour, minute) def add_operators(widget): def key_press(editable, event): if not editable.get_editable(): return False if event.keyval in OPERATORS: value = widget.props.value if value: if isinstance(value, datetime.time): value = datetime.datetime.combine( datetime.date.today(), value) try: widget.props.value = value + OPERATORS[event.keyval] except TypeError: return False return True elif event.keyval in (gtk.keysyms.KP_Equal, gtk.keysyms.equal): widget.props.value = datetime.datetime.now() return True return False if isinstance(widget, DateTime): for child in widget.get_children(): add_operators(child) return widget if isinstance(widget, gtk.ComboBoxEntry): editable = widget.get_child() else: editable = widget editable.connect('key-press-event', key_press) return widget OPERATORS = { gtk.keysyms.S: relativedelta(seconds=-1), gtk.keysyms.s: relativedelta(seconds=1), gtk.keysyms.I: relativedelta(minutes=-1), gtk.keysyms.i: relativedelta(minutes=1), gtk.keysyms.H: relativedelta(hours=-1), gtk.keysyms.h: relativedelta(hours=1), gtk.keysyms.D: relativedelta(days=-1), gtk.keysyms.d: relativedelta(days=1), gtk.keysyms.W: relativedelta(weeks=-1), gtk.keysyms.w: relativedelta(weeks=1), gtk.keysyms.M: relativedelta(months=-1), gtk.keysyms.m: relativedelta(months=1), gtk.keysyms.Y: relativedelta(years=-1), gtk.keysyms.y: relativedelta(years=1), } if __name__ == '__main__': win = gtk.Window() win.connect('delete-event', gtk.main_quit) v = gtk.VBox() v.show() d = add_operators(Date()) d.show() v.pack_start(d, False, False) t = add_operators(Time()) t.show() v.pack_start(t, False, False) t = add_operators(Time()) t.props.format = '%H:%M' t.show() v.pack_start(t, False, False) dt = add_operators(DateTime()) dt.show() v.pack_start(dt, False, False) win.add(v) win.show() gtk.main() tryton-5.0.17/tryton/common/timedelta.py0000644000175000017500000001076313566557275017660 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime import gettext import locale import operator __all__ = ['format', 'parse'] _ = gettext.gettext DEFAULT_CONVERTER = { 's': 1, } DEFAULT_CONVERTER['m'] = DEFAULT_CONVERTER['s'] * 60 DEFAULT_CONVERTER['h'] = DEFAULT_CONVERTER['m'] * 60 DEFAULT_CONVERTER['d'] = DEFAULT_CONVERTER['h'] * 24 DEFAULT_CONVERTER['w'] = DEFAULT_CONVERTER['d'] * 7 DEFAULT_CONVERTER['M'] = DEFAULT_CONVERTER['d'] * 30 DEFAULT_CONVERTER['Y'] = DEFAULT_CONVERTER['d'] * 365 def _get_separators(): return { 'Y': _('Y'), 'M': _('M'), 'w': _('w'), 'd': _('d'), 'h': _('h'), 'm': _('m'), 's': _('s'), } def format(value, converter=None): 'Convert timedelta to text' if value is None: return '' if not converter: converter = DEFAULT_CONVERTER text = [] value = value.total_seconds() sign = '' if value < 0: sign = '-' value = abs(value) converter = sorted(list(converter.items()), key=operator.itemgetter(1), reverse=True) values = [] for k, v in converter: part = value // v value -= part * v values.append(part) for (k, _), v in zip(converter[:-3], values): if v: text.append(locale.format('%d', v, True) + _get_separators()[k]) if any(values[-3:]) or not text: time = '%02d:%02d' % tuple(values[-3:-1]) if values[-1] or value: time += ':%02d' % values[-1] text.append(time) text = sign + ' '.join(text) if value: if not any(values[-3:]): # Add space if no time text += ' ' text += ('%.6f' % value)[1:] return text def parse(text, converter=None): if not text: return if not converter: converter = DEFAULT_CONVERTER for separator in list(_get_separators().values()): text = text.replace(separator, separator + ' ') seconds = 0 for part in text.split(): if ':' in part: for t, v in zip(part.split(':'), [converter['h'], converter['m'], converter['s']]): try: seconds += abs(locale.atof(t)) * v except ValueError: pass else: for key, separator in list(_get_separators().items()): if part.endswith(separator): part = part[:-len(separator)] try: seconds += abs(locale.atof(part)) * converter[key] except ValueError: pass break else: try: seconds += abs(locale.atof(part)) except ValueError: pass if '-' in text: seconds *= -1 return datetime.timedelta(seconds=seconds) _tests = [ (None, ''), (datetime.timedelta(), '00:00'), (datetime.timedelta(days=3, hours=5, minutes=30), '3d 05:30'), (datetime.timedelta(weeks=48), '11M 6d'), (datetime.timedelta(weeks=50), '11M 2w 6d'), (datetime.timedelta(weeks=52), '12M 4d'), (datetime.timedelta(days=360), '12M'), (datetime.timedelta(days=364), '12M 4d'), (datetime.timedelta(days=365), '1Y'), (datetime.timedelta(days=366), '1Y 1d'), (datetime.timedelta(hours=2, minutes=5, seconds=10), '02:05:10'), (datetime.timedelta(minutes=15, microseconds=42), '00:15:00.000042'), (datetime.timedelta(days=1, microseconds=42), '1d .000042'), (datetime.timedelta(seconds=-1), '-00:00:01'), (datetime.timedelta(days=-1, hours=-5, minutes=-30), '-1d 05:30'), ] def test_format(): for timedelta, text in _tests: assert format(timedelta) == text _tests_parse = [ (datetime.timedelta(), ' '), (datetime.timedelta(), 'foo'), (datetime.timedelta(days=1.5), '1.5d'), (datetime.timedelta(days=-2), '1d -1d'), (datetime.timedelta(hours=1, minutes=5, seconds=10), '1:5:10:42'), (datetime.timedelta(hours=2), '1: 1:'), (datetime.timedelta(hours=.25), ':15'), (datetime.timedelta(hours=1), '1h'), (datetime.timedelta(hours=.25), '.25h'), ] def test_parse(): for timedelta, text, in _tests + _tests_parse: assert parse(text) == timedelta if __name__ == '__main__': for name in list(globals()): if name.startswith('test_'): func = globals()[name] func() tryton-5.0.17/tryton/common/underline.py0000644000175000017500000000040413463252532017644 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. def set_underline(label): "Set underscore for mnemonic accelerator" return '_' + label.replace('_', '__') tryton-5.0.17/tryton/common/completion.py0000644000175000017500000000520713463252531020035 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import logging import gettext import gtk import gobject from tryton.config import CONFIG from tryton.common import RPCExecute from tryton.exceptions import TrytonServerError, TrytonError _ = gettext.gettext logger = logging.getLogger(__name__) def get_completion(search=True, create=True): "Return a EntryCompletion" completion = gtk.EntryCompletion() completion.set_match_func(lambda *a: True) completion.set_model(gtk.ListStore(str, int)) completion.set_text_column(0) completion.props.popup_set_width = False if search: completion.insert_action_markup(0, _('Search...')) if create: completion.insert_action_markup(1, _('Create...')) return completion def update_completion(entry, record, field, model, domain=None): "Update entry completion" def update(search_text, domain): if not entry.props.window: return False if search_text != entry.get_text(): return False completion_model = entry.get_completion().get_model() if not search_text or not model: completion_model.clear() completion_model.search_text = search_text return False if getattr(completion_model, 'search_text', None) == search_text: return False if domain is None: domain = field.domain_get(record) context = field.get_search_context(record) domain = [('rec_name', 'ilike', '%' + search_text + '%'), domain] order = field.get_search_order(record) def callback(results): try: results = results() except (TrytonError, TrytonServerError): results = [] if search_text != entry.get_text(): return False completion_model.clear() for result in results: completion_model.append([result['rec_name'], result['id']]) completion_model.search_text = search_text # Force display of popup entry.emit('changed') try: RPCExecute('model', model, 'search_read', domain, 0, CONFIG['client.limit'], order, ['rec_name'], context=context, process_exception=False, callback=callback) except Exception: logging.warn( _("Unable to search for completion of %s") % model, exc_info=True) return False search_text = entry.get_text() gobject.timeout_add(300, update, search_text, domain) tryton-5.0.17/tryton/common/cellrenderertext.py0000644000175000017500000000154413463252531021237 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject class CellRendererText(gtk.CellRendererText): def __init__(self): super(CellRendererText, self).__init__() self.connect('editing-started', self.__class__.on_editing_started) def on_editing_started(self, editable, path): pass class CellRendererTextCompletion(CellRendererText): def __init__(self, set_completion): super(CellRendererTextCompletion, self).__init__() self.set_completion = set_completion def on_editing_started(self, editable, path): super().on_editing_started(editable, path) self.set_completion(editable, path) gobject.type_register(CellRendererText) gobject.type_register(CellRendererTextCompletion) tryton-5.0.17/tryton/common/cellrendererinteger.py0000644000175000017500000000160213463252531021703 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gobject from .cellrenderertext import CellRendererText import locale class CellRendererInteger(CellRendererText): def on_editing_started(self, editable, path): super().on_editing_started(editable, path) editable.set_alignment(1.0) editable.connect('insert_text', self.sig_insert_text) def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] if new_value == '-': return try: locale.atoi(new_value) except ValueError: entry.stop_emission('insert-text') gobject.type_register(CellRendererInteger) tryton-5.0.17/tryton/common/popup_menu.py0000644000175000017500000001132713463252531020053 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from tryton.common import RPCExecute, RPCException, IconFactory from tryton.gui.window.view_form.screen import Screen from tryton.action import Action from tryton.gui.window import Window from tryton.gui.window.attachment import Attachment from tryton.gui.window.note import Note _ = gettext.gettext def populate(menu, model, record, title='', field=None, context=None): ''' Fill menu with the actions of model for the record. If title is filled, the actions will be put in a submenu. ''' if record is None: return elif isinstance(record, int): if record < 0: return elif record.id < 0: return def load(record): if isinstance(record, int): screen = Screen(model, context=context) screen.load([record]) record = screen.current_record return record def id_(record): if not isinstance(record, int): return record.id return record def activate(menuitem, action, atype): rec = load(record) action = Action.evaluate(action, atype, rec) data = { 'model': model, 'id': rec.id, 'ids': [rec.id], } event = gtk.get_current_event() allow_similar = False if (event.state & gtk.gdk.CONTROL_MASK or event.state & gtk.gdk.MOD1_MASK): allow_similar = True with Window(hide_current=True, allow_similar=allow_similar): Action._exec_action(action, data, rec.get_context()) def attachment(menuitem): Attachment(load(record), None) def note(menuitem): Note(load(record), None) def edit(menuitem): with Window(hide_current=True, allow_similar=True): Window.create(model, view_ids=field.attrs.get('view_ids', '').split(','), res_id=id_(record), mode=['form'], name=field.attrs.get('string')) if title: if len(menu): menu.append(gtk.SeparatorMenuItem()) title_item = gtk.MenuItem(title) menu.append(title_item) submenu = gtk.Menu() title_item.set_submenu(submenu) action_menu = submenu else: action_menu = menu if len(action_menu): action_menu.append(gtk.SeparatorMenuItem()) if field: edit_item = gtk.MenuItem(_('Edit...')) edit_item.connect('activate', edit) action_menu.append(edit_item) action_menu.append(gtk.SeparatorMenuItem()) attachment_item = gtk.ImageMenuItem() attachment_item.set_label(_('Attachments...')) attachment_item.set_image(IconFactory.get_image( 'tryton-attach', gtk.ICON_SIZE_MENU)) action_menu.append(attachment_item) attachment_item.connect('activate', attachment) note_item = gtk.ImageMenuItem() note_item.set_label(_('Notes...')) note_item.set_image(IconFactory.get_image( 'tryton-note', gtk.ICON_SIZE_MENU)) action_menu.append(note_item) note_item.connect('activate', note) def set_toolbar(toolbar): try: toolbar = toolbar() except RPCException: return for atype, icon, label, flavor in ( ('action', 'tryton-launch', _('Actions...'), None), ('relate', 'tryton-link', _('Relate...'), None), ('print', 'tryton-open', _('Report...'), 'open'), ('print', 'tryton-email', _('E-Mail...'), 'email'), ('print', 'tryton-print', _('Print...'), 'print'), ): if len(action_menu): action_menu.append(gtk.SeparatorMenuItem()) title_item = gtk.ImageMenuItem() title_item.set_label(label) title_item.set_image(IconFactory.get_image( icon, gtk.ICON_SIZE_MENU)) action_menu.append(title_item) if not toolbar[atype]: title_item.set_sensitive(False) continue submenu = gtk.Menu() title_item.set_submenu(submenu) for action in toolbar[atype]: action = action.copy() item = gtk.MenuItem(action['name']) submenu.append(item) if flavor == 'print': action['direct_print'] = True elif flavor == 'email': action['email_print'] = True item.connect('activate', activate, action, atype) menu.show_all() RPCExecute('model', model, 'view_toolbar_get', callback=set_toolbar) menu.show_all() tryton-5.0.17/tryton/common/entry_position.py0000644000175000017500000000043113354423127020743 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. def reset_position(entry): if entry.get_alignment() <= 0.5: entry.set_position(0) else: entry.set_position(-1) tryton-5.0.17/tryton/common/widget_style.py0000644000175000017500000000051713463252532020367 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. def widget_class(widget, name, value): style_context = widget.get_style_context() if value: style_context.add_class(name) else: style_context.remove_class(name) tryton-5.0.17/tryton/common/focus.py0000644000175000017500000000567413367164774017031 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from functools import cmp_to_key import gtk def get_invisible_ancestor(widget): if not widget.get_visible(): return widget if not widget.props.parent: return None return get_invisible_ancestor(widget.props.parent) def find_focused_child(widget): if widget.has_focus(): return widget if not hasattr(widget, 'get_children'): return None for child in widget.get_children(): focused_widget = find_focused_child(child) if focused_widget: return focused_widget def tab_compare(a, b): text_direction = gtk.widget_get_default_direction() a_allocation = a.get_allocation() b_allocation = b.get_allocation() y1 = a_allocation.y + a_allocation.height // 2 y2 = b_allocation.y + b_allocation.height // 2 if y1 == y2: x1 = a_allocation.x + a_allocation.width // 2 x2 = b_allocation.x + b_allocation.width // 2 if text_direction == gtk.TEXT_DIR_RTL: return (x2 > x1) - (x2 < x1) else: return (x1 > x2) - (x1 < x2) else: return (y1 > y2) - (y1 < y2) def get_focus_chain(widget): focus_chain = widget.get_focus_chain() # If the focus_chain is not defined on the widget then we will simply # search into all its children widgets return (focus_chain if focus_chain is not None else sorted(widget.get_children(), key=cmp_to_key(tab_compare))) def find_focusable_child(widget): if not widget.get_visible(): return None if widget.get_can_focus(): return widget if not hasattr(widget, 'get_children'): return None for child in get_focus_chain(widget): focusable = find_focusable_child(child) if focusable: return focusable def next_focus_widget(widget): if not widget.props.parent: return None focus_chain = widget.props.parent.get_focus_chain() if focus_chain is not None: idx = focus_chain.index(widget) focus_widget = None for widget in focus_chain[idx:] + focus_chain[:idx]: focus_widget = find_focusable_child(widget) if focus_widget: return focus_widget if not focus_widget: return next_focus_widget(widget.props.parent) else: focus_widget = find_focusable_child(widget.props.parent) if focus_widget: return focus_widget else: return next_focus_widget(widget.props.parent) def find_first_focus_widget(ancestor, widgets): "Return the widget from widgets which should have first the focus" if len(widgets) == 1: return widgets[0] for child in get_focus_chain(ancestor): common = [w for w in widgets if w.is_ancestor(child)] if common: return find_first_focus_widget(child, common) tryton-5.0.17/tryton/common/treeviewcontrol.py0000644000175000017500000000172313367164774021134 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of this # repository contains the full copyright notices and license terms. import gtk import gobject MOVEMENT_KEYS = {gtk.keysyms.Up, gtk.keysyms.Down, gtk.keysyms.space, gtk.keysyms.Left, gtk.keysyms.KP_Left, gtk.keysyms.Right, gtk.keysyms.KP_Right, gtk.keysyms.Home, gtk.keysyms.KP_Home, gtk.keysyms.End, gtk.keysyms.KP_End} __all__ = ['TreeViewControl'] class TreeViewControl(gtk.TreeView): def do_button_press_event(self, event): self.grab_focus() # grab focus because it doesn't whith CONTROL MASK if event.button == 1: event.state ^= gtk.gdk.CONTROL_MASK return gtk.TreeView.do_button_press_event(self, event) def do_key_press_event(self, event): if event.keyval in MOVEMENT_KEYS: event.state ^= gtk.gdk.CONTROL_MASK return gtk.TreeView.do_key_press_event(self, event) gobject.type_register(TreeViewControl) tryton-5.0.17/tryton/common/__init__.py0000644000175000017500000000073713463252531017426 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .common import * from .datetime_strftime import * from .domain_inversion import domain_inversion, eval_domain, localize_domain, \ merge, inverse_leaf, filter_leaf, prepare_reference_domain, \ extract_reference_models, concat, simplify, unique_value from .environment import EvalEnvironment from . import timedelta tryton-5.0.17/tryton/common/cellrenderercombo.py0000644000175000017500000000071413463252531021350 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject from tryton.common.selection import selection_shortcuts class CellRendererCombo(gtk.CellRendererCombo): def on_editing_started(self, editable, path): super().on_editing_started(editable, path) selection_shortcuts(editable) gobject.type_register(CellRendererCombo) tryton-5.0.17/tryton/common/htmltextbuffer.py0000644000175000017500000003404713566557275020754 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import sys from io import StringIO import xml.etree.ElementTree as ET from xml.sax.saxutils import escape, unescape from html.parser import HTMLParser from gi.repository import Gtk, Gdk, Pango def guess_decode(bytes, errors='strict'): for encoding in [sys.getfilesystemencoding(), 'utf-8', 'utf-16', 'utf-32']: try: return bytes.decode(encoding) except UnicodeDecodeError: continue else: return bytes.decode('ascii', errors=errors) MIME = Gdk.Atom.intern('text/html', False) # Disable serialize/deserialize registration function because it does not work # on GTK-3, the "guint8 *data" is converted into a Gtk.TextIter use_serialize_func = False def _reverse_dict(dct): return {j: i for i, j in dct.items()} SIZE2SCALE = { '1': 1 / (1.2 * 1.2 * 1.2), '2': 1 / (1.2 * 1.2), '3': 1 / 1.2, '4': 1, '5': 1.2, '6': 1.2 * 1.2, '7': 1.2 * 1.2 * 1.2, } SCALE2SIZE = _reverse_dict(SIZE2SCALE) ALIGN2JUSTIFICATION = { 'left': Gtk.Justification.LEFT, 'center': Gtk.Justification.CENTER, 'right': Gtk.Justification.RIGHT, 'justify': Gtk.Justification.FILL, } JUSTIFICATION2ALIGN = _reverse_dict(ALIGN2JUSTIFICATION) FAMILIES = ['normal', 'sans', 'serif', 'monospace'] def gdk_to_hex(gdk_color): "Convert color to 2 digit hex" colors = [gdk_color.red, gdk_color.green, gdk_color.blue] return "#" + "".join(["%02x" % (color // 256) for color in colors]) def _markup(text): return '%s' % text def _strip_markup(text): return text[len(''):-len('')] def _strip_newline(text): return ''.join(text.splitlines()) class MarkupHTMLParse(HTMLParser): def __init__(self): HTMLParser.__init__(self) self.root = ET.Element('markup') self._tags = [self.root] self.head = False self.body = True def handle_starttag(self, tag, attrs): if tag in ['b', 'i', 'u', 'div', 'font']: el = ET.SubElement(self._tags[-1], tag) for key, value in attrs: el.set(key, value) self._tags.append(el) elif tag == 'br': ET.SubElement(self._tags[-1], tag) elif tag == 'head': self.head = True def handle_endtag(self, tag): if tag in ['b', 'i', 'u', 'div', 'font']: el = self._tags.pop() assert el.tag == tag elif tag == 'head': self.head = False elif tag == 'body': self.body = False def handle_data(self, data): if self.head or not self.body: return el = self._tags[-1] if len(el) == 0: if el.text is None: el.text = '' el.text += data else: child = el[-1] if child.tail is None: child.tail = '' child.tail += data def parse_markup(markup_text): 'Return plain text and a list of start, end TextTag' markup_text = StringIO(_markup(markup_text)) plain_text = '' tag_stack = [] tags = [] for event, element in ET.iterparse(markup_text, events=['start', 'end']): if element.tag == 'markup': if event == 'start' and element.text: plain_text += unescape(element.text) if event == 'end' and element.tail: plain_text += unescape(element.tail) continue if event == 'start': tag_stack.append((element, len(plain_text))) if element.text: plain_text += unescape(element.text) elif event == 'end': if element.tag == 'div': plain_text += '\n' assert tag_stack[-1][0] == element _, start = tag_stack.pop() end = len(plain_text) tags.append((start, end, element)) if element.tail: plain_text += unescape(element.tail) return plain_text, tags def normalize_markup(markup_text, method='html'): parser = MarkupHTMLParse() parser.feed(_strip_newline(markup_text)) root = parser.root parent_map = {c: p for p in root.iter() for c in p} def order(em): "Re-order alphabetically tags" if (len(em) == 1 and not em.text and em.tag not in ['div', 'markup']): child, = em if ((em.tag > child.tag or child.tag == 'div') and not child.tail): em.tag, child.tag = child.tag, em.tag em.attrib, child.attrib = child.attrib, em.attrib if em in parent_map: order(parent_map[em]) # Add missing div for the first line if len(root) > 0 and root[0].tag != 'div': div = ET.Element('div') for em in list(root): if em.tag != 'div': root.remove(em) div.append(em) else: break root.insert(0, div) for em in root.iter(): while em.text is None and len(em) == 1: dup, = em if dup.tag == em.tag and dup.tail is None: em.attrib.update(dup.attrib) em.remove(dup) em.extend(dup) em.text = dup.text else: break order(em) # Add missing br to empty lines for em in root.findall('div'): if em.text is None and len(em) == 0: em.append(ET.Element('br')) # TODO order attributes return _strip_markup( ET.tostring(root, encoding='utf-8', method=method).decode('utf-8')) def find_list_delta(old, new): added = [e for e in new if e not in old] removed = [e for e in reversed(old) if e not in new] return added, removed def serialize(register, content, start, end, data): text = '' if start.compare(end) == 0: return text iter_ = start while True: # Loop over line per line to get a div per line tags = [] active_tags = [] end_line = iter_.copy() if not end_line.ends_line(): end_line.forward_to_line_end() if end_line.compare(end) > 0: end_line = end # Open div of the line align = None for tag in iter_.get_tags(): if tag.props.justification_set: align = JUSTIFICATION2ALIGN[tag.props.justification] if align: text += '
' % align else: text += '
' while True: new_tags = iter_.get_tags() added, removed = find_list_delta(tags, new_tags) for tag in removed: if tag not in active_tags: continue # close all open tags after this one while active_tags: atag = active_tags.pop() text += _get_html(atag, close=True) if atag == tag: break added.insert(0, atag) for tag in added: text += _get_html(tag) active_tags.append(tag) tags = new_tags old_iter = iter_.copy() # Move to next tag toggle while True: iter_.forward_char() if iter_.compare(end) == 0: break if iter_.toggles_tag(): break # Might have moved too far if iter_.compare(end_line) > 0: iter_ = end_line text += escape(old_iter.get_text(iter_)) if iter_.compare(end_line) == 0: break # close any open tags for tag in reversed(active_tags): text += _get_html(tag, close=True) # Close the div of the line text += '
' iter_.forward_char() if iter_.compare(end) >= 0: break return normalize_markup(text) def deserialize(register, content, iter_, text, create_tags, data): if not isinstance(text, str): text = guess_decode(text, errors='replace') text, tags = parse_markup(normalize_markup(text, method='xml')) offset = iter_.get_offset() content.insert(iter_, text) def sort_key(tag): start, end, element = tag return start, -end, element.tag for start, end, element in sorted(tags, key=sort_key): for tag in _get_tags(content, element): istart = content.get_iter_at_offset(start + offset) iend = content.get_iter_at_offset(end + offset) content.apply_tag(tag, istart, iend) return True def setup_tags(text_buffer): for name, props in reversed(_TAGS): text_buffer.create_tag(name, **props) _TAGS = [ ('bold', {'weight': Pango.Weight.BOLD}), ('italic', {'style': Pango.Style.ITALIC}), ('underline', {'underline': Pango.Underline.SINGLE}), ] _TAGS.extend([('family %s' % family, {'family': family}) for family in FAMILIES]) _TAGS.extend([('size %s' % size, {'scale': scale}) for size, scale in SIZE2SCALE.items()]) _TAGS.extend([('justification %s' % align, {'justification': justification}) for align, justification in ALIGN2JUSTIFICATION.items()]) def register_foreground(text_buffer, color): name = 'foreground %s' % color tag_table = text_buffer.get_tag_table() tag = tag_table.lookup(name) if not tag: tag = text_buffer.create_tag(name, foreground_rgba=color) return tag def _get_tags(content, element): 'Return tag for the element' tag_table = content.get_tag_table() if element.tag == 'b': yield tag_table.lookup('bold') elif element.tag == 'i': yield tag_table.lookup('italic') elif element.tag == 'u': yield tag_table.lookup('underline') if 'face' in element.attrib: tag = tag_table.lookup('family %s' % element.attrib['face']) if tag: yield tag size = element.attrib.get('size') if size in SIZE2SCALE: yield tag_table.lookup('size %s' % size) if 'color' in element.attrib: color = Gdk.RGBA() color.parse(element.attrib['color']) yield register_foreground(content, color) align = element.attrib.get('align') if align in ALIGN2JUSTIFICATION: yield tag_table.lookup('justification %s' % align) # TODO style background-color def _get_html(texttag, close=False, div_only=False): 'Return the html tag' # div alignment is managed at line level tags = [] attrib = {} font = attrib['font'] = {} if texttag.props.weight_set and texttag.props.weight == Pango.Weight.BOLD: tags.append('b') if texttag.props.style_set and texttag.props.style == Pango.Style.ITALIC: tags.append('i') if (texttag.props.underline_set and texttag.props.underline == Pango.Underline.SINGLE): tags.append('u') if texttag.props.family_set and texttag.props.family: font['face'] = texttag.props.family if texttag.props.scale_set and texttag.props.scale != 1: font['size'] = SCALE2SIZE[texttag.props.scale] if (texttag.props.foreground_set and texttag.props.foreground_gdk != Gdk.Color(0, 0, 0)): font['color'] = gdk_to_hex(texttag.props.foreground_gdk) # TODO style background-color if font: tags.append('font') if close: return ''.join('' % t for t in tags) return ''.join('<%s %s>' % (t, ' '.join('%s="%s"' % (a, v) for a, v in attrib.get(t, {}).items())) for t in tags) def get_tags(content, start, end): 'Get all tags' iter_ = start.copy() tags = set() while True: tags.update(iter_.get_tags()) iter_.forward_char() if iter_.compare(end) > 0: iter_ = end if iter_.compare(end) == 0: break tags.update(iter_.get_tags()) return tags def remove_tags(content, start, end, *names): 'Remove all tags starting by names' tags = get_tags(content, start, end) for tag in sorted(tags, key=lambda t: t.get_priority()): for name in names: if tag.props.name and tag.props.name.startswith(name): content.remove_tag(tag, start, end) if __name__ == '__main__': html = '''Bold Italic Underline

Center
Sans6red
Title
''' win = Gtk.Window() win.set_title('HTMLTextBuffer') def cb(window, event): if use_serialize_func: print(text_buffer.serialize( text_buffer, MIME, text_buffer.get_start_iter(), text_buffer.get_end_iter())) else: print(serialize( text_buffer, text_buffer, text_buffer.get_start_iter(), text_buffer.get_end_iter(), None)) Gtk.main_quit() win.connect('delete-event', cb) vbox = Gtk.VBox() win.add(vbox) text_buffer = Gtk.TextBuffer() text_view = Gtk.TextView() text_view.set_buffer(text_buffer) vbox.pack_start(text_view, expand=True, fill=True, padding=0) setup_tags(text_buffer) text_buffer.register_serialize_format(str(MIME), serialize, None) text_buffer.register_deserialize_format(str(MIME), deserialize, None) if use_serialize_func: text_buffer.deserialize( text_buffer, MIME, text_buffer.get_start_iter(), html) result = text_buffer.serialize( text_buffer, MIME, text_buffer.get_start_iter(), text_buffer.get_end_iter()) else: deserialize( text_buffer, text_buffer, text_buffer.get_start_iter(), html, text_buffer.deserialize_get_can_create_tags(MIME), None) result = serialize( text_buffer, text_buffer, text_buffer.get_start_iter(), text_buffer.get_end_iter(), None) assert normalize_markup(html) == result, (normalize_markup(html), result) win.show_all() Gtk.main() tryton-5.0.17/tryton/common/environment.py0000644000175000017500000000321413463252531020224 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. class EvalEnvironment(dict): def __init__(self, parent, eval_type='eval'): super(EvalEnvironment, self).__init__() self.parent = parent assert eval_type in ('eval', 'on_change') self.eval_type = eval_type def __getitem__(self, item): if item == 'id': return self.parent.id if item == '_parent_' + self.parent.parent_name and self.parent.parent: return EvalEnvironment(self.parent.parent, eval_type=self.eval_type) if self.eval_type == 'eval': return self.parent.get_eval()[item] else: return self.parent.group.fields[item].get_on_change_value( self.parent) def __getattr__(self, item): try: return self.__getitem__(item) except KeyError: raise AttributeError(item) def get(self, item, default=None): try: return self.__getitem__(item) except KeyError: pass return super(EvalEnvironment, self).get(item, default) def __bool__(self): return True def __str__(self): return str(self.parent) __repr__ = __str__ def __contains__(self, item): if item == 'id': return True if item == '_parent_' + self.parent.parent_name and self.parent.parent: return True if self.eval_type == 'eval': return item in self.parent.get_eval() else: return item in self.parent.group.fields tryton-5.0.17/tryton/common/cellrendererfloat.py0000644000175000017500000000274213463252531021361 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import locale from .cellrendererinteger import CellRendererInteger class CellRendererFloat(CellRendererInteger): def __init__(self): super(CellRendererFloat, self).__init__() self.digits = None def on_editing_started(self, editable, path): super().on_editing_started(editable, path) editable.connect('key-press-event', self.key_press_event) def key_press_event(self, widget, event): for name in ('KP_Decimal', 'KP_Separator'): if event.keyval == gtk.gdk.keyval_from_name(name): event.keyval = int(gtk.gdk.unicode_to_keyval( ord(locale.localeconv()['decimal_point']))) def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] decimal_point = locale.localeconv()['decimal_point'] if new_value in ('-', decimal_point): return try: value = locale.atof(new_value) except ValueError: entry.stop_emission('insert-text') return if self.digits and not (round(value, self.digits[1]) == float(value)): entry.stop_emission('insert-text') gobject.type_register(CellRendererFloat) tryton-5.0.17/tryton/common/cellrenderertoggle.py0000644000175000017500000000042313463252531021527 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject class CellRendererToggle(gtk.CellRendererToggle): pass gobject.type_register(CellRendererToggle) tryton-5.0.17/tryton/common/domain_parser.py0000644000175000017500000014474413563616132020523 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from shlex import shlex from types import GeneratorType import gettext import locale import decimal from decimal import Decimal import datetime import io from collections import OrderedDict from tryton.common import untimezoned_date, timezoned_date, datetime_strftime from tryton.common.datetime_ import date_parse from tryton.common.timedelta import parse as timedelta_parse from tryton.common.timedelta import format as timedelta_format from tryton.pyson import PYSONDecoder __all__ = ['DomainParser'] _ = gettext.gettext ListGeneratorType = type(iter([])) TupleGeneratorType = type(iter(())) OPERATORS = ( '!=', '<=', '>=', '=', '!', '<', '>', ) class udlex(shlex): "A lexical analyzer class for human domain syntaxes." def __init__(self, instream=None): shlex.__init__(self, io.StringIO(instream), posix=True) self.commenters = '' self.quotes = '"' class DummyWordchars(object): "Simulate str that contains all chars except somes" def __contains__(self, item): return item not in (':', '>', '<', '=', '!', '"', ';', '(', ')') self.wordchars = DummyWordchars() def isgenerator(value): "Test if value is a generator type" return isinstance(value, (GeneratorType, ListGeneratorType, TupleGeneratorType)) def rlist(value): "Convert recursivly generator into list" if isgenerator(value) or isinstance(value, list): return [rlist(x) for x in value] return value def simplify(value): "Remove double nested list" if isinstance(value, list): if len(value) == 1 and isinstance(value[0], list): return simplify(value[0]) elif (len(value) == 2 and value[0] in ('AND', 'OR') and isinstance(value[1], list)): return simplify(value[1]) elif (len(value) == 3 and value[0] in ('AND', 'OR') and isinstance(value[1], list) and value[0] == value[1][0]): value = simplify(value[1]) + [value[2]] return [simplify(x) for x in value] return value def group_operator(tokens): "Group token of operators" try: cur = next(tokens) except StopIteration: return nex = None for nex in tokens: if nex == '=' and cur and cur + nex in OPERATORS: yield cur + nex cur = None else: if cur is not None: yield cur cur = nex if cur is not None: yield cur def test_group_operator(): assert list(group_operator(iter(['a', '>', '=']))) == ['a', '>='] assert list(group_operator(iter(['>', '=', 'b']))) == ['>=', 'b'] assert list(group_operator(iter(['a', '=', 'b']))) == ['a', '=', 'b'] assert list(group_operator(iter(['a', '>', '=', 'b']))) == ['a', '>=', 'b'] assert list(group_operator(iter(['a', '>', '=', '=']))) == ['a', '>=', '='] def likify(value): "Add % if needed" if not value: return '%' escaped = value.replace('%%', '__') if '%' in escaped: return value else: return '%' + value + '%' def quote(value): "Quote string if needed" if not isinstance(value, str): return value if '\\' in value: value = value.replace('\\', '\\\\') if '"' in value: value = value.replace('"', '\\"') for test in (':', ' ', '(', ')') + OPERATORS: if test in value: return '"%s"' % value return value def test_quote(): assert quote('test') == 'test' assert quote('foo bar') == '"foo bar"' assert quote('"foo"') == '\\\"foo\\\"' assert quote('foo\\bar') == 'foo\\\\bar' def ending_clause(domain, deep=0): "Return the ending clause" if not domain: return None, deep if isinstance(domain[-1], list): return ending_clause(domain[-1], deep + 1) return domain[-1], deep def replace_ending_clause(domain, clause): "Replace the ending clause" for dom in domain[:-1]: yield dom if isinstance(domain[-1], list): yield replace_ending_clause(domain[-1], clause) else: yield clause def append_ending_clause(domain, clause, deep): "Append clause after the ending clause" if not domain: yield clause return for dom in domain[:-1]: yield dom if isinstance(domain[-1], list): yield append_ending_clause(domain[-1], clause, deep - 1) else: yield domain[-1] if deep == 0: yield clause def default_operator(field): "Return default operator for field" if field['type'] in ('char', 'text', 'many2one', 'many2many', 'one2many', 'reference'): return 'ilike' else: return '=' def negate_operator(operator): "Return negate operator" if operator == 'ilike': return 'not ilike' elif operator == '=': return '!=' elif operator == 'in': return 'not in' def time_format(field): return PYSONDecoder({}).decode(field['format']) def split_target_value(field, value): "Split the reference value into target and value" assert field['type'] == 'reference' target = None if isinstance(value, str): for key, text in field['selection']: if value.lower().startswith(text.lower() + ','): target = key value = value[len(text) + 1:] break return target, value def test_split_target_value(): field = { 'type': 'reference', 'selection': [ ('spam', 'Spam'), ('ham', 'Ham'), ('e', 'Eggs'), ] } for value, result in ( ('Spam', (None, 'Spam')), ('foo', (None, 'foo')), ('Spam,', ('spam', '')), ('Ham,bar', ('ham', 'bar')), ('Eggs,foo', ('e', 'foo')), ): assert split_target_value(field, value) == result def convert_value(field, value, context=None): "Convert value for field" if context is None: context = {} def convert_boolean(): if isinstance(value, str): return any(test.lower().startswith(value.lower()) for test in ( _('y'), _('Yes'), _('True'), _('t'), '1')) else: return bool(value) def convert_float(): factor = float(field.get('factor', 1)) try: return locale.atof(value) / factor except (ValueError, AttributeError): return def convert_integer(): factor = float(field.get('factor', 1)) try: return int(locale.atof(value) / factor) except (ValueError, AttributeError): return def convert_numeric(): factor = Decimal(field.get('factor', 1)) try: return locale.atof(value, Decimal) / factor except (decimal.InvalidOperation, AttributeError): return def convert_selection(): if isinstance(value, str): for key, text in field['selection']: if value.lower() == text.lower(): return key return value def convert_datetime(): if not value: return format_ = context.get('date_format', '%x') + ' %X' try: dt = date_parse(value, format_) return untimezoned_date(dt) except ValueError: return def convert_date(): if not value: return format_ = context.get('date_format', '%x') try: return date_parse(value, format_).date() except (ValueError, TypeError): return def convert_time(): if not value: return try: return date_parse(value).time() except (ValueError, TypeError): return def convert_timedelta(): return timedelta_parse(value, context.get(field.get('converter'))) def convert_many2one(): if value == '': return None return value converts = { 'boolean': convert_boolean, 'float': convert_float, 'integer': convert_integer, 'numeric': convert_numeric, 'selection': convert_selection, 'reference': convert_selection, 'datetime': convert_datetime, 'date': convert_date, 'time': convert_time, 'timedelta': convert_timedelta, 'many2one': convert_many2one, } return converts.get(field['type'], lambda: value)() def test_convert_boolean(): field = { 'type': 'boolean', } for value, result in ( ('Y', True), ('yes', True), ('t', True), ('1', True), ('N', False), ('False', False), ('no', False), ('0', False), (None, False), ): assert convert_value(field, value) == result def test_convert_float(): field = { 'type': 'float', } for value, result in ( ('1', 1.0), ('1.5', 1.5), ('', None), ('test', None), (None, None), ): assert convert_value(field, value) == result def test_convert_float_factor(): field = { 'type': 'float', 'factor': '100', } assert convert_value(field, '42') == 0.42 def test_convert_integer(): field = { 'type': 'integer', } for value, result in ( ('1', 1), ('1.5', 1), ('', None), ('test', None), (None, None), ): assert convert_value(field, value) == result def test_convert_integer_factor(): field = { 'type': 'integer', 'factor': '2', } assert convert_value(field, '6') == 3 def test_convert_numeric(): field = { 'type': 'numeric', } for value, result in ( ('1', Decimal(1)), ('1.5', Decimal('1.5')), ('', None), ('test', None), (None, None), ): assert convert_value(field, value) == result def test_convert_numeric_factor(): field = { 'type': 'numeric', 'factor': '5', } assert convert_value(field, '1') == Decimal('0.2') def test_convert_selection(): field = { 'type': 'selection', 'selection': [ ('male', 'Male'), ('female', 'Female'), ], } field_with_empty = field.copy() field_with_empty['selection'] = (field_with_empty['selection'] + [('', '')]) for value, result in ( ('Male', 'male'), ('male', 'male'), ('test', 'test'), (None, None), ('', ''), ): assert convert_value(field, value) == result assert convert_value(field_with_empty, value) == result def test_convert_datetime(): field = { 'type': 'datetime', 'format': '"%H:%M:%S"', } for value, result in ( ('12/04/2002', untimezoned_date(datetime.datetime(2002, 12, 4))), ('12/04/2002 12:30:00', untimezoned_date( datetime.datetime(2002, 12, 4, 12, 30))), ('02/03/04', untimezoned_date(datetime.datetime(2004, 2, 3))), ('02/03/04 05:06:07', untimezoned_date( datetime.datetime(2004, 2, 3, 5, 6, 7))), ('test', None), (None, None), ): assert convert_value(field, value) == result, (value, convert_value(field, value), result) def test_convert_date(): field = { 'type': 'date', } for value, result in ( ('12/04/2002', datetime.date(2002, 12, 4)), ('test', None), (None, None), ): assert convert_value(field, value) == result def test_convert_time(): field = { 'type': 'time', 'format': '"%H:%M:%S"', } for value, result in ( ('12:30:00', datetime.time(12, 30, 0)), ('test', None), (None, None), ): assert convert_value(field, value) == result def test_convert_timedelta(): field = { 'type': 'timedelta', } for value, result in [ ('1d 2:00', datetime.timedelta(days=1, hours=2)), ('foo', datetime.timedelta()), (None, None), ]: assert convert_value(field, value) == result def format_value(field, value, target=None, context=None): "Format value for field" if context is None: context = {} def format_boolean(): return _('True') if value else _('False') def format_integer(): factor = float(field.get('factor', 1)) if value or value is 0 or isinstance(value, float): return str(int(value * factor)) return '' def format_float(): if (not value and value is not 0 and not isinstance(value, (float, Decimal))): return '' if isinstance(value, Decimal): cast = Decimal else: cast = float factor = cast(field.get('factor', 1)) try: digit = len(str(value * factor).rstrip('0').split('.')[1]) except IndexError: digit = 0 return locale.format('%.*f', (digit, value * factor or 0), True) def format_selection(): selections = dict(field['selection']) return selections.get(value, value) or '' def format_reference(): if not target: return format_selection() selections = dict(field['selection']) return '%s,%s' % (selections.get(target, target), value) def format_datetime(): if not value: return '' format_ = context.get('date_format', '%x') + ' ' + time_format(field) if not isinstance(value, datetime.datetime): time = datetime.datetime.combine(value, datetime.time.min) else: time = timezoned_date(value) if time.time() == datetime.time.min: format_ = '%x' return datetime_strftime(time, format_) def format_date(): if not value: return '' format_ = context.get('date_format', '%x') return datetime_strftime(value, format_) def format_time(): if not value: return '' return datetime.time.strftime(value, time_format(field)) def format_timedelta(): if not value: return '' return timedelta_format(value, context.get(field.get('converter'))) def format_many2one(): if value is None: return '' return value converts = { 'boolean': format_boolean, 'integer': format_integer, 'float': format_float, 'numeric': format_float, 'selection': format_selection, 'reference': format_reference, 'datetime': format_datetime, 'date': format_date, 'time': format_time, 'timedelta': format_timedelta, 'many2one': format_many2one, } if isinstance(value, (list, tuple)): return ';'.join(format_value(field, x, context=context) for x in value) return quote(converts.get(field['type'], lambda: value if value is not None else '')()) def test_format_boolean(): field = { 'type': 'boolean', } for value, result in ( (True, 'True'), (False, 'False'), (None, 'False'), ): assert format_value(field, value) == result def test_format_integer(): field = { 'type': 'integer', } for value, result in ( (1, '1'), (1.5, '1'), (0, '0'), (0.0, '0'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_integer_factor(): field = { 'type': 'integer', 'factor': '2', } assert format_value(field, 3) == '6' def test_format_float(): field = { 'type': 'float', } for value, result in ( (1, '1'), (1.5, '1.5'), (1.50, '1.5'), (150.79, '150.79'), (0, '0'), (0.0, '0'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_float_factor(): field = { 'type': 'float', 'factor': '100', } assert format_value(field, 0.42) == '42' def test_format_numeric(): field = { 'type': 'numeric', } for value, result in ( (Decimal(1), '1'), (Decimal('1.5'), '1.5'), (Decimal('1.50'), '1.5'), (Decimal('150.79'), '150.79'), (Decimal(0), '0'), (Decimal('0.0'), '0'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_numeric_factor(): field = { 'type': 'numeric', 'factor': '5', } assert format_value(field, Decimal('0.2')) == '1' def test_format_selection(): field = { 'type': 'selection', 'selection': [ ('male', 'Male'), ('female', 'Female'), ], } field_with_empty = field.copy() field_with_empty['selection'] = (field_with_empty['selection'] + [('', '')]) for value, result in ( ('male', 'Male'), ('test', 'test'), (False, ''), (None, ''), ('', ''), ): assert format_value(field, value) == result assert format_value(field_with_empty, value) == result def test_format_datetime(): field = { 'type': 'datetime', 'format': '"%H:%M:%S"', } for value, result in ( (datetime.date(2002, 12, 4), '12/04/2002'), (untimezoned_date(datetime.datetime(2002, 12, 4)), '12/04/2002'), (untimezoned_date(datetime.datetime(2002, 12, 4, 12, 30)), '"12/04/2002 12:30:00"'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_date(): field = { 'type': 'date', } for value, result in ( (datetime.date(2002, 12, 4), '12/04/2002'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_time(): field = { 'type': 'time', 'format': '"%H:%M:%S"', } for value, result in ( (datetime.time(12, 30, 0), '"12:30:00"'), (False, ''), (None, ''), ): assert format_value(field, value) == result def test_format_timedelta(): field = { 'type': 'timedelta', } for value, result in [ (datetime.timedelta(days=1, hours=2), '"1d 02:00"'), (datetime.timedelta(), ''), (None, ''), ('', ''), ]: assert format_value(field, value) == result def complete_value(field, value): "Complete value for field" def complete_boolean(): if value: yield False else: yield True def complete_selection(): test_value = value if value is not None else '' if isinstance(value, list): test_value = value[-1] or '' test_value = test_value.strip('%') for svalue, test in field['selection']: if test.lower().startswith(test_value.lower()): if isinstance(value, list): yield value[:-1] + [svalue] else: yield svalue def complete_reference(): test_value = value if value is not None else '' if isinstance(value, list): test_value = value[-1] test_value = test_value.strip('%') for svalue, test in field['selection']: if test.lower().startswith(test_value.lower()): if isinstance(value, list): yield value[:-1] + [svalue] else: yield likify(svalue) def complete_datetime(): yield datetime.date.today() yield datetime.datetime.utcnow() def complete_date(): yield datetime.date.today() def complete_time(): yield datetime.datetime.now().time() completes = { 'boolean': complete_boolean, 'selection': complete_selection, 'reference': complete_reference, 'datetime': complete_datetime, 'date': complete_date, 'time': complete_time, } return completes.get(field['type'], lambda: [])() def test_complete_selection(): field = { 'type': 'selection', 'selection': [ ('male', 'Male'), ('female', 'Female'), ], } for value, result in ( ('m', ['male']), ('test', []), ('', ['male', 'female']), (None, ['male', 'female']), (['male', 'f'], [['male', 'female']]), (['male', None], [['male', 'male'], ['male', 'female']]), ): assert list(complete_value(field, value)) == result field_with_empty = field.copy() field_with_empty['selection'] = (field_with_empty['selection'] + [('', '')]) for value, result in ( ('m', ['male']), ('test', []), ('', ['male', 'female', '']), (None, ['male', 'female', '']), (['male', 'f'], [['male', 'female']]), ): assert list(complete_value(field_with_empty, value)) == result def test_complete_reference(): field = { 'type': 'reference', 'selection': [ ('spam', 'Spam'), ('ham', 'Ham'), ('', ''), ], } for value, result in ( ('s', ['%spam%']), ('test', []), ('', ['%spam%', '%ham%', '%']), (None, ['%spam%', '%ham%', '%']), (['spam', 'h'], [['spam', 'ham']]), ): assert list(complete_value(field, value)) == result def parenthesize(tokens): "Nest tokens according to parenthesis" for token in tokens: if token == '(': yield iter(list(parenthesize(tokens))) elif token == ')': break else: yield token def test_parenthesize(): for value, result in ( (['a'], ['a']), (['a', 'b'], ['a', 'b']), (['(', 'a', ')'], [['a']]), (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f', ')', 'g'], ['a', 'b', ['c', ['d', 'e'], 'f'], 'g']), (['a', 'b', '(', 'c'], ['a', 'b', ['c']]), (['a', 'b', '(', 'c', '(', 'd', 'e', ')', 'f'], ['a', 'b', ['c', ['d', 'e'], 'f']]), (['a', 'b', ')'], ['a', 'b']), (['a', 'b', ')', 'c', ')', 'd)'], ['a', 'b']), ): assert rlist(parenthesize(iter(value))) == result def operatorize(tokens, operator='or'): "Convert operators" test = (operator, (operator,)) try: cur = next(tokens) while cur in test: cur = next(tokens) except StopIteration: return if isgenerator(cur): cur = operatorize(cur, operator) nex = None for nex in tokens: if isgenerator(nex): nex = operatorize(nex, operator) if nex in test: try: nex = next(tokens) while nex in test: nex = next(tokens) if isgenerator(nex): nex = operatorize(nex, operator) cur = iter([operator.upper(), cur, nex]) except StopIteration: if cur not in test: yield iter([operator.upper(), cur]) cur = None nex = None else: if cur not in test: yield cur cur = nex else: if nex is not None and nex not in test: yield nex elif cur is not None and cur not in test: yield cur def test_operatorize(): a = ('a', 'a', 'a') b = ('b', 'b', 'b') c = ('c', 'c', 'c') null_ = ('d', None, 'x') double_null_ = ('e', None, None) for value, result in ( (['a'], ['a']), (['a', 'or', 'b'], [['OR', 'a', 'b']]), (['a', 'or', 'b', 'or', 'c'], [['OR', ['OR', 'a', 'b'], 'c']]), (['a', 'b', 'or', 'c'], ['a', ['OR', 'b', 'c']]), (['a', 'or', 'b', 'c'], [['OR', 'a', 'b'], 'c']), (['a', iter(['b', 'c'])], ['a', ['b', 'c']]), (['a', iter(['b', 'c']), 'd'], ['a', ['b', 'c'], 'd']), (['a', 'or', iter(['b', 'c'])], [['OR', 'a', ['b', 'c']]]), (['a', 'or', iter(['b', 'c']), 'd'], [['OR', 'a', ['b', 'c']], 'd']), (['a', iter(['b', 'c']), 'or', 'd'], ['a', ['OR', ['b', 'c'], 'd']]), (['a', 'or', iter(['b', 'or', 'c'])], [['OR', 'a', [['OR', 'b', 'c']]]]), (['or'], []), (['or', 'a'], ['a']), (['a', iter(['or', 'b'])], ['a', ['b']]), (['a', 'or', 'or', 'b'], [['OR', 'a', 'b']]), (['or', 'or', 'a'], ['a']), (['or', 'or', 'a', 'b'], ['a', 'b']), (['or', 'or', 'a', 'or', 'b'], [['OR', 'a', 'b']]), (['a', iter(['b', 'or', 'c'])], ['a', [['OR', 'b', 'c']]]), ([a, iter([b, ('or',), c])], [a, [['OR', b, c]]]), (['a', iter(['b', 'or'])], ['a', [['OR', 'b']]]), ([null_], [null_]), ([null_, 'or', double_null_], [['OR', null_, double_null_]]), ): assert rlist(operatorize(iter(value))) == result class DomainParser(object): "A parser for domain" def __init__(self, fields, context=None): self.fields = OrderedDict((name, f) for name, f in fields.items() if f.get('searchable', True)) self.strings = dict((f['string'].lower(), f) for f in fields.values() if f.get('searchable', True)) self.context = context def parse(self, input_): "Return domain for the input string" try: tokens = udlex(input_) tokens = group_operator(tokens) tokens = parenthesize(tokens) tokens = self.group(tokens) tokens = operatorize(tokens, 'or') tokens = operatorize(tokens, 'and') tokens = self.parse_clause(tokens) return simplify(rlist(tokens)) except ValueError as exception: if str(exception) == 'No closing quotation': return self.parse(input_ + '"') def stringable(self, domain): def stringable_(clause): if not clause: return True if (((clause[0] in ('AND', 'OR')) or isinstance(clause[0], (list, tuple))) and all(isinstance(c, (list, tuple)) for c in clause[1:])): return self.stringable(clause) name, _, value = clause[:3] if name.endswith('.rec_name'): name = name[:-len('.rec_name')] if name in self.fields: field = self.fields[name] if field['type'] in { 'many2one', 'one2one', 'one2many', 'many2many'}: if field['type'] == 'many2one': types = (str, type(None)) else: types = str if isinstance(value, (list, tuple)): return all(isinstance(v, types) for v in value) else: return isinstance(value, types) else: return True elif name == 'rec_name': return True return False if not domain: return True if domain[0] in ('AND', 'OR'): domain = domain[1:] return all(stringable_(clause) for clause in domain) def string(self, domain): "Return string for the domain" def string_(clause): if not clause: return '' if (not isinstance(clause[0], str) or clause[0] in ('AND', 'OR')): return '(%s)' % self.string(clause) name, operator, value = clause[:3] if name.endswith('.rec_name'): name = name[:-9] if name not in self.fields: escaped = value.replace('%%', '__') if escaped.startswith('%') and escaped.endswith('%'): value = value[1:-1] return quote(value) field = self.fields[name] if len(clause) > 3: target = clause[3] else: target = None if 'ilike' in operator: escaped = value.replace('%%', '__') if escaped.startswith('%') and escaped.endswith('%'): value = value[1:-1] elif '%' not in escaped: if operator == 'ilike': operator = '=' else: operator = '!' value = value.replace('%%', '%') def_operator = default_operator(field) if def_operator == operator.strip(): operator = '' if value in OPERATORS: # As the value could be interpreted as an operator, # the default operator must be forced operator = '"" ' elif (def_operator in operator and ('not' in operator or '!' in operator)): operator = operator.rstrip(def_operator ).replace('not', '!').strip() if operator.endswith('in'): if operator == 'not in': operator = '!' else: operator = '' formatted_value = format_value(field, value, target, self.context) if (operator in OPERATORS and field['type'] in ('char', 'text', 'selection') and value == ''): formatted_value = '""' return '%s: %s%s' % (quote(field['string']), operator, formatted_value) if not domain: return '' if domain[0] in ('AND', 'OR'): nary = ' ' if domain[0] == 'AND' else ' or ' domain = domain[1:] else: nary = ' ' return nary.join(string_(clause) for clause in domain) def completion(self, input_): "Return completion for the input string" domain = self.parse(input_) closing = 0 for i in range(1, len(input_)): if input_[-i] not in (')', ' '): break if input_[-i] == ')': closing += 1 ending, deep_ending = ending_clause(domain) deep = deep_ending - closing if deep: pslice = slice(-deep) else: pslice = slice(None) if self.string(domain)[pslice] != input_: yield self.string(domain)[pslice] complete = None if ending is not None and closing == 0: for complete in self.complete(ending): yield self.string(rlist( replace_ending_clause(domain, complete)))[pslice] if input_: if input_[-1] != ' ': return if len(input_) >= 2 and input_[-2] == ':': return for field in self.strings.values(): operator = default_operator(field) value = '' if 'ilike' in operator: value = likify(value) yield self.string(rlist(append_ending_clause(domain, (field['name'], operator, value), deep)))[pslice] def complete(self, clause): "Return all completion for the clause" if len(clause) == 1: name, = clause elif len(clause) == 3: name, operator, value = clause else: name, operator, value, target = clause if name.endswith('.rec_name'): name = name[:-9] value = target if name == 'rec_name': if operator == 'ilike': escaped = value.replace('%%', '__') if escaped.startswith('%') and escaped.endswith('%'): value = value[1:-1] elif '%' not in escaped: value = value.replace('%%', '%') operator = None name = value value = '' if not name: name = '' if (name.lower() not in self.strings and name not in self.fields): for field in self.strings.values(): if field['string'].lower().startswith(name.lower()): operator = default_operator(field) value = '' if 'ilike' in operator: value = likify(value) yield (field['name'], operator, value) return if name in self.fields: field = self.fields[name] else: field = self.strings[name.lower()] if not operator: operator = default_operator(field) value = '' if 'ilike' in operator: value = likify(value) yield (field['name'], operator, value) else: for comp in complete_value(field, value): yield (field['name'], operator, comp) def group(self, tokens): "Group tokens by clause" def _group(parts): try: i = parts.index(':') except ValueError: for part in parts: yield (part,) return for j in range(i): name = ' '.join(parts[j:i]) if name.lower() in self.strings: if parts[:j]: for part in parts[:j]: yield (part,) else: yield (None,) name = (name,) # empty string is also the default operator if (i + 1 < len(parts) and parts[i + 1] in OPERATORS + ('',)): name += (parts[i + 1],) i += 1 else: name += (None,) lvalue = [] while i + 2 < len(parts): if parts[i + 2] == ';': lvalue.append(parts[i + 1]) i += 2 else: break for part in _group(parts[i + 1:]): if name: if lvalue: if part[0] is not None: lvalue.append(part[0]) yield name + (lvalue,) else: yield name + part name = None else: yield part if name: if lvalue: yield name + (lvalue,) else: yield name + (None,) break parts = [] for token in tokens: if isgenerator(token): for group in _group(parts): if group != (None,): yield group parts = [] yield self.group(token) else: parts.append(token) for group in _group(parts): if group != (None,): yield group def parse_clause(self, tokens): "Parse clause" for clause in tokens: if isgenerator(clause): yield self.parse_clause(clause) elif clause in ('OR', 'AND'): yield clause else: if len(clause) == 1: yield ('rec_name', 'ilike', likify(clause[0])) else: name, operator, value = clause field = self.strings[name.lower()] field_name = field['name'] target = None if field['type'] == 'reference': target, value = split_target_value(field, value) if target: field_name += '.rec_name' if not operator: operator = default_operator(field) if isinstance(value, list): if operator == '!': operator = 'not in' else: operator = 'in' if operator == '!': operator = negate_operator(default_operator(field)) if field['type'] in ('integer', 'float', 'numeric', 'datetime', 'date', 'time'): if isinstance(value, str) and '..' in value: lvalue, rvalue = value.split('..', 1) lvalue = convert_value(field, lvalue, self.context) rvalue = convert_value(field, rvalue, self.context) yield iter([ (field_name, '>=', lvalue), (field_name, '<=', rvalue), ]) continue if isinstance(value, list): value = [convert_value(field, v, self.context) for v in value] if field['type'] in ('many2one', 'one2many', 'many2many', 'one2one'): field_name += '.rec_name' else: value = convert_value(field, value, self.context) if 'like' in operator: value = likify(value) if target: yield (field_name, operator, value, target) else: yield field_name, operator, value def test_stringable(): dom = DomainParser({ 'name': { 'string': 'Name', 'type': 'char', }, 'relation': { 'string': 'Relation', 'type': 'many2one', }, 'relations': { 'string': 'Relations', 'type': 'many2many', }, }) valid = ('name', '=', 'Doe') invalid = ('surname', '=', 'John') assert dom.stringable([valid]) assert not dom.stringable([invalid]) assert dom.stringable(['AND', valid]) assert not dom.stringable(['AND', valid, invalid]) assert dom.stringable([[valid]]) assert not dom.stringable([[valid], [invalid]]) assert dom.stringable([('relation', '=', None)]) assert dom.stringable([('relation', '=', "Foo")]) assert dom.stringable([('relation.rec_name', '=', "Foo")]) assert not dom.stringable([('relation', '=', 1)]) assert dom.stringable([('relations', '=', "Foo")]) assert dom.stringable([('relations', 'in', ["Foo"])]) assert not dom.stringable([('relations', 'in', [42])]) def test_string(): dom = DomainParser({ 'name': { 'string': 'Name', 'type': 'char', }, 'surname': { 'string': '(Sur)Name', 'type': 'char', }, 'date': { 'string': 'Date', 'type': 'date', }, 'selection': { 'string': 'Selection', 'type': 'selection', 'selection': [ ('male', 'Male'), ('female', 'Female'), ('', ''), ], }, 'reference': { 'string': 'Reference', 'type': 'reference', 'selection': [ ('spam', 'Spam'), ('ham', 'Ham'), ] }, 'many2one': { 'string': 'Many2One', 'name': 'many2one', 'type': 'many2one', }, }) assert dom.string([('name', '=', 'Doe')]) == 'Name: =Doe' assert dom.string([('name', '=', None)]) == 'Name: =' assert dom.string([('name', '=', '')]) == 'Name: =""' assert dom.string([('name', 'ilike', '%')]) == 'Name: ' assert dom.string([('name', 'ilike', '%Doe%')]) == 'Name: Doe' assert dom.string([('name', 'ilike', '%<%')]) == 'Name: "" "<"' assert dom.string([('name', 'ilike', 'Doe')]) == 'Name: =Doe' assert dom.string([('name', 'ilike', 'Doe%')]) == 'Name: Doe%' assert dom.string([('name', 'ilike', 'Doe%%')]) == 'Name: =Doe%' assert dom.string([('name', 'not ilike', '%Doe%')]) == 'Name: !Doe' assert dom.string([('name', 'in', ['John', 'Jane'])]) == 'Name: John;Jane' assert dom.string([('name', 'not in', ['John', 'Jane'])]) == \ 'Name: !John;Jane' assert dom.string([ ('name', 'ilike', '%Doe%'), ('name', 'ilike', '%Jane%')]) == 'Name: Doe Name: Jane' assert dom.string(['AND', ('name', 'ilike', '%Doe%'), ('name', 'ilike', '%Jane%')]) == 'Name: Doe Name: Jane' assert dom.string(['OR', ('name', 'ilike', '%Doe%'), ('name', 'ilike', '%Jane%')]) == 'Name: Doe or Name: Jane' assert dom.string([ ('name', 'ilike', '%Doe%'), ['OR', ('name', 'ilike', '%John%'), ('name', 'ilike', '%Jane%')]]) == \ 'Name: Doe (Name: John or Name: Jane)' assert dom.string([]) == '' assert dom.string([('surname', 'ilike', '%Doe%')]) == '"(Sur)Name": Doe' assert dom.string([('date', '>=', datetime.date(2012, 10, 24))]) == \ 'Date: >=10/24/2012' assert dom.string([('selection', '=', '')]) == 'Selection: ' assert dom.string([('selection', '=', None)]) == 'Selection: ' assert dom.string([('selection', '!=', '')]) == 'Selection: !""' assert dom.string([('selection', '=', 'male')]) == 'Selection: Male' assert dom.string([('selection', '!=', 'male')]) == 'Selection: !Male' assert dom.string([('reference', 'ilike', '%foo%')]) == \ 'Reference: foo' assert dom.string([('reference.rec_name', 'ilike', '%bar%', 'spam')]) == \ 'Reference: Spam,bar' assert dom.string([('reference', 'in', ['foo', 'bar'])]) == \ 'Reference: foo;bar' assert dom.string([('many2one', 'ilike', '%John%')]) == 'Many2One: John' assert dom.string([('many2one.rec_name', 'in', ['John', 'Jane'])]) == \ 'Many2One: John;Jane' def test_group(): dom = DomainParser({ 'name': { 'string': 'Name', }, 'firstname': { 'string': 'First Name', }, 'surname': { 'string': '(Sur)Name', }, }) assert rlist(dom.group(udlex('Name: Doe'))) == [('Name', None, 'Doe')] assert rlist(dom.group(udlex('"(Sur)Name": Doe'))) == [ ('(Sur)Name', None, 'Doe'), ] assert rlist(dom.group(udlex('Name: Doe Name: John'))) == [ ('Name', None, 'Doe'), ('Name', None, 'John')] assert rlist(dom.group(udlex('Name: Name: John'))) == [ ('Name', None, None), ('Name', None, 'John')] assert rlist(dom.group(udlex('First Name: John'))) == [ ('First Name', None, 'John'), ] assert rlist(dom.group(udlex('Name: Doe First Name: John'))) == [ ('Name', None, 'Doe'), ('First Name', None, 'John'), ] assert rlist(dom.group(udlex('First Name: John Name: Doe'))) == [ ('First Name', None, 'John'), ('Name', None, 'Doe'), ] assert rlist(dom.group(udlex('First Name: John First Name: Jane'))) == [ ('First Name', None, 'John'), ('First Name', None, 'Jane'), ] assert rlist(dom.group(udlex('Name: John Doe'))) == [ ('Name', None, 'John'), ('Doe',), ] assert rlist(dom.group(udlex('Name: "John Doe"'))) == [ ('Name', None, 'John Doe'), ] assert rlist(dom.group(udlex('Name: =Doe'))) == [('Name', '=', 'Doe')] assert rlist(dom.group(udlex('Name: =Doe Name: >John'))) == [ ('Name', '=', 'Doe'), ('Name', '>', 'John'), ] assert rlist(dom.group(udlex('First Name: =John First Name: =Jane'))) == [ ('First Name', '=', 'John'), ('First Name', '=', 'Jane'), ] assert rlist(dom.group(udlex('Name: John;Jane'))) == [ ('Name', None, ['John', 'Jane']) ] assert rlist(dom.group(udlex('Name: John;'))) == [ ('Name', None, ['John']) ] assert rlist(dom.group(udlex('Name: John;Jane Name: Doe'))) == [ ('Name', None, ['John', 'Jane']), ('Name', None, 'Doe'), ] assert rlist(dom.group(udlex('Name: John; Name: Doe'))) == [ ('Name', None, ['John']), ('Name', None, 'Doe'), ] assert rlist(dom.group(udlex('Name:'))) == [ ('Name', None, None), ] assert rlist(dom.group(udlex('Name: ='))) == [ ('Name', '=', None), ] assert rlist(dom.group(udlex('Name: =""'))) == [ ('Name', '=', ''), ] assert rlist(dom.group(udlex('Name: = ""'))) == [ ('Name', '=', ''), ] assert rlist(dom.group(udlex('Name: = Name: Doe'))) == [ ('Name', '=', None), ('Name', None, 'Doe'), ] assert rlist(dom.group(udlex('Name: \\"foo\\"'))) == [ ('Name', None, '"foo"'), ] assert rlist(dom.group(udlex('Name: "" <'))) == [ ('Name', '', '<'), ] def test_parse_clause(): dom = DomainParser({ 'name': { 'string': 'Name', 'name': 'name', 'type': 'char', }, 'integer': { 'string': 'Integer', 'name': 'integer', 'type': 'integer', }, 'selection': { 'string': 'Selection', 'name': 'selection', 'type': 'selection', 'selection': [ ('male', 'Male'), ('female', 'Female'), ], }, 'reference': { 'string': 'Reference', 'name': 'reference', 'type': 'reference', 'selection': [ ('spam', 'Spam'), ('ham', 'Ham'), ] }, 'many2one': { 'string': 'Many2One', 'name': 'many2one', 'type': 'many2one', }, }) assert rlist(dom.parse_clause([('John',)])) == [ ('rec_name', 'ilike', '%John%')] assert rlist(dom.parse_clause([('Name', None, None)])) == [ ('name', 'ilike', '%')] assert rlist(dom.parse_clause([('Name', '', None)])) == [ ('name', 'ilike', '%')] assert rlist(dom.parse_clause([('Name', '=', None)])) == [ ('name', '=', None)] assert rlist(dom.parse_clause([('Name', '=', '')])) == [ ('name', '=', '')] assert rlist(dom.parse_clause([('Name', None, 'Doe')])) == [ ('name', 'ilike', '%Doe%')] assert rlist(dom.parse_clause([('Name', '!', 'Doe')])) == [ ('name', 'not ilike', '%Doe%')] assert rlist(dom.parse_clause([('Name', None, ['John', 'Jane'])])) == [ ('name', 'in', ['John', 'Jane']), ] assert rlist(dom.parse_clause([('Name', '!', ['John', 'Jane'])])) == [ ('name', 'not in', ['John', 'Jane']), ] assert rlist(dom.parse_clause([('Selection', None, None)])) == [ ('selection', '=', None), ] assert rlist(dom.parse_clause([('Selection', None, '')])) == [ ('selection', '=', ''), ] assert rlist(dom.parse_clause([('Selection', None, ['Male', 'Female'])])) \ == [ ('selection', 'in', ['male', 'female']) ] assert rlist(dom.parse_clause([('Integer', None, None)])) == [ ('integer', '=', None), ] assert rlist(dom.parse_clause([('Integer', None, '3..5')])) == [[ ('integer', '>=', 3), ('integer', '<=', 5), ]] assert rlist(dom.parse_clause([('Reference', None, 'foo')])) == [ ('reference', 'ilike', '%foo%'), ] assert rlist(dom.parse_clause([('Reference', None, 'Spam')])) == [ ('reference', 'ilike', '%spam%'), ] assert rlist(dom.parse_clause([('Reference', None, 'Spam,bar')])) == [ ('reference.rec_name', 'ilike', '%bar%', 'spam'), ] assert rlist(dom.parse_clause([('Reference', None, ['foo', 'bar'])])) == [ ('reference', 'in', ['foo', 'bar']), ] assert rlist(dom.parse_clause(['OR', ('Name', None, 'John'), ('Name', None, 'Jane')])) == ['OR', ('name', 'ilike', '%John%'), ('name', 'ilike', '%Jane%'), ] assert rlist(dom.parse_clause([('Many2One', None, 'John')])) == [ ('many2one', 'ilike', '%John%'), ] assert rlist(dom.parse_clause([('Many2One', None, ['John', 'Jane'])])) == [ ('many2one.rec_name', 'in', ['John', 'Jane']), ] assert rlist(dom.parse_clause(iter([iter([['John']])]))) == [ [('rec_name', 'ilike', '%John%')]] def test_completion(): dom = DomainParser({ 'name': { 'string': 'Name', 'name': 'name', 'type': 'char', }, }) assert list(dom.completion('Nam')) == ['Name: '] assert list(dom.completion('Name:')) == ['Name: '] assert list(dom.completion('Name: foo')) == [] assert list(dom.completion('Name: !=')) == [] assert list(dom.completion('Name: !=foo')) == [] assert list(dom.completion('')) == ['Name: '] assert list(dom.completion(' ')) == ['', 'Name: '] if __name__ == '__main__': for name in list(globals()): if name.startswith('test_'): func = globals()[name] func() tryton-5.0.17/tryton/common/domain_inversion.py0000644000175000017500000007075113563615121021234 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import re import operator import datetime from collections import defaultdict from functools import reduce, partial def sql_like(value, pattern, ignore_case=True): flag = re.IGNORECASE if ignore_case else 0 escape = False chars = [] for char in re.split(r'(\\|.)', pattern)[1::2]: if escape: if char in ('%', '_'): chars.append(char) else: chars.extend(['\\', char]) escape = False elif char == '\\': escape = True elif char == '_': chars.append('.') elif char == '%': chars.append('.*') else: chars.append(re.escape(char)) regexp = re.compile(''.join(chars), flag) return bool(regexp.fullmatch(value)) like = partial(sql_like, ignore_case=False) ilike = partial(sql_like, ignore_case=True) def in_(a, b): if isinstance(a, (list, tuple)): if isinstance(b, (list, tuple)): return any(operator.contains(b, x) for x in a) else: return operator.contains(a, b) else: return operator.contains(b, a) OPERATORS = defaultdict(lambda: lambda a, b: True) OPERATORS.update({ '=': operator.eq, '>': operator.gt, '<': operator.lt, '<=': operator.le, '>=': operator.ge, '!=': operator.ne, 'in': in_, 'not in': lambda a, b: not in_(a, b), 'ilike': ilike, 'not ilike': lambda a, b: not ilike(a, b), 'like': like, 'not like': lambda a, b: not like(a, b), }) def locale_part(expression, field_name, locale_name='id'): if expression == field_name: return locale_name if '.' in expression: fieldname, local = expression.split('.', 1) return local return expression def is_leaf(expression): return (isinstance(expression, (list, tuple)) and len(expression) > 2 and isinstance(expression[1], str)) def constrained_leaf(part, boolop=operator.and_): field, operand, value = part[:3] if operand == '=' and boolop == operator.and_: # We should consider that other domain inversion will set a correct # value to this field return True return False def eval_leaf(part, context, boolop=operator.and_): field, operand, value = part[:3] if '.' in field: # In the case where the leaf concerns a m2o then having a value in the # evaluation context is deemed suffisant return bool(context.get(field.split('.')[0])) context_field = context.get(field) if isinstance(context_field, datetime.date) and not value: if isinstance(context_field, datetime.datetime): value = datetime.datetime.min else: value = datetime.date.min if isinstance(value, datetime.date) and not context_field: if isinstance(value, datetime.datetime): context_field = datetime.datetime.min else: context_field = datetime.date.min if isinstance(context_field, (list, tuple)) and value is None: value = type(context_field)() if (isinstance(context_field, str) and isinstance(value, (list, tuple))): try: value = '%s,%s' % tuple(value) except TypeError: pass elif (isinstance(context_field, (list, tuple)) and isinstance(value, str)): try: context_field = '%s,%s' % tuple(context_field) except TypeError: pass elif ((isinstance(context_field, list) and isinstance(value, tuple)) or (isinstance(context_field, tuple) and isinstance(value, list))): context_field = list(context_field) value = list(value) if (operand in ('=', '!=') and isinstance(context_field, (list, tuple)) and isinstance(value, int)): operand = { '=': 'in', '!=': 'not in', }[operand] try: return OPERATORS[operand](context_field, value) except TypeError: return False def inverse_leaf(domain): if domain in ('AND', 'OR'): return domain elif is_leaf(domain): if 'child_of' in domain[1] and '.' not in domain[0]: if len(domain) == 3: return domain else: return [domain[3]] + list(domain[1:]) return domain else: return list(map(inverse_leaf, domain)) def filter_leaf(domain, field, model): if domain in ('AND', 'OR'): return domain elif is_leaf(domain): if domain[0].startswith(field) and len(domain) > 3: if domain[3] != model: return ('id', '=', None) return domain else: return [filter_leaf(d, field, model) for d in domain] def prepare_reference_domain(domain, reference): "convert domain to replace reference fields by their local part" if domain in ('AND', 'OR'): return domain elif is_leaf(domain): # When a Reference field is using the dotted notation the model # specified must be removed from the clause if domain[0].count('.') and len(domain) > 3: local_name, target_name = domain[0].split('.', 1) if local_name == reference: return [target_name] + list(domain[1:3] + domain[4:]) return domain else: return [prepare_reference_domain(d, reference) for d in domain] def extract_reference_models(domain, field_name): "returns the set of the models available for field_name" if domain in ('AND', 'OR'): return set() elif is_leaf(domain): local_part = domain[0].split('.', 1)[0] if local_part == field_name and len(domain) > 3: return {domain[3]} return set() else: return reduce(operator.or_, (extract_reference_models(d, field_name) for d in domain)) def eval_domain(domain, context, boolop=operator.and_): "compute domain boolean value according to the context" if is_leaf(domain): return eval_leaf(domain, context, boolop=boolop) elif not domain and boolop is operator.and_: return True elif not domain and boolop is operator.or_: return False elif domain[0] == 'AND': return eval_domain(domain[1:], context) elif domain[0] == 'OR': return eval_domain(domain[1:], context, operator.or_) else: return boolop(eval_domain(domain[0], context), eval_domain(domain[1:], context, boolop)) def localize_domain(domain, field_name=None, strip_target=False): "returns only locale part of domain. eg: langage.code -> code" if domain in ('AND', 'OR', True, False): return domain elif is_leaf(domain): if 'child_of' in domain[1]: if domain[0].count('.'): _, target_part = domain[0].split('.', 1) return [target_part] + list(domain[1:]) if len(domain) == 3: return domain else: return [domain[3]] + list(domain[1:-1]) locale_name = 'id' if isinstance(domain[2], str): locale_name = 'rec_name' n = 3 if strip_target else 4 return [locale_part(domain[0], field_name, locale_name)] \ + list(domain[1:n]) + list(domain[4:]) else: return [localize_domain(part, field_name, strip_target) for part in domain] def simplify(domain): "remove unused domain delimiter" if is_leaf(domain): return domain elif domain in ('OR', 'AND'): return domain elif domain in (['OR'], ['AND']): return [] elif (isinstance(domain, list) and len(domain) == 1 and not is_leaf(domain[0])): return simplify(domain[0]) elif (isinstance(domain, list) and len(domain) == 2 and domain[0] in ('AND', 'OR')): return [simplify(domain[1])] else: return [simplify(branch) for branch in domain] def merge(domain, domoperator=None): if not domain or domain in ('AND', 'OR'): return [] domain_type = 'OR' if domain[0] == 'OR' else 'AND' if is_leaf(domain): return [domain] elif domoperator is None: return [domain_type] + reduce(operator.add, [merge(e, domain_type) for e in domain]) elif domain_type == domoperator: return reduce(operator.add, [merge(e, domain_type) for e in domain]) else: # without setting the domoperator return [merge(domain)] def concat(*domains, **kwargs): domoperator = kwargs.get('domoperator') result = [] if domoperator: result.append(domoperator) for domain in domains: if domain: result.append(domain) return simplify(merge(result)) def unique_value(domain): "Return if unique, the field and the value" if (isinstance(domain, list) and len(domain) == 1 and '.' not in domain[0][0] and domain[0][1] == '='): return True, domain[0][1], domain[0][2] else: return False, None, None def parse(domain): if is_leaf(domain): return domain elif not domain: return And([]) elif domain[0] == 'OR': return Or(domain[1:]) else: return And(domain[1:] if domain[0] == 'AND' else domain) def domain_inversion(domain, symbol, context=None): """compute an inversion of the domain eventually the context is used to simplify the expression""" if context is None: context = {} expression = parse(domain) if symbol not in expression.variables: return True return expression.inverse(symbol, context) class And(object): def __init__(self, expressions): self.branches = list(map(parse, expressions)) self.variables = set() for expression in self.branches: if is_leaf(expression): self.variables.add(self.base(expression[0])) elif isinstance(expression, And): self.variables |= expression.variables def base(self, expression): if '.' not in expression: return expression else: return expression.split('.')[0] def inverse(self, symbol, context): result = [] for part in self.branches: if isinstance(part, And): part_inversion = part.inverse(symbol, context) evaluated = isinstance(part_inversion, bool) if not evaluated: result.append(part_inversion) elif part_inversion: continue else: return False elif is_leaf(part) and self.base(part[0]) == symbol: result.append(part) else: field = part[0] if (field not in context or field in context and (eval_leaf(part, context, operator.and_) or constrained_leaf(part, operator.and_))): result.append(True) else: return False result = [e for e in result if e is not True] if result == []: return True else: return simplify(result) class Or(And): def inverse(self, symbol, context): result = [] known_variables = set(context.keys()) if (symbol not in self.variables and not known_variables >= self.variables): # In this case we don't know anything about this OR part, we # consider it to be True (because people will have the constraint # on this part later). return True for part in self.branches: if isinstance(part, And): part_inversion = part.inverse(symbol, context) evaluated = isinstance(part_inversion, bool) if symbol not in part.variables: if evaluated and part_inversion: return True continue if not evaluated: result.append(part_inversion) elif part_inversion: return True else: continue elif is_leaf(part) and self.base(part[0]) == symbol: result.append(part) else: field = part[0] field = self.base(field) if (field in context and (eval_leaf(part, context, operator.or_) or constrained_leaf(part, operator.or_))): return True elif (field in context and not eval_leaf(part, context, operator.or_)): result.append(False) result = [e for e in result if e is not False] if result == []: return False else: return simplify(['OR'] + result) # Test stuffs def test_simple_inversion(): domain = [['x', '=', 3]] assert domain_inversion(domain, 'x') == [['x', '=', 3]] domain = [] assert domain_inversion(domain, 'x') is True assert domain_inversion(domain, 'y') is True assert domain_inversion(domain, 'x', {'x': 5}) is True assert domain_inversion(domain, 'z', {'x': 7}) is True domain = [['x.id', '>', 5]] assert domain_inversion(domain, 'x') == [['x.id', '>', 5]] def test_and_inversion(): domain = [['x', '=', 3], ['y', '>', 5]] assert domain_inversion(domain, 'x') == [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 4}) is False assert domain_inversion(domain, 'x', {'y': 6}) == [['x', '=', 3]] domain = [['x', '=', 3], ['y', '=', 5]] assert domain_inversion(domain, 'z') is True assert domain_inversion(domain, 'z', {'x': 2, 'y': 7}) is True assert domain_inversion(domain, 'x', {'y': None}) == [['x', '=', 3]] domain = [['x.id', '>', 5], ['y', '<', 3]] assert domain_inversion(domain, 'y') == [['y', '<', 3]] assert domain_inversion(domain, 'y', {'x': 3}) == [['y', '<', 3]] assert domain_inversion(domain, 'x') == [['x.id', '>', 5]] def test_or_inversion(): domain = ['OR', ['x', '=', 3], ['y', '>', 5], ['z', '=', 'abc']] assert domain_inversion(domain, 'x') == [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 4}) == [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 4, 'z': 'ab'}) ==\ [['x', '=', 3]] assert domain_inversion(domain, 'x', {'y': 7}) is True assert domain_inversion(domain, 'x', {'y': 7, 'z': 'b'}) is True assert domain_inversion(domain, 'x', {'z': 'abc'}) is True assert domain_inversion(domain, 'x', {'y': 4, 'z': 'abc'}) is True domain = ['OR', ['x', '=', 3], ['y', '=', 5]] assert domain_inversion(domain, 'x', {'y': None}) == [['x', '=', 3]] domain = ['OR', ['x', '=', 3], ['y', '>', 5]] assert domain_inversion(domain, 'z') is True domain = ['OR', ['x.id', '>', 5], ['y', '<', 3]] assert domain_inversion(domain, 'y') == [['y', '<', 3]] assert domain_inversion(domain, 'y', {'z': 4}) == [['y', '<', 3]] assert domain_inversion(domain, 'y', {'x': 3}) is True domain = ['OR', ['length', '>', 5], ['language.code', '=', 'de_DE']] assert domain_inversion(domain, 'length', {'length': 0, 'name': 'n'}) ==\ [['length', '>', 5]] def test_orand_inversion(): domain = ['OR', [['x', '=', 3], ['y', '>', 5], ['z', '=', 'abc']], [['x', '=', 4]], [['y', '>', 6]]] assert domain_inversion(domain, 'x') is True assert domain_inversion(domain, 'x', {'y': 4}) == [[['x', '=', 4]]] assert domain_inversion(domain, 'x', {'z': 'abc', 'y': 7}) is True assert domain_inversion(domain, 'x', {'y': 7}) is True assert domain_inversion(domain, 'x', {'z': 'ab'}) is True def test_andor_inversion(): domain = [['OR', ['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]] assert domain_inversion(domain, 'z') == [['z', '=', 3]] assert domain_inversion(domain, 'z', {'x': 5}) == [['z', '=', 3]] assert domain_inversion(domain, 'z', {'x': 5, 'y': 5}) is False assert domain_inversion(domain, 'z', {'x': 5, 'y': 7}) == [['z', '=', 3]] def test_andand_inversion(): domain = [[['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]] assert domain_inversion(domain, 'z') == [['z', '=', 3]] assert domain_inversion(domain, 'z', {'x': 5}) == [['z', '=', 3]] assert domain_inversion(domain, 'z', {'y': 5}) is False assert domain_inversion(domain, 'z', {'x': 4, 'y': 7}) == [['z', '=', 3]] domain = [[['x', '=', 4], ['y', '>', 6], ['z', '=', 2]], [['w', '=', 2]]] assert domain_inversion(domain, 'z', {'x': 4}) == [['z', '=', 2]] def test_oror_inversion(): domain = ['OR', ['OR', ['x', '=', 3], ['y', '>', 5]], ['OR', ['x', '=', 2], ['z', '=', 'abc']], ['OR', ['y', '=', 8], ['z', '=', 'y']]] assert domain_inversion(domain, 'x') is True assert domain_inversion(domain, 'x', {'y': 4}) is True assert domain_inversion(domain, 'x', {'z': 'ab'}) is True assert domain_inversion(domain, 'x', {'y': 7}) is True assert domain_inversion(domain, 'x', {'z': 'abc'}) is True assert domain_inversion(domain, 'x', {'z': 'y'}) is True assert domain_inversion(domain, 'x', {'y': 8}) is True assert domain_inversion(domain, 'x', {'y': 8, 'z': 'b'}) is True assert domain_inversion(domain, 'x', {'y': 4, 'z': 'y'}) is True assert domain_inversion(domain, 'x', {'y': 7, 'z': 'abc'}) is True assert domain_inversion(domain, 'x', {'y': 4, 'z': 'b'}) == \ ['OR', [['x', '=', 3]], [['x', '=', 2]]] def test_parse(): domain = parse([['x', '=', 5]]) assert domain.variables == set('x') domain = parse(['OR', ['x', '=', 4], ['y', '>', 6]]) assert domain.variables == set('xy') domain = parse([['OR', ['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]]) assert domain.variables == set('xyz') domain = parse([[['x', '=', 4], ['y', '>', 6]], ['z', '=', 3]]) assert domain.variables == set('xyz') def test_simplify(): domain = [['x', '=', 3]] assert simplify(domain) == [['x', '=', 3]] domain = [[['x', '=', 3]]] assert simplify(domain) == [['x', '=', 3]] domain = ['OR', ['x', '=', 3]] assert simplify(domain) == [['x', '=', 3]] domain = ['OR', [['x', '=', 3]], [['y', '=', 5]]] assert simplify(domain) == ['OR', [['x', '=', 3]], [['y', '=', 5]]] domain = ['OR', ['x', '=', 3], ['AND', ['y', '=', 5]]] assert simplify(domain) == ['OR', ['x', '=', 3], [['y', '=', 5]]] domain = ['AND'] assert simplify(domain) == [] domain = ['OR'] assert simplify(domain) == [] def test_merge(): domain = [['x', '=', 6], ['y', '=', 7]] assert merge(domain) == ['AND', ['x', '=', 6], ['y', '=', 7]] domain = ['AND', ['x', '=', 6], ['y', '=', 7]] assert merge(domain) == ['AND', ['x', '=', 6], ['y', '=', 7]] domain = [['z', '=', 8], ['AND', ['x', '=', 6], ['y', '=', 7]]] assert merge(domain) == ['AND', ['z', '=', 8], ['x', '=', 6], ['y', '=', 7]] domain = ['OR', ['x', '=', 1], ['y', '=', 2], ['z', '=', 3]] assert merge(domain) == ['OR', ['x', '=', 1], ['y', '=', 2], ['z', '=', 3]] domain = ['OR', ['x', '=', 1], ['OR', ['y', '=', 2], ['z', '=', 3]]] assert merge(domain) == ['OR', ['x', '=', 1], ['y', '=', 2], ['z', '=', 3]] domain = ['OR', ['x', '=', 1], ['AND', ['y', '=', 2], ['z', '=', 3]]] assert merge(domain) == ['OR', ['x', '=', 1], ['AND', ['y', '=', 2], ['z', '=', 3]]] domain = [['z', '=', 8], ['OR', ['x', '=', 6], ['y', '=', 7]]] assert merge(domain) == ['AND', ['z', '=', 8], ['OR', ['x', '=', 6], ['y', '=', 7]]] domain = ['AND', ['OR', ['a', '=', 1], ['b', '=', 2]], ['OR', ['c', '=', 3], ['AND', ['d', '=', 4], ['d2', '=', 6]]], ['AND', ['d', '=', 5], ['e', '=', 6]], ['f', '=', 7]] assert merge(domain) == ['AND', ['OR', ['a', '=', 1], ['b', '=', 2]], ['OR', ['c', '=', 3], ['AND', ['d', '=', 4], ['d2', '=', 6]]], ['d', '=', 5], ['e', '=', 6], ['f', '=', 7]] def test_concat(): domain1 = [['a', '=', 1]] domain2 = [['b', '=', 2]] assert concat(domain1, domain2) == ['AND', ['a', '=', 1], ['b', '=', 2]] assert concat([], domain1) == domain1 assert concat(domain2, []) == domain2 assert concat([], []) == [] assert concat(domain1, domain2, domoperator='OR') == [ 'OR', [['a', '=', 1]], [['b', '=', 2]]] def test_unique_value(): domain = [['a', '=', 1]] assert unique_value(domain) == (True, '=', 1) domain = [['a', '!=', 1]] assert unique_value(domain)[0] is False domain = [['a', '=', 1], ['a', '=', 2]] assert unique_value(domain)[0] is False domain = [['a.b', '=', 1]] assert unique_value(domain)[0] is False def test_evaldomain(): domain = [['x', '>', 5]] assert eval_domain(domain, {'x': 6}) assert not eval_domain(domain, {'x': 4}) domain = [['x', '>', None]] assert eval_domain(domain, {'x': datetime.date.today()}) assert eval_domain(domain, {'x': datetime.datetime.now()}) domain = [['x', '<', datetime.date.today()]] assert eval_domain(domain, {'x': None}) domain = [['x', '<', datetime.datetime.now()]] assert eval_domain(domain, {'x': None}) domain = [['x', 'in', [3, 5]]] assert eval_domain(domain, {'x': 3}) assert not eval_domain(domain, {'x': 4}) assert eval_domain(domain, {'x': [3]}) assert eval_domain(domain, {'x': [3, 4]}) assert not eval_domain(domain, {'x': [1, 2]}) domain = [['x', 'not in', [3, 5]]] assert not eval_domain(domain, {'x': 3}) assert eval_domain(domain, {'x': 4}) assert not eval_domain(domain, {'x': [3]}) assert not eval_domain(domain, {'x': [3, 4]}) assert eval_domain(domain, {'x': [1, 2]}) domain = [['x', 'like', 'abc']] assert eval_domain(domain, {'x': 'abc'}) assert not eval_domain(domain, {'x': ''}) assert not eval_domain(domain, {'x': 'xyz'}) assert not eval_domain(domain, {'x': 'abcd'}) domain = [['x', 'not like', 'abc']] assert eval_domain(domain, {'x': 'xyz'}) assert eval_domain(domain, {'x': 'ABC'}) assert not eval_domain(domain, {'x': 'abc'}) domain = [['x', 'not ilike', 'abc']] assert eval_domain(domain, {'x': 'xyz'}) assert not eval_domain(domain, {'x': 'ABC'}) assert not eval_domain(domain, {'x': 'abc'}) domain = [['x', 'like', 'a%']] assert eval_domain(domain, {'x': 'a'}) assert eval_domain(domain, {'x': 'abcde'}) assert not eval_domain(domain, {'x': ''}) assert not eval_domain(domain, {'x': 'ABCDE'}) assert not eval_domain(domain, {'x': 'xyz'}) domain = [['x', 'ilike', 'a%']] assert eval_domain(domain, {'x': 'a'}) assert eval_domain(domain, {'x': 'A'}) assert not eval_domain(domain, {'x': ''}) assert not eval_domain(domain, {'x': 'xyz'}) domain = [['x', 'like', 'a_']] assert eval_domain(domain, {'x': 'ab'}) assert not eval_domain(domain, {'x': 'a'}) assert not eval_domain(domain, {'x': 'abc'}) domain = [['x', 'like', 'a\\%b']] assert eval_domain(domain, {'x': 'a%b'}) assert not eval_domain(domain, {'x': 'ab'}) assert not eval_domain(domain, {'x': 'a123b'}) domain = [['x', 'like', '\\%b']] assert eval_domain(domain, {'x': '%b'}) assert not eval_domain(domain, {'x': 'b'}) assert not eval_domain(domain, {'x': '123b'}) domain = [['x', 'like', 'a\\_c']] assert eval_domain(domain, {'x': 'a_c'}) assert not eval_domain(domain, {'x': 'abc'}) assert not eval_domain(domain, {'x': 'ac'}) domain = [['x', 'like', 'a\\\\_c']] assert eval_domain(domain, {'x': 'a\\bc'}) assert not eval_domain(domain, {'x': 'abc'}) domain = ['OR', ['x', '>', 10], ['x', '<', 0]] assert eval_domain(domain, {'x': 11}) assert eval_domain(domain, {'x': -4}) assert not eval_domain(domain, {'x': 5}) domain = ['OR', ['x', '>', 0], ['x', '=', None]] assert eval_domain(domain, {'x': 1}) assert eval_domain(domain, {'x': None}) assert not eval_domain(domain, {'x': -1}) assert not eval_domain(domain, {'x': 0}) domain = [['x', '>', 0], ['OR', ['x', '=', 3], ['x', '=', 2]]] assert not eval_domain(domain, {'x': 1}) assert eval_domain(domain, {'x': 3}) assert eval_domain(domain, {'x': 2}) assert not eval_domain(domain, {'x': 4}) assert not eval_domain(domain, {'x': 5}) assert not eval_domain(domain, {'x': 6}) domain = ['OR', ['x', '=', 4], [['x', '>', 6], ['x', '<', 10]]] assert eval_domain(domain, {'x': 4}) assert eval_domain(domain, {'x': 7}) assert not eval_domain(domain, {'x': 3}) assert not eval_domain(domain, {'x': 5}) assert not eval_domain(domain, {'x': 11}) domain = [['x', '=', 'test,1']] assert eval_domain(domain, {'x': ('test', 1)}) assert eval_domain(domain, {'x': 'test,1'}) assert not eval_domain(domain, {'x': ('test', 2)}) assert not eval_domain(domain, {'x': 'test,2'}) domain = [['x', '=', ('test', 1)]] assert eval_domain(domain, {'x': ('test', 1)}) assert eval_domain(domain, {'x': 'test,1'}) assert not eval_domain(domain, {'x': ('test', 2)}) assert not eval_domain(domain, {'x': 'test,2'}) domain = [['x', '=', 1]] assert eval_domain(domain, {'x': [1, 2]}) assert not eval_domain(domain, {'x': [2]}) domain = [['x', '=', None]] assert eval_domain(domain, {'x': []}) domain = [['x', '=', ['foo', 1]]] assert eval_domain(domain, {'x': 'foo,1'}) assert eval_domain(domain, {'x': ('foo', 1)}) assert eval_domain(domain, {'x': ['foo', 1]}) domain = [['x', '=', ('foo', 1)]] assert eval_domain(domain, {'x': 'foo,1'}) assert eval_domain(domain, {'x': ('foo', 1)}) assert eval_domain(domain, {'x': ['foo', 1]}) domain = [['x', '=', 'foo,1']] assert eval_domain(domain, {'x': ['foo', 1]}) assert eval_domain(domain, {'x': ('foo', 1)}) def test_localize(): domain = [['x', '=', 5]] assert localize_domain(domain) == [['x', '=', 5]] domain = [['x', '=', 5], ['x.code', '=', 7]] assert localize_domain(domain, 'x') == [['id', '=', 5], ['code', '=', 7]] domain = [['x', 'ilike', 'foo%'], ['x.code', '=', 'test']] assert localize_domain(domain, 'x') == \ [['rec_name', 'ilike', 'foo%'], ['code', '=', 'test']] domain = ['OR', ['AND', ['x', '>', 7], ['x', '<', 15]], ['x.code', '=', 8]] assert localize_domain(domain, 'x') == \ ['OR', ['AND', ['id', '>', 7], ['id', '<', 15]], ['code', '=', 8]] domain = [['x', 'child_of', [1]]] assert localize_domain(domain, 'x') == [['x', 'child_of', [1]]] domain = [['x', 'child_of', [1], 'y']] assert localize_domain(domain, 'x') == [['y', 'child_of', [1]]] domain = [['x.y', 'child_of', [1], 'parent']] assert localize_domain(domain, 'x') == [['y', 'child_of', [1], 'parent']] domain = [['x.y.z', 'child_of', [1], 'parent', 'model']] assert localize_domain(domain, 'x') == \ [['y.z', 'child_of', [1], 'parent', 'model']] domain = [['x.id', '=', 1, 'y']] assert localize_domain(domain, 'x', False) == [['id', '=', 1, 'y']] assert localize_domain(domain, 'x', True) == [['id', '=', 1]] domain = [['a.b.c', '=', 1, 'y', 'z']] assert localize_domain(domain, 'x', False) == [['b.c', '=', 1, 'y', 'z']] assert localize_domain(domain, 'x', True) == [['b.c', '=', 1, 'z']] def test_prepare_reference_domain(): domain = [['x', 'like', 'A%']] assert prepare_reference_domain(domain, 'x') == [['x', 'like', 'A%']] domain = [['x.y', 'like', 'A%', 'model']] assert prepare_reference_domain(domain, 'x') == [['y', 'like', 'A%']] domain = [['x.y', 'child_of', [1], 'model', 'parent']] assert prepare_reference_domain(domain, 'x') == \ [['y', 'child_of', [1], 'parent']] def test_extract_models(): domain = [['x', 'like', 'A%']] assert extract_reference_models(domain, 'x') == set() assert extract_reference_models(domain, 'y') == set() domain = [['x', 'like', 'A%', 'model']] assert extract_reference_models(domain, 'x') == {'model'} assert extract_reference_models(domain, 'y') == set() domain = ['OR', ['x.y', 'like', 'A%', 'model_A'], ['x.z', 'like', 'B%', 'model_B']] assert extract_reference_models(domain, 'x') == {'model_A', 'model_B'} assert extract_reference_models(domain, 'y') == set() if __name__ == '__main__': test_simple_inversion() test_and_inversion() test_or_inversion() test_orand_inversion() test_andor_inversion() test_andand_inversion() test_oror_inversion() test_parse() test_simplify() test_evaldomain() test_localize() test_prepare_reference_domain() test_extract_models() tryton-5.0.17/tryton/common/cellrendererbutton.py0000644000175000017500000000724613463252531021573 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import pango class CellRendererButton(gtk.GenericCellRenderer): # TODO Add keyboard editing __gproperties__ = { "text": (gobject.TYPE_STRING, None, "Text", "Displayed text", gobject.ParamFlags.READWRITE), 'visible': (gobject.TYPE_INT, 'Visible', 'Visible', 0, 10, 0, gobject.ParamFlags.READWRITE), 'sensitive': (gobject.TYPE_INT, 'Sensitive', 'Sensitive', 0, 10, 0, gobject.ParamFlags.READWRITE), } __gsignals__ = { 'clicked': (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING, )), } def __init__(self, text=""): self.__gobject_init__() self.text = text self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE) self.clicking = False self.visible = True self.sensitive = True def do_set_property(self, pspec, value): setattr(self, pspec.name, value) def do_get_property(self, pspec): return getattr(self, pspec.name) def do_render(self, cr, widget, background_area, cell_area, flags): if not self.visible: return state = gtk.StateFlags.NORMAL if self.clicking and flags & gtk.CELL_RENDERER_SELECTED: state = gtk.StateFlags.ACTIVE elif not self.sensitive: state = gtk.StateFlags.INSENSITIVE context = widget.get_style_context() context.save() context.add_class('button') context.set_state(state) xpad, ypad = self.get_padding() x = cell_area.x + xpad y = cell_area.y + ypad w = cell_area.width - 2 * xpad h = cell_area.height - 2 * ypad gtk.render_background(context, cr, x, y, w, h) gtk.render_frame(context, cr, x, y, w, h) padding = context.get_padding(state) layout = widget.create_pango_layout(self.text) layout.set_width((w - padding.left - padding.right) * pango.SCALE) layout.set_ellipsize(pango.ELLIPSIZE_END) layout.set_wrap(pango.WRAP_CHAR) lw, lh = layout.get_size() # Can not use get_pixel_extents lw /= pango.SCALE lh /= pango.SCALE if w < lw: x = x + padding.left else: x = x + padding.left + 0.5 * ( w - padding.left - padding.right - lw) y = y + padding.top + 0.5 * (h - padding.top - padding.bottom - lh) gtk.render_layout(context, cr, x, y, layout) context.restore() def on_get_size(self, widget, cell_area=None): if cell_area is None: return (0, 0, 30, 18) else: return (cell_area.x, cell_area.y, cell_area.width, cell_area.height) do_get_size = on_get_size def on_start_editing(self, event, widget, path, background_area, cell_area, flags): if not self.visible or not self.sensitive: return if (event is None) or ((event.type == gtk.gdk.BUTTON_PRESS) or (event.type == gtk.gdk.KEY_PRESS and event.keyval == gtk.keysyms.space)): self.clicking = True widget.queue_draw() while gtk.events_pending(): gtk.main_iteration() self.emit("clicked", path) def timeout(self, widget): self.clicking = False widget.queue_draw() gobject.timeout_add(60, timeout, self, widget) do_start_editing = on_start_editing gobject.type_register(CellRendererButton) tryton-5.0.17/tryton/common/cellrendererbinary.py0000644000175000017500000001515313463252531021540 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import pango from .common import IconFactory BUTTON_BORDER = 2 BUTTON_SPACING = 1 class CellRendererBinary(gtk.GenericCellRenderer): __gproperties__ = { 'visible': (gobject.TYPE_BOOLEAN, 'Visible', 'Visible', True, gobject.ParamFlags.READWRITE), 'editable': (gobject.TYPE_BOOLEAN, 'Editable', 'Editable', False, gobject.ParamFlags.READWRITE), 'size': (gobject.TYPE_STRING, 'Size', 'Size', '', gobject.ParamFlags.READWRITE), } __gsignals__ = { 'select': (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), 'open': (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), 'save': (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), 'clear': (gobject.SignalFlags.RUN_LAST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)), } def __init__(self, use_filename): self.__gobject_init__() self.visible = True self.editable = False self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) self.use_filename = use_filename self.images = {} for key, icon in ( ('select', 'tryton-search'), ('open', 'tryton-open'), ('save', 'tryton-save'), ('clear', 'tryton-clear')): # hack to get gtk.gdk.Image from stock icon img_sensitive = IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_SMALL_TOOLBAR) img_insensitive = img_sensitive.copy() img_sensitive.saturate_and_pixelate(img_insensitive, 0, False) width = img_sensitive.get_width() height = img_sensitive.get_height() self.images[key] = (img_sensitive, img_insensitive, width, height) @property def buttons(self): buttons = [] if self.size: if self.use_filename: buttons.append('open') buttons.append('save') buttons.append('clear') else: buttons.append('select') return buttons def do_set_property(self, pspec, value): setattr(self, pspec.name, value) def do_get_property(self, pspec): return getattr(self, pspec.name) def button_width(self): return (sum(width for n, (_, _, width, _) in self.images.items() if n in self.buttons) + (2 * (BUTTON_BORDER + BUTTON_SPACING) * len(self.buttons)) - 2 * BUTTON_SPACING) def on_get_size(self, widget, cell_area=None): if cell_area is None: return (0, 0, 30, 18) else: return (cell_area.x, cell_area.y, cell_area.width, cell_area.height) do_get_size = on_get_size def on_activate(self, event, widget, path, background_area, cell_area, flags): if event is None: return True button_width = self.button_width() for index, button_name in enumerate(self.buttons): _, _, pxbf_width, _ = self.images[button_name] if index == 0 and button_name == 'open': x_offset = 0 else: x_offset = (cell_area.width - button_width + (pxbf_width + (2 * BUTTON_BORDER) + BUTTON_SPACING) * index) x_button = cell_area.x + x_offset if x_button < event.x < (x_button + pxbf_width + (2 * BUTTON_BORDER)): break else: button_name = None if not self.visible or not button_name: return True if not self.editable and button_name in ('select', 'clear'): return True if not self.size and button_name in {'open', 'save'}: return True if event.type == gtk.gdk.BUTTON_PRESS: self.emit(button_name, path) return True do_activate = on_activate def do_render(self, cr, widget, background_area, cell_area, flags): if not self.visible: return button_width = self.button_width() state = self.get_state(widget, flags) context = widget.get_style_context() context.save() context.add_class('button') xpad, ypad = self.get_padding() x = cell_area.x + xpad y = cell_area.y + ypad w = cell_area.width - 2 * xpad h = cell_area.height - 2 * ypad padding = context.get_padding(state) layout = widget.create_pango_layout(self.size) lwidth = w - button_width - padding.left - padding.right if lwidth < 0: lwidth = 0 layout.set_width(lwidth * pango.SCALE) layout.set_ellipsize(pango.ELLIPSIZE_END) layout.set_wrap(pango.WRAP_CHAR) layout.set_alignment(pango.ALIGN_RIGHT) if lwidth > 0: lw, lh = layout.get_size() # Can not use get_pixel_extents lw /= pango.SCALE lh /= pango.SCALE lx = x + padding.left if self.buttons and self.buttons[0] == 'open': pxbf_width = self.images['open'][2] lx += pxbf_width + 2 * BUTTON_BORDER + BUTTON_SPACING ly = y + padding.top + 0.5 * ( h - padding.top - padding.bottom - lh) gtk.render_layout(context, cr, lx, ly, layout) for index, button_name in enumerate(self.buttons): pxbf_sens, pxbf_insens, pxbf_width, pxbf_height = \ self.images[button_name] if (not self.editable and button_name in {'select', 'clear'} or not self.size and button_name in {'open', 'save'}): pixbuf = pxbf_insens else: pixbuf = pxbf_sens if index == 0 and button_name == 'open': x_offset = 0 else: x_offset = (w - button_width + (pxbf_width + (2 * BUTTON_BORDER) + BUTTON_SPACING) * index) if x_offset < 0: continue bx = cell_area.x + x_offset by = cell_area.y bw = pxbf_width + (2 * BUTTON_BORDER) gtk.render_background(context, cr, bx, by, bw, h) gtk.render_frame(context, cr, bx, by, bw, h) gtk.gdk.cairo_set_source_pixbuf( cr, pixbuf, bx + BUTTON_BORDER, by + (h - pxbf_height) / 2) cr.paint() context.restore() gobject.type_register(CellRendererBinary) tryton-5.0.17/tryton/common/common.py0000644000175000017500000012166013524765775017177 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import glib import pango import gettext import os import subprocess import tempfile import re import logging import unicodedata import colorsys import xml.etree.ElementTree as ET from collections import defaultdict from decimal import Decimal try: from http import HTTPStatus except ImportError: from http import client as HTTPStatus from functools import partial from tryton.config import CONFIG from tryton.config import TRYTON_ICON, PIXMAPS_DIR import sys import xmlrpc.client from functools import reduce try: import hashlib except ImportError: hashlib = None import md5 import webbrowser import traceback import tryton.rpc as rpc import socket import _thread import urllib.request import urllib.parse import urllib.error from string import Template import shlex try: import ssl except ImportError: ssl = None from threading import Lock from gi.repository import Gtk from tryton import __version__ from tryton.exceptions import TrytonServerError, TrytonError from tryton.pyson import PYSONEncoder from .underline import set_underline from .widget_style import widget_class _ = gettext.gettext logger = logging.getLogger(__name__) class IconFactory: batchnum = 10 _tryton_icons = [] _name2id = {} _icons = {} _local_icons = {} _pixbufs = defaultdict(dict) @classmethod def load_local_icons(cls): for fname in os.listdir(PIXMAPS_DIR): name = os.path.splitext(fname)[0] path = os.path.join(PIXMAPS_DIR, fname) cls._local_icons[name] = path @classmethod def load_icons(cls, refresh=False): if not refresh: cls._name2id.clear() cls._icons.clear() del cls._tryton_icons[:] try: icons = rpc.execute('model', 'ir.ui.icon', 'list_icons', rpc.CONTEXT) except TrytonServerError: icons = [] for icon_id, icon_name in icons: if refresh and icon_name in cls._icons: continue cls._tryton_icons.append((icon_id, icon_name)) cls._name2id[icon_name] = icon_id @classmethod def register_icon(cls, iconname): # iconname might be '' when page do not define icon if (not iconname or iconname in cls._icons or iconname in cls._local_icons): return if iconname not in cls._name2id: cls.load_icons(refresh=True) try: icon_ref = (cls._name2id[iconname], iconname) except KeyError: return idx = cls._tryton_icons.index(icon_ref) to_load = slice(max(0, idx - cls.batchnum // 2), idx + cls.batchnum // 2) ids = [e[0] for e in cls._tryton_icons[to_load]] try: icons = rpc.execute('model', 'ir.ui.icon', 'read', ids, ['name', 'icon'], rpc.CONTEXT) except TrytonServerError: icons = [] for icon in icons: name = icon['name'] data = icon['icon'].encode('utf-8') cls._icons[name] = data cls._tryton_icons.remove((icon['id'], icon['name'])) del cls._name2id[icon['name']] @classmethod def get_pixbuf(cls, iconname, size=Gtk.IconSize.MENU, color=None): cls.register_icon(iconname) if iconname not in cls._pixbufs[size]: if iconname in cls._icons: data = cls._icons[iconname] elif iconname in cls._local_icons: path = cls._local_icons[iconname] with open(path, 'rb') as fp: data = fp.read() else: logger.error("Unknown icon %s" % iconname) return if color is None: color = CONFIG['icon.color'] try: ET.register_namespace('', 'http://www.w3.org/2000/svg') root = ET.fromstring(data) root.attrib['fill'] = color data = ET.tostring(root) except ET.ParseError: pass width = height = { Gtk.IconSize.MENU: 16, Gtk.IconSize.SMALL_TOOLBAR: 16, Gtk.IconSize.LARGE_TOOLBAR: 24, Gtk.IconSize.BUTTON: 16, Gtk.IconSize.DND: 12, Gtk.IconSize.DIALOG: 48, }.get(size) cls._pixbufs[size][iconname] = data2pixbuf(data, width, height) return cls._pixbufs[size][iconname] @classmethod def get_image(cls, iconname, size=Gtk.IconSize.BUTTON, color=None): pixbuf = cls.get_pixbuf(iconname, size, color) image = Gtk.Image() image.set_from_pixbuf(pixbuf) return image IconFactory.load_local_icons() class ModelAccess(object): batchnum = 100 _access = {} _models = [] def load_models(self, refresh=False): if not refresh: self._access.clear() del self._models[:] try: self._models = rpc.execute('model', 'ir.model', 'list_models', rpc.CONTEXT) except TrytonServerError: pass def __getitem__(self, model): if model in self._access: return self._access[model] if model not in self._models: self.load_models(refresh=True) idx = self._models.index(model) to_load = slice(max(0, idx - self.batchnum // 2), idx + self.batchnum // 2) try: access = rpc.execute('model', 'ir.model.access', 'get_access', self._models[to_load], rpc.CONTEXT) except TrytonServerError: access = {} self._access.update(access) return self._access[model] MODELACCESS = ModelAccess() class ModelHistory(object): _models = set() def load_history(self): self._models.clear() try: self._models.update(rpc.execute('model', 'ir.model', 'list_history', rpc.CONTEXT)) except TrytonServerError: pass def __contains__(self, model): return model in self._models MODELHISTORY = ModelHistory() class ViewSearch(object): searches = {} def __init__(self): class Encoder(PYSONEncoder): def default(self, obj): if isinstance(obj, Decimal): return float(obj) return super(Encoder, self).default(obj) self.encoder = Encoder() def load_searches(self): try: self.searches = rpc.execute('model', 'ir.ui.view_search', 'get_search', rpc.CONTEXT) except TrytonServerError: self.searches = {} def __getitem__(self, model): return self.searches.get(model, []) def add(self, model, name, domain): try: id_, = RPCExecute('model', 'ir.ui.view_search', 'create', [{ 'model': model, 'name': name, 'domain': self.encoder.encode(domain), }]) except RPCException: return self.searches.setdefault(model, []).append((id_, name, domain)) def remove(self, model, id_): try: RPCExecute('model', 'ir.ui.view_search', 'delete', [id_]) except RPCException: return for i, domain in enumerate(self.searches[model]): if domain[0] == id_: del self.searches[model][i] break VIEW_SEARCH = ViewSearch() def find_in_path(name): if os.name == "nt": sep = ';' else: sep = ':' path = [directory for directory in os.environ['PATH'].split(sep) if os.path.isdir(directory)] for directory in path: val = os.path.join(directory, name) if os.path.isfile(val) or os.path.islink(val): return val return name def get_toplevel_window(): from tryton.gui.main import Main return Main().get_active_window() def get_sensible_widget(window): from tryton.gui.main import Main main = Main() if main and window == main.window: focus_widget = window.get_focus() page = main.get_page() if page and focus_widget and focus_widget.is_ancestor(page.widget): return page.widget return window def selection(title, values, alwaysask=False): if not values or len(values) == 0: return None elif len(values) == 1 and (not alwaysask): key = list(values.keys())[0] return (key, values[key]) parent = get_toplevel_window() dialog = gtk.Dialog(_('Selection'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) dialog.add_button(set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) dialog.add_button(set_underline(_("OK")), gtk.RESPONSE_OK) dialog.set_icon(TRYTON_ICON) dialog.set_default_response(gtk.RESPONSE_OK) dialog.set_default_size(400, 400) label = gtk.Label(title or _('Your selection:')) dialog.vbox.pack_start(label, False, False) dialog.vbox.pack_start(gtk.HSeparator(), False, True) scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) treeview = gtk.TreeView() treeview.set_headers_visible(False) scrolledwindow.add(treeview) dialog.vbox.pack_start(scrolledwindow, True, True) treeview.get_selection().set_mode(gtk.SELECTION_SINGLE) cell = gtk.CellRendererText() column = gtk.TreeViewColumn("Widget", cell, text=0) treeview.append_column(column) treeview.set_search_column(0) model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_INT) keys = list(values.keys()) keys.sort() i = 0 for val in keys: model.append([str(val), i]) i += 1 treeview.set_model(model) treeview.connect('row-activated', lambda x, y, z: dialog.response(gtk.RESPONSE_OK) or True) dialog.show_all() response = dialog.run() res = None if response == gtk.RESPONSE_OK: sel = treeview.get_selection().get_selected() if sel: (model, i) = sel if i: index = model.get_value(i, 1) value = keys[index] res = (value, values[value]) parent.present() dialog.destroy() return res def file_selection(title, filename='', action=gtk.FILE_CHOOSER_ACTION_OPEN, preview=True, multi=False, filters=None): parent = get_toplevel_window() if action == gtk.FILE_CHOOSER_ACTION_OPEN: buttons = (set_underline(_("Cancel")), gtk.RESPONSE_CANCEL, set_underline(_("Select")), gtk.RESPONSE_OK) else: buttons = (set_underline(_("Cancel")), gtk.RESPONSE_CANCEL, set_underline(_("Save")), gtk.RESPONSE_OK) win = gtk.FileChooserDialog(title, None, action, buttons) win.set_transient_for(parent) win.set_icon(TRYTON_ICON) if filename: if action in (gtk.FILE_CHOOSER_ACTION_SAVE, gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER): win.set_current_name(filename) else: win.set_filename(filename) if hasattr(win, 'set_do_overwrite_confirmation'): win.set_do_overwrite_confirmation(True) win.set_select_multiple(multi) win.set_default_response(gtk.RESPONSE_OK) if filters is not None: for filt in filters: win.add_filter(filt) def update_preview_cb(win, img): have_preview = False filename = win.get_preview_filename() if filename: try: pixbuf = gtk.gdk.pixbuf_new_from_file_at_size( filename, 128, 128) img.set_from_pixbuf(pixbuf) have_preview = True except (IOError, glib.GError): pass win.set_preview_widget_active(have_preview) return if preview: img_preview = gtk.Image() win.set_preview_widget(img_preview) win.connect('update-preview', update_preview_cb, img_preview) button = win.run() if button != gtk.RESPONSE_OK: result = None elif not multi: result = win.get_filename() else: result = win.get_filenames() parent.present() win.destroy() return result _slugify_strip_re = re.compile(r'[^\w\s-]') _slugify_hyphenate_re = re.compile(r'[-\s]+') def slugify(value): if not isinstance(value, str): value = str(value) value = unicodedata.normalize('NFKD', value) value = str(_slugify_strip_re.sub('', value).strip()) return _slugify_hyphenate_re.sub('-', value) def file_write(filename, data): if isinstance(data, str): data = data.encode('utf-8') dtemp = tempfile.mkdtemp(prefix='tryton_') if not isinstance(filename, str): name, ext = filename else: name, ext = os.path.splitext(filename) filename = ''.join([slugify(name), os.extsep, slugify(ext)]) filepath = os.path.join(dtemp, filename) with open(filepath, 'wb') as fp: fp.write(data) return filepath def file_open(filename, type=None, print_p=False): def save(): save_name = file_selection(_('Save As...'), action=gtk.FILE_CHOOSER_ACTION_SAVE) if save_name: file_p = open(filename, 'rb') save_p = open(save_name, 'wb+') save_p.write(file_p.read()) save_p.close() file_p.close() if os.name == 'nt': operation = 'open' if print_p: operation = 'print' try: os.startfile(os.path.normpath(filename), operation) except WindowsError: save() elif sys.platform == 'darwin': try: subprocess.Popen(['/usr/bin/open', filename]) except OSError: save() else: try: subprocess.Popen(['xdg-open', filename]) except OSError: save() def mailto(to=None, cc=None, subject=None, body=None, attachment=None): if CONFIG['client.email']: cmd = Template(CONFIG['client.email']).substitute( to=to or '', cc=cc or '', subject=subject or '', body=body or '', attachment=attachment or '', ) args = shlex.split(str(cmd)) subprocess.Popen(args) return if os.name != 'nt' and sys.platform != 'darwin': args = ['xdg-email', '--utf8'] if cc: args.extend(['--cc', cc]) if subject: args.extend(['--subject', subject]) if body: args.extend(['--body', body]) if attachment: args.extend(['--attach', attachment]) if to: args.append(to) try: subprocess.Popen(args) return except OSError: pass # http://www.faqs.org/rfcs/rfc2368.html url = "mailto:" if to: url += urllib.parse.quote(to.strip(), "@,") url += '?' if cc: url += "&cc=" + urllib.parse.quote(cc, "@,") if subject: url += "&subject=" + urllib.parse.quote(subject, "") if body: body = "\r\n".join(body.splitlines()) url += "&body=" + urllib.parse.quote(body, "") if attachment: url += "&attachment=" + urllib.parse.quote(attachment, "") webbrowser.open(url, new=1) class UniqueDialog(object): def __init__(self): self.running = False def build_dialog(self, *args): raise NotImplementedError def process_response(self, response): return response def __call__(self, *args, **kwargs): if self.running: return parent = kwargs.pop('parent', None) if not parent: parent = get_toplevel_window() dialog = self.build_dialog(parent, *args, **kwargs) dialog.set_icon(TRYTON_ICON) self.running = True dialog.show_all() response = dialog.run() response = self.process_response(response) if parent: parent.present() dialog.destroy() self.running = False return response class MessageDialog(UniqueDialog): def build_dialog(self, parent, message, msg_type=gtk.MESSAGE_INFO, buttons=gtk.BUTTONS_OK, secondary=None): dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, msg_type, buttons, message) if secondary: dialog.format_secondary_text(secondary) return dialog def __call__(self, message, *args, **kwargs): return super(MessageDialog, self).__call__(message, *args, **kwargs) message = MessageDialog() class WarningDialog(MessageDialog): def __call__(self, message, title, buttons=gtk.BUTTONS_OK, **kwargs): return super().__call__( title, gtk.MESSAGE_WARNING, buttons, message, **kwargs) warning = WarningDialog() class UserWarningDialog(WarningDialog): def __init__(self): super(UserWarningDialog, self).__init__() self.always = False def _set_always(self, toggle): self.always = toggle.get_active() def build_dialog(self, *args, **kwargs): dialog = super().build_dialog(*args, **kwargs) check = gtk.CheckButton(_('Always ignore this warning.')) check.connect_after('toggled', self._set_always) alignment = gtk.Alignment(0, 0.5) alignment.add(check) dialog.vbox.pack_start(alignment, True, False) label = gtk.Label(_('Do you want to proceed?')) label.set_alignment(1, 0.5) dialog.vbox.pack_start(label, True, True) return dialog def process_response(self, response): if response == gtk.RESPONSE_YES: if self.always: return 'always' return 'ok' return 'cancel' def __call__(self, message, title): return super().__call__(message, title, gtk.BUTTONS_YES_NO) userwarning = UserWarningDialog() class ConfirmationDialog(MessageDialog): def __call__(self, message, *args, **kwargs): return super().__call__(message, gtk.MESSAGE_QUESTION, *args, **kwargs) class SurDialog(ConfirmationDialog): def __call__(self, message): response = super().__call__(message, buttons=gtk.BUTTONS_YES_NO) return response == gtk.RESPONSE_YES sur = SurDialog() class Sur3BDialog(ConfirmationDialog): response_mapping = { gtk.RESPONSE_YES: 'ok', gtk.RESPONSE_NO: 'ko', gtk.RESPONSE_CANCEL: 'cancel' } def build_dialog(self, *args, **kwargs): dialog = super().build_dialog(*args, **kwargs) dialog.add_button(set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) dialog.add_button(set_underline(_("No")), gtk.RESPONSE_NO) dialog.add_button(set_underline(_("Yes")), gtk.RESPONSE_YES) dialog.set_default_response(gtk.RESPONSE_YES) return dialog def __call__(self, message): response = super().__call__(message, buttons=gtk.BUTTONS_NONE) return self.response_mapping.get(response, 'cancel') sur_3b = Sur3BDialog() class AskDialog(MessageDialog): def build_dialog(self, *args, **kwargs): visibility = kwargs.pop('visibility') dialog = super().build_dialog(*args, **kwargs) dialog.set_default_response(gtk.RESPONSE_OK) box = dialog.get_message_area() self.entry = gtk.Entry() self.entry.set_activates_default(True) self.entry.set_visibility(visibility) box.pack_start(self.entry) return dialog def process_response(self, response): if response == gtk.RESPONSE_OK: return self.entry.get_text() def __call__(self, question, visibility=True): return super().__call__( question, gtk.MESSAGE_QUESTION, buttons=gtk.BUTTONS_OK_CANCEL, visibility=visibility) ask = AskDialog() class ConcurrencyDialog(UniqueDialog): def build_dialog(self, parent, resource, obj_id, context): tooltips = Tooltips() dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_QUESTION, gtk.BUTTONS_NONE, _('Concurrency Exception')) dialog.format_secondary_text( _('This record has been modified while you were editing it.')) cancel_button = dialog.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) tooltips.set_tip(cancel_button, _('Cancel saving')) compare_button = dialog.add_button( set_underline(_("Compare")), gtk.RESPONSE_APPLY) tooltips.set_tip(compare_button, _('See the modified version')) write_button = dialog.add_button( set_underline(_("Write Anyway")), gtk.RESPONSE_OK) tooltips.set_tip(write_button, _('Save your current version')) dialog.set_default_response(gtk.RESPONSE_CANCEL) return dialog def __call__(self, resource, obj_id, context): res = super(ConcurrencyDialog, self).__call__(resource, obj_id, context) if res == gtk.RESPONSE_OK: return True if res == gtk.RESPONSE_APPLY: from tryton.gui.window import Window Window.create(resource, res_id=obj_id, domain=[('id', '=', obj_id)], context=context, mode=['form', 'tree']) return False concurrency = ConcurrencyDialog() class ErrorDialog(UniqueDialog): def build_dialog(self, parent, title, details): dialog = gtk.MessageDialog(parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_ERROR, gtk.BUTTONS_NONE, _('Application Error')) dialog.set_default_size(600, 400) dialog.add_button(set_underline(_("Report Bug")), gtk.RESPONSE_OK) dialog.add_button(set_underline(_("Close")), gtk.RESPONSE_CANCEL) dialog.set_default_response(gtk.RESPONSE_CANCEL) vbox = dialog.vbox scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) box = gtk.VBox() label_error = gtk.Label() label_error.set_markup('') label_error.set_alignment(0, 0.5) label_error.set_padding(-1, 14) label_error.modify_font(pango.FontDescription("monospace")) label_error.set_markup('' + _('Error: ') + '' + to_xml(title)) box.pack_start(label_error, False, False) textview = gtk.TextView() buf = gtk.TextBuffer() buf.set_text(details) textview.set_buffer(buf) textview.set_editable(False) textview.set_sensitive(True) textview.modify_font(pango.FontDescription("monospace")) box.pack_start(textview, True, True) viewport.add(box) scrolledwindow.add(viewport) vbox.pack_start(scrolledwindow, expand=True, fill=True) button_roundup = Gtk.LinkButton.new_with_label( CONFIG['roundup.url'], _('To report bugs you must have an account on %s') % CONFIG['roundup.url']) button_roundup.set_alignment(0, 0.5) button_roundup.connect('activate-link', lambda widget: webbrowser.open(CONFIG['roundup.url'], new=2)) vbox.pack_start(button_roundup, False, False) return dialog def __call__(self, title, details): if title == details: title = '' log = logging.getLogger(__name__) log.error(details + '\n' + title) response = super(ErrorDialog, self).__call__(title, details) if response == gtk.RESPONSE_OK: send_bugtracker(title, details) error = ErrorDialog() def send_bugtracker(title, msg): parent = get_toplevel_window() win = gtk.Dialog(_('Bug Tracker'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) win.add_button(set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) win.add_button(set_underline(_("OK")), gtk.RESPONSE_OK) win.set_icon(TRYTON_ICON) win.set_default_response(gtk.RESPONSE_OK) hbox = gtk.HBox() hbox.pack_start( IconFactory.get_image( 'tryton-info', gtk.ICON_SIZE_DIALOG), False, False) table = gtk.Table(2, 2) table.set_col_spacings(3) table.set_row_spacings(3) table.set_border_width(1) label_user = gtk.Label(_('User:')) label_user.set_alignment(1.0, 0.5) table.attach(label_user, 0, 1, 0, 1, yoptions=False, xoptions=gtk.FILL) entry_user = gtk.Entry() entry_user.set_activates_default(True) table.attach(entry_user, 1, 2, 0, 1, yoptions=False, xoptions=gtk.FILL) label_password = gtk.Label(_('Password:')) label_password.set_alignment(1.0, 0.5) table.attach(label_password, 0, 1, 1, 2, yoptions=False, xoptions=gtk.FILL) entry_password = gtk.Entry() entry_password.set_activates_default(True) entry_password.set_visibility(False) table.attach(entry_password, 1, 2, 1, 2, yoptions=False, xoptions=gtk.FILL) hbox.pack_start(table) win.vbox.pack_start(hbox) win.show_all() entry_user.grab_focus() response = win.run() parent.present() user = entry_user.get_text() password = entry_password.get_text() win.destroy() if response == gtk.RESPONSE_OK: try: msg = msg.encode('ascii', 'replace') title = title.encode('ascii', 'replace') protocol = 'http' if ssl or hasattr(socket, 'ssl'): protocol = 'https' quote = partial(urllib.parse.quote, safe="!$&'()*+,;=:") server = xmlrpc.client.Server( ('%s://%s:%s@' + CONFIG['roundup.xmlrpc']) % (protocol, quote(user), quote(password)), allow_none=True) if hashlib: msg_md5 = hashlib.md5(msg + b'\n' + title).hexdigest() else: msg_md5 = md5.new(msg + b'\n' + title).hexdigest() if not title: title = '[no title]' issue_id = None msg_ids = server.filter('msg', None, {'summary': str(msg_md5)}) for msg_id in msg_ids: summary = server.display( 'msg%s' % msg_id, 'summary')['summary'] if summary == msg_md5: issue_ids = server.filter( 'issue', None, {'messages': msg_id}) if issue_ids: issue_id = issue_ids[0] break if issue_id: # issue to same message already exists, add user to nosy-list server.set('issue' + str(issue_id), *['nosy=+' + user]) message( _('The same bug was already reported by another user.\n' 'To keep you informed your username is added ' 'to the nosy-list of this issue') + '%s' % issue_id) else: # create a new issue for this error-message # first create message msg_id = server.create('msg', *['content=' + msg, 'author=' + user, 'summary=' + msg_md5]) # second create issue with this message issue_id = server.create('issue', *['messages=' + str(msg_id), 'nosy=' + user, 'title=' + title, 'priority=bug']) message(_('Created new bug with ID ') + 'issue%s' % issue_id) webbrowser.open(CONFIG['roundup.url'] + 'issue%s' % issue_id, new=2) except (socket.error, xmlrpc.client.Fault) as exception: if (isinstance(exception, xmlrpc.client.Fault) and 'roundup.cgi.exceptions.Unauthorised' in exception.faultString): message(_('Connection error.\nBad username or password.')) return send_bugtracker(title, msg) tb_s = reduce(lambda x, y: x + y, traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2])) message(_('Exception:') + '\n' + tb_s, msg_type=gtk.MESSAGE_ERROR) def check_version(box, version=__version__): def info_bar_response(info_bar, response, box, url): if response == Gtk.ResponseType.ACCEPT: webbrowser.open(url) box.remove(info_bar) class HeadRequest(urllib.request.Request): def get_method(self): return 'HEAD' version = version.split('.') series = '.'.join(version[:2]) version[2] = str(int(version[2]) + 1) version = '.'.join(version) filename = 'tryton-%s.tar.gz' % version if hasattr(sys, 'frozen'): if sys.platform == 'win32': filename = 'tryton-setup-%s.exe' % version elif sys.platform == 'darwin': filename = 'tryton-%s.dmg' % version url = list(urllib.parse.urlparse(CONFIG['download.url'])) url[2] = '/%s/%s' % (series, filename) url = urllib.parse.urlunparse(url) logger.info(_("Check URL: %s"), url) try: urllib.request.urlopen( HeadRequest(url), timeout=5, cafile=rpc._CA_CERTS) except (urllib.error.HTTPError, socket.timeout): return True except Exception: logger.error( _("Unable to check for new version"), exc_info=True) return True else: if check_version(box, version): info_bar = Gtk.InfoBar() info_bar.get_content_area().pack_start( gtk.Label(_("A new version is available!"))) info_bar.set_show_close_button(True) info_bar.add_button(_("Download"), Gtk.ResponseType.ACCEPT) info_bar.connect('response', info_bar_response, box, url) box.pack_start(info_bar) info_bar.show_all() return False def to_xml(string): return string.replace('&', '&' ).replace('<', '<').replace('>', '>') PLOCK = Lock() def process_exception(exception, *args, **kwargs): rpc_execute = kwargs.get('rpc_execute', rpc.execute) if isinstance(exception, TrytonServerError): if exception.faultCode == 'UserWarning': name, msg, description = exception.args res = userwarning(description, msg) if res in ('always', 'ok'): RPCExecute('model', 'res.user.warning', 'create', [{ 'user': rpc._USER, 'name': name, 'always': (res == 'always'), }], process_exception=False) return rpc_execute(*args) elif exception.faultCode == 'UserError': msg, description = exception.args warning(description, msg) elif exception.faultCode == 'ConcurrencyException': if len(args) >= 6: if concurrency(args[1], args[3][0], args[5]): if '_timestamp' in args[5]: del args[5]['_timestamp'] return rpc_execute(*args) else: message(_('Concurrency Exception'), msg_type=gtk.MESSAGE_ERROR) elif exception.faultCode == str(int(HTTPStatus.UNAUTHORIZED)): from tryton.gui.main import Main if PLOCK.acquire(False): try: Login() except TrytonError as exception: if exception.faultCode == 'QueryCanceled': Main().sig_quit() raise finally: PLOCK.release() if args: return rpc_execute(*args) else: error(exception.faultCode, exception.faultString) else: error(str(exception), traceback.format_exc()) raise RPCException(exception) class Login(object): def __init__(self, func=rpc.login): parameters = {} while True: try: func(parameters) except TrytonServerError as exception: if exception.faultCode == str(int(HTTPStatus.UNAUTHORIZED)): parameters.clear() continue if exception.faultCode != 'LoginException': raise name, message, type = exception.args value = getattr(self, 'get_%s' % type)(message) if value is None: raise TrytonError('QueryCanceled') parameters[name] = value continue else: return @classmethod def get_char(cls, message): return ask(message) @classmethod def get_password(cls, message): return ask(message, visibility=False) class Logout: def __init__(self): try: rpc.logout() except TrytonServerError: pass def node_attributes(node): result = {} attrs = node.attributes if attrs is None: return {} for i in range(attrs.length): result[str(attrs.item(i).localName)] = str(attrs.item(i).nodeValue) return result def hex2rgb(hexstring, digits=2): """ Converts a hexstring color to a rgb tuple. Example: #ff0000 -> (1.0, 0.0, 0.0) digits is an integer number telling how many characters should be interpreted for each component in the hexstring. """ if isinstance(hexstring, (tuple, list)): return hexstring top = float(int(digits * 'f', 16)) r = int(hexstring[1:digits + 1], 16) g = int(hexstring[digits + 1:digits * 2 + 1], 16) b = int(hexstring[digits * 2 + 1:digits * 3 + 1], 16) return r / top, g / top, b / top def highlight_rgb(r, g, b, amount=0.1): h, s, v = colorsys.rgb_to_hsv(r, g, b) return colorsys.hsv_to_rgb(h, s, (v + amount) % 1) def generateColorscheme(masterColor, keys, light=0.1): """ Generates a dictionary where the keys match the keys argument and the values are colors derivated from the masterColor. Each color has a value higher then the previous of `light`. Each color has a hue separated from the previous by the golden angle. The masterColor is given in a hex string format. """ r, g, b = hex2rgb(COLOR_SCHEMES.get(masterColor, masterColor)) h, s, v = colorsys.rgb_to_hsv(r, g, b) if keys: light = min(light, (1. - v) / len(keys)) golden_angle = 0.618033988749895 return {key: colorsys.hsv_to_rgb((h + golden_angle * i) % 1, s, (v + light * i) % 1) for i, key in enumerate(keys)} class RPCException(Exception): def __init__(self, exception): super(RPCException, self).__init__(exception) self.exception = exception class RPCProgress(object): def __init__(self, method, args): self.method = method self.args = args self.parent = None self.res = None self.error = False self.exception = None def start(self): try: self.res = getattr(rpc, self.method)(*self.args) except Exception as exception: self.error = True self.res = False self.exception = exception else: if not self.res: self.error = True if self.callback: # Post to GTK queue to be run by the main thread gobject.idle_add(self.process) return True def run(self, process_exception_p=True, callback=None): self.process_exception_p = process_exception_p self.callback = callback if callback: # Parent is only useful if it is asynchronous # otherwise the cursor is not updated. self.parent = get_toplevel_window() if self.parent.get_window(): watch = gtk.gdk.Cursor(gtk.gdk.WATCH) self.parent.get_window().set_cursor(watch) _thread.start_new_thread(self.start, ()) return else: self.start() return self.process() def process(self): if self.parent and self.parent.get_window(): self.parent.get_window().set_cursor(None) if self.exception and self.process_exception_p: def rpc_execute(*args): return RPCProgress('execute', args).run( self.process_exception_p, self.callback) try: return process_exception( self.exception, *self.args, rpc_execute=rpc_execute) except RPCException as exception: self.exception = exception def return_(): if self.exception: raise self.exception else: return self.res if self.callback: self.callback(return_) else: return return_() def RPCExecute(*args, **kwargs): rpc_context = rpc.CONTEXT.copy() if kwargs.get('context'): rpc_context.update(kwargs['context']) args = args + (rpc_context,) process_exception = kwargs.get('process_exception', True) callback = kwargs.get('callback') return RPCProgress('execute', args).run(process_exception, callback) def RPCContextReload(callback=None): def update(context): rpc.context_reset() try: rpc.CONTEXT.update(context()) except RPCException: pass if callback: callback() # Use RPCProgress to not send rpc.CONTEXT RPCProgress('execute', ('model', 'res.user', 'get_preferences', True, {}) ).run(True, update) class Tooltips(object): _tooltips = None def set_tip(self, widget, tip_text): if hasattr(widget, 'set_tooltip_text'): return widget.set_tooltip_text(tip_text) if not self._tooltips: self._tooltips = gtk.Tooltips() return self._tooltips.set_tip(widget, tip_text) def enable(self): if self._tooltips: self._tooltips.enable() def disable(self): if self._tooltips: self._tooltips.disable() COLOR_SCHEMES = { 'red': '#cf1d1d', 'green': '#3fb41b', 'blue': '#224565', 'grey': '#444444', 'black': '#000000', 'darkcyan': '#305755', } def filter_domain(domain): ''' Return the biggest subset of domain with only AND operator ''' res = [] for arg in domain: if isinstance(arg, str): if arg == 'OR': res = [] break continue if isinstance(arg, tuple): res.append(arg) elif isinstance(arg, list): res.extend(filter_domain(arg)) return res def timezoned_date(date, reverse=False): try: from dateutil.tz.win import tzwinlocal as tzlocal except ImportError: from dateutil.tz import tzlocal from dateutil.tz import tzutc lzone = tzlocal() szone = tzutc() if reverse: lzone, szone = szone, lzone return date.replace(tzinfo=szone).astimezone(lzone).replace(tzinfo=None) def untimezoned_date(date): return timezoned_date(date, reverse=True) def humanize(size): for x in ('bytes', 'KB', 'MB', 'GB', 'TB', 'PB'): if size < 1000: return '%3.1f%s' % (size, x) size /= 1000.0 def get_hostname(netloc): if '[' in netloc and ']' in netloc: hostname = netloc.split(']')[0][1:] elif ':' in netloc: hostname = netloc.split(':')[0] else: hostname = netloc return hostname.strip() def get_port(netloc): netloc = netloc.split(']')[-1] if ':' in netloc: try: return int(netloc.split(':')[1]) except ValueError: pass return 8000 def resize_pixbuf(pixbuf, width, height): img_height = pixbuf.get_height() height = min(img_height, height) if height != -1 else img_height img_width = pixbuf.get_width() width = min(img_width, width) if width != -1 else img_width if img_width / width < img_height / height: width = float(img_width) / float(img_height) * float(height) else: height = float(img_height) / float(img_width) * float(width) return pixbuf.scale_simple(int(width), int(height), gtk.gdk.INTERP_BILINEAR) def _data2pixbuf(data, width=None, height=None): loader = gtk.gdk.PixbufLoader() if width and height: loader.set_size(width, height) loader.write(data) loader.close() return loader.get_pixbuf() def data2pixbuf(data, width=None, height=None): if data: try: return _data2pixbuf(data, width, height) except glib.GError: pass def apply_label_attributes(label, readonly, required): if not readonly: widget_class(label, 'editable', True) widget_class(label, 'required', required) else: widget_class(label, 'editable', False) widget_class(label, 'required', False) def ellipsize(string, length): if len(string) <= length: return string ellipsis = _('...') return string[:length - len(ellipsis)] + ellipsis def date_format(format_): return format_ or rpc.CONTEXT.get('locale', {}).get('date', '%x') tryton-5.0.17/tryton/common/datetime_strftime.py0000644000175000017500000000312513463252531021372 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # Copyright (c) 2002-2007 John D. Hunter; All Rights Reserved import datetime import time def datetime_strftime(dt, fmt): ''' Allow datetime strftime formatting for years before 1900. See http://bugs.python.org/issue1777412 ''' if not isinstance(dt, datetime.date): raise TypeError('datetime_strftime requires a ''datetime.date'' object' 'but received a ''%s''' % type(dt)) if dt.year > 1900: return dt.strftime(fmt) def _findall(text, substr): # Also finds overlaps sites = [] i = 0 while True: j = text.find(substr, i) if j == -1: break sites.append(j) i = j + 1 return sites year = dt.year # For every non-leap year century, advance by # 6 years to get into the 28-year repeat cycle delta = 2000 - year off = 6 * (delta // 100 + delta // 400) year = year + off # Move to around the year 2000 year = year + ((2000 - year) // 28) * 28 timetuple = dt.timetuple() s1 = time.strftime(fmt, (year,) + timetuple[1:]) sites1 = _findall(s1, str(year)) s2 = time.strftime(fmt, (year + 28,) + timetuple[1:]) sites2 = _findall(s2, str(year + 28)) sites = [] for site in sites1: if site in sites2: sites.append(site) s = s1 syear = "%04d" % (dt.year,) for site in sites: s = s[:site] + syear + s[site + 4:] return s tryton-5.0.17/tryton/common/button.py0000644000175000017500000000411113463252531017170 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext from gi.repository import Gtk from tryton.common import IconFactory _ = gettext.gettext class Button(Gtk.Button): def __init__(self, attrs=None): self.attrs = attrs or {} self.label = '_' + attrs.get('string', '').replace('_', '__') super(Button, self).__init__(label=self.label, stock=None, use_underline=True) self._set_icon(attrs.get('icon')) def _set_icon(self, stock): self.set_always_show_image(bool(stock)) image = self.get_image() if not image and not stock: return elif image and image.get_stock()[0] == stock: return if not stock: self.set_image(None) return self.set_image(IconFactory.get_image(stock, Gtk.IconSize.BUTTON)) def state_set(self, record): if record: states = record.expr_eval(self.attrs.get('states', {})) else: states = {} if states.get('invisible', False): self.hide() else: self.show() self.set_sensitive(not states.get('readonly', False)) self._set_icon(states.get('icon', self.attrs.get('icon'))) if self.attrs.get('rule'): label = self.label tip = self.attrs.get('help', '') if record: clicks = record.get_button_clicks(self.attrs['name']) if clicks: label += ' (%s)' % len(clicks) if tip: tip += '\n' tip += _('By: ') + _(', ').join(iter(clicks.values())) self.set_label(label) self.set_tooltip_text(tip) if self.attrs.get('type', 'class') == 'class': parent = record.parent if record else None while parent: if parent.modified: self.set_sensitive(False) break parent = parent.parent tryton-5.0.17/tryton/exceptions.py0000644000175000017500000000054213463252532016553 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .jsonrpc import Fault TrytonServerError = Fault class TrytonServerUnavailable(Exception): pass class TrytonError(Exception): def __init__(self, faultCode): self.faultCode = faultCode tryton-5.0.17/tryton/config.py0000644000175000017500000001417013463252532015641 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import configparser import optparse import os import gettext import logging import sys import locale import gtk from tryton import __version__ _ = gettext.gettext def get_config_dir(): if os.name == 'nt': appdata = os.environ['APPDATA'] if not isinstance(appdata, str): appdata = str(appdata, sys.getfilesystemencoding()) return os.path.join(appdata, '.config', 'tryton', __version__.rsplit('.', 1)[0]) return os.path.join(os.environ['HOME'], '.config', 'tryton', __version__.rsplit('.', 1)[0]) if not os.path.isdir(get_config_dir()): os.makedirs(get_config_dir(), 0o700) class ConfigManager(object): "Config manager" def __init__(self): short_version = '.'.join(__version__.split('.', 2)[:2]) demo_server = 'demo%s.tryton.org' % short_version demo_database = 'demo%s' % short_version self.defaults = { 'login.profile': demo_server, 'login.login': 'demo', 'login.host': demo_server, 'login.db': demo_database, 'login.expanded': False, 'client.title': 'Tryton', 'client.modepda': False, 'client.toolbar': 'default', 'client.save_width_height': True, 'client.save_tree_state': True, 'client.fast_tabbing': True, 'client.spellcheck': False, 'client.lang': locale.getdefaultlocale()[0], 'client.language_direction': 'ltr', 'client.email': '', 'client.limit': 1000, 'client.check_version': True, 'client.bus_timeout': 10 * 60, 'icon.color': '#3465a4', 'image.max_size': 10 ** 6, 'roundup.url': 'http://bugs.tryton.org/', 'roundup.xmlrpc': 'roundup-xmlrpc.tryton.org', 'download.url': 'https://downloads.tryton.org/', 'download.frequency': 60 * 60 * 8, 'menu.pane': 200, } self.config = {} self.options = {} self.arguments = [] def parse(self): parser = optparse.OptionParser(version=("Tryton %s" % __version__), usage="Usage: %prog [options] [url]") parser.add_option("-c", "--config", dest="config", help=_("specify alternate config file")) parser.add_option("-d", "--dev", action="store_true", default=False, dest="dev", help=_("development mode")) parser.add_option("-v", "--verbose", action="store_true", default=False, dest="verbose", help=_("logging everything at INFO level")) parser.add_option("-l", "--log-level", dest="log_level", help=_("specify the log level: " "DEBUG, INFO, WARNING, ERROR, CRITICAL")) parser.add_option("-u", "--user", dest="login", help=_("specify the login user")) parser.add_option("-s", "--server", dest="host", help=_("specify the server hostname:port")) opt, self.arguments = parser.parse_args() self.rcfile = opt.config or os.path.join( get_config_dir(), 'tryton.conf') self.load() self.options['dev'] = opt.dev logging.basicConfig() loglevels = { 'DEBUG': logging.DEBUG, 'INFO': logging.INFO, 'WARNING': logging.WARNING, 'ERROR': logging.ERROR, 'CRITICAL': logging.CRITICAL, } if not opt.log_level: if opt.verbose: opt.log_level = 'INFO' else: opt.log_level = 'ERROR' logging.getLogger().setLevel(loglevels[opt.log_level.upper()]) for arg in ['login', 'host']: if getattr(opt, arg): self.options['login.' + arg] = getattr(opt, arg) def save(self): try: parser = configparser.ConfigParser() for entry in list(self.config.keys()): if not len(entry.split('.')) == 2: continue section, name = entry.split('.') if not parser.has_section(section): parser.add_section(section) parser.set(section, name, str(self.config[entry])) with open(self.rcfile, 'w') as fp: parser.write(fp) except IOError: logging.getLogger(__name__).warn( _('Unable to write config file %s.') % (self.rcfile,)) return False return True def load(self): parser = configparser.ConfigParser() parser.read([self.rcfile]) for section in parser.sections(): for (name, value) in parser.items(section): if value.lower() == 'true': value = True elif value.lower() == 'false': value = False if section == 'client' and name == 'limit': # First convert to float to be backward compatible with old # configuration value = int(float(value)) self.config[section + '.' + name] = value return True def __setitem__(self, key, value, config=True): self.options[key] = value if config: self.config[key] = value def __getitem__(self, key): return self.options.get(key, self.config.get(key, self.defaults.get(key))) CONFIG = ConfigManager() CURRENT_DIR = os.path.dirname(__file__) if hasattr(sys, 'frozen'): CURRENT_DIR = os.path.dirname(sys.executable) if not isinstance(CURRENT_DIR, str): CURRENT_DIR = str(CURRENT_DIR, sys.getfilesystemencoding()) PIXMAPS_DIR = os.path.join(CURRENT_DIR, 'data', 'pixmaps', 'tryton') if not os.path.isdir(PIXMAPS_DIR): # do not import when frozen import pkg_resources PIXMAPS_DIR = pkg_resources.resource_filename( 'tryton', 'data/pixmaps/tryton') TRYTON_ICON = gtk.gdk.pixbuf_new_from_file( os.path.join(PIXMAPS_DIR, 'tryton-icon.png')) tryton-5.0.17/tryton/data/0000755000175000017500000000000013571264253014733 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/0000755000175000017500000000000013571264253016172 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/lo/0000755000175000017500000000000013571264253016604 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/lo/LC_MESSAGES/0000755000175000017500000000000013571264253020371 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/lo/LC_MESSAGES/tryton.po0000644000175000017500000013055213463252532022273 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "ລະບຸ config file ທີ່ສະຫຼັບກັນ" #: tryton/config.py:77 msgid "development mode" msgstr "ຮູບແບບການພັດທະນາ" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "ເຂົ້າໃຊ້ທຸກຢ່າງໃນລະດັບຂໍ້ມູນ" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" "ລະບຸ ລະດັບ ການບັນທຶກ: ແກ້ໄຂຂໍ້ຜິດພາດ, ຂໍ້ມູນ, ຄຳເຕືອນ, ຂໍ້ຜິດພາດ, ທີ່ສຳຄັນ" #: tryton/config.py:85 msgid "specify the login user" msgstr "ລະບຸ ຜູ້ເຂົ້າໃຊ້ງານ" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "ລະບຸ ທີ່ຢູ່ ຂອງ ເຄື່ອງແມ່ຂ່າຍ" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "ບໍ່ສາມາດ ຂຽນ ຟາຍລ໌ ຕັ້ງຄ່າ (config file) %s ນີ້ໄດ້." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "ບໍ່ສາມາດຕັ້ງຄ່າ ທ້ອງຖິ່ນ %s ໄດ້." #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr "," #: tryton/action/main.py:91 msgid ",…" msgstr ",..." #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "ເລືອກການດຳເນີນການຂອງທ່ານ" #: tryton/action/main.py:193 msgid "No action defined." msgstr "ບໍ່ມີ ການດຳເນີນການ ທີ່ລະບຸໄວ້!" #: tryton/common/button.py:54 msgid "By: " msgstr "ໂດຍ:" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "ການເລືອກ" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_ຍົກເລີກ" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "ການເລືອກຂອງທ່ານ:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "ເລືອກ..." #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "ບັນທຶກ" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "ບັນທຶກເປັນ..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "ບໍ່ສົນກັບຄຳເຕືອນນີ້ເລີຍ." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "ທ່ານຕ້ອງການດຳເນີນການຕໍ່ໄປບໍ່?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "ແມ່ນ" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "ຍົກເວັ້ນການເຂົ້າເຖິງພ້ອມກັນ" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "ສົມທຽບ" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "ຂຽນລົງເລີຍ" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "ໂປຣແກຣມ ມີຂໍ້ຜິດພາດ!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "ລາຍງານຂໍ້ຜິດພາດ" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "ຂໍ້ຜິດພາດ:" #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "ທ່ານຕ້ອງມີບັນຊີໃຊ້ຈຶ່ງຈະສາມາດລາຍງານຂໍ້ຜິດພາດ %s ນີ້ໄດ້" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "ໂຕຕິດຕາມ ຂໍ້ຜິດພາດ" #: tryton/common/common.py:811 msgid "User:" msgstr "ຜູ້ໃຊ້:" #: tryton/common/common.py:819 msgid "Password:" msgstr "ລະຫັດຜ່ານ:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "ຂໍ້ຜິດພາດອັນດຽວກັນນີ້ ຖືກລາຍງານ ໂດຍຜູ້ໃຊ້ງານຄົນອື່ນແລ້ວ.\n" "ເພື່ອໃຫ້ທ່ານໄດ້ຮັບຂໍ້ມູນການແກ້ໄຂ ຊື່ເຂົ້າໃຊ້ງານຂອງທ່ານ ໄດ້ຖືກເພີ່ມ ເຂົ້າໃນ ບັນຊີລາຍຊື່ຂອງບັນຫານີ້້" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "ສ້າງ ລາຍການຂໍ້ຜິດພາດ ໃໝ່ ດ້ວຍ ເລກກຳກັບ " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "ການເຊື່ອມຕໍ່ ຜິດພາດ!\n" "ຊື່ຜູໃຊ້ ຫຼື ລະຫັດຜ່ານ ບໍ່ຖືກຕ້ອງ!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "ຂໍ້ຍົກເວັ້ນ:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "ຊອກຫາ..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "ສ້າງ..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "ຄ່າ" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "ຄ່າສະແດງອອກ" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "ຮູບແບບ" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "ຮູບແບບສະແດງອອກ" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "ໄຂປະຕິທິນ" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "ຮູບແບບວັນທີ" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "ຮູບແບບວັນທີທີ່ສະແດງອອກ" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "ມ" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "ຈິງ" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "ຈ" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "ຜິດ" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "ແກ້ໄຂ..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "ຄັດຕິດ..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "ໝາຍເຫດ..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "ດຳເນີນການ..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "ທີ່ກ່ຽວພັນ..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "ລາຍງານ..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "ອີ-ເມວລ໌..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "ພິມອອກ..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "ປ" #: tryton/common/timedelta.py:27 msgid "M" msgstr "ດ" #: tryton/common/timedelta.py:28 msgid "w" msgstr "ອ" #: tryton/common/timedelta.py:29 msgid "d" msgstr "ມ" #: tryton/common/timedelta.py:30 msgid "h" msgstr "ມ." #: tryton/common/timedelta.py:31 msgid "m" msgstr "ນ" #: tryton/common/timedelta.py:32 msgid "s" msgstr "ວ" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_ການຕັ້ງຄ່າຂອງ..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_ແຖບເຄື່ອງມື" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_ຄ່າເດີມ" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_ຂໍ້ຄວາມ ແລະ ປຸ່ມລັດ" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_ຂໍ້ຄວາມ" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_ປຸ່ມລັດ" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_ແບບຟອມ" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "ບັນທຶກ ຄວາມກວ້າງ/ຄວາມສູງ" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "ບັນທຶກ ສະຖານະ ໂຄງສ້າງ" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "ຍ້າຍແບບໄວ" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "ກວດສອບການສະກົດຄຳ" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "ຈຳກັດການຊອກຫາ..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_ອີເມວລ໌..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_ທາງເລືອກ" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_ປຸ່ມລັດທາງແປ້ນພິມ..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_ກ່ຽວກັບ..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_ຊ່ອຍເຫຼືອ" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "ບໍ່ພົບຜົນຊອກຫາ" #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "ທີ່_ມັກຫຼາຍ" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "ການດຳເນີນການ" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "ການດຳເນີນການດັ່ງຕໍ່ໄປນີ້ ຕ້ອງການໃຫ້ ອັດແຖບງານທັງໝົດລົງ\n" "ທ່ານຕ້ອງການສືບຕໍ່ບໍ່?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "ອັດແຖບງານ" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "ເອກະສານຄັດຕິດ (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "ຂໍ້ມູນລາຍລະອຽດບັນນາທິການ" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "ຂໍ້ມູນລາຍລະອຽດ" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "ແມ່ຂ່າຍ:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "ຖານຂໍ້ມູນ:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "ລາຍການດຶງເອົາຖານຂໍ້ມູນ" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "ຜູ້ໃຊ້:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "ບໍ່ຖືກລຸ່ນກັບແມ່ຂ່າຍ" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "ບໍ່ສາມາດເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍໄດ້" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "ເຂົ້າສູ່ລະບົບ" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_ຍົກເລີກ" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "ຍົກເລີກການເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍ ໄຕຣຕັອນ" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "ເ_ຊື່ອມຕໍ່" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "ເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍ ໄຕຣຕັອນ" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "ຂໍ້ມູນລາຍລະອຽດ:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "ແມ່ຂ່າຍ / ຂໍ້ມູນກ່ຽວກັບຖານຂໍ້ມູນ" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "ຊື່ຜູ້ໃຊ້:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "ອີເມວລ໌" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "ການຕັ້ງຄ່າໂປຣແກຣມອີເມວລ໌" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "ຄຳສັ່ງງານ:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "ເລື່ອງຂອງ ທີ່ຢູ່ ທີ່ມີປັດຈຸບັນ:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "ເຖິງ:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "ຫົວເລື່ອງ:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "ເນື້ອຄວາມ:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "ເອກະສານຄັດຕິດ:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "ຄັດຕິດ(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "ບັນທຶກ (%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "ທ່ານຕ້ອງໄດ້ເລືອກ ໜຶ່ງແຖວຂໍ້ມູນ." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ເລກລໍາດັບ:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "ຜູ້ສ້າງ:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "ວັນທີສ້າງ:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "ປັບປ່ຽນລ້າສຸດ ໂດຍ:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "ວັນທີປັບປ່ຽນລ້າສຸດ:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "ແບບ:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "ທ່ານແນ່ໃຈບໍ່ທີ່ຈະລຶບແຖວຂໍ້ມູນນີ້?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "ທ່ານແນ່ໃຈບໍ່ທີ່ຈະລຶບແຖວຂໍ້ມູນເຫຼົ່ານີ້?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "ແຖວຂໍ້ມູນບໍ່ທັນຖືກເອົາອອກ." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "ແຖວຂໍ້ມູນຖືກເອົາອອກແລ້ວ." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "ດຽວນີ້ກຳລັງເຮັດວຽກກັບແຖວຂໍ້ມູນທີ່ສ້າງຂຶ້ນຊ້ອນກັນ." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "ແຖວຂໍ້ມູນບັນທຶກແລ້ວ" #: tryton/gui/window/form.py:485 msgid " of " msgstr "ຂອງ" #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "ແຖວຂໍ້ມູນນີ້ ຖືກແກ້ໄຂແລ້ວ ທ່ານຕ້ອງການບັນທຶກໄວ້ບໍ່?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "ເປີດການດຳເນີນການ" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "ທີ່ກ່ຽວພັນ" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "ໄຂແຖວຂໍ້ມູນທີ່ກ່ຽວພັນ" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "ລາຍງານ..." #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "ໄຂບົດລາຍງານ" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "ອີ-ເມວລ໌" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "ລາຍງານທາງອີເມວລ໌" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "ພິມອອກ" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "ພິມລາຍງານອອກ" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_ກ່າຍ URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "ກ່າຍເອົາ URL ໃສ່ ຄລິບບອດ" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "ບໍ່ຮູ້" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "ຂີດຈຳກັດ:" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "ການຕັ້ງຄ່າຂີດຈຳກັດການຊອກຫາ" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "ຂີດຈຳກັດ:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "ບັນທຶກ (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "ການຕັ້ງຄ່າ" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "ແກ້ໄຂການຕັ້ງຄ່າຜູ້ໃຊ້ງານ" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "ການຕັ້ງຄ່າ" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "ການກວດແກ້ຄືນ" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "ເລືອກໜຶ່ງການກວດແກ້ຄືນ" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "ການກວດແກ້ຄືນ:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "ປຸ່ມລັດແປ້ນພິມ" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "ປຸ່ມລັດການປ້ອນຂໍ້ຄວາມ" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "ຕັດຂໍ້ຄວາມທີ່ເລືອກໄວ້" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "ກ່າຍເອົາຂໍ້ຄວາມທີ່ເລືອກໄວ້" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "ວາງຂໍ້ຄວາມທີ່ກ່າຍເອົາໃສ່" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "ເຄື່ອງມື ຕໍ່ໄປ" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "ເຄື່ອງມືກ່ອນໜ້ານີ້" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "ປຸ່ມລັດລາຍການສາຍພົວພັນ" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "ສ້າງການກ່ຽວພັນໃໝ່" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "ໄຂ/ຊອກຫາການກ່ຽວພັນ" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "ປຸ່ມລັດການປ້ອນລາຍການ" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "ສ້າງແຖວໃໝ່" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "ໄຂການກ່ຽວພັນ" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "ໝາຍແຖວເພື່ອລຶບອອກ" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "ບໍ່ໝາຍແຖວທີ່ຈະລຶບ" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "ເຄື່ອງມືການແກ້ໄຂ" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "ຍ້າຍ ເຄິກເຊີຣ໌" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "ຍ້າຍໄປຂວາ" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "ຍ້າຍໄປຊ້າຍ" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "ຍ້າຍຂຶ້ນ" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "ຍ້າຍລົງ" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "ຫຍັບຂຶ້ນໜຶ່ງໜ້າ" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "ຍ້າຍລົງລຸ່ມໜຶ່ງໜ້າ" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "ຍ້າຍຂຶ້ນເທິງສຸດ" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "ຍ້າຍລົງລຸ່ມ" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "ຍ້າຍໄປຫາບັນຊີແມ່" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "ເລືອກທັງໝົດ" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "ບໍ່ເລືອກທັງໝົດ" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "ເລືອກ ບັນຊີແມ່" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "ເລືອກ/ໃຊ້ງານແຖວປັດຈຸບັນ" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "ສະຫຼັບການເລືອກ" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "ຂະຫຽາຍອອກ/ຍຸບເຂົ້າກັນ" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "ຂະຫຽາຍແຖວອອກ" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "ຍຸບແຖວເຂົ້າກັນ" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "ສະຫຼັບແຖວ" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "ຍຸບແຖວທັງໝົດ" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "ຂະຫຽາຍແຖວທັງໝົດ" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "ມູມມອງແບບຕົ້ນໄມ້" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_ສະຫຼັບໜ້າເບິ່ງ" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "_ສະຫຼັບໜ້າເບິ່ງ" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_ກ່ອນໜ້າ" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "ແຖວຂໍ້ມູນກ່ອນນີ້" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_ຕໍ່ໄປ" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "ແຖວຂໍ້ມູນ ຕໍ່ໄປ" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_ຊອກຫາ" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_ສ້າງໃໝ່" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "ສ້າງແຖວຂໍ້ມູນໃໝ່" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_ບັນທຶກ" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "ບັນທຶກແຖວຂໍ້ມູນນີ້" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_ໂຫຼດຄືນໃໝ່/ຍົກເລີກ" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "_ໂຫຼດຄືນໃໝ່/ຍົກເລີກ" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_ເຮັດຊໍ້າກັນ" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_ລຶບ..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "ເບິ່ງ_ບັນທຶກ..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "ສະແດງການກວດແກ້ຄືນ..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "ຄ_ັດຕິດ..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "ເພີ່ມເອກະສານຄັດຕິດໃສ່ແຖວຂໍ້ມູນ" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_ຈົດບັນທຶກ..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "ເພີ່ມບັນທຶກຂໍ້ຄວາມໃສ່ແຖວຂໍ້ມູນ" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_ດຳເນີນການ..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_ທີ່ກ່ຽວພັນ..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_ລາຍງານ..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_ອີ-ແມວລ໌.." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_ພິມອອກ..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_ສົ່ງອອກຂໍ້ມູນ..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_ນໍາເຂົ້າຂໍ້ມູນ..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "ກ່າຍ_URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_ອັດແຖບງານ" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "ຊ່ອງຂໍ້ມູນທັງໝົດ" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_ເພີ່ມເຂົ້າ" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_ເອົາອອກ" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_ໃຫ້ເປົາ" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "ຊ່ອງຂໍ້ມູນທີ່ເລືອກໄວ້" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "ຂອບເຂດການໃຊ້ (parameters) ຂອງ ຟາຍລ໌ CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "ຕົວຂັ້ນ:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "ຂໍ້ຄວາມອ້າງອີງ:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "ເຂົ້າລະຫັດ:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "ຊື່ຊ່ອງຂໍ້ມູນ" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_ບັນທຶກການສົ່ງອອກ" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_ລຶບການສົ່ງອອກ" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "ການສົ່ງອອກທີ່ຈັດຕຽມໄວ້ກ່ອນ" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "ຊື່" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "ໄຂ" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "ເພີ່ມ_ຊ່ອງຂໍ້ມູນ" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (ສະຕຣິງ)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "ຊື່ຂອງການສົ່ງອອກນີ້ແມ່ນຫຍັງ?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "ຂຽນທັບ ຄຳອະທິບາຍ '%s' ນີ້ບໍ່?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "ແຖວຂໍ້ມູນ %d ຖືກບັນທຶກແລ້ວ!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "ບັນດາແຖວຂໍ້ມູນ %d ຖືກບັນທຶກແລ້ວ!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "ການດຳເນີນການລົ້ມເຫຼວ!\n" "ຂໍ້ຄວາມເຕືອນຂໍ້ຜິດພາດ:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "ຜິດພາດ" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "ເຊື່ອມໂຍງ" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "ລືບ" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "ສ້າງໃໝ່" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "ສະຫຼັບ" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "ກ່ອນໜ້າ" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "ຕໍ່ໄປ" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "ເພີ່ມ" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "ເອົາອອກ" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "ສ້າງແຖວຂໍ້ມູນໃໝ່ " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "ລຶບແຖວຂໍ້ມູນທີ່ເລືອກ " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "ຍົກເລີກການລຶບແຖວທີ່ເລືອກ" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_ກວດຫາ-ອັດຕະໂນມັດ" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "ຟາຍລ໌ທີ່ຈະນໍາເຂົ້າ:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "ໄຂ..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "ແຖວທີ່ຈະຂວ້າມ:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "ກ່ອນອື່ນ ທ່ານຕ້ອງໄດ້ເລືອກ ຟາຍລ໌ ທີ່ຈະນໍາເຂົ້າກ່ອນ." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "ຜິດພາດໃນການໄຂ ຟາຍລ໌ CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "ປະມວນຜົນ ຟາຍລ໌ ຜິດພາດ ໃນຊ່ອງຂໍ້ມູນ %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "ແຖວຂໍ້ມູນ %d ຖືກນໍາເຂົ້າແລ້ວ!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "ບັນດາແຖວຂໍ້ມູນ %d ຖືກນໍາເຂົ້າແລ້ວ!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "ຊອກຫາ" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "ຊອກຫາ %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "ໂຕນໍາພາສ້າງ" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ເລກລໍາດັບ" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "ຜູ້ສ້າງ" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "ວັນທີສ້າງ" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "ຜູ້ປັບປ່ຽນ" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "ວັນທີປັບປ່ຽນ" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy, python-format msgid "Unable to get view tree state for %s" msgstr "ບໍ່ສາມາດຕັ້ງຄ່າສະຖານະມູມມອງແບບຕົ້ນໄມ້ໄດ້ %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "ບໍ່ສາມາດຕັ້ງຄ່າສະຖານະມູມມອງແບບຕົ້ນໄມ້ໄດ້" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" ບໍ່ຖືກຕ້ອງ ກັບ ໂດເມນຂອງມັນ" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "ຕ້ອງໃຫ້ມີ \"%s\"" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "ຄ່າຂອງ \"%s\" ນີ້ ບໍ່ຖືກຕ້ອງ" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "ກ່ອນ-ການກວດສອບ" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "ຂະໜາດຮູບ" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "ຄວາມກວ້າງ:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "ຄວາມສູງ:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "ຮູບແບບ PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "ບັນທຶກເປັນ" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "ຂະໜາດຮູບ ໃຫຍ່ໂພດ." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "ໄຂໂຕກັ່ນຕອງ" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "ສະແດງໝາຍໜ້າຂອງການກັ່ນຕອງ" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "ເອົາໝາຍໜ້ານີ້ອອກ" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "ໝາຍໜ້າກັ່ນຕອງນີ້" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "ຊື່ໝາຍໜ້າ:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "ຊອກພົບ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "ມື້ນີ້" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "ກັບຄືນ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "ໄປໜ້າ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "ປີກ່ອນ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "ປີຕໍ່ໄປ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "ເບິ່ງເປັນລາຍອາທິດ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "ເບິ່ງເປັນເດືອນ" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "ອາທິດ" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "ເລືອກ..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "ໃຫ້ເປົ່າ" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "ຟາຍລ໌ ທັງໝົດ" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "ສະແດງເປັນຂໍ້ຄວາມທຳມະດາ" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "ເພີ່ມຄ່າ" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "ເອົາ \"%s\" ອອກ" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "ຮູບ" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "ເພີ່ມແຖວຂໍ້ມູນທີ່ມີຢູ່" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "ເອົາແຖວຂໍ້ມູນທີ່ເລືອກນີ້ອອກ " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "ໄຂແຖວຂໍ້ມູນ " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 #, fuzzy msgid "Clear the field " msgstr "ອະນາໄມແຖວຂໍ້ມູນ " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "ຊອກຫາແຖວຂໍ້ມູນໜຶ່ງ " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "ເອົາແຖວຂໍ້ມູນທີ່ເລືອກນີ້ອອກ" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "ແກ້ໄຂ ແຖວຂໍ້ມູນ ທີ່ເລືອກ " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "ພື້ນໜ້າ" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "ເລືອກສີ" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "ການແປ" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "ແກ້ໄຂ" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "ເລືອນລາງ" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "ທ່ານຕ້ອງບັນທຶກຂໍ້ມູນໄວ້ກ່ອນຈຶ່ງເພີ່ມການແປເຂົ້າໄປໄດ້." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "ບໍ່ມີພາສາອື່ນໃຫ້ໃຊ້." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "ມູມມອງການແປ" tryton-5.0.17/tryton/data/locale/lo/LC_MESSAGES/tryton.mo0000644000175000017500000006075113571264250022273 0ustar cedced00000000000000Kt ) !2GYaq  %5 <GK\u  #%: IUfu{ &   -;A GQ c p~+ :Ngw      *5DZj   $&;b ju     '-0 4?U"\ !,2 4>U\n      ! & 2>ATq     #'Ken       ' , 8 F [ l s }     ! ! $!.! 7!A!F! N!Y!i!{!!! !!!!! ""!" 3" >"L" _"i" """""""# ##I+#}u# #5$8J$$$ $$$ $ $$$$%%4%L%j%%%% % %% %% %& & &6&=&(D& m&z&|&&%&7&& '' '+'3' :' E'O' ^' i' t''''' ' ' ' ' '' '' '( (((.( 6(A( C(d($f( ( (((<())),).)0) *O* +M2+G+\+V%,|,,,,,,,,,,7,F -UQ-----$ .0.O.._.Z.Z.BD////"/F/a!0s00(1,71d1z110141 2%2)282OG22m2 "3 03 >3L3e3k3$3*333Q4OY44<A5~5N5Z50<65m6636k6b7~777?78!%8 G8BQ88*8B8!9U;9990999H :IU::0::H:B;b;;u;d;<"3<-V<$<=< <<B ='P=7x=====>Z>w>>>>/> ?<?*W?7?2?0?W@v@@(@@<@',ATA XA3bA A$AA*A(B9B6OB!BB0BB-CBC-[C CCC+C(CDTD:fD*DDDDEE!E?>E$~E!EE&E F4FGFGFGG9GHVG(GGGH0H6MHH$HH*HHH+FIrI+wI9ILIF*JqJ!JBJJK'KQ?KWK0KL-0L^L$tL%LLL!L;MDOM6MMMMNN*WN;NNNN?O!@O(bOHOOCO+PDPHXPPBP6P01QbQQ?QQR@qTT8CU |UUU*U!UV0V GVQVqV%VTVxWmWHW7X3JX*~XXXX X%XY3.YRbYY!YYZZ ZYZ[[.:\i\\/\\\]$](6] _]"m]]+].]^^-^M^d^"{^5^^^_1_H_+Y__0____T_7`$;```v``=``7aaaaa of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearCloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: lo Language-Team: lo Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 ຂອງ"%s" ບໍ່ຖືກຕ້ອງ ກັບ ໂດເມນຂອງມັນຕ້ອງໃຫ້ມີ "%s"ແຖວຂໍ້ມູນ %d ຖືກນໍາເຂົ້າແລ້ວ!ແຖວຂໍ້ມູນ %d ຖືກບັນທຶກແລ້ວ!ບັນດາແຖວຂໍ້ມູນ %d ຖືກນໍາເຂົ້າແລ້ວ!ບັນດາແຖວຂໍ້ມູນ %d ຖືກບັນທຶກແລ້ວ!%s (%s)%s (model name)%s (record name)%s (ສະຕຣິງ)%s%%,,........:ຊ່ອງຂໍ້ມູນທັງໝົດຊ່ອງຂໍ້ມູນທີ່ເລືອກໄວ້ການສົ່ງອອກທີ່ຈັດຕຽມໄວ້ກ່ອນສ້າງ...ຊອກຫາ...A new version is available!ຄ_ັດຕິດ...ການດຳເນີນການດຳເນີນການ...ເພີ່ມເພີ່ມ_ຊ່ອງຂໍ້ມູນເພີ່ມບັນທຶກຂໍ້ຄວາມໃສ່ແຖວຂໍ້ມູນເພີ່ມເອກະສານຄັດຕິດໃສ່ແຖວຂໍ້ມູນເພີ່ມແຖວຂໍ້ມູນທີ່ມີຢູ່Add new profileເພີ່ມຄ່າAdd...ຟາຍລ໌ ທັງໝົດບໍ່ສົນກັບຄຳເຕືອນນີ້ເລີຍ.ທ່ານແນ່ໃຈບໍ່ທີ່ຈະລຶບແຖວຂໍ້ມູນນີ້?ທ່ານແນ່ໃຈບໍ່ທີ່ຈະລຶບແຖວຂໍ້ມູນເຫຼົ່ານີ້?ຄັດຕິດ(%d)ເອກະສານຄັດຕິດ:ເອກະສານຄັດຕິດ (%s)ຄັດຕິດ...ເນື້ອຄວາມ:ຊື່ໝາຍໜ້າ:ໝາຍໜ້າກັ່ນຕອງນີ້ໂຕຕິດຕາມ ຂໍ້ຜິດພາດໂດຍ:CC:CSV Export: %sCSV Import: %sຂອບເຂດການໃຊ້ (parameters) ຂອງ ຟາຍລ໌ CSVເ_ຊື່ອມຕໍ່ຍົກເລີກການເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍ ໄຕຣຕັອນCancel savingCheck URL: %sCheck Versionໃຫ້ເປົ່າCloseອັດແຖບງານຍຸບແຖວທັງໝົດຍຸບແຖວເຂົ້າກັນຄຳສັ່ງງານ:ສົມທຽບຍົກເວັ້ນການເຂົ້າເຖິງພ້ອມກັນເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍ ໄຕຣຕັອນການເຊື່ອມຕໍ່ ຜິດພາດ! ຊື່ຜູໃຊ້ ຫຼື ລະຫັດຜ່ານ ບໍ່ຖືກຕ້ອງ!ກ່າຍເອົາ URL ໃສ່ ຄລິບບອດກ່າຍ_URL...ກ່າຍເອົາຂໍ້ຄວາມທີ່ເລືອກໄວ້ບໍ່ສາມາດເຊື່ອມຕໍ່ກັບແມ່ຂ່າຍໄດ້ສ້າງແຖວຂໍ້ມູນໃໝ່ສ້າງແຖວຂໍ້ມູນໃໝ່ ສ້າງແຖວໃໝ່ສ້າງການກ່ຽວພັນໃໝ່ສ້າງ ລາຍການຂໍ້ຜິດພາດ ໃໝ່ ດ້ວຍ ເລກກຳກັບ ວັນທີສ້າງວັນທີສ້າງ:ຜູ້ສ້າງຜູ້ສ້າງ:ຕັດຂໍ້ຄວາມທີ່ເລືອກໄວ້ຖານຂໍ້ມູນ:ຮູບແບບວັນທີລືບລຶບແຖວຂໍ້ມູນທີ່ເລືອກ ຕົວຂັ້ນ:ຮູບແບບສະແດງອອກຮູບແບບວັນທີທີ່ສະແດງອອກຄ່າສະແດງອອກທ່ານຕ້ອງການດຳເນີນການຕໍ່ໄປບໍ່?Downloadອີ-ເມວລ໌ລາຍງານທາງອີເມວລ໌ອີ-ເມວລ໌...ແກ້ໄຂແກ້ໄຂການຕັ້ງຄ່າຜູ້ໃຊ້ງານແກ້ໄຂ ແຖວຂໍ້ມູນ ທີ່ເລືອກ ແກ້ໄຂ...ເຄື່ອງມືການແກ້ໄຂອີເມວລ໌ການຕັ້ງຄ່າໂປຣແກຣມອີເມວລ໌ເຂົ້າລະຫັດ:ຜິດພາດຜິດພາດໃນການໄຂ ຟາຍລ໌ CSVປະມວນຜົນ ຟາຍລ໌ ຜິດພາດ ໃນຊ່ອງຂໍ້ມູນ %s.ຂໍ້ຜິດພາດ:ຂໍ້ຍົກເວັ້ນ:ຂະຫຽາຍແຖວທັງໝົດຂະຫຽາຍແຖວອອກຂະຫຽາຍອອກ/ຍຸບເຂົ້າກັນຜິດຍ້າຍແບບໄວລາຍການດຶງເອົາຖານຂໍ້ມູນຊື່ຊ່ອງຂໍ້ມູນຟາຍລ໌ທີ່ຈະນໍາເຂົ້າ:ຊອກພົບພື້ນໜ້າຮູບແບບເລືອນລາງຄວາມສູງ:ແມ່ຂ່າຍ / ຂໍ້ມູນກ່ຽວກັບຖານຂໍ້ມູນແມ່ຂ່າຍ:ເລກລໍາດັບເລກລໍາດັບ:ຂະໜາດຮູບຂະໜາດຮູບ ໃຫຍ່ໂພດ.ຮູບບໍ່ຖືກລຸ່ນກັບແມ່ຂ່າຍປຸ່ມລັດແປ້ນພິມວັນທີປັບປ່ຽນລ້າສຸດ:ປັບປ່ຽນລ້າສຸດ ໂດຍ:ເປີດການດຳເນີນການເລື່ອງຂອງ ທີ່ຢູ່ ທີ່ມີປັດຈຸບັນ:ຂີດຈຳກັດ:ຂີດຈຳກັດ:ແຖວທີ່ຈະຂວ້າມ:ເຊື່ອມໂຍງປຸ່ມລັດການປ້ອນລາຍການເຂົ້າສູ່ລະບົບດManage...ໝາຍແຖວເພື່ອລຶບອອກແບບ:ວັນທີປັບປ່ຽນຜູ້ປັບປ່ຽນເບິ່ງເປັນເດືອນຍ້າຍ ເຄິກເຊີຣ໌ຍ້າຍລົງຍ້າຍລົງລຸ່ມໜຶ່ງໜ້າຍ້າຍລົງລຸ່ມຍ້າຍໄປຊ້າຍຍ້າຍໄປຫາບັນຊີແມ່ຍ້າຍໄປຂວາຍ້າຍຂຶ້ນເທິງສຸດຍ້າຍຂຶ້ນຫຍັບຂຶ້ນໜຶ່ງໜ້າຊື່ສ້າງໃໝ່ຕໍ່ໄປແຖວຂໍ້ມູນ ຕໍ່ໄປເຄື່ອງມື ຕໍ່ໄປNoບໍ່ມີ ການດຳເນີນການ ທີ່ລະບຸໄວ້!ບໍ່ມີພາສາອື່ນໃຫ້ໃຊ້.ບໍ່ພົບຜົນຊອກຫາບັນທຶກ (%d)ບັນທຶກ (%s)ໝາຍເຫດ...OKໄຂໄຂໂຕກັ່ນຕອງໄຂແຖວຂໍ້ມູນທີ່ກ່ຽວພັນໄຂການກ່ຽວພັນໄຂບົດລາຍງານໄຂປະຕິທິນໄຂແຖວຂໍ້ມູນ ໄຂ...ໄຂ/ຊອກຫາການກ່ຽວພັນການດຳເນີນການລົ້ມເຫຼວ! ຂໍ້ຄວາມເຕືອນຂໍ້ຜິດພາດ: %sຂຽນທັບ ຄຳອະທິບາຍ '%s' ນີ້ບໍ່?PDA Modeຮູບແບບ PNG (*.png)ລະຫັດຜ່ານ:ວາງຂໍ້ຄວາມທີ່ກ່າຍເອົາໃສ່ກ່ອນ-ການກວດສອບການຕັ້ງຄ່າການຕັ້ງຄ່າກ່ອນໜ້າແຖວຂໍ້ມູນກ່ອນນີ້ເຄື່ອງມືກ່ອນໜ້ານີ້ພິມອອກພິມລາຍງານອອກພິມອອກ...ຂໍ້ມູນລາຍລະອຽດຂໍ້ມູນລາຍລະອຽດບັນນາທິການຂໍ້ມູນລາຍລະອຽດ:Quitຂໍ້ຄວາມອ້າງອີງ:ແຖວຂໍ້ມູນບັນທຶກແລ້ວແຖວຂໍ້ມູນບໍ່ທັນຖືກເອົາອອກ.ແຖວຂໍ້ມູນຖືກເອົາອອກແລ້ວ.ທີ່ກ່ຽວພັນທີ່ກ່ຽວພັນ...ປຸ່ມລັດລາຍການສາຍພົວພັນເອົາ "%s" ອອກເອົາອອກRemove selected profileເອົາແຖວຂໍ້ມູນທີ່ເລືອກນີ້ອອກເອົາແຖວຂໍ້ມູນທີ່ເລືອກນີ້ອອກ ເອົາໝາຍໜ້ານີ້ອອກລາຍງານ...ລາຍງານຂໍ້ຜິດພາດລາຍງານ...ການກວດແກ້ຄືນການກວດແກ້ຄືນ:ບັນທຶກບັນທຶກເປັນບັນທຶກເປັນ...ບັນທຶກ ສະຖານະ ໂຄງສ້າງບັນທຶກ ຄວາມກວ້າງ/ຄວາມສູງບັນທຶກແຖວຂໍ້ມູນນີ້Save your current versionຊອກຫາຊອກຫາ %sການຕັ້ງຄ່າຂີດຈຳກັດການຊອກຫາຈຳກັດການຊອກຫາ...ຊອກຫາແຖວຂໍ້ມູນໜຶ່ງ See the modified versionເລືອກ...ເລືອກສີເລືອກໜຶ່ງການກວດແກ້ຄືນເລືອກທັງໝົດເລືອກ ບັນຊີແມ່ເລືອກການດຳເນີນການຂອງທ່ານເລືອກ...ເລືອກ/ໃຊ້ງານແຖວປັດຈຸບັນການເລືອກShow active recordsສະແດງໝາຍໜ້າຂອງການກັ່ນຕອງShow inactive recordsສະແດງເປັນຂໍ້ຄວາມທຳມະດາສະແດງການກວດແກ້ຄືນ...ກວດສອບການສະກົດຄຳຫົວເລື່ອງ:ສະຫຼັບປຸ່ມລັດການປ້ອນຂໍ້ຄວາມການດຳເນີນການດັ່ງຕໍ່ໄປນີ້ ຕ້ອງການໃຫ້ ອັດແຖບງານທັງໝົດລົງ ທ່ານຕ້ອງການສືບຕໍ່ບໍ່?ຂໍ້ຜິດພາດອັນດຽວກັນນີ້ ຖືກລາຍງານ ໂດຍຜູ້ໃຊ້ງານຄົນອື່ນແລ້ວ. ເພື່ອໃຫ້ທ່ານໄດ້ຮັບຂໍ້ມູນການແກ້ໄຂ ຊື່ເຂົ້າໃຊ້ງານຂອງທ່ານ ໄດ້ຖືກເພີ່ມ ເຂົ້າໃນ ບັນຊີລາຍຊື່ຂອງບັນຫານີ້້ຄ່າຂອງ "%s" ນີ້ ບໍ່ຖືກຕ້ອງແຖວຂໍ້ມູນນີ້ ຖືກແກ້ໄຂແລ້ວ ທ່ານຕ້ອງການບັນທຶກໄວ້ບໍ່?This record has been modified while you were editing it.ເຖິງ:ມື້ນີ້ສະຫຼັບແຖວສະຫຼັບການເລືອກມູມມອງການແປການແປມູມມອງແບບຕົ້ນໄມ້ຈິງUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sບໍ່ສາມາດຕັ້ງຄ່າ ທ້ອງຖິ່ນ %s ໄດ້.ບໍ່ສາມາດຕັ້ງຄ່າສະຖານະມູມມອງແບບຕົ້ນໄມ້ໄດ້ບໍ່ສາມາດ ຂຽນ ຟາຍລ໌ ຕັ້ງຄ່າ (config file) %s ນີ້ໄດ້.ຍົກເລີກການລຶບແຖວທີ່ເລືອກບໍ່ຮູ້ບໍ່ໝາຍແຖວທີ່ຈະລຶບບໍ່ເລືອກທັງໝົດຊື່ຜູ້ໃຊ້:ຜູ້ໃຊ້:ຜູ້ໃຊ້:ຄ່າເບິ່ງ_ບັນທຶກ...ອາທິດເບິ່ງເປັນລາຍອາທິດຊື່ຂອງການສົ່ງອອກນີ້ແມ່ນຫຍັງ?ຄວາມກວ້າງ:ໂຕນໍາພາສ້າງດຽວນີ້ກຳລັງເຮັດວຽກກັບແຖວຂໍ້ມູນທີ່ສ້າງຂຶ້ນຊ້ອນກັນ.ຂຽນລົງເລີຍປແມ່ນທ່ານຕ້ອງໄດ້ເລືອກ ໜຶ່ງແຖວຂໍ້ມູນ.ກ່ອນອື່ນ ທ່ານຕ້ອງໄດ້ເລືອກ ຟາຍລ໌ ທີ່ຈະນໍາເຂົ້າກ່ອນ.ທ່ານຕ້ອງບັນທຶກຂໍ້ມູນໄວ້ກ່ອນຈຶ່ງເພີ່ມການແປເຂົ້າໄປໄດ້.ການເລືອກຂອງທ່ານ:_ດຳເນີນການ..._ເພີ່ມເຂົ້າ_ກວດຫາ-ອັດຕະໂນມັດ_ຍົກເລີກ_ໃຫ້ເປົາ_ອັດແຖບງານ_ກ່າຍ URL_ລຶບການສົ່ງອອກ_ລຶບ..._ເຮັດຊໍ້າກັນ_ອີ-ແມວລ໌.._ສົ່ງອອກຂໍ້ມູນ..._ນໍາເຂົ້າຂໍ້ມູນ..._ສ້າງໃໝ່_ຕໍ່ໄປ_ຈົດບັນທຶກ..._ກ່ອນໜ້າ_ພິມອອກ..._ທີ່ກ່ຽວພັນ..._ໂຫຼດຄືນໃໝ່/ຍົກເລີກ_ເອົາອອກ_ລາຍງານ..._ບັນທຶກ_ບັນທຶກການສົ່ງອອກ_ຊອກຫາ_ສະຫຼັບໜ້າເບິ່ງມຮູບແບບການພັດທະນາກັບຄືນໄປໜ້າມ.ເຂົ້າໃຊ້ທຸກຢ່າງໃນລະດັບຂໍ້ມູນນmodularity, scalability and securityປີຕໍ່ໄປປີກ່ອນວລະບຸ config file ທີ່ສະຫຼັບກັນລະບຸ ລະດັບ ການບັນທຶກ: ແກ້ໄຂຂໍ້ຜິດພາດ, ຂໍ້ມູນ, ຄຳເຕືອນ, ຂໍ້ຜິດພາດ, ທີ່ສຳຄັນລະບຸ ຜູ້ເຂົ້າໃຊ້ງານຈtranslator-creditsອມtryton-5.0.17/tryton/data/locale/ca/0000755000175000017500000000000013571264253016555 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ca/LC_MESSAGES/0000755000175000017500000000000013571264253020342 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ca/LC_MESSAGES/tryton.po0000644000175000017500000011124213463252532022237 0ustar cedced00000000000000# Catalan translations for tryton. # Copyright (C) 2012 Zikzakmedia SL # This file is distributed under the same license as the tryton project. # Sergi Almacellas Abellana 2012. # Jordi Esteve Cusiné 2012. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "Indica un fitxer de configuració alternatiu" #: tryton/config.py:77 msgid "development mode" msgstr "mode desenvolupament" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Registra tota la informació amb nivell INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "indica el nivell de log: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Indica l'usuari" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "Indica el nom:port del servidor" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "No s'ha pogut escriure el fitxer configuració %s" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "No s'ha pogut establir l'idioma %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Seleccioneu la vostra acció" #: tryton/action/main.py:193 msgid "No action defined." msgstr "No s'ha definit cap acció." #: tryton/common/button.py:54 msgid "By: " msgstr "Per: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Selecció" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 msgid "Cancel" msgstr "Cancel·la" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "D'acord" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "La vostra selecció:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Selecciona" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Desa" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Desa com..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Ignora sempre aquest advertiment." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Voleu continuar?" #: tryton/common/common.py:643 msgid "No" msgstr "No" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Si" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Excepció de concurrència" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "Aquest registre ha estat modificat mentre l'editàveu." #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "No desis els canvis" #: tryton/common/common.py:696 msgid "Compare" msgstr "Compara" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "Mostra la versió modificada" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Desa de totes formes" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "Deseu els vostres canvis" #: tryton/common/common.py:729 msgid "Application Error" msgstr "Error d'aplicació" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Informa de l'error" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "Tanca" #: tryton/common/common.py:751 msgid "Error: " msgstr "Error: " #: tryton/common/common.py:768 #, python-format, python-format, python-format msgid "To report bugs you must have an account on %s" msgstr "Per informar d'errors heu de tenir un compte a %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Seguiment d'errors" #: tryton/common/common.py:811 msgid "User:" msgstr "Usuari:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Contrasenya:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "El mateix error ja ha estat notificat per un altre usuari.\n" "Per mantenir-vos informat afegirem el vostre usuari a la llista d'interessats en aquest assumpte." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "S'ha creat una nou informe d'error amb l'identificador " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Error de connexió.\n" "Nom d'usuari o contrasenya incorrectes." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Excepció:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "URL de comprovació: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "No s'ha pogut comprovar si existeix una nova versió." #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Hi ha una nova versió disponible!" #: tryton/common/common.py:942 msgid "Download" msgstr "Baixa" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Cerca..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Crea..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "No es pot buscar l'autocompletat de %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valor" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valor a mostrar" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Format" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Format a mostrar" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Obre el calendari" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Format dates" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Format dates a mostrar" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "a" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Verdader" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "v" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Fals" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Edita..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Adjunts..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notes..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Accions..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Relacionat..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Informe..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Correu electrònic..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Imprimeix..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "S" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 msgid "Preferences..." msgstr "Preferències..." #: tryton/gui/main.py:127 msgid "Toolbar" msgstr "Barra d'eines" #: tryton/gui/main.py:128 msgid "Default" msgstr "Per defecte" #: tryton/gui/main.py:129 msgid "Text and Icons" msgstr "Text i icones" #: tryton/gui/main.py:130 msgid "Text" msgstr "Text" #: tryton/gui/main.py:131 msgid "Icons" msgstr "Icones" #: tryton/gui/main.py:134 msgid "Form" msgstr "Formulari" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Desa ample/alt" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Desa l'estat de l'arbre" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Tabulació ràpida" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Correcció ortogràfica" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "Mode PDA" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "_Límit de cerca..." #: tryton/gui/main.py:142 msgid "Email..." msgstr "Correu electrònic..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Comprova versió" #: tryton/gui/main.py:145 msgid "Options" msgstr "Opcions" #: tryton/gui/main.py:148 msgid "Keyboard Shortcuts..." msgstr "Combinacions de tecles..." #: tryton/gui/main.py:149 msgid "About..." msgstr "Quant a..." #: tryton/gui/main.py:150 msgid "Help" msgstr "Ajuda" #: tryton/gui/main.py:153 msgid "Quit" msgstr "Sortir" #: tryton/gui/main.py:395 msgid "No result found." msgstr "No s'han trobat resultats." #: tryton/gui/main.py:447 msgid "Favorites" msgstr "Preferits" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "Gestiona..." #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Acció" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "L'acció seleccionada requereix tancar totes les pestanyes.\n" "Voleu continuar?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Tanca pestanya" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "modularitat, escalabilitat i seguretat" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "Crèdits de traducció" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Adjunts (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Editor de perfils" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Perfil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "Afegeix un nou perfil" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "Elimina el perfil seleccionat" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Servidor:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Base de dades:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Recuperant llista de bases de dades" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Nom d'usuari:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "El client no és compatible amb la versió del servidor" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "No s'ha pogut connectar amb el servidor." #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Usuari" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Cancel·la" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Cancel·la connexió amb el servidor Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onnecta" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Connecta amb el servidor Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Perfil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Informació del Servidor / Base de dades" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Nom d'usuari:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Correu electrònic" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Configuració del programa de correu electrònic" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Línia de comandes:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Llegenda de paraules clau disponibles:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "A:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Assumpte:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Missatge:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Adjunt:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "Afegeix..." #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Adjunt(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Nota(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Heu de triar un registre." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "Identificador:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Creat per:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Data creació:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Última modificació per:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Última data de modificació:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Model:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Esteu segur que voleu eliminar aquest registre?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Esteu segur que voleu eliminar aquests registres?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Els registres no s'han eliminat." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Registres eliminats." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Ara esteu treballant en el registre duplicat." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Registre desat." #: tryton/gui/window/form.py:485 msgid " of " msgstr " de " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Aquest registre ha estat modificat.\n" "Voleu desar-lo?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Executa acció" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "_Relacionat" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Obre registres relacionats" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Informes" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Obre informe" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Correu electrònic" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Informe per email" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Imprimeix" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Imprimeix informe" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Copia l'URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Copia l'URL al porta-retalls" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Desconegut" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Límit" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Preferències del límit de cerca" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Límit:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notes (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferències" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Edita preferències d'usuari" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferències" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Revisió" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Seleccioneu una revisió" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Revisió:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Combinacions de tecles" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Dreceres en camps de text" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Talla el text seleccionat" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copia el text seleccionat" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Enganxa el text seleccionat" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Camp següent" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Camp anterior" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Dreceres en relacions" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Crea una nova relació" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Obre/Cerca una relació" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Dreceres en llistes" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Crea una nova línia" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Obre una relació" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Marca la línia per ser eliminada" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Desmarca la línia per ser eliminada" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Controls en l'edició" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Mou cursor" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Mou a la dreta" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Mou a l'esquerra" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Mou amunt" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Mou avall" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Mou amunt una pàgina" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Mou avall una pàgina" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Mou al principi" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Mou al final" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Mou al pare" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Selecciona tot" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Deselecciona tot" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Selecciona pare" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Selecciona/Activa fila actual" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Commuta selecció" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Expandeix/Contrau" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Expandeix fila" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Contrau fila" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Commuta fila" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Contrau totes les files" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Expandeix totes les files" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Vista d'arbre" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Canvia la vi_sta" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Canvia la vista" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Anterior" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Registre anterior" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Seg_üent" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Registre següent" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Cerca" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nou" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Crea un nou registre" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Desa" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Desa aquest registre" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Recarrega/Desfés" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Recarrega/Desfés" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplica" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Elimina..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Veure _registre..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Mostra revisions..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Adjun_ts..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Afegeix un adjunt al registre" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notes..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Afegeix una nota al registre" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Accions..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Relacionat..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Informes..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_Correu electrònic..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Im_primeix..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Exporta dades..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importa dades..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Copia l'_URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Tanca la pestanya" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Tots els camps" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Afegeix" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Elimina" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Neteja" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Camps seleccionats" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Paràmetres CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Separador:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Delimitador de text:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codificació:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nom del camp" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "Exportació CSV: %s" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Desa exportació" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Elimina exportació" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Exportacions predeterminades" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nom" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Obre" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Afegeix noms de _camp" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (text)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (nom del model)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (nom del registre)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Quin és el nom d'aquesta exportació?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Voleu sobreescriure la definició de '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "S'ha desat %d registre." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "S'han desat %d registres." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Ha fallat l'operació.\n" "Missatge d'error:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Error" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Enllaç" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Elimina" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Nou" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Canvia la vista" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Anterior" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Següent" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Afegeix" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Elimina " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Crea un nou registre " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Elimina el registre seleccionat " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Recupera el registre seleccionat " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "Importació CSV: %s" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "Detecta _automàticament " #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Fitxer a importar:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Obre..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Línies a ometre:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Primer heu de seleccionar un fitxer a importar." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Error a l'obrir el fitxer CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "S'ha produït un error en processar el fitxer en el camp %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "S'ha importat %d registre." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "S'han importat %d registres." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Cerca" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Cerca %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "No s'ha pogut eliminar l'assistent %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Assistent" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Creat per" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Data de creació" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Modificat per" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Data de modificació" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "No s'ha pogut obtenir l'estat de la vista d'arbre de %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "No s'ha pogut desar l'estat de la vista d'arbre" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" no és vàlid segons el seu domini." #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" és obligatori." #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Els valors de \"%s\" no són vàlids." #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Prevalidació" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Mida de la imatge" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Amplada:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Altura:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Imatge PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Anomena i desa" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "La mida de la imatge és massa gran." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Obre filtres" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Mostra les cerques preferides" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Elimina de les cerques preferides" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Desa com a cerca preferida" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Mostra registres actius" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Mostra registres inactius" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nom de la cerca preferida:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Cerca" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Avui" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "vés enrere" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "vés endavant" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "any anterior" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "l'any següent" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Vista setmanal" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Vista mensual" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Setmana" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Selecciona..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Neteja" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Tots els fitxers" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Mostra com a text pla" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Afegeix un valor" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Eliminar \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Imatges" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Afegeix un registre existent" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Elimina el registre seleccionat " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Obre el registre " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Eliminar el registre " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Cerca un registre " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Elimina el registre seleccionat" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Edita registre seleccionat " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Primer pla" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Seleccioneu un color" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Traducció" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Edita" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Dubtosa" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Heu de desar el registre abans d'afegir traduccions." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "No hi ha cap altre idioma disponible." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Tradueix la vista" tryton-5.0.17/tryton/data/locale/ca/LC_MESSAGES/tryton.mo0000644000175000017500000004377613571264250022254 0ustar cedced00000000000000` )"L]q 7HYu   #-I#[%  .=LU&\      $+>j  ,: IWf x   " 0:?Uow &  )9 ? LV ny  "2E[u ! %7 I T `j        : K T _ h k p }     # !!6!?! Q![!m! |! !!!!!! !!!!!" " "&";"L" S"]" x" " """""" # ## ##-#2# :#E#U#g#x## ####### $ $ *$8$ K$U$ q${$$$$$$$$ % %%(%I7%}% %5 &8V&-&&& &&&& & '''5'$P'%u'''''(( 1( >(I( O(Y( _(m( r( |((((( ((((%)7,)d) t)) ))) ) )) ) ) )))* * * * %* /* :*G* O*Z* `*m* u**** ** **$* * * + +<*+g+ ~++++++F-(K-t-------. $...3.6.;.>.B.D.Z.#t...". . .. ./ /!/>/\/y// //!////1!0 S0^0 f0 s0 ~000000001 1 1+(1T1h1111111 112 2$2;D2222(2233437K333 3 333 3 33&4 )444E4\4l4}44444445 5 5035d5 z555<55 556%676<6 O6#Y6 }666 6 66666(6 67 77!7$37X77`777778&878>8F8X8`8t8{8 }8!888 8 8 8 88 99 ,989G9 W9a9w9{999 999%99: ::%:-: 2:?:Z: l:y::::+::*: ;); <;I; e; s; ;;;; ; ;; ;;; <<</< ?<`< u< <<< <<<<&=!9=[=d= w== === ===== >>!>;>O>f> >>>>>> >? $?.?F?d?~??? ????? @L@d@#A3%A6YA1AAA AA AA B B"B5+B%aB7B&B"B/ C19C&kC C$CC CC CCCDD&'DND WD-aDDDDD/D4D(E =EIERE lExEE EE EEEEEF F F F (F6FEFXF aFnFtFFFFF F FF,FF&G'G 6GCG,EG>rGGGGGGG of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...About...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Application ErrorAre you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancelCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDefaultDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEmail...Encoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFormFormatFuzzyHeight:HelpHost / Database informationHost:IDID:IconsImage SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsKeyboard Shortcuts...Latest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOptionsOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreferences...PreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewTextText Entries ShortcutsText and IconsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To report bugs you must have an account on %sTo:TodayToggle rowToggle selectionToolbarTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: ca Language-Team: ca Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 de "%s" no és vàlid segons el seu domini."%s" és obligatori.S'ha importat %d registre.S'ha desat %d registre.S'han importat %d registres.S'han desat %d registres.%s (%s)%s (nom del model)%s (nom del registre)%s (text)%s%%, ,….....:Tots els campsCamps seleccionatsExportacions predeterminadesCrea...Cerca...Hi ha una nova versió disponible!Adjun_ts...Quant a...AccióAccions...AfegeixAfegeix noms de _campAfegeix una nota al registreAfegeix un adjunt al registreAfegeix un registre existentAfegeix un nou perfilAfegeix un valorAfegeix...Tots els fitxersIgnora sempre aquest advertiment.Error d'aplicacióEsteu segur que voleu eliminar aquest registre?Esteu segur que voleu eliminar aquests registres?Adjunt(%d)Adjunt:Adjunts (%s)Adjunts...Missatge:Nom de la cerca preferida:Desa com a cerca preferidaSeguiment d'errorsPer: CC:Exportació CSV: %sImportació CSV: %sParàmetres CSVC_onnectaCancel·laCancel·la connexió amb el servidor TrytonNo desis els canvisURL de comprovació: %sComprova versióNetejaEliminar el registre TancaTanca pestanyaContrau totes les filesContrau filaLínia de comandes:ComparaExcepció de concurrènciaConnecta amb el servidor TrytonError de connexió. Nom d'usuari o contrasenya incorrectes.Copia l'URL al porta-retallsCopia l'_URL...Copia el text seleccionatNo s'ha pogut connectar amb el servidor.Crea un nou registreCrea un nou registre Crea una nova líniaCrea una nova relacióS'ha creat una nou informe d'error amb l'identificador Data de creacióData creació:Creat perCreat per:Talla el text seleccionatBase de dades:Format datesPer defecteEliminaElimina el registre seleccionat Separador:Format a mostrarFormat dates a mostrarValor a mostrarVoleu continuar?BaixaCorreu electrònicInforme per emailCorreu electrònic...EditaEdita preferències d'usuariEdita registre seleccionat Edita...Controls en l'edicióCorreu electrònicConfiguració del programa de correu electrònicCorreu electrònic...Codificació:ErrorError a l'obrir el fitxer CSVS'ha produït un error en processar el fitxer en el camp %s.Error: Excepció:Expandeix totes les filesExpandeix filaExpandeix/ContrauFalsTabulació ràpidaPreferitsRecuperant llista de bases de dadesNom del campFitxer a importar:CercaPrimer plaFormulariFormatDubtosaAltura:AjudaInformació del Servidor / Base de dadesServidor:IDIdentificador:IconesMida de la imatgeLa mida de la imatge és massa gran.ImatgesEl client no és compatible amb la versió del servidorCombinacions de teclesCombinacions de tecles...Última data de modificació:Última modificació per:Executa accióLlegenda de paraules clau disponibles:LímitLímit:Línies a ometre:EnllaçDreceres en llistesUsuariMGestiona...Marca la línia per ser eliminadaModel:Data de modificacióModificat perVista mensualMou cursorMou avallMou avall una pàginaMou al finalMou a l'esquerraMou al pareMou a la dretaMou al principiMou amuntMou amunt una pàginaNomNouSegüentRegistre següentCamp següentNoNo s'ha definit cap acció.No hi ha cap altre idioma disponible.No s'han trobat resultats.Nota(%d)Notes (%s)Notes...D'acordObreObre filtresObre registres relacionatsObre una relacióObre informeObre el calendariObre el registre Obre...Obre/Cerca una relacióHa fallat l'operació. Missatge d'error: %sOpcionsVoleu sobreescriure la definició de '%s'?Mode PDAImatge PNG (*.png)Contrasenya:Enganxa el text seleccionatPrevalidacióPreferènciesPreferènciesPreferències...AnteriorRegistre anteriorCamp anteriorImprimeixImprimeix informeImprimeix...PerfilEditor de perfilsPerfil:SortirDelimitador de text:Registre desat.Els registres no s'han eliminat.Registres eliminats._RelacionatRelacionat...Dreceres en relacionsRecarrega/DesfésEliminar "%s"Elimina Elimina el perfil seleccionatElimina el registre seleccionatElimina el registre seleccionat Elimina de les cerques preferidesInformesInforma de l'errorInforme...RevisióRevisió:DesaAnomena i desaDesa com...Desa l'estat de l'arbreDesa ample/altDesa aquest registreDeseu els vostres canvisCercaCerca %sPreferències del límit de cerca_Límit de cerca...Cerca un registre Mostra la versió modificadaSeleccionaSeleccioneu un colorSeleccioneu una revisióSelecciona totSelecciona pareSeleccioneu la vostra accióSelecciona...Selecciona/Activa fila actualSeleccióMostra registres actiusMostra les cerques preferidesMostra registres inactiusMostra com a text plaMostra revisions...Correcció ortogràficaAssumpte:Canvia la vistaCanvia la vistaTextDreceres en camps de textText i iconesL'acció seleccionada requereix tancar totes les pestanyes. Voleu continuar?El mateix error ja ha estat notificat per un altre usuari. Per mantenir-vos informat afegirem el vostre usuari a la llista d'interessats en aquest assumpte.Els valors de "%s" no són vàlids.Aquest registre ha estat modificat. Voleu desar-lo?Aquest registre ha estat modificat mentre l'editàveu.Per informar d'errors heu de tenir un compte a %sA:AvuiCommuta filaCommuta seleccióBarra d'einesTradueix la vistaTraduccióVista d'arbreVerdaderNo s'ha pogut comprovar si existeix una nova versió.No s'ha pogut eliminar l'assistent %sNo s'ha pogut obtenir l'estat de la vista d'arbre de %sNo es pot buscar l'autocompletat de %sNo s'ha pogut establir l'idioma %sNo s'ha pogut desar l'estat de la vista d'arbreNo s'ha pogut escriure el fitxer configuració %sRecupera el registre seleccionat DesconegutDesmarca la línia per ser eliminadaDeselecciona totNom d'usuari:Usuari:Nom d'usuari:ValorVeure _registre...SetmanaVista setmanalQuin és el nom d'aquesta exportació?Amplada:AssistentAra esteu treballant en el registre duplicat.Desa de totes formesASiHeu de triar un registre.Primer heu de seleccionar un fitxer a importar.Heu de desar el registre abans d'afegir traduccions.La vostra selecció:_Accions..._AfegeixDetecta _automàticament _Cancel·la_Neteja_Tanca la pestanya_Copia l'URL_Elimina exportació_Elimina..._Duplica_Correu electrònic..._Exporta dades..._Importa dades..._NouSeg_üent_Notes..._AnteriorIm_primeix..._Relacionat..._Recarrega/Desfés_Elimina_Informes..._Desa_Desa exportació_CercaCanvia la vi_stadmode desenvolupamentvés enrerevés endavanthRegistra tota la informació amb nivell INFOmmodularitat, escalabilitat i seguretatl'any següentany anteriorsIndica un fitxer de configuració alternatiuindica el nivell de log: DEBUG, INFO, WARNING, ERROR, CRITICALIndica l'usuariIndica el nom:port del servidorvCrèdits de traduccióSatryton-5.0.17/tryton/data/locale/zh_CN/0000755000175000017500000000000013571264253017173 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/zh_CN/LC_MESSAGES/0000755000175000017500000000000013571264253020760 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/zh_CN/LC_MESSAGES/tryton.po0000644000175000017500000010550013463252532022655 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "备选配置文件" #: tryton/config.py:77 msgid "development mode" msgstr "开发模式" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "INFO级别记录日志" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "设置日志级别: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "设置登录用户" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "设置服务器名称:端口号" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "无法写入配置文件 %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "无法设置语言地域 %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "选择一项操作" #: tryton/action/main.py:193 msgid "No action defined." msgstr "没有定义任何操作 !" #: tryton/common/button.py:54 msgid "By: " msgstr "By: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "选择" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "取消(_C)" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "已选择:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "选择" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "保存" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "另存为..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "下次不再提示." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "继续此项操作 ?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "是" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "并行操作异常" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "对比" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "覆写" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "程序错误 !" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "报告Bug" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "错误:" #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "提交Bug报告,需要 %s账户" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Bug 追踪器" #: tryton/common/common.py:811 msgid "User:" msgstr "用户名:" #: tryton/common/common.py:819 msgid "Password:" msgstr "密码:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "已有其他用户报告相同bug.\n" "用户名已加入通知列表,将随时接收相关信息" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Bug 已提交备案" #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "连接错误!\n" "用户名或密码有误!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "异常:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "查找..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "创建..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "无法找到“ %s ”的匹配项" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "值" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "显示" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "格式" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "显示格式" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "打开日历" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "日期格式" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "日期显示格式" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "y" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "True" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "t" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "False" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "编辑..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "附件文档..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "注释..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "操作..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "关联..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "报告..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "用电子邮件发送..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "打印..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "年" #: tryton/common/timedelta.py:27 msgid "M" msgstr "月" #: tryton/common/timedelta.py:28 msgid "w" msgstr "星期" #: tryton/common/timedelta.py:29 msgid "d" msgstr "日" #: tryton/common/timedelta.py:30 msgid "h" msgstr "时" #: tryton/common/timedelta.py:31 msgid "m" msgstr "分" #: tryton/common/timedelta.py:32 msgid "s" msgstr "秒" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "设置偏好(_P)..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "工具栏(_T)" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "默认设置(_D)" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "图标文字(_R)" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "显示文字(_T)" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "显示图标(_I)" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "表单视图(_F)" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "保存窗体大小" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "保存导航状态" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "快速切换标签" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "开启拼写检查" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "数据查询..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "电子邮件(_E)..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "选项(_O)" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "快捷键(K)..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "关于(_A)..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "帮助(_H)" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "无符合条件的数据." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "收藏(_V)" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "操作" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "该操作需要关闭打开的项目\n" "是否继续?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "关闭标签" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "附件文档(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "数据服务配置器" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "配置列表" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "主机:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "服务标识:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "获取服务列表..." #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "用户名:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "服务器版本与客户端不兼容" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "无法连接服务器" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "登录" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "取消(_C)" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "取消与服务器的连接" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "连机(_O)" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "连接数据服务器" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "配置:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "数据服务器:" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "用户:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "邮件" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "电子邮件相关设置" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "电子邮件程序命令行" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "替换变量列表:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "收件人:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "抄送:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "主题:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "内容:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "附件:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "附件文档(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "注释(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "选择需要操作的项目" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "标识:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "创建者:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "创建日期:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "最近更改:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "最近更改日期:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "模型:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "确定要删除此项吗?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "确定要删除这些项目?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "所选项目未删除成功." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "项目已成功删除" #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "当前处理的是项目的副本." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "保存成功." #: tryton/gui/window/form.py:485 msgid " of " msgstr "of" #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "记录有改动, 是否保存?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "执行操作" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "关联" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "打开关联项目" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "报告(_R)..." #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "打开报表" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "邮件发送" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "用电子邮件发送报表" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "打印" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "打印报表" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "复制(_C)URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "将URL复制到粘贴板" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "未知" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "限制" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "查询限制..." #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "限制:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "注释(%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "偏好" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "设置用户偏好..." #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "偏好" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "版本" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "选择版本" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "版本:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "快捷键" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "文本相关" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "剪切" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "复制" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "粘贴" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "下一个文本" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "上一个文本" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "关联操作" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "新建关联" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "打开. 查找关联" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "列表项相关" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "新建一行" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "打开关联项" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "标定删除选择" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "取消删除选择" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "编辑界面" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "光标移动" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "右移" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "左移" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "上移" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "下移" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "上移一页" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "下移一页" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "移到顶端" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "移到底部" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "上一级" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "全选" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "全不选" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "选择上一级" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "选择/激活当前行" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "切换状态" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "展开/收起" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "展开" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "收起" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "切换状态" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "收起所有" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "展开所有" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "树形导航" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "切换视图(_S)" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "切换视图" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "向前(_P)" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "前一项" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "向后(_N)" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "后一项" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "查找(_S)" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "新建(_N)" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "新建项目" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "保存(_S)" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "保存项目" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "刷新/撤销(_R)" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "刷新/撤销" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "复制(_D)" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "删除(_D)..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "日志(_V)..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "显示版本..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "附件(_T)..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "给当前项添加附件" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "注释(_N)..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "给当前项添加注释" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "操作(_A)..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "关联(_L)..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "报告(_R)..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "邮件发送(_E)..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "打印(_P)..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "导出数据(_X)" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "导入数据(_I)" #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "复制URL(_U)..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "关闭标签页(_C)" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "数据项" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "添加(_A)" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "删除(_R)" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "清除(_C)" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "选中字段" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV 参数" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "分隔符:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "限定符:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "编码:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "列名" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "保存设定(_S)" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "删除设定(_D)" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "导出设定" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "名称" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "打开" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "添加列名称(_F)" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (string)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (模型名称)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (记录名称)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "导出设定的名称" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "替换设定 '%s' ?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "%d 项保存成功!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "%d 记录保存成功!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "操作失败!\n" "相关错误信息:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "错误" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "链接" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "删除" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "新建" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "切换" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "向前" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "向后" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "添加" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "删除 " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "新建项目 " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "删除选择项 " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "回滚删除项 " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "自动设置(_A)" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "数据文件:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "打开..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "跳过行:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "必须先选择要导入的文件!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "打开CSV出错 !" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "处理数值 %s 时出错" #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "%d 项记录导入成功!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "%d 项记录导入成功!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "查找" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "查找 %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "无法删除向导 %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "向导" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "标识" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "创建者" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "创建日期" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "修改者" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "修改日期" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "无法获取视图树状态: %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "无法设置视图树状态" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "根据域设置,\"%s\"不可用" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" 是必填项" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "无法获得\"%s\" 的值" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "预校验" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "图片尺寸" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "宽:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "高:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG 图片格式 (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "另存为" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "图片尺寸过大 !" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "打开过滤器" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "显示筛选器书签" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "移除书签" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "收藏筛选器" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "书签名称:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "查找" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "今天" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "回退" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "前进" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "上年度" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "下年度" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "周视图" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "月视图" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "周" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "选择..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "清除" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "所有文件" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "显示纯文本" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "添加条目" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "删除\"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "图片" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "添加现存条目" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "删除选择项 " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "打开条目 " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 #, fuzzy msgid "Clear the field " msgstr "删除记录 " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "查找条目 " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "删除所选条目" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "编辑所选条目" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "字体颜色" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "选择颜色" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "翻译" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "编辑" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "模糊" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "请先保存已翻译条目,再增加新翻译 !" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "没有其他可翻译语言!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "翻译视图" tryton-5.0.17/tryton/data/locale/zh_CN/LC_MESSAGES/tryton.mo0000644000175000017500000003736313571264250022665 0ustar cedced00000000000000O  )<Mar  '8Ieu |  #0%Tz  !&* Q _ m{   +" :GZz   0 :FM ju  '7= T^d&{    & +6=CKgmp t" !4:APUlr t~     " 0<DX]a f r~    #5JR#g      + 1 > G O ^ g l x      !,!I!^! e! p!z! !!! !!!!!! !"")">"W"^"m" " "" "" """ ##/#A#P#Y# `#l#I#}# K$5l$8$$$ $$% % %&%+%K%$f%%%%%%&&&.& G& T&_& e&o& u&& & &&&(& &&&&%'7B'z' '' ''' ' '' ' ' '' ((!( '( 1( ;( E( P(]( e(p( v(( (((( (( (($( ) ) )")<@)}) ))))))[+^+~+++++++ , ,',,,/,4,7,;,=,N,b,v,,, ,, ,,,,- -3- C-P- W-d-x------- -. .!. &.0.?. N. Y.d. . . ... . ...../'$/L/e/z// // / // / / / 00 0 )060=0 S0 ^0k0~000 000001 1 #10171P1X1_1q111 11 11111 12 222#2(292A2H2 P2]2r2$y2 22 2 2222 2333%3 )333F3 N3 [3 e3 o3|3 3 33 33 33 3333 3344%4D4 ^4 i4 t4~44444 4 44 44$5+5?5H5a5i5 p5z555 555 5 5 5555 5 66-6C6 J6 T6 a6 o6 z6666 6 6 6 6667 7 7$777 J7W7q7 x777777 7 7778 8"898@8T8j888888 8 848_9q9 989 99 9 : :: #:0:5:U:!k:"::::;;"; 5;?; G; R;]; a;o; s;};;;";;;;;$;2< E< P< ^<i< ~<<<<< < <<== "= -=8= J= U= c=q= = = == === =====>$> ;> E>O>S>9f>>!>>>>> of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearCloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: zh_CN Language-Team: zh_CN Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 of根据域设置,"%s"不可用"%s" 是必填项%d 项记录导入成功!%d 项保存成功!%d 项记录导入成功!%d 记录保存成功!%s (%s)%s (模型名称)%s (记录名称)%s (string)%s%%, ,….....:数据项选中字段导出设定创建...查找...A new version is available!附件(_T)...操作操作...添加添加列名称(_F)给当前项添加注释给当前项添加附件添加现存条目Add new profile添加条目Add...所有文件下次不再提示.确定要删除此项吗?确定要删除这些项目?附件文档(%d)附件:附件文档(%s)附件文档...内容:书签名称:收藏筛选器Bug 追踪器By: 抄送:CSV Export: %sCSV Import: %sCSV 参数连机(_O)取消与服务器的连接Cancel savingCheck URL: %sCheck Version清除Close关闭标签收起所有收起电子邮件程序命令行对比并行操作异常连接数据服务器连接错误! 用户名或密码有误!将URL复制到粘贴板复制URL(_U)...复制无法连接服务器新建项目新建项目 新建一行新建关联Bug 已提交备案创建日期创建日期:创建者创建者:剪切服务标识:日期格式删除删除选择项 分隔符:显示格式日期显示格式显示继续此项操作 ?Download邮件发送用电子邮件发送报表用电子邮件发送...编辑设置用户偏好...编辑所选条目编辑...编辑界面邮件电子邮件相关设置编码:错误打开CSV出错 !处理数值 %s 时出错错误:异常:展开所有展开展开/收起False快速切换标签获取服务列表...列名数据文件:查找字体颜色格式模糊高:数据服务器:主机:标识标识:图片尺寸图片尺寸过大 !图片服务器版本与客户端不兼容快捷键最近更改日期:最近更改:执行操作替换变量列表:限制限制:跳过行:链接列表项相关登录月Manage...标定删除选择模型:修改日期修改者月视图光标移动下移下移一页移到底部左移上一级右移移到顶端上移上移一页名称新建向后后一项下一个文本No没有定义任何操作 !没有其他可翻译语言!无符合条件的数据.注释(%d)注释(%s)注释...OK打开打开过滤器打开关联项目打开关联项打开报表打开日历打开条目 打开...打开. 查找关联操作失败! 相关错误信息: %s替换设定 '%s' ?PDA ModePNG 图片格式 (*.png)密码:粘贴预校验偏好偏好向前前一项上一个文本打印打印报表打印...配置列表数据服务配置器配置:Quit限定符:保存成功.所选项目未删除成功.项目已成功删除关联关联...关联操作刷新/撤销删除"%s"删除 Remove selected profile删除所选条目删除选择项 移除书签报告(_R)...报告Bug报告...版本版本:保存另存为另存为...保存导航状态保存窗体大小保存项目Save your current version查找查找 %s查询限制...数据查询...查找条目 See the modified version选择选择颜色选择版本全选选择上一级选择一项操作选择...选择/激活当前行选择Show active records显示筛选器书签Show inactive records显示纯文本显示版本...开启拼写检查主题:切换切换视图文本相关该操作需要关闭打开的项目 是否继续?已有其他用户报告相同bug. 用户名已加入通知列表,将随时接收相关信息无法获得"%s" 的值记录有改动, 是否保存?This record has been modified while you were editing it.收件人:今天切换状态切换状态翻译视图翻译树形导航TrueUnable to check for new version无法删除向导 %s无法获取视图树状态: %s无法找到“ %s ”的匹配项无法设置语言地域 %s无法设置视图树状态无法写入配置文件 %s!回滚删除项 未知取消删除选择全不选用户:用户名:用户名:值日志(_V)...周周视图导出设定的名称宽:向导当前处理的是项目的副本.覆写年是选择需要操作的项目必须先选择要导入的文件!请先保存已翻译条目,再增加新翻译 !已选择:操作(_A)...添加(_A)自动设置(_A)取消(_C)清除(_C)关闭标签页(_C)复制(_C)URL删除设定(_D)删除(_D)...复制(_D)邮件发送(_E)...导出数据(_X)导入数据(_I)新建(_N)向后(_N)注释(_N)...向前(_P)打印(_P)...关联(_L)...刷新/撤销(_R)删除(_R)报告(_R)...保存(_S)保存设定(_S)查找(_S)切换视图(_S)日开发模式回退前进时INFO级别记录日志分modularity, scalability and security下年度上年度秒备选配置文件设置日志级别: DEBUG, INFO, WARNING, ERROR, CRITICAL设置登录用户设置服务器名称:端口号ttranslator-credits星期ytryton-5.0.17/tryton/data/locale/sl/0000755000175000017500000000000013571264253016610 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/sl/LC_MESSAGES/0000755000175000017500000000000013571264253020375 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/sl/LC_MESSAGES/tryton.po0000644000175000017500000010710313463252532022273 0ustar cedced00000000000000# Slovenian (Slovenia) translations for tryton. # Copyright (C) 2010 B2CK # This file is distributed under the same license as the tryton project. # Venceslav Vezjak , 2010. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "določi alterntivno konfiguracijsko datoteko" #: tryton/config.py:77 msgid "development mode" msgstr "Razvijalski način" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "beleženje vsega na INFO ravni" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "določi nivo beleženja: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "določi uporabniško ime" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "določi ime in vrata strežniškega gostitelja" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "Ni možno zapisati konfiguracijske datoteke %s." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Ni možno nastaviti krajevnih nastavitev %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" # ? #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Izberi ukrep" #: tryton/action/main.py:193 msgid "No action defined." msgstr "Nobenega ukrepa ni določenega." #: tryton/common/button.py:54 msgid "By: " msgstr "Od: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Izbira" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Prekliči" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Vaša izbira:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Izberi" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Shrani" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Shrani kot..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Vedno prezri to opozorilo." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Ali želite nadaljevati?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Da" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Izjema sočasnega izvajanja" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Primerjaj" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Vseeno zapiši" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Napaka programa." #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Prijava programske napake" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Napaka: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Za prijavo programskih napak morate imeti odprt račun pri %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Sledilnik programskih napak" #: tryton/common/common.py:811 msgid "User:" msgstr "Uporabnik:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Geslo:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Drugi uporabnik je že prijavil enako programsko napako.\n" "Zaradi obveščanja je vaše uporabniško ime dodano na seznam te programske napake" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Evidentirana je nova programska napaka z ID " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Napaka pri povezavovanju.\n" "Napačno uporabniško ime ali geslo." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Izjema:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Išči..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Ustvari..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Vrednost" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Prikazana vrednost" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Oblika" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Oblika prikaza" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Odpri koledar" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Oblika datuma" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Prikazana oblika datuma" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "d" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Da" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "t" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Ne" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Uredi ..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Priponke..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Zabeležke ..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "_Ukrepi..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "_Veze..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Poročila..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "_Elektronska pošta..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "_Izpis..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "l" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "t" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "u" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Nastavitve..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_Orodna vrstica" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Privzeto" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "Bese_dilo in ikone" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Besedilo" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_Ikone" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "O_brazec" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Shrani širino/višino" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Shrani stanje drevesa" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Hitri premik" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Črkovanje" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Omejitev iskanja..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_Epošta..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Možnosti" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Bližnjice na tipkovnici..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_Vizitka..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Pomoč" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Brez rezultatov." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "P_riljubljeno" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Ukrep" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Za naslednji ukrep morajo biti vsi zavihki zaprti.\n" "Ali želite nadaljevati?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Zapri zavihek" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Priponke (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Urejevalnik profilov" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Strežnik:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Podatkovna baza:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Pridobivanje seznama podatkovnih baz" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Uporabniško ime:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Nezdružljiva inačica strežnika" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Ni se možno povezati s strežnikom" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Prijava" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Prekliči" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Prekliči povezavo do Tryton strežnika" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "P_oveži" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Poveži se s Tryton strežnikom" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Strežnik in podatkovna baza" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Uporabnik:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Epošta" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Nastavitve poštnega odjemalca" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Ukazna vrstica:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Opis možnih prostornikov:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Za:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "Kp:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Zadeva:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Vsebina:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Priponka:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Priponka(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Zabeležka(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "En zapis mora biti izbran." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Ustvaril:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Ustvarjeno:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Nazadnje popravil:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Nazadnje popravljeno:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Model:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Ali res želiš izbrisati ta zapis?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Ali res želiš izbrisati te zapise?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Zapisi niso izbrisani." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Zapisi izbrisani." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Trenutno se dela na podvojenih zapisih." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Zapis shranjen." #: tryton/gui/window/form.py:485 msgid " of " msgstr " od " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Ta zapis je bil spremenjen,\n" "ga želiš shraniti?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Zaženi ukrep" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Veza" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Odpri vezo" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Poročila" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Odpri poročilo" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Pošlji" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Pošlji poročilo" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Tisk" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Izpis poročila" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Kopirak URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Kopiraj URL na odložišče" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Neznano" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Omejitev" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Nastavitev omejitev iskanja" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Omejitev:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Zabeležke (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Nastavitve" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Uredi uporabniške nastavitve" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Nastavitev" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Različica" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Izberi različico" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Različica:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Bližnjice" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Bližnjice za urejanje" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Izreži vsebino" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Kopiraj vsebino" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Prilepi vsebino" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Naslednje polje" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Prejšnje polje" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Bližnjice za veze" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Dodajanje nove veze" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Urejanje/iskanje veze" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Bližnjice za postavke" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Dodajanje postavke" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Urejenje postavke" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Postavka označena za brisanje" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Postavka neoznačena za brisanje" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Vnašanje podatkov" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Premiki" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Premik desno" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Premik levo" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Premik gor" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Premik dol" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Premik za eno stran gor" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Premik za eno stran dol" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Premik na začetek" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Premik na konec" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Premik na nadrejeno vejo" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Izberi vse" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Odznači vse" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Izberi nadrejeno vejo" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Izberi/Aktiviraj trenutno vrstico" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Vklopi/Izklopi izbor" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Razširi/Skrči" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Razširi vrstico" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Skrči vrstico" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Razširi/Skrči vrstico" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Skrči vse vrstice" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Razširi vse vrstice" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Drevesni pogled" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Preklopi po_gled" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Preklopi pogled" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "P_rejšnji" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Prejšnji zapis" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Nas_lednji" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Naslednji zapis" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Išči" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nov" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Ustvari nov zapis" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Shrani" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Shrani ta zapis" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Ponovno naloži/Razvel_javi" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Ponovno naloži/Razveljavi" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Podvoji" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Z_briši..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Poglej dnevni_k..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Prikaži različice ..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "P_riponke..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Dodaj priponko zapisu" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Zabeležke ..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "K zapisu dodaj zabeležko" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Ukrepi..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Veze..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "P_oročila..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_Elektronska pošta..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Tiskaj..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "I_zvozi podatke..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Uv_ozi podatke..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "_Kopiraj URL ..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Zapri zavi_hek" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Vsa polja" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Dodaj" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Odstrani" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Počisti" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Izbrana polja" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV parametri" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Ločilo:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Narekovaj:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Kodiranje:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Naziv polja" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Shrani izvoz" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Izbriši izvoz" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Predefinirani izvozi" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Naziv" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Odpri" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Dodaj imena _polj" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (niz)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (ime modela)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (ime zapisa)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Kako se imenuje ta izvoz?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Prepišem definicijo izvoza '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "%d zapis shranjen." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "%d zapisov shranjenih." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Operacija odpovedala.\n" "Sporočilo napake:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Napaka" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Povezava" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Zbriši" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Novo" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Preklopi" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Prejšnji" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Naslednji" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Dodaj" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Odstrani " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Ustvari nov zapis " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Zbriši izbran zapis " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Povrni izbran zapis " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_Samozaznava" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Datoteka za uvoz:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Odpri..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Izpuščene vrstice:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Najprej morate izbrati datoteke za uvažanje." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Napaka pri odpiranju CSV datoteke" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Napaka obdelave datoteke pri polju %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "%d zapis uvožen." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "%d zapisov uvoženih." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Išči" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Išči %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Čarovnik" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Ustvaril" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Ustvarjeno" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Popravil" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Popravljeno" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy, python-format msgid "Unable to get view tree state for %s" msgstr "Ni možno nastaviti stanja obrazca %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Ni možno nastaviti stanja obrazca" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "Polje \"%s\" ni veljavno glede na svojo domeno" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "Polje \"%s\" je obvezno" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Vrednosti v polju \"%s\" niso veljavne" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Predpreverjanje" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Velikost slike" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Širina:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Velikost:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG slika (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Shrani kot" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "Slika je prevelika." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Odpri filtre" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Prikaži zaznamke filtrov" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Odstrani ta zaznamek" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Shrani ta filter" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Ime zaznamka:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Najdi" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Danes" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "pojdi nazaj" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "pojdi naprej" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "Prejšnje leto" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "naslednje leto" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Tedensko" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Mesečno" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Teden" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Izberi ..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Počisti" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Vse datoteke" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Prikaži navadno besedilo" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Dodaj vrednost" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Odstrani \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Slike" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Dodaj obstoječi zapis" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Odstrani izbran zapis " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Odpri zapis " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 #, fuzzy msgid "Clear the field " msgstr "Počisti zapis " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Poišči zapis " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Odstrani izbran zapis" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Uredi izbran zapis " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Ospredje" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Izberi barvo" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Prevod" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Uredi" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Nejasno" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Pred dodajanjem prevodov morate zapis shraniti." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "Drugih jezikov ni na voljo." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Prevedi pogled" tryton-5.0.17/tryton/data/locale/sl/LC_MESSAGES/tryton.mo0000644000175000017500000004077013571264250022276 0ustar cedced00000000000000N ),=Qbw (9Ue lw{  # %Dj y & A O ]kq w  + *7Jj~    *6= Zet  '- DNT&k     &-3;W]` do" !$*1@E\b dn      ,4HMQ V bnq    %:B#W{     ! . 7 ? N W \ h v     !!9!N! U! `!j! s!}!! !!!!!! !! ""."G"N"]" o" z"" "" """"##1#@#I# P#\#Is#}# ;$5\$8$$$ $$$ % %%%;%%V%|%%%%%% & &*& 0&:& @&N& S& ]&~&&(& &&&&%&7 'E' U'a' f's'{' ' '' ' ' ''''' ' ' ( ( ((( 0(;( A(N( V(c(e(v( ~(( (($( ( (((< )H) _))))))[+,`++++++++ ,,&,+,.,3,6,:,<,M,b,~,,, ,, ,,,, -#-:-J-Y- `-m-#-$- - - - -. ..*.F.K.O.^. m.{.'. . . ... ..// %///K/>k////#/ 0040G0,[0 0 00 000 0001 1141G1`1i1q11111 1111 2%2!,2&N2u2~22222 2$2 22333%3 -373 T3_3b3f3u33!3 333 334 4!464?4V4^4 `4j44 4444 444 44 55 .595Q5W5 \5f5v5555555566 6 6%676 G6U6f6o6+6!666667 7 7 +757E7U7Z7 j7t7{777 77777778 8+8:8R8h88 88 8 8 88 8 899.9>9X9 _9i99999 99 99 : :!%:G:N:b:|::: :::::K;S;$;0<86<o<s<y<<<<<<<<% =+0="\=/=== = = = >>'>0>C>I>R>l> u>'>>>>>->/? 4? B?M? T? a? l?v? ?? ?????? ?@ @ @)@2@ N@ X@f@ n@|@@@@ @ @@@@$@ AA)A,+A>XAA.AAAAA of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearCloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: sl Language-Team: sl Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 od Polje "%s" ni veljavno glede na svojo domenoPolje "%s" je obvezno%d zapis uvožen.%d zapis shranjen.%d zapisov uvoženih.%d zapisov shranjenih.%s (%s)%s (ime modela)%s (ime zapisa)%s (niz)%s%%, ,….....:Vsa poljaIzbrana poljaPredefinirani izvoziUstvari...Išči...A new version is available!P_riponke...Ukrep_Ukrepi...DodajDodaj imena _poljK zapisu dodaj zabeležkoDodaj priponko zapisuDodaj obstoječi zapisAdd new profileDodaj vrednostAdd...Vse datotekeVedno prezri to opozorilo.Ali res želiš izbrisati ta zapis?Ali res želiš izbrisati te zapise?Priponka(%d)Priponka:Priponke (%s)Priponke...Vsebina:Ime zaznamka:Shrani ta filterSledilnik programskih napakOd: Kp:CSV Export: %sCSV Import: %sCSV parametriP_ovežiPrekliči povezavo do Tryton strežnikaCancel savingCheck URL: %sCheck VersionPočistiCloseZapri zavihekSkrči vse vrsticeSkrči vrsticoUkazna vrstica:PrimerjajIzjema sočasnega izvajanjaPoveži se s Tryton strežnikomNapaka pri povezavovanju. Napačno uporabniško ime ali geslo.Kopiraj URL na odložišče_Kopiraj URL ...Kopiraj vsebinoNi se možno povezati s strežnikomUstvari nov zapisUstvari nov zapis Dodajanje postavkeDodajanje nove vezeEvidentirana je nova programska napaka z ID UstvarjenoUstvarjeno:UstvarilUstvaril:Izreži vsebinoPodatkovna baza:Oblika datumaZbrišiZbriši izbran zapis Ločilo:Oblika prikazaPrikazana oblika datumaPrikazana vrednostAli želite nadaljevati?DownloadPošljiPošlji poročilo_Elektronska pošta...UrediUredi uporabniške nastavitveUredi izbran zapis Uredi ...Vnašanje podatkovEpoštaNastavitve poštnega odjemalcaKodiranje:NapakaNapaka pri odpiranju CSV datotekeNapaka obdelave datoteke pri polju %s.Napaka: Izjema:Razširi vse vrsticeRazširi vrsticoRazširi/SkrčiNeHitri premikPridobivanje seznama podatkovnih bazNaziv poljaDatoteka za uvoz:NajdiOspredjeOblikaNejasnoVelikost:Strežnik in podatkovna bazaStrežnik:IDID:Velikost slikeSlika je prevelika.SlikeNezdružljiva inačica strežnikaBližnjiceNazadnje popravljeno:Nazadnje popravil:Zaženi ukrepOpis možnih prostornikov:OmejitevOmejitev:Izpuščene vrstice:PovezavaBližnjice za postavkePrijavaMManage...Postavka označena za brisanjeModel:PopravljenoPopravilMesečnoPremikiPremik dolPremik za eno stran dolPremik na konecPremik levoPremik na nadrejeno vejoPremik desnoPremik na začetekPremik gorPremik za eno stran gorNazivNovoNaslednjiNaslednji zapisNaslednje poljeNoNobenega ukrepa ni določenega.Drugih jezikov ni na voljo.Brez rezultatov.Zabeležka(%d)Zabeležke (%s)Zabeležke ...OKOdpriOdpri filtreOdpri vezoUrejenje postavkeOdpri poročiloOdpri koledarOdpri zapis Odpri...Urejanje/iskanje vezeOperacija odpovedala. Sporočilo napake: %sPrepišem definicijo izvoza '%s'?PDA ModePNG slika (*.png)Geslo:Prilepi vsebinoPredpreverjanjeNastavitevNastavitvePrejšnjiPrejšnji zapisPrejšnje poljeTiskIzpis poročila_Izpis...ProfilUrejevalnik profilovProfil:QuitNarekovaj:Zapis shranjen.Zapisi niso izbrisani.Zapisi izbrisani.Veza_Veze...Bližnjice za vezePonovno naloži/RazveljaviOdstrani "%s"Odstrani Remove selected profileOdstrani izbran zapisOdstrani izbran zapis Odstrani ta zaznamekPoročilaPrijava programske napakePoročila...RazličicaRazličica:ShraniShrani kotShrani kot...Shrani stanje drevesaShrani širino/višinoShrani ta zapisSave your current versionIščiIšči %sNastavitev omejitev iskanjaOmejitev iskanja...Poišči zapis See the modified versionIzberiIzberi barvoIzberi različicoIzberi vseIzberi nadrejeno vejoIzberi ukrepIzberi ...Izberi/Aktiviraj trenutno vrsticoIzbiraShow active recordsPrikaži zaznamke filtrovShow inactive recordsPrikaži navadno besediloPrikaži različice ...ČrkovanjeZadeva:PreklopiPreklopi pogledBližnjice za urejanjeZa naslednji ukrep morajo biti vsi zavihki zaprti. Ali želite nadaljevati?Drugi uporabnik je že prijavil enako programsko napako. Zaradi obveščanja je vaše uporabniško ime dodano na seznam te programske napakeVrednosti v polju "%s" niso veljavneTa zapis je bil spremenjen, ga želiš shraniti?This record has been modified while you were editing it.Za:DanesRazširi/Skrči vrsticoVklopi/Izklopi izborPrevedi pogledPrevodDrevesni pogledDaUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sNi možno nastaviti krajevnih nastavitev %sNi možno nastaviti stanja obrazcaNi možno zapisati konfiguracijske datoteke %s.Povrni izbran zapis NeznanoPostavka neoznačena za brisanjeOdznači vseUporabnik:Uporabnik:Uporabniško ime:VrednostPoglej dnevni_k...TedenTedenskoKako se imenuje ta izvoz?Širina:ČarovnikTrenutno se dela na podvojenih zapisih.Vseeno zapišilDaEn zapis mora biti izbran.Najprej morate izbrati datoteke za uvažanje.Pred dodajanjem prevodov morate zapis shraniti.Vaša izbira:_Ukrepi..._Dodaj_Samozaznava_Prekliči_PočistiZapri zavi_hek_Kopirak URL_Izbriši izvozZ_briši..._Podvoji_Elektronska pošta...I_zvozi podatke...Uv_ozi podatke..._NovNas_lednji_Zabeležke ...P_rejšnji_Tiskaj..._Veze...Ponovno naloži/Razvel_javi_OdstraniP_oročila..._Shrani_Shrani izvoz_IščiPreklopi po_gleddRazvijalski načinpojdi nazajpojdi naprejubeleženje vsega na INFO ravnimmodularity, scalability and securitynaslednje letoPrejšnje letosdoloči alterntivno konfiguracijsko datotekodoloči nivo beleženja: DEBUG, INFO, WARNING, ERROR, CRITICALdoloči uporabniško imedoloči ime in vrata strežniškega gostiteljattranslator-creditstdtryton-5.0.17/tryton/data/locale/cs/0000755000175000017500000000000013571264253016577 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/cs/LC_MESSAGES/0000755000175000017500000000000013571264253020364 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/cs/LC_MESSAGES/tryton.po0000644000175000017500000010522113463252532022261 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "zadejte alternativní konfigurační soubor" #: tryton/config.py:77 msgid "development mode" msgstr "" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:85 msgid "specify the login user" msgstr "zadejte uživatelské jméno" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "zadejte název hostitele pro server" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Nelze zapsat konfigurační soubor %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Nemohu nastavit lokalizaci %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Vyberte akci" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Žádná akce není definována!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Výběr" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Zrušit" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Váš výběr:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 #, fuzzy msgid "Save" msgstr "_Uložit" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Uložit jako..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "zadejte alternativní konfigurační soubor" #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Výjimka při souběhu" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Porovnat" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Přesto zapsat" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Chyba aplikace!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Nahlásit chybu" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Chyba:" #: tryton/common/common.py:768 #, python-format, fuzzy msgid "To report bugs you must have an account on %s" msgstr "Pro hlášení chyb musíte mít účet na %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Sledování chyb" #: tryton/common/common.py:811 msgid "User:" msgstr "Uživatel:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Heslo:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Ta samá chyba již byla nahlášena jiným uživatelem.\n" "Vaše uživatelské jméno bylo přidáno na její seznam." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Založena nová chyba s ID" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Chyba při spojení!\n" "Špatné uživatelské jméno nebo heslo!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Výjimka:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "" #: tryton/common/completion.py:27 msgid "Create..." msgstr "" #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "Nepravda" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "_Normální" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "Otevřít kalendář" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Pravda" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Nepravda" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "Konec..." #: tryton/common/popup_menu.py:89 #, fuzzy msgid "Attachments..." msgstr "Příloha:" #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 #, fuzzy msgid "Actions..." msgstr "Akce..." #: tryton/common/popup_menu.py:108 #, fuzzy msgid "Relate..." msgstr "_Odstranit..." #: tryton/common/popup_menu.py:109 #, fuzzy msgid "Report..." msgstr "Importovat data..." #: tryton/common/popup_menu.py:110 #, fuzzy msgid "E-Mail..." msgstr "_Email..." #: tryton/common/popup_menu.py:111 #, fuzzy msgid "Print..." msgstr "_Tisk..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "" #: tryton/common/timedelta.py:27 msgid "M" msgstr "" #: tryton/common/timedelta.py:28 msgid "w" msgstr "" #: tryton/common/timedelta.py:29 msgid "d" msgstr "" #: tryton/common/timedelta.py:30 msgid "h" msgstr "" #: tryton/common/timedelta.py:31 msgid "m" msgstr "" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Vlastnosti..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "Nástrojová lišta" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Výchozí" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_Text a ikony" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Text" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_Ikony" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "Formulář" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Kontrola pravopisu" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "" #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_Email..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Volby" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Klávesové zkratky..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_O programu..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "Nápo_věda" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "" #: tryton/gui/main.py:447 msgid "Favorites" msgstr "" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Akce" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Zavřít záložku" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Příloha(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 #, fuzzy msgid "Host:" msgstr "Port:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Databáze:" #: tryton/gui/window/dblogin.py:108 #, fuzzy msgid "Fetching databases list" msgstr "Nastavení nové databáze:" #: tryton/gui/window/dblogin.py:122 #, fuzzy msgid "Username:" msgstr "Uživatelské jméno:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 #, fuzzy msgid "Incompatible version of the server" msgstr "Verze serveru není kompatibilní!" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 #, fuzzy msgid "Could not connect to the server" msgstr "Nelze se spojit se serverem!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Přihlášení" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Zrušit" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Zrušit spojení k Tryton serveru." #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "_Připojit" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Připojit k Tryton serveru" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Uživatelské jméno:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Email" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Poslat nastavení programu emailem" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Příkazový řádek:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Seznam dostupných náhrad:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Komu:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Předmět: " #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Tělo:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Příloha:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Příloha(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Musíte vybrat právě jeden záznam!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Vytvořeno uživatelem:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Datum vytvoření:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Poslední úpravu provedl:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Datum poslední úpravy:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Model:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Opravdu chcete odstranit tento záznam?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Opravdu chcete odstranit tyto záznamy?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Záznamy neodstraněny!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Záznamy odstraněny!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Nyní pracujete s duplicitním záznamem!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Záznam uložen!" #: tryton/gui/window/form.py:485 msgid " of " msgstr " z " #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Tento záznam byl upraven\n" "chcete ho uložit?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Relate" msgstr "_Vytvořit" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Open related records" msgstr "Otevřít záznam" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Report" msgstr "Sestavy" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Open report" msgstr "Otevřít záznam" #: tryton/gui/window/form.py:563 #, fuzzy msgid "E-Mail" msgstr "Email" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Tisk" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Neznámý" #: tryton/gui/window/limit.py:20 #, fuzzy msgid "Limit" msgstr "Omezit:" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "" #: tryton/gui/window/limit.py:40 #, fuzzy msgid "Limit:" msgstr "Omezit:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Nastavení" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Upravit uživatelské nastavení" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Nastavení" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "Předchozí" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "Výběr" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "Předchozí" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Klávesové zkratky" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Zkratky pro texty" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Vyjmout vybraný text" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Kopírovat vybraný text" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Vložit vybraný text" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Další prvek" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Předchozí prvek" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Zkratky pro relace" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Vytvořit novou relaci" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Otevřít/prohledat relaci" #: tryton/gui/window/shortcuts.py:44 #, fuzzy msgid "List Entries Shortcuts" msgstr "Zkratky pro texty" #: tryton/gui/window/shortcuts.py:45 #, fuzzy msgid "Create new line" msgstr "Vytvořit novou relaci" #: tryton/gui/window/shortcuts.py:46 #, fuzzy msgid "Open relation" msgstr "Otevřít/prohledat relaci" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Editovací prvky" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Přepnout pohled" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "Přepnout pohled" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Předchozí" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Předchozí záznam" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Následující" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Následující záznam" #: tryton/gui/window/tabcontent.py:61 #, fuzzy msgid "_Search" msgstr "Hledat" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nový" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Vytvořit nový záznam" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Uložit" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Uložit tento záznam" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Obnovit/Zpět" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "Obnovit/Zpět" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplikovat" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Odstranit..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Zobrazit záznamy..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 #, fuzzy msgid "A_ttachments..." msgstr "Příloha:" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Přidat přílohu k záznamu" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "Akce..." #: tryton/gui/window/tabcontent.py:123 #, fuzzy msgid "_Relate..." msgstr "_Odstranit..." #: tryton/gui/window/tabcontent.py:129 #, fuzzy msgid "_Report..." msgstr "Importovat data..." #: tryton/gui/window/tabcontent.py:134 #, fuzzy msgid "_E-Mail..." msgstr "_Email..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Tisk..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Exportovat data" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Importovat data..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Zavřít kartu" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Všechna pole" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Přidat" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Odstranit" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Vymazat" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parametry CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Kódování:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Jméno pole" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Uložit exportu" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Smazat exportu" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Předdefinované exporty" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Otevřít" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Přidat jména polí" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d záznam uložen!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d záznamů uloženo!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Operace selhala.\n" "Chybová zpráva:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Chyba" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Odkaz" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Smazat" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "_Nový" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Přepnout" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Předchozí" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Další" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Přidat" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 #, fuzzy msgid "Create a new record " msgstr "Vytvořit nový záznam" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 #, fuzzy msgid "Delete selected record " msgstr "Smazat vybraný záznam" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 #, fuzzy msgid "Undelete selected record " msgstr "Smazat vybraný záznam" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Automatická detekce" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Soubor k importu:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Otevřít..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Vynechané řádky:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Nejprve je nutné vybrat soubor pro import!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Chyba při otevírání CSV souboru" #: tryton/gui/window/win_import.py:138 #, python-format, python-format, python-format, fuzzy, python-format msgid "Error processing the file at field %s." msgstr "Chyba při zpracování souboru u pole %s.\n" #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d záznam načten!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d záznamů načteno!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Hledat" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Průvodce" #: tryton/gui/window/view_form/screen/screen.py:206 #, fuzzy msgid "ID" msgstr "Najít" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "Vytvořeno uživatelem:" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "Datum vytvoření:" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "Datum poslední úpravy:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "Datum poslední úpravy:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "Nemohu nastavit lokalizaci %s" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "Nemohu nastavit lokalizaci %s" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Velikost obrázku" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Šířka:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Výška:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Obrázek PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Uložit jako" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Rozměry obrázku jsou příliš velké!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Najít" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "Tělo:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "Přepnout pohled" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "Přepnout pohled" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Vymazat" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Všechny soubory" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Obrázky" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 #, fuzzy msgid "Add existing record" msgstr "Uložit tento záznam" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 #, fuzzy msgid "Remove selected record " msgstr "Smazat vybraný záznam" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Otevřít záznam" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 #, fuzzy msgid "Search a record " msgstr "Hledat záznam" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 #, fuzzy msgid "Remove selected record" msgstr "Smazat vybraný záznam" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 #, fuzzy msgid "Edit selected record " msgstr "Upravit vybraný záznam" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 #, fuzzy msgid "Translation" msgstr "Přidat překlad" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Musíte uložit záznam před přidáváním překladů!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Jiný jazyk není k dispozici!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Přeložit pohled" tryton-5.0.17/tryton/data/locale/cs/LC_MESSAGES/tryton.mo0000644000175000017500000003023413571264250022257 0ustar cedced00000000000000)-5E Vbgjl~ "B R\ cm#%  $)-<KZ&c       +E ]j}   %;Kc lz   ' - : DO_ dou}  !$38> @Ja h t~     / 8CLO Tai~    $19HQ Vb }   . 5?Ue~    4DVenuI} T8u   %'Mem       " - 7 BM]mr x      $  . 8FH<f~ )         !(!H!Y!j!!!!!!! !!!+"'<"'d" " """"""""" # #"!# D# R# `#n#v#### #####$ -$:$S$k$$$$$ $ $$ $%%,%<%T% ]%k% p%%%"% %%#%& && #&.&>& G& T& ^&j&|& &&&&&&&&&' '.'J'^'d's' u''' ' ''' '' ' (((*(/(6(>( U(c(f(w( ((( ( ( ((((())+) :) E) P)\)p)) ))))) )) ) )) ** .*;*K*[*m*** ****** + + + )+3+O+W+k+++++ + ++I+sB, ,8,- -!-2- D-N-U-u-%-- -- -. .%.:. ?. `. j.t........ . . ... // / */7/ @/ N/Y/b/s/u// // //$/ / //+/<)0f00000 of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!ActionAddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCreate a new recordCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEditEdit User PreferencesEdition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationID:Image SizeImagesKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:Lines to Skip:LinkLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportProfileProfile EditorProfile:QuitQuote char:Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove this bookmarkReport BugSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnknownUnmark line for deletionUnselect allUser name:User:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Reload/Undo_Remove_Save_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: cs Language-Team: cs Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 z "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:Všechna poleFields selectedPředdefinované exportyCreate...Search...A new version is available!AkcePřidatPřidat jména políAdd a note to the recordPřidat přílohu k záznamuAdd new profileAdd valueAdd...Všechny souboryzadejte alternativní konfigurační souborOpravdu chcete odstranit tento záznam?Opravdu chcete odstranit tyto záznamy?Příloha(%d)Příloha:Tělo:Bookmark Name:Bookmark this filterSledování chybBy: CC:CSV Export: %sCSV Import: %sParametry CSV_PřipojitZrušit spojení k Tryton serveru.Cancel savingCheck URL: %sCheck VersionVymazatClear the field CloseZavřít záložkuCollapse all rowsCollapse rowPříkazový řádek:PorovnatVýjimka při souběhuPřipojit k Tryton serveruCopy URL into clipboardCopy _URL...Kopírovat vybraný textVytvořit nový záznamVytvořit novou relaciZaložena nová chyba s IDDatum vytvoření:Vytvořeno uživatelem:Vyjmout vybraný textDatabáze:Date FormatSmazatDelimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEditUpravit uživatelské nastaveníEditovací prvkyEmailPoslat nastavení programu emailemKódování:ChybaChyba při otevírání CSV souboruChyba:Výjimka:Expand all rowsExpand rowExpand/CollapseNepravdaFast TabbingFavoritesJméno poleSoubor k importu:NajítForegroundFuzzyVýška:Host / Database informationID:Velikost obrázkuObrázkyKlávesové zkratkyDatum poslední úpravy:Poslední úpravu provedl:Launch actionSeznam dostupných náhrad:Vynechané řádky:OdkazPřihlášeníMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageName_NovýDalšíNásledující záznamDalší prvekNoNo result found.Note(%d)Notes (%s)Notes...OKOtevřítOpen filtersOtevřít...Otevřít/prohledat relaciOverride '%s' definition?PDA ModeObrázek PNG (*.png)Heslo:Vložit vybraný textPre-validationNastaveníNastaveníPředchozíPředchozí záznamPředchozí prvekTiskPrint reportProfileProfile EditorProfile:QuitQuote char:Zkratky pro relaceRemove "%s"Remove Remove selected profileRemove this bookmarkNahlásit chybuUložit jakoUložit jako...Save Tree StateSave Width/HeightUložit tento záznamSave your current versionHledatSearch %sSearch Limit SettingsSearch Limit...See the modified versionSelectSelect a colorSelect allSelect parentVyberte akciSelect...Select/Activate current rowVýběrShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Kontrola pravopisuPředmět: PřepnoutZkratky pro textyThe following action requires to close all tabs. Do you want to continue?Ta samá chyba již byla nahlášena jiným uživatelem. Vaše uživatelské jméno bylo přidáno na její seznam.The values of "%s" are not validThis record has been modified while you were editing it.Komu:Toggle rowToggle selectionPřeložit pohledTree viewPravdaUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sNemohu nastavit lokalizaci %sNeznámýUnmark line for deletionUnselect allUživatelské jméno:Uživatel:Zobrazit záznamy...WeekWhat is the name of this export?Šířka:PrůvodcePřesto zapsatYYesVáš výběr:Akce..._Přidat_Zrušit_Zavřít kartu_Copy URL_Odstranit..._DuplikovatExportovat dataImportovat data..._Nový_Následující_Notes..._Předchozí_Tisk...Obnovit/Zpět_Odstranit_UložitPřepnout pohledddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearszadejte alternativní konfigurační souborspecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALzadejte uživatelské jménottranslator-creditswytryton-5.0.17/tryton/data/locale/pl/0000755000175000017500000000000013571264253016605 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/pl/LC_MESSAGES/0000755000175000017500000000000013571264253020372 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/pl/LC_MESSAGES/tryton.po0000644000175000017500000010777613463252532022310 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "podaj alternatywny plik konfiguracji" #: tryton/config.py:77 msgid "development mode" msgstr "tryb dewelopera" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "rejestrowanie wszystkiego na poziomie INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "podaj poziom rejestrowania: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "podaj login użytkownika" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "podaj nazwę:port serwera" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "Nie można zapisać pliku konfiguracyjnego %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Nie można ustawić lokalizacji %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Wybierz akcję" #: tryton/action/main.py:193 msgid "No action defined." msgstr "Brak zdefiniowanej akcji." #: tryton/common/button.py:54 msgid "By: " msgstr "Przez: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Zaznaczenie" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 msgid "Cancel" msgstr "Anuluj" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "OK" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Twoje zaznaczenie:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Wybierz" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Zapisz" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Zapisz jako..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Zawsze ignoruj takie ostrzeżenie." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Czy chcesz kontynuować?" #: tryton/common/common.py:643 msgid "No" msgstr "Nie" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Tak" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Wyjątek równoczesnego zapisu danych" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "Ten rekord został zmodyfikowany w trakcie twojej edycji." #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "Anuluj zapis" #: tryton/common/common.py:696 msgid "Compare" msgstr "Porównaj" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "Zobacz zmienioną wersję" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Zapisz" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "Zapisz swoją bieżącą wersję" #: tryton/common/common.py:729 msgid "Application Error" msgstr "Błąd aplikacji" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Zgłoś błąd" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "Zamknij" #: tryton/common/common.py:751 msgid "Error: " msgstr "Błąd: " #: tryton/common/common.py:768 #, python-format msgid "To report bugs you must have an account on %s" msgstr "Aby zgłosić błędy musisz posiadać konto w %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Bug Tracker" #: tryton/common/common.py:811 msgid "User:" msgstr "Użytkownik:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Hasło:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Ten błąd został już zgłoszony przez innego użytkownika.\n" "Abyś był na bieżąco z informacjami o błędzie zostałeś dopisany do właściwej listy" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Nowe zgłoszenie o błędzie otrzymało ID " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Błąd połączenia.\n" "Niewłaściwa nazwa użytkownika lub hasło!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Wyjątek:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "Sprawdź URL: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "Nie można sprawdzić dostępności nowej wersji" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Nowa wersja jest dostępna!" #: tryton/common/common.py:942 msgid "Download" msgstr "Pobierz" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Szukaj..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Utwórz..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "Brak możliwości wyszukania uzupełnienia dla %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Wartość" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Wyświetlana wartość" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Format" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Wyświetl format" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Otwórz kalendarz" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Format daty" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Wyświetlany format daty" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "t" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Tak" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "p" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Nie" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Edycja..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Załączniki..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notatki..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Akcje..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Otwórz..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Utwórz raport..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Wyślij e-mail..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Wydrukuj..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "R" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "t" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "g" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 msgid "Preferences..." msgstr "Preferencje..." #: tryton/gui/main.py:127 msgid "Toolbar" msgstr "Pasek narzędzi" #: tryton/gui/main.py:128 msgid "Default" msgstr "Domyślnie" #: tryton/gui/main.py:129 msgid "Text and Icons" msgstr "Tekst i ikony" #: tryton/gui/main.py:130 msgid "Text" msgstr "Tekst" #: tryton/gui/main.py:131 msgid "Icons" msgstr "Ikony" #: tryton/gui/main.py:134 msgid "Form" msgstr "Formularz" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Zapamiętaj szerokość/wysokość" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Zapamiętaj stan drzewa" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Szybki tabulator" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Sprawdzanie pisowni" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "Tryb PDA" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Ograniczenie wyszukiwania..." #: tryton/gui/main.py:142 msgid "Email..." msgstr "E-mail..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Sprawdź wersję" #: tryton/gui/main.py:145 msgid "Options" msgstr "Opcje" #: tryton/gui/main.py:148 msgid "Keyboard Shortcuts..." msgstr "Skróty klawiszowe..." #: tryton/gui/main.py:149 msgid "About..." msgstr "O programie..." #: tryton/gui/main.py:150 msgid "Help" msgstr "Pomoc" #: tryton/gui/main.py:153 msgid "Quit" msgstr "Zakończ" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Nie znaleziono wyniku." #: tryton/gui/main.py:447 msgid "Favorites" msgstr "Ulubione" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "Zarządzaj..." #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Akcja" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Wykonanie polecenia wymaga zamknięcia wszystkich kart.\n" "Czy chcesz kontynuować?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Zamknij kartę" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "modułowość, skalowalność i bezpieczeństwo" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "Wojciech Warczakowski" #: tryton/gui/window/attachment.py:24 #, python-format msgid "Attachments (%s)" msgstr "Załączniki (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Edytor profili" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "Dodaj nowy profil" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "Usuń wybrany profil" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Host:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Baza danych:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Pobieranie listy baz danych" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Użytkownik:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Niewłaściwa wersja serwera" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Nie można połączyć się z serwerem" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Login" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "Anuluj" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Anuluj połączenie z serwerem Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "Połącz" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Połącz z serwerem Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Informacje o hoście / bazie danych" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Użytkownik:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "E-mail" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Ustawienia czytnika poczty" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Linia poleceń:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Lista dostępnych symboli zastępczych:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Do:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "DW:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Temat:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Treść:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Załącznik:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "Dodaj..." #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Załącznik(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Notatka(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Musisz wybrać jeden rekord." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Utworzył:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Data utworzenia:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Autor ostatniej modyfikacji:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Data ostatniej modyfikacji:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Model:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Czy na pewno usunąć wybrany rekord?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Czy na pewno usunąć wybrane rekordy?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Rekordy nie zostały usunięte." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Rekordy zostały usunięte." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Pracujesz na zduplikowanym(ch) rekordzie(ch)." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Rekord został zapisany." #: tryton/gui/window/form.py:485 msgid " of " msgstr " z " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Rekord został zmodyfikowany.\n" "Czy chcesz go zapisać?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Uruchom akcję" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Otwórz" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Otwórz powiązane rekordy" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Raport" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Otwórz raport" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Wyślij raport" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Wydruk" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Drukuj raport" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "Skopiuj adres URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Skopiuj adres URL do schowka" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Nieznany" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limit" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Ustawienia limitu wyszukiwania" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Limit:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notatki (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferencje" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Edytuj preferencje użytkownika" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferencje" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Rewizja" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Wybierz rewizję" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Rewizja:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Skróty klawiszowe" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Skróty dotyczące tekstu" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Wytnij zaznaczony tekst" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Skopiuj zaznaczony tekst" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Wklej zaznaczony tekst" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Następny widżet" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Poprzedni widżet" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Skróty dotyczące odniesień" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Utwórz nowe odniesienie" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Otwórz/Szukaj odniesienie" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Skróty dotyczące list" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Utwórz nowy wiersz" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Utwórz odnośnik" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Zaznacz wiersz do usunięcia" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Odznacz wiersz do usunięcia" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Widżety edycji" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Przesuń kursor" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Przesuń w prawo" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Przesuń w lewo" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Przesuń w górę" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Przesuń w dół" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Przesuń w górę o jedną stronę" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Przesuń w dół o jedną stronę" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Przesuń do góry" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Przesuń do dołu" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Przesuń do elementu nadrzędnego" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Zaznacz wszystko" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Odznacz wszystko" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Zaznacz element nadrzędny" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Zaznacz/Aktywuj bieżący wiersz" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Przełącz zaznaczenie" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Rozwiń/Zwiń" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Rozwiń wiersz" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Zwiń wiersz" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Przełącz wiersz" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Zwiń wszystkie wiersze" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Rozwiń wszystkie wiersze" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Widok drzewa" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Przełącz widok" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Przełącz widok" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "Poprzedni" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Poprzedni rekord" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Następny" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Następny rekord" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "Szukaj" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "Nowy" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Utwórz nowy rekord" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "Zapisz" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Zapisz rekord" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Odśwież/Przywróć" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Odśwież/Przywróć" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "Duplikuj" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Usuń..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Przeglądaj dziennik..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Pokaż rewizje..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Załączniki..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Dodaj załącznik do rekordu" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "Notatki..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Dodaj notatkę do rekordu" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "Akcje..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "Odnośnik..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "Raport..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "E-mail..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Wydruk..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Eksportuj dane..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Importuj dane..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Skopiuj adres URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Zamknij kartę" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Wszystkie pola" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "Dodaj" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "Usuń" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "Wyczyść" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Pola wybrane" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parametry CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Separator:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Znak cudzysłowa:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Kodowanie:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nazwa pola" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "Eksport do CSV: %s" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "Zapisz eksport" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "Usuń eksport" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Predefiniowane eksporty" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nazwa" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Otwórz" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Dodaj nazwy pól" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (string)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (model name)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (record name)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Jaka jest nazwa tego eksportu?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Czy nadpisać definicję '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format msgid "%d record saved." msgstr "%d rekord został zapisany." #: tryton/gui/window/win_export.py:330 #, python-format msgid "%d records saved." msgstr "%d rekordy zostały zapisane." #: tryton/gui/window/win_export.py:333 #, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Operacja nie powiodła się.\n" "Komunikat błędu:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Błąd" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Link" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Usuń" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Nowy" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Przełącz" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Poprzedni" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Następny" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Dodaj" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Usuń " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Utwórz nowy rekord " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Usuń zaznaczony rekord " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Przywróć zaznaczony rekord " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "Import z CSV: %s" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "Rozpoznaj" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Plik do zaimportowania:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Otwórz..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Wiersze do ominięcia:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Najpierw wybierz plik do zaimportowania." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Błąd otwarcia pliku CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Błąd przetwarzania pliku w polu %s." #: tryton/gui/window/win_import.py:198 #, python-format msgid "%d record imported." msgstr "Rekord %d został zaimportowany." #: tryton/gui/window/win_import.py:200 #, python-format msgid "%d records imported." msgstr "Rekordy %d zostały zaimportowane." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Szukaj" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Szukaj %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "Brak możliwości usunięcia kreatora %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Kreator" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Utworzył" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Data utworzenia" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Zmodyfikował" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Data modyfikacji" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "Brak możliwości uzyskania stanu widoku drzewa dla %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Brak możliwości ustawienia stanu widoku drzewa" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" jest nieprawidłowy pod względem swojej domeny" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" jest wymagany" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Wartości \"%s\" nie są prawidłowe" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Wstępna walidacja" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Rozmiar obrazka" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Szerokość:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Wysokość:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Obrazek w formacie PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Zapisz jako" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "Za duży rozmiar obrazka." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Otwórz filtry" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Pokaż zakładki filtrów" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Usuń zakładkę" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Dodaj filtr do zakładek" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Pokaż aktywne rekordy" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Pokaż nieaktywne rekordy" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Dodaj do zakładek nazwę:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Znajdź" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Dzisiaj" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "wstecz" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "dalej" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "poprzedni rok" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "następny rok" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Widok tygodnia" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Widok miesiąca" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Tydzień" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Wybierz..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Wyczyść" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Wszystkie pliki" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Pokaż tekst" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Dodaj wartość" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Usuń \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Obrazki" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Dodaj istniejący rekord" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Usuń wybrany rekored " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Otwórz rekord " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Wyczyść pole " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Szukaj rekord " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Usuń wybrany rekord" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Edytuj wybrany rekord " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Przód" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Wybierz kolor" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Tłumaczenie" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Edycja" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Niejasne" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Musisz zapisać rekord przed dodaniem tłumaczeń." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "Brak innych języków." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Widok tłumaczenia" tryton-5.0.17/tryton/data/locale/pl/LC_MESSAGES/tryton.mo0000644000175000017500000004341513571264250022272 0ustar cedced00000000000000` )"L]q 7HYu   #-I#[%  .=LU&\      $+>j  ,: IWf x   " 0:?Uow &  )9 ? LV ny  "2E[u ! %7 I T `j        : K T _ h k p }     # !!6!?! Q![!m! |! !!!!!! !!!!!" " "&";"L" S"]" x" " """""" # ## ##-#2# :#E#U#g#x## ####### $ $ *$8$ K$U$ q${$$$$$$$$ % %%(%I7%}% %5 &8V&-&&& &&&& & '''5'$P'%u'''''(( 1( >(I( O(Y( _(m( r( |((((( ((((%)7,)d) t)) ))) ) )) ) ) )))* * * * %* /* :*G* O*Z* `*m* u**** ** **$* * * + +<*+g+ ~++++++-4-- --" .,.J.R.b. s............//-/9P9T9n99 9 9 999999::(: <:G:2b:::::::; ; ;,; ;;E;V;h; o; };;;;;;;;;< <*<H< ]< h<t<<<<<<<<<= ==&=">= a= o== ===== > > >1>B>]> l> w> >>>> >>?"? )?4?E?K? e?Ps??"^@5@9@1@#A'A/AAAXAhA {A AA0A(A6A1*B"\B0B.B"BC C(C 9C FC SC `CjCCCC CC-CCDD D(&D2ODDDD DD DDD DDD E EE-E 2E All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...About...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Application ErrorAre you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancelCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDefaultDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEmail...Encoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFormFormatFuzzyHeight:HelpHost / Database informationHost:IDID:IconsImage SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsKeyboard Shortcuts...Latest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOptionsOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreferences...PreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewTextText Entries ShortcutsText and IconsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To report bugs you must have an account on %sTo:TodayToggle rowToggle selectionToolbarTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: pl Language-Team: pl Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 z "%s" jest nieprawidłowy pod względem swojej domeny"%s" jest wymaganyRekord %d został zaimportowany.%d rekord został zapisany.Rekordy %d zostały zaimportowane.%d rekordy zostały zapisane.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:Wszystkie polaPola wybranePredefiniowane eksportyUtwórz...Szukaj...Nowa wersja jest dostępna!Załączniki...O programie...AkcjaAkcje...DodajDodaj nazwy pólDodaj notatkę do rekorduDodaj załącznik do rekorduDodaj istniejący rekordDodaj nowy profilDodaj wartośćDodaj...Wszystkie plikiZawsze ignoruj takie ostrzeżenie.Błąd aplikacjiCzy na pewno usunąć wybrany rekord?Czy na pewno usunąć wybrane rekordy?Załącznik(%d)Załącznik:Załączniki (%s)Załączniki...Treść:Dodaj do zakładek nazwę:Dodaj filtr do zakładekBug TrackerPrzez: DW:Eksport do CSV: %sImport z CSV: %sParametry CSVPołączAnulujAnuluj połączenie z serwerem TrytonAnuluj zapisSprawdź URL: %sSprawdź wersjęWyczyśćWyczyść pole ZamknijZamknij kartęZwiń wszystkie wierszeZwiń wierszLinia poleceń:PorównajWyjątek równoczesnego zapisu danychPołącz z serwerem TrytonBłąd połączenia. Niewłaściwa nazwa użytkownika lub hasło!Skopiuj adres URL do schowkaSkopiuj adres URL...Skopiuj zaznaczony tekstNie można połączyć się z serweremUtwórz nowy rekordUtwórz nowy rekord Utwórz nowy wierszUtwórz nowe odniesienieNowe zgłoszenie o błędzie otrzymało ID Data utworzeniaData utworzenia:UtworzyłUtworzył:Wytnij zaznaczony tekstBaza danych:Format datyDomyślnieUsuńUsuń zaznaczony rekord Separator:Wyświetl formatWyświetlany format datyWyświetlana wartośćCzy chcesz kontynuować?PobierzE-mailWyślij raportWyślij e-mail...EdycjaEdytuj preferencje użytkownikaEdytuj wybrany rekord Edycja...Widżety edycjiE-mailUstawienia czytnika pocztyE-mail...Kodowanie:BłądBłąd otwarcia pliku CSVBłąd przetwarzania pliku w polu %s.Błąd: Wyjątek:Rozwiń wszystkie wierszeRozwiń wierszRozwiń/ZwińNieSzybki tabulatorUlubionePobieranie listy baz danychNazwa polaPlik do zaimportowania:ZnajdźPrzódFormularzFormatNiejasneWysokość:PomocInformacje o hoście / bazie danychHost:IDID:IkonyRozmiar obrazkaZa duży rozmiar obrazka.ObrazkiNiewłaściwa wersja serweraSkróty klawiszoweSkróty klawiszowe...Data ostatniej modyfikacji:Autor ostatniej modyfikacji:Uruchom akcjęLista dostępnych symboli zastępczych:LimitLimit:Wiersze do ominięcia:LinkSkróty dotyczące listLoginMZarządzaj...Zaznacz wiersz do usunięciaModel:Data modyfikacjiZmodyfikowałWidok miesiącaPrzesuń kursorPrzesuń w dółPrzesuń w dół o jedną stronęPrzesuń do dołuPrzesuń w lewoPrzesuń do elementu nadrzędnegoPrzesuń w prawoPrzesuń do góryPrzesuń w góręPrzesuń w górę o jedną stronęNazwaNowyNastępnyNastępny rekordNastępny widżetNieBrak zdefiniowanej akcji.Brak innych języków.Nie znaleziono wyniku.Notatka(%d)Notatki (%s)Notatki...OKOtwórzOtwórz filtryOtwórz powiązane rekordyUtwórz odnośnikOtwórz raportOtwórz kalendarzOtwórz rekord Otwórz...Otwórz/Szukaj odniesienieOperacja nie powiodła się. Komunikat błędu: %sOpcjeCzy nadpisać definicję '%s'?Tryb PDAObrazek w formacie PNG (*.png)Hasło:Wklej zaznaczony tekstWstępna walidacjaPreferencjePreferencjePreferencje...PoprzedniPoprzedni rekordPoprzedni widżetWydrukDrukuj raportWydrukuj...ProfilEdytor profiliProfil:ZakończZnak cudzysłowa:Rekord został zapisany.Rekordy nie zostały usunięte.Rekordy zostały usunięte.OtwórzOtwórz...Skróty dotyczące odniesieńOdśwież/PrzywróćUsuń "%s"Usuń Usuń wybrany profilUsuń wybrany rekordUsuń wybrany rekored Usuń zakładkęRaportZgłoś błądUtwórz raport...RewizjaRewizja:ZapiszZapisz jakoZapisz jako...Zapamiętaj stan drzewaZapamiętaj szerokość/wysokośćZapisz rekordZapisz swoją bieżącą wersjęSzukajSzukaj %sUstawienia limitu wyszukiwaniaOgraniczenie wyszukiwania...Szukaj rekord Zobacz zmienioną wersjęWybierzWybierz kolorWybierz rewizjęZaznacz wszystkoZaznacz element nadrzędnyWybierz akcjęWybierz...Zaznacz/Aktywuj bieżący wierszZaznaczeniePokaż aktywne rekordyPokaż zakładki filtrówPokaż nieaktywne rekordyPokaż tekstPokaż rewizje...Sprawdzanie pisowniTemat:PrzełączPrzełącz widokTekstSkróty dotyczące tekstuTekst i ikonyWykonanie polecenia wymaga zamknięcia wszystkich kart. Czy chcesz kontynuować?Ten błąd został już zgłoszony przez innego użytkownika. Abyś był na bieżąco z informacjami o błędzie zostałeś dopisany do właściwej listyWartości "%s" nie są prawidłoweRekord został zmodyfikowany. Czy chcesz go zapisać?Ten rekord został zmodyfikowany w trakcie twojej edycji.Aby zgłosić błędy musisz posiadać konto w %sDo:DzisiajPrzełącz wierszPrzełącz zaznaczeniePasek narzędziWidok tłumaczeniaTłumaczenieWidok drzewaTakNie można sprawdzić dostępności nowej wersjiBrak możliwości usunięcia kreatora %sBrak możliwości uzyskania stanu widoku drzewa dla %sBrak możliwości wyszukania uzupełnienia dla %sNie można ustawić lokalizacji %sBrak możliwości ustawienia stanu widoku drzewaNie można zapisać pliku konfiguracyjnego %s!Przywróć zaznaczony rekord NieznanyOdznacz wiersz do usunięciaOdznacz wszystkoUżytkownik:Użytkownik:Użytkownik:WartośćPrzeglądaj dziennik...TydzieńWidok tygodniaJaka jest nazwa tego eksportu?Szerokość:KreatorPracujesz na zduplikowanym(ch) rekordzie(ch).ZapiszRTakMusisz wybrać jeden rekord.Najpierw wybierz plik do zaimportowania.Musisz zapisać rekord przed dodaniem tłumaczeń.Twoje zaznaczenie:Akcje...DodajRozpoznajAnulujWyczyśćZamknij kartęSkopiuj adres URLUsuń eksportUsuń...DuplikujE-mail...Eksportuj dane...Importuj dane...NowyNastępnyNotatki...PoprzedniWydruk...Odnośnik...Odśwież/PrzywróćUsuńRaport...ZapiszZapisz eksportSzukajPrzełącz widokdtryb deweloperawsteczdalejgrejestrowanie wszystkiego na poziomie INFOmmodułowość, skalowalność i bezpieczeństwonastępny rokpoprzedni rokspodaj alternatywny plik konfiguracjipodaj poziom rejestrowania: DEBUG, INFO, WARNING, ERROR, CRITICALpodaj login użytkownikapodaj nazwę:port serwerapWojciech Warczakowskitttryton-5.0.17/tryton/data/locale/ja_JP/0000755000175000017500000000000013571264253017155 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ja_JP/LC_MESSAGES/0000755000175000017500000000000013571264253020742 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ja_JP/LC_MESSAGES/tryton.po0000644000175000017500000010760013463252532022642 0ustar cedced00000000000000# Japanese (Japan) translations for tryton. # Copyright (C) 2010 B2CK # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2010. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "代替設定ファイルを指定" #: tryton/config.py:77 msgid "development mode" msgstr "" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "全てをINFOレベルでログを取る" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:85 msgid "specify the login user" msgstr "ログインユーザーを指定" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "サーバーホスト名を指定" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "設定ファイル %s が書きこめません!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "%s ロケールに設定できません" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "動作を選択する" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "動作が定義されていません!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "選択" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "キャンセル(_C)" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "あなたの選択:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "保存" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "名前を付けて保存" #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "常にこの警告を無視する。" #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "並列性例外" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "比較" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "とにかく書き込む" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "アプリケーションエラー!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "バグ報告" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "エラー:" #: tryton/common/common.py:768 #, python-format, fuzzy msgid "To report bugs you must have an account on %s" msgstr "記録しておきたいバグを報告%s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "バグトラッカー" #: tryton/common/common.py:811 msgid "User:" msgstr "ユーザー:" #: tryton/common/common.py:819 msgid "Password:" msgstr "パスワード:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "別のユーザーに同じバグが報告されています。\n" "お知らせするためにこの問題の通知リストにあなたのユーザー名を追加しました。" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "新しいバグがID番号と一緒に作成されました" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "接続エラー!\n" "ユーザー名またはパスワードが違います!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "例外:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "" #: tryton/common/completion.py:27 msgid "Create..." msgstr "" #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "偽" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "ノーマル(_N)" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "カレンダーを開く" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "真" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "偽" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "終了(_Q)" #: tryton/common/popup_menu.py:89 #, fuzzy msgid "Attachments..." msgstr "添付:" #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 #, fuzzy msgid "Actions..." msgstr "実行(_A)" #: tryton/common/popup_menu.py:108 #, fuzzy msgid "Relate..." msgstr "削除(_D)" #: tryton/common/popup_menu.py:109 #, fuzzy msgid "Report..." msgstr "データのインポート(_I)" #: tryton/common/popup_menu.py:110 #, fuzzy msgid "E-Mail..." msgstr "Eメール(_E)" #: tryton/common/popup_menu.py:111 #, fuzzy msgid "Print..." msgstr "印刷(_P)" #: tryton/common/timedelta.py:26 msgid "Y" msgstr "年" #: tryton/common/timedelta.py:27 msgid "M" msgstr "月" #: tryton/common/timedelta.py:28 msgid "w" msgstr "週" #: tryton/common/timedelta.py:29 msgid "d" msgstr "日" #: tryton/common/timedelta.py:30 msgid "h" msgstr "時" #: tryton/common/timedelta.py:31 msgid "m" msgstr "分" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "設定(_P)" #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "ツールバー(_T)" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "デフォルト(_D)" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "テキストとアイコン(_T)" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "テキスト(_T)" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "アイコン(_I)" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "フォーム(_F)" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "幅/高さを保存" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "スペルチェック" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "" #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "Eメール(_E)" #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "オプション(_O)" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "キーボードショートカット(_K)" #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "Trytonについて" #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "ヘルプ(_H)" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "" #: tryton/gui/main.py:447 msgid "Favorites" msgstr "" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "実行" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "タブを閉じる" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "添付(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 #, fuzzy msgid "Host:" msgstr "ポート番号:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "データベース:" #: tryton/gui/window/dblogin.py:108 #, fuzzy msgid "Fetching databases list" msgstr "新規データベースセットアップ:" #: tryton/gui/window/dblogin.py:122 #, fuzzy msgid "Username:" msgstr "ユーザー名:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 #, fuzzy msgid "Incompatible version of the server" msgstr "サーバのバージョンが非互換です!" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 #, fuzzy msgid "Could not connect to the server" msgstr "サーバーに接続できませんでした!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "ログイン" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "キャンセル(_C)" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Trytonサーバへの接続を中止する" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "接続(_N)" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Trytonサーバーへ接続する" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "ユーザー名:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Eメール" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Emailプログラムの設定" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "コマンドライン:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "利用できるプレースホルダーの凡例:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "宛先:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "題名:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "本文:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "添付:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "添付(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "レコードを一つ選択して下さい!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "作成ユーザー:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "作成日:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "最終更新ユーザー:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "最終更新日:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "モデル:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "このレコードを削除しますか?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "このレコードを削除しますか?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "レコードが削除されませんでした!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "レコードが削除されました!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "重複したレコードで作業中です!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "レコードが保存されました!" #: tryton/gui/window/form.py:485 msgid " of " msgstr " 中 " #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "レコードが変更されています\n" "保存しますか?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Relate" msgstr "作成(_C)" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Open related records" msgstr "レコードを開く" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Report" msgstr "レポート" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Open report" msgstr "レコードを開く" #: tryton/gui/window/form.py:563 #, fuzzy msgid "E-Mail" msgstr "Eメール" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "印刷" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "未知" #: tryton/gui/window/limit.py:20 #, fuzzy msgid "Limit" msgstr "リミット:" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "リミット:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "設定" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "個人設定の編集" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "設定" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "前" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "選択" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "前" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "キーボードショートカット" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "テキストエントリショートカット" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "選択されたテキストを切り取り" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "選択されたテキストをコピー" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "コピーされたテキストを貼り付け" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "次のウィジェット" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "前のウィジェット" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "リレーションエントリショートカット" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "新しいリレーションを作る" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "リレーションを開く/検索" #: tryton/gui/window/shortcuts.py:44 #, fuzzy msgid "List Entries Shortcuts" msgstr "テキストエントリショートカット" #: tryton/gui/window/shortcuts.py:45 #, fuzzy msgid "Create new line" msgstr "新しいリレーションを作る" #: tryton/gui/window/shortcuts.py:46 #, fuzzy msgid "Open relation" msgstr "リレーションを開く/検索" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "エディションウィジェット" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "ビューの切替(_S)" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "ビューの切替(_S)" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "前(_P)" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "前のレコード" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "次(_N)" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "次のレコード" #: tryton/gui/window/tabcontent.py:61 #, fuzzy msgid "_Search" msgstr "検索" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "新規(_N)" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "レコードの新規作成" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "保存(_S)" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "レコードの保存" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "再読み込み/やり直し(_R)" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "再読み込み/やり直し(_R)" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "複製(_D)" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "削除(_D)" #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "ログの閲覧(_L)" #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 #, fuzzy msgid "A_ttachments..." msgstr "添付:" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "レコードに添付を追加する" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "実行(_A)" #: tryton/gui/window/tabcontent.py:123 #, fuzzy msgid "_Relate..." msgstr "削除(_D)" #: tryton/gui/window/tabcontent.py:129 #, fuzzy msgid "_Report..." msgstr "データのインポート(_I)" #: tryton/gui/window/tabcontent.py:134 #, fuzzy msgid "_E-Mail..." msgstr "Eメール(_E)" #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "印刷(_P)" #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "データのエクスポート(_E)" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "データのインポート(_I)" #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "タブを閉じる(_C)" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "全てのフィールド" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "追加(_A)" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "削除(_R)" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "クリア" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSVパラメータ" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "エンコーディング:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "フィールド名" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "エクスポートを保存" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "エクスポートを削除" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "定義済みエキスポート" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "名前" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "開く" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "フィールド名を追加(_F)" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "このエクスポートの名前は何ですか?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d レコード保存されました!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d レコード保存されました!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "操作が失敗しました!\n" "エラーメッセージ:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "エラー" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "リンク" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "削除" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "新規(_N)" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "切替" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "前" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "次" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "追加" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 #, fuzzy msgid "Create a new record " msgstr "レコードの新規作成" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 #, fuzzy msgid "Delete selected record " msgstr "選択したレコードを削除" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 #, fuzzy msgid "Undelete selected record " msgstr "選択したレコードを削除" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "自動検出" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "インポートするファイル:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "開く" #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "スキップする行:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "最初にインポートするファイルを選択して下さい!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "CSVファイルを開くときにエラーが起こりました" #: tryton/gui/window/win_import.py:138 #, python-format, python-format, fuzzy, python-format msgid "Error processing the file at field %s." msgstr "ファイルの%sフィールドの処理でエラーが起こりました。" #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d レコードをインポートしました!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d レコードをインポートしました。" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "検索" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "ウィザード" #: tryton/gui/window/view_form/screen/screen.py:206 #, fuzzy msgid "ID" msgstr "日" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "作成ユーザー:" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "作成日:" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "最終更新日:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "最終更新日:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "%s ロケールに設定できません" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "%s ロケールに設定できません" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "画像サイズ" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "幅:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "高さ:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG画像 (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "名前をつけて保存" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "画像サイズが大きすぎます!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "検索" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "本文:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "ビューの切替" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "ビューの切替" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "クリア" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "全てのファイル" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "画像" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 #, fuzzy msgid "Add existing record" msgstr "レコードの保存" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 #, fuzzy msgid "Remove selected record " msgstr "選択したレコードを削除" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "レコードを開く" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 #, fuzzy msgid "Search a record " msgstr "レコードを検索する" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 #, fuzzy msgid "Remove selected record" msgstr "選択したレコードを削除" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 #, fuzzy msgid "Edit selected record " msgstr "選択したレコードを編集" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 #, fuzzy msgid "Translation" msgstr "翻訳を追加" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "翻訳を追加する前にレコードを保存して下さい!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "他の利用できる言語はありません" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "翻訳ビュー" tryton-5.0.17/tryton/data/locale/ja_JP/LC_MESSAGES/tryton.mo0000644000175000017500000003133513571264250022640 0ustar cedced00000000000000  )<MUe v )Bb r| #% # 8DIM\kz&      -5Ke }  $ +6E[k     ,7G M Z do   !"DKZ_e gq     !% * 6BEV _jsv {   %5E KX`ox }     /@Z ak    0J`pI} 8  8%Sy      !% 5AF N Y c ny       3$5 Z drt< )     !! ! !,!%C!i!z!!!!!!$!" #"-"4"$J"(o"(" """""####.#=# P#*[# # # # ##### #$$&$!6$X$ p$'}$$$$;$ "%-%*A%l% %% %%%%%% %&&$& B&M&k& &?& &&& && ' ' '('";'^' e'p'v'~''''$''' (1( E(S( j( t(( (( ( ( ((( (( ) )")*)>) E)P)T)g)))) )))) ))")) **'*-8*f*u*|***** ***** *3* ,+ 8+E+]+ r++++++++ , ,,3,C,\,c, r, },, ,,,,,,-"-4-J-R--Y-I-- .8.. ... ///=/%X/'~/// // //01 0=0B0R0k0o0s0 0 000 0 0 0"0 1 +161 >1H1 P1 [1 |1 11111 11(11$2 '2 12?2!A2<c2!22222 of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!ActionAddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCreate a new recordCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEditEdit User PreferencesEdition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationID:Image SizeImagesKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:Limit:Lines to Skip:LinkLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportProfileProfile EditorProfile:QuitQuote char:Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove this bookmarkReport BugSaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnknownUnmark line for deletionUnselect allUser name:User:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Reload/Undo_Remove_Save_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: ja_JP Language-Team: ja_JP Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 中 "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:全てのフィールドFields selected定義済みエキスポートCreate...Search...A new version is available!実行追加フィールド名を追加(_F)Add a note to the recordレコードに添付を追加するAdd new profileAdd valueAdd...全てのファイル常にこの警告を無視する。このレコードを削除しますか?このレコードを削除しますか?添付(%d)添付:本文:Bookmark Name:Bookmark this filterバグトラッカーBy: CC:CSV Export: %sCSV Import: %sCSVパラメータ接続(_N)Trytonサーバへの接続を中止するCancel savingCheck URL: %sCheck VersionクリアClear the field Closeタブを閉じるCollapse all rowsCollapse rowコマンドライン:比較並列性例外Trytonサーバーへ接続するCopy URL into clipboardCopy _URL...選択されたテキストをコピーレコードの新規作成新しいリレーションを作る新しいバグがID番号と一緒に作成されました作成日:作成ユーザー:選択されたテキストを切り取りデータベース:Date Format削除Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEdit個人設定の編集エディションウィジェットEメールEmailプログラムの設定エンコーディング:エラーCSVファイルを開くときにエラーが起こりましたエラー:例外:Expand all rowsExpand rowExpand/Collapse偽Fast TabbingFavoritesフィールド名インポートするファイル:検索ForegroundFuzzy高さ:Host / Database informationID:画像サイズ画像キーボードショートカット最終更新日:最終更新ユーザー:Launch action利用できるプレースホルダーの凡例:リミット:スキップする行:リンクログイン月Manage...Mark line for deletionモデル:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one page名前新規(_N)次次のレコード次のウィジェットNoNo result found.Note(%d)Notes (%s)Notes...OK開くOpen filters開くリレーションを開く/検索Override '%s' definition?PDA ModePNG画像 (*.png)パスワード:コピーされたテキストを貼り付けPre-validation設定設定前前のレコード前のウィジェット印刷Print reportProfileProfile EditorProfile:QuitQuote char:リレーションエントリショートカットRemove "%s"Remove Remove selected profileRemove this bookmarkバグ報告保存名前をつけて保存名前を付けて保存Save Tree State幅/高さを保存レコードの保存Save your current version検索Search %sSearch Limit SettingsSearch Limit...See the modified versionSelectSelect a colorSelect allSelect parent動作を選択するSelect...Select/Activate current row選択Show active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...スペルチェック題名:切替テキストエントリショートカットThe following action requires to close all tabs. Do you want to continue?別のユーザーに同じバグが報告されています。 お知らせするためにこの問題の通知リストにあなたのユーザー名を追加しました。The values of "%s" are not validThis record has been modified while you were editing it.宛先:Toggle rowToggle selection翻訳ビューTree view真Unable to check for new versionUnable to delete wizard %sUnable to search for completion of %s%s ロケールに設定できません未知Unmark line for deletionUnselect allユーザー名:ユーザー:ログの閲覧(_L)Weekこのエクスポートの名前は何ですか?幅:ウィザードとにかく書き込む年Yesあなたの選択:実行(_A)追加(_A)キャンセル(_C)タブを閉じる(_C)_Copy URL削除(_D)複製(_D)データのエクスポート(_E)データのインポート(_I)新規(_N)次(_N)_Notes...前(_P)印刷(_P)再読み込み/やり直し(_R)削除(_R)保存(_S)ビューの切替(_S)日development modego backgo forward時全てをINFOレベルでログを取る分modularity, scalability and securitynext yearprevious years代替設定ファイルを指定specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALログインユーザーを指定ttranslator-credits週ytryton-5.0.17/tryton/data/locale/pt_BR/0000755000175000017500000000000013571264253017200 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/pt_BR/LC_MESSAGES/0000755000175000017500000000000013571264253020765 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/pt_BR/LC_MESSAGES/tryton.po0000644000175000017500000011046013463252532022663 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "especificar arquivo de configuração alternativo" #: tryton/config.py:77 msgid "development mode" msgstr "modo de desenvolvimento" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Registrar (log) tudo com nível INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" "Especifique o nível de registro (log level): DEBUG, INFO, WARNING, ERROR, " "CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Especifique o nome do usuário" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "Especifique o servidor hostname:porta" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "Não foi possível gravar o arquivo de configuração %s." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Não foi possível definir as configurações regionais %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Selecione sua ação" #: tryton/action/main.py:193 msgid "No action defined." msgstr "Nenhuma ação definida." #: tryton/common/button.py:54 msgid "By: " msgstr "Por: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Seleção" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Cancelar" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Sua seleção:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Selecionar" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Gravar" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Salvar como..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Sempre ignorar este aviso." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Você deseja prosseguir?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Sim" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Exceção de concorrência" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Comparar" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Gravar mesmo assim" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Erro da aplicação." #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Reportar erro (bug)" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Erro: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Para reportar erros você deve ter uma conta em %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Sistema de registro de erros" #: tryton/common/common.py:811 msgid "User:" msgstr "Usuário:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Senha:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "O mesmo erro já foi reportado por outro usuário.\n" "Para mantê-lo informado, seu nome de usuário foi adicionado à lista de acompanhamento deste caso" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Criar novo erro (bug) com ID " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Erro de conexão.\n" "Usuário ou senha incorretos." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Exceção:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Buscar..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Criar..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "Não foi possível encontrar complementos de %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valor" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valor exibido" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Formato" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Formato de exibição" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Abrir o calendário" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Formato de Data" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Formato de data exibido" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "s" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Verdadeiro" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "v" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Falso" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Editar..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Anexos..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notas..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Ações..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Relacionado..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Relatório..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "E-mail..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Imprimir..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "s" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Preferências..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_Barra de Ferramentas" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Padrão" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_Texto e Ícones" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Texto" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_Ícones" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_Formulário" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Gravar Largura/Altura" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Gravar Estado da Árvore" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Tabulação rápida" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Verificar Ortografia" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Limite de Buscas..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_Email..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Opções" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Atalhos do Teclado..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_Sobre..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Ajuda" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Nenhum resultado encontrado." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "Fa_voritos" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Ação" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "A ação seguinte requer que todas as abas sejam fechadas.\n" "Você deseja prosseguir?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Fechar Aba" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Anexos (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Editor de Perfil" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Perfil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Servidor:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Banco de Dados:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Obtendo a lista de bancos de dados" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Usuário:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Versão do servidor incompatível" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Não foi possível se conectar ao servidor" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Entrar" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Cancelar" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Cancelar a conexão com o servidor do Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onectar" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Conectar ao servidor do Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Perfil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Informações do Servidor / Banco de Dados" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Nome de Usuário:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Email" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Enviar preferências do programa por email" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Linha de Comado:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Legenda de posições de palavras disponíveis:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Para:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Assunto:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Conteúdo:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Anexo:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Anexo(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Nota(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Você deve selecionar um registro." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Criado por:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Data de criação:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Última Modificação por:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Data da última modificação:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modelo:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Você tem certeza que deseja apagar este registro?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Você tem certeza que deseja apagar estes registros?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Registros não apagados." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Registros apagados." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Trabalhando no(s) registro(s) duplicados(s)." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Registro gravado." #: tryton/gui/window/form.py:485 msgid " of " msgstr " de " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Este registro foi modificado\n" "você deseja salvá-lo?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Executar ação" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Relacionar" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Abrir registros relacionados" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Relatório" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Abrir relatório" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-Mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Enviar relatório por e-mail" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Imprimir" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Imprimir relatório" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Copiar URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Copiar URL para a área de transferência" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Desconhecido" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limite" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Preferências de limite de buscas" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Limite:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notas (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferências" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Editar preferências do usuário" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferência" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Revisão" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Selecione uma revisão" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Revisão:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Atalhos do teclado" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Atalhos de entradas de texto" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Recortar o texto selecionado" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copiar o texto selecionado" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Colar o texto copiado" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Próximo campo" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Campo anterior" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Atalhos para campos de relações" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Criar nova relação" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Abrir/Buscar relação" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Atalhos em listas" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Criar nova linha" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Abrir relação" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Marcar para apagar linha" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Desmarcar linha para apagar" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Controles de edição" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Mover cursor" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Mover para a direita" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Mover para a esquerda" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Mover para cima" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Mover para baixo" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Mover uma página para cima" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Mover uma página para baixo" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Mover para o topo" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Mover para o final" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Mover para o pai" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Selecionar todos" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Desmarcar Todos" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Selecionar pai" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Selecionar/Ativar linha atual" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Alternar seleção" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Expandir/Recolher" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Expandir a linha" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Recolher a linha" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Alternar linha" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Recolher todas as linhas" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Expandir todas as linhas" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Exibição em árvore" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_Alternar Exibição" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Alternar" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Anterior" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Registro Anterior" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Próximo" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Próximo Registro" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Buscar" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Novo" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Criar novo registro" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Salvar" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Gravar este registro" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Recarregar/Desfazer" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Recarregar/Desfazer" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplicado" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Apagar..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Ver _Logs..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Mostrar revisões..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "A_nexos..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Adicionar um anexo ao registro" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notas..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Adicionar uma nota ao registro" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Ações..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Relacionar" #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Relatório..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_E-Mail..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Imprimir..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Exportar Dados..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importar Dados..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Copiar _URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Fechar aba" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Todos os campos" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Adicionar" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Remover" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Limpar" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Campos selecionados" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parâmetros CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Delimitador:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Caractere de citação:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codificação:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nome do campo" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Gravar exportação" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Apagar exportação" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Exportações pré-definidas" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nome" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Abrir" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Adicionar _nomes de campos" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (texto)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (nome do modelo)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (nome do registro) " #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Qual é o nome dessa exportação?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Sobrescrever a definição '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "%d registro gravado." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "%d registros gravados." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Operação Falhou.\n" "Mensagem de erro:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Erro" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Vínculo" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Apagar" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Novo" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Alternar" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Anterior" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Próximo" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Adicionar" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Remover " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Criar novo registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Apagar o registro selecionado " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Recuperar o registro selecionado " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_Auto-Detectar" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Arquivo para importar:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Abrir..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Linhas a ignorar:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Primeiro você deve selecionar um arquivo para importar." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Erro ao abrir arquivo CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Erro ao processar o arquivo no campo %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "%d registros importados." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "%d registros importados." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Busca" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Buscar %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "Não é possível apagar o assistente %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Assistente" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Criado por" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Data de criação" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Editado por" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Data de modificação" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "Não foi possível obter o estado da visualização em árvore para %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Não foi possível definir o estado da visão em árvore" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" não é válido de acordo com seu domínio" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" é obrigatório" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Os valores de \"%s\" não são válidos" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Pré-validação" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Tamanho da imagem" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Largura:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Altura:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Imagem PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Salvar como" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "Imagem muito grande." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Abrir filtros" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Mostrar filtros favoritos" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Remover este favorito" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Marcar este filtro como favorito" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nome do favorito:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Localizar" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Hoje" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "voltar" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "avançar" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "ano anterior" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "próximo ano" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Visão Semanal" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Visão Mensal" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Semana" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Selecionar..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Limpar" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Todos os arquivos" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Mostrar em formato texto" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Adicionar valor" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Remover \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Imagens" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Adicionar um registro existente" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Remover registro selecionado " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Abrir o registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 #, fuzzy msgid "Clear the field " msgstr "Apagar o registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Buscar um registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Remover o registro selecionado" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Editar o registro selecionado " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Cor de primeiro plano" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Selecione uma cor" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Tradução" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Editar" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Vago" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Você precisa salvar o registro antes de adicionar traduções." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "Não há outros idiomas disponíveis." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Traduzir visão" tryton-5.0.17/tryton/data/locale/pt_BR/LC_MESSAGES/tryton.mo0000644000175000017500000004234513571264250022666 0ustar cedced00000000000000O  )<Mar  '8Ieu |  #0%Tz  !&* Q _ m{   +" :GZz   0 :FM ju  '7= T^d&{    & +6=CKgmp t" !4:APUlr t~     " 0<DX]a f r~    #5JR#g      + 1 > G O ^ g l x      !,!I!^! e! p!z! !!! !!!!!! !"")">"W"^"m" " "" "" """ ##/#A#P#Y# `#l#I#}# K$5l$8$$$ $$% % %&%+%K%$f%%%%%%&&&.& G& T&_& e&o& u&& & &&&(& &&&&%'7B'z' '' ''' ' '' ' ' '' ((!( '( 1( ;( E( P(]( e(p( v(( (((( (( (($( ) ) )")<@)}) ))))))a+/f++++++ ,,%, <,G,L,O,T,W,[,],t,#,,,, ,, - --2-Q-p------2-4. L.V. ]. i. s.~. ....... /,/ =/ K/ Y/g/n/ t/////////)-0W0f0*0000001/1 B1 M1Y1v111#1 111 1 2#2,232 P2Z2 a2"2 222*223 3($3M3 T3_3x3333"3 33 344%4*4*24 ]4g4j4n444!4444 5/5L5S5[5m5v555 5555 5 5 55 6'6:6P6a6v6666666666%7*7G7 P7[7d7g7 m7{7777777'8 +8L8U8h8o88 8 888888 89 99$9)9A9S9l9 99!99 9 99:"":E: [:f: z:: :: :::::;; !;!+;M;a;y; ;;;;;; ; < '<1<E<_<u<<<<<<<S<D=%=4>86>o>u>z>>> >> >>(>F!?/h?:?8?9 @&F@ m@z@@@ @ @@ @@@"@A !A,,AYAlAnA"rA8A?AB B )B4B CBMB UB aBmB B B BBBB B B B B BCC$C3C;CPCXCmCoCCCC$CC$C C CC1DS3DD%DDDDD of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearCloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: pt_BR Language-Team: pt_BR Plural-Forms: nplurals=2; plural=(n > 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 de "%s" não é válido de acordo com seu domínio"%s" é obrigatório%d registros importados.%d registro gravado.%d registros importados.%d registros gravados.%s (%s)%s (nome do modelo)%s (nome do registro) %s (texto)%s%%, ,….....:Todos os camposCampos selecionadosExportações pré-definidasCriar...Buscar...A new version is available!A_nexos...AçãoAções...AdicionarAdicionar _nomes de camposAdicionar uma nota ao registroAdicionar um anexo ao registroAdicionar um registro existenteAdd new profileAdicionar valorAdd...Todos os arquivosSempre ignorar este aviso.Você tem certeza que deseja apagar este registro?Você tem certeza que deseja apagar estes registros?Anexo(%d)Anexo:Anexos (%s)Anexos...Conteúdo:Nome do favorito:Marcar este filtro como favoritoSistema de registro de errosPor: CC:CSV Export: %sCSV Import: %sParâmetros CSVC_onectarCancelar a conexão com o servidor do TrytonCancel savingCheck URL: %sCheck VersionLimparCloseFechar AbaRecolher todas as linhasRecolher a linhaLinha de Comado:CompararExceção de concorrênciaConectar ao servidor do TrytonErro de conexão. Usuário ou senha incorretos.Copiar URL para a área de transferênciaCopiar _URL...Copiar o texto selecionadoNão foi possível se conectar ao servidorCriar novo registroCriar novo registro Criar nova linhaCriar nova relaçãoCriar novo erro (bug) com ID Data de criaçãoData de criação:Criado porCriado por:Recortar o texto selecionadoBanco de Dados:Formato de DataApagarApagar o registro selecionado Delimitador:Formato de exibiçãoFormato de data exibidoValor exibidoVocê deseja prosseguir?DownloadE-MailEnviar relatório por e-mailE-mail...EditarEditar preferências do usuárioEditar o registro selecionado Editar...Controles de ediçãoEmailEnviar preferências do programa por emailCodificação:ErroErro ao abrir arquivo CSVErro ao processar o arquivo no campo %s.Erro: Exceção:Expandir todas as linhasExpandir a linhaExpandir/RecolherFalsoTabulação rápidaObtendo a lista de bancos de dadosNome do campoArquivo para importar:LocalizarCor de primeiro planoFormatoVagoAltura:Informações do Servidor / Banco de DadosServidor:IDID:Tamanho da imagemImagem muito grande.ImagensVersão do servidor incompatívelAtalhos do tecladoData da última modificação:Última Modificação por:Executar açãoLegenda de posições de palavras disponíveis:LimiteLimite:Linhas a ignorar:VínculoAtalhos em listasEntrarMManage...Marcar para apagar linhaModelo:Data de modificaçãoEditado porVisão MensalMover cursorMover para baixoMover uma página para baixoMover para o finalMover para a esquerdaMover para o paiMover para a direitaMover para o topoMover para cimaMover uma página para cimaNomeNovoPróximoPróximo RegistroPróximo campoNoNenhuma ação definida.Não há outros idiomas disponíveis.Nenhum resultado encontrado.Nota(%d)Notas (%s)Notas...OKAbrirAbrir filtrosAbrir registros relacionadosAbrir relaçãoAbrir relatórioAbrir o calendárioAbrir o registro Abrir...Abrir/Buscar relaçãoOperação Falhou. Mensagem de erro: %sSobrescrever a definição '%s'?PDA ModeImagem PNG (*.png)Senha:Colar o texto copiadoPré-validaçãoPreferênciaPreferênciasAnteriorRegistro AnteriorCampo anteriorImprimirImprimir relatórioImprimir...PerfilEditor de PerfilPerfil:QuitCaractere de citação:Registro gravado.Registros não apagados.Registros apagados.RelacionarRelacionado...Atalhos para campos de relaçõesRecarregar/DesfazerRemover "%s"Remover Remove selected profileRemover o registro selecionadoRemover registro selecionado Remover este favoritoRelatórioReportar erro (bug)Relatório...RevisãoRevisão:GravarSalvar comoSalvar como...Gravar Estado da ÁrvoreGravar Largura/AlturaGravar este registroSave your current versionBuscaBuscar %sPreferências de limite de buscasLimite de Buscas...Buscar um registro See the modified versionSelecionarSelecione uma corSelecione uma revisãoSelecionar todosSelecionar paiSelecione sua açãoSelecionar...Selecionar/Ativar linha atualSeleçãoShow active recordsMostrar filtros favoritosShow inactive recordsMostrar em formato textoMostrar revisões...Verificar OrtografiaAssunto:AlternarAlternarAtalhos de entradas de textoA ação seguinte requer que todas as abas sejam fechadas. Você deseja prosseguir?O mesmo erro já foi reportado por outro usuário. Para mantê-lo informado, seu nome de usuário foi adicionado à lista de acompanhamento deste casoOs valores de "%s" não são válidosEste registro foi modificado você deseja salvá-lo?This record has been modified while you were editing it.Para:HojeAlternar linhaAlternar seleçãoTraduzir visãoTraduçãoExibição em árvoreVerdadeiroUnable to check for new versionNão é possível apagar o assistente %sNão foi possível obter o estado da visualização em árvore para %sNão foi possível encontrar complementos de %sNão foi possível definir as configurações regionais %sNão foi possível definir o estado da visão em árvoreNão foi possível gravar o arquivo de configuração %s.Recuperar o registro selecionado DesconhecidoDesmarcar linha para apagarDesmarcar TodosNome de Usuário:Usuário:Usuário:ValorVer _Logs...SemanaVisão SemanalQual é o nome dessa exportação?Largura:AssistenteTrabalhando no(s) registro(s) duplicados(s).Gravar mesmo assimASimVocê deve selecionar um registro.Primeiro você deve selecionar um arquivo para importar.Você precisa salvar o registro antes de adicionar traduções.Sua seleção:_Ações..._Adicionar_Auto-Detectar_Cancelar_Limpar_Fechar aba_Copiar URL_Apagar exportação_Apagar..._Duplicado_E-Mail..._Exportar Dados..._Importar Dados..._Novo_Próximo_Notas..._Anterior_Imprimir..._Relacionar_Recarregar/Desfazer_Remover_Relatório..._Salvar_Gravar exportação_Buscar_Alternar Exibiçãodmodo de desenvolvimentovoltaravançarhRegistrar (log) tudo com nível INFOmmodularity, scalability and securitypróximo anoano anteriorsespecificar arquivo de configuração alternativoEspecifique o nível de registro (log level): DEBUG, INFO, WARNING, ERROR, CRITICALEspecifique o nome do usuárioEspecifique o servidor hostname:portavtranslator-creditssstryton-5.0.17/tryton/data/locale/es_419/0000755000175000017500000000000013571264253017176 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/es_419/LC_MESSAGES/0000755000175000017500000000000013571264253020763 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/es_419/LC_MESSAGES/tryton.po0000644000175000017500000011056313463252532022665 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "Indica un archivo de configuración alternativo" #: tryton/config.py:77 msgid "development mode" msgstr "Modo desarrollo" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Registra toda la información con nivel INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "Indica el nivel de log: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Indica el usuario" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "Indica el nombre:puerto del servidor" #: tryton/config.py:127 #, python-format msgid "Unable to write config file %s." msgstr "No se ha podido escribir el archivo de configuración %s." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "No se ha podido establecer el idioma %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Seleccione su acción" #: tryton/action/main.py:193 msgid "No action defined." msgstr "No se ha definido ninguna acción." #: tryton/common/button.py:54 msgid "By: " msgstr "Por: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Selección" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Cancelar" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Su selección:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Seleccionar" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Guardar" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Guardar como..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Ignorar siempre esta advertencia." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "¿Desea continuar?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Sí" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Excepción de concurrencia" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Comparar" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Guardar de todas formas" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Error de aplicación." #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Informar del error" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Error: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Para informar de errores debe tener una cuenta en %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Seguimiento de errores" #: tryton/common/common.py:811 msgid "User:" msgstr "Usuario:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Contraseña:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "El mismo error ya fue notificado por otro usuario.Para mantenerle informado " "añadiremos su usuario a la lista de interesados en esta incidencia." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Se creó un nuevo error con identificador " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "Error de conexión.Nombre de usuario o contraseña incorrectos." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Excepción:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "URL de comprobación: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "No se ha podido comprobar si existe una nueva versión." #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Esta disponible una nueva versión!" #: tryton/common/common.py:942 msgid "Download" msgstr "Descargar" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Buscar..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Crear..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "No se ha podido buscar el autocompletado de %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valor" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valor a mostrar" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Formato" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Formato a mostrar" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Abrir el calendario" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Formato fecha" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Formato fecha actual" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "a" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Verdadero" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "v" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Falso" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Editar..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Adjuntos..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notas..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Acciones..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Relacionado..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Informe..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Correo electrónico..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Imprimir..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "S" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Preferencias..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "Barra de herramien_tas" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "Por _defecto" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "Texto _e iconos" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Texto" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_Iconos" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_Formulario" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Guardar ancho/alto" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Guardar estado de expansión del árbol" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Tabulación rápida" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Corrección ortográfica" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "_Límite de búsqueda..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_Correo electrónico..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Comprobar versión" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Opciones" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "Com_binaciones de teclas..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_Acerca de..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "Ay_uda" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "No se han encontrado resultados." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "Fa_voritos" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Acción" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "La acción seleccionada requiere cerrar todas las pestañas.¿Desea continuar?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Cerrar pestaña" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "modularidad, escalabilidad y seguridad" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "Créditos de traducción" #: tryton/gui/window/attachment.py:24 #, python-format msgid "Attachments (%s)" msgstr "Adjuntos (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Editor de perfiles" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Perfil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Servidor:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Base de datos:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Recuperando lista de bases de datos" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Nombre de usuario:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "El cliente no es compatible con la versión del servidor" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "No se ha podido conectar con el servidor" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Usuario" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Cancelar" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Cancelar conexión con el servidor Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onectar" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Conectar con el servidor Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Perfil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Información del Servidor / Base de datos" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Nombre de usuario:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Correo electrónico" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Configuración del programa de correo electrónico" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Línea de comando:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Leyenda de palabras clave disponibles:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Para:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Asunto:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Mensaje:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Adjunto:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Adjunto(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Nota(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Debe elegir un registro." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Creado por:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Fecha creación:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Última modificación por:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Última fecha de modificación:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modelo:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "¿Está seguro que quiere eliminar este registro?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "¿Está seguro que quiere eliminar estos registros?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Los registros no se han eliminado." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Registros eliminados." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Ahora está trabajando en el registro duplicado." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Registro guardado." #: tryton/gui/window/form.py:485 msgid " of " msgstr " de " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "Este registro ha sido modificado.¿Desea guardarlo?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Ejecutar acción" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "_Relacionado" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Abrir registros relacionados" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Informes" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Abrir informe" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Email" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Informe por email" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Imprimir" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Imprimir informe" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Copiar la URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Copiar la URL al portapapeles" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Desconocido" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Límite" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Preferencias del límite de búsqueda" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Límite:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notas (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferencias" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Editar preferencias de usuario" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferencias" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Versión" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Seleccionar una versión" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Versión:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Combinaciones de teclas" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Atajos en campos de texto" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Cortar texto seleccionado" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copiar texto seleccionado" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Pegar texto seleccionado" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Campo siguiente" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Campo anterior" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Atajos en relaciones" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Crear nueva relación" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Abrir/Buscar relación" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Atajos en listas" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Crear nueva línea" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Abrir relación" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Marcar para eliminación" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Desmarcar para eliminación" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Controles de edición" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Mover cursor" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Mover a la derecha" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Mover a la izquierda" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Mover arriba" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Mover abajo" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Mover arriba una página" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Mover abajo una página" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Mover al principio" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Mover al final" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Mover al padre" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Seleccionar todo" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Deseleccionar todo" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Seleccionar padre" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Seleccionar/Activar fila actual" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Conmutar selección" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Expandir/Contraer" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Expandir fila" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Contraer fila" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Conmutar fila" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Contraer todas las filas" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Expandir todas las filas" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Vista de árbol" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Cambiar vi_sta" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Cambiar vista" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Anterior" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Registro anterior" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Sig_uiente" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Registro siguiente" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Buscar" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nuevo" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Crear un nuevo registro" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Guardar" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Guardar este registro" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Recargar/Deshacer" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Recargar/Deshacer" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplicar" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Eliminar..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Ver _registro..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Mostrar versiones..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Adjun_tos..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Añadir un adjunto al registro" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notas..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Añadir una nota al registro" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Acciones..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Relacionado..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Informes..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_Correo electrónico..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Im_primir..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Exportar datos..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importar datos..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Copiar _URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Cerrar pestaña" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Todos los campos" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Añadir" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Eliminar" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Limpiar" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Campos seleccionados" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parámetros CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Separador de campo:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Delimitador de texto:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codificación:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nombre del campo" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Guardar exportación" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Eliminar exportación" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Exportaciones predeterminadas" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nombre" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Abrir" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Añadir nombres de _campo" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (cadena)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (nombre del modelo)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (nombre del registro)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "¿Cuál es el nombre de esta exportación?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Sobrescribir la definición de '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format msgid "%d record saved." msgstr "Se ha guardado %d registro." #: tryton/gui/window/win_export.py:330 #, python-format msgid "%d records saved." msgstr "Se han guardado %d registros." #: tryton/gui/window/win_export.py:333 #, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "Ha fallado la operación.Mensaje de error:%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Error" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Enlace" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 #, fuzzy msgid "New" msgstr "_Nuevo" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Cambiar vista" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Anterior" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Siguiente" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Añadir" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Eliminar " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Crear un nuevo registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Eliminar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Recuperar registro seleccionado " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_Auto-detectar" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Archivo a importar:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Abrir..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Líneas a omitir:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Primero debe elegir un archivo a importar." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Error al abrir el archivo CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Se ha producido un error al procesar el archivo en el campo %s." #: tryton/gui/window/win_import.py:198 #, python-format msgid "%d record imported." msgstr "Se ha importado %d registro." #: tryton/gui/window/win_import.py:200 #, python-format msgid "%d records imported." msgstr "Se han importado %d registros." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Buscar" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Buscar %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "No se ha podido eliminar el asistente %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Asistente" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Creado por:" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Fecha creación:" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Última modificación por:" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Última fecha de modificación:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format msgid "Unable to get view tree state for %s" msgstr "No se ha podido obtener el estado de expansión del árbol de %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "No se ha podido establecer el estado de expansión del árbol" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" no es válido según su dominio." #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" es obligatorio." #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Los valores de \"%s\" no son válidos." #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Prevalidación" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Tamaño de la imagen" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Anchura:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Altura:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Imagen PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Guardar como" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "El tamaño de la imagen es muy grande." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Abrir filtros" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Muestra las búsquedas favoritas" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Eliminar de las búsquedas favoritas" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Guardar como búsqueda favorita" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Mostrar registros activos" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Mostrar registros inactivos" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nombre de la búsqueda favorita:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Buscar" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Hoy:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "retroceder" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "ir adelante" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "año anterior" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "año próximo" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Vista semanal" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Vista mensual" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Semana" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Seleccionar…" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Limpiar" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Todos los archivos" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Mostrar como texto plano" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Añadir un valor" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Eliminar \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Imágenes" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Añadir un registro existente" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Eliminar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Abrir registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Eliminar el registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Buscar registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Eliminar registro seleccionado" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Editar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Primer plano" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Seleccione un color" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Traducción" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Editar" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Revisión" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Debe guardar el registro antes de añadir traducciones." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "No hay otro idioma disponible." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Traducir vista" tryton-5.0.17/tryton/data/locale/es_419/LC_MESSAGES/tryton.mo0000644000175000017500000004301313571264251022656 0ustar cedced00000000000000O  )<Mar  '8Ieu |  #0%Tz  !&* Q _ m{   + 8 P]p  %4 F P\c   5=MS jtz&     !,< ALSYa} " !(JPWfk      ) 8 FRZns x     )5G\d#y      - = C P Y a p y ~     !!'!>![!p! w! !! !!! !!!!!" ""+";"P"i"p"" " "" "" ""##1#A#S#b#k# r#~#I#}# ]$5~$8$$$ $%% "% .%8%=%]%$x%%%%%%&8&@& Y& f&q& w&& && & &&&(& & ' ''%.'7T'' '' ''' ' '' ' ' (((.(3( 9( C( M( W( b(o( w(( (( (((( (( (($( ) $)2)4)<R)) ))))))v+%{+++++,,,4,K, d,p,u,x,},,,,,$,,,#- $-1- 9-E-M-g-------!-1.3P. .. . .. ...///-/>N(>w>$?3-?8a??? ??? ?? ?7?(4@@]@.@'@=@93A%mA AAAAAAABB B*)BTB ]B0gBBBBB*B7B2C ACNCWC fCpCyCCC C CCCCD D D !D +D8DHD [D eDrD{DDDDD D DD,DE&E )E 7EEE/GE=wEE$EEEF F of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: es_419 Language-Team: es_419 Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 de "%s" no es válido según su dominio."%s" es obligatorio.Se ha importado %d registro.Se ha guardado %d registro.Se han importado %d registros.Se han guardado %d registros.%s (%s)%s (nombre del modelo)%s (nombre del registro)%s (cadena)%s%%, ,….....:Todos los camposCampos seleccionadosExportaciones predeterminadasCrear...Buscar...Esta disponible una nueva versión!Adjun_tos...AcciónAcciones...AñadirAñadir nombres de _campoAñadir una nota al registroAñadir un adjunto al registroAñadir un registro existenteAdd new profileAñadir un valorAdd...Todos los archivosIgnorar siempre esta advertencia.¿Está seguro que quiere eliminar este registro?¿Está seguro que quiere eliminar estos registros?Adjunto(%d)Adjunto:Adjuntos (%s)Adjuntos...Mensaje:Nombre de la búsqueda favorita:Guardar como búsqueda favoritaSeguimiento de erroresPor: CC:CSV Export: %sCSV Import: %sParámetros CSVC_onectarCancelar conexión con el servidor TrytonCancel savingURL de comprobación: %sComprobar versiónLimpiarEliminar el registro CloseCerrar pestañaContraer todas las filasContraer filaLínea de comando:CompararExcepción de concurrenciaConectar con el servidor TrytonError de conexión.Nombre de usuario o contraseña incorrectos.Copiar la URL al portapapelesCopiar _URL...Copiar texto seleccionadoNo se ha podido conectar con el servidorCrear un nuevo registroCrear un nuevo registro Crear nueva líneaCrear nueva relaciónSe creó un nuevo error con identificador Fecha creación:Fecha creación:Creado por:Creado por:Cortar texto seleccionadoBase de datos:Formato fechaDeleteEliminar registro seleccionado Separador de campo:Formato a mostrarFormato fecha actualValor a mostrar¿Desea continuar?DescargarEmailInforme por emailCorreo electrónico...EditarEditar preferencias de usuarioEditar registro seleccionado Editar...Controles de ediciónCorreo electrónicoConfiguración del programa de correo electrónicoCodificación:ErrorError al abrir el archivo CSVSe ha producido un error al procesar el archivo en el campo %s.Error: Excepción:Expandir todas las filasExpandir filaExpandir/ContraerFalsoTabulación rápidaRecuperando lista de bases de datosNombre del campoArchivo a importar:BuscarPrimer planoFormatoRevisiónAltura:Información del Servidor / Base de datosServidor:IDID:Tamaño de la imagenEl tamaño de la imagen es muy grande.ImágenesEl cliente no es compatible con la versión del servidorCombinaciones de teclasÚltima fecha de modificación:Última modificación por:Ejecutar acciónLeyenda de palabras clave disponibles:LímiteLímite:Líneas a omitir:EnlaceAtajos en listasUsuarioMManage...Marcar para eliminaciónModelo:Última fecha de modificación:Última modificación por:Vista mensualMover cursorMover abajoMover abajo una páginaMover al finalMover a la izquierdaMover al padreMover a la derechaMover al principioMover arribaMover arriba una páginaNombreSiguienteRegistro siguienteCampo siguienteNoNo se ha definido ninguna acción.No hay otro idioma disponible.No se han encontrado resultados.Nota(%d)Notas (%s)Notas...OKAbrirAbrir filtrosAbrir registros relacionadosAbrir relaciónAbrir informeAbrir el calendarioAbrir registro Abrir...Abrir/Buscar relaciónHa fallado la operación.Mensaje de error:%sSobrescribir la definición de '%s'?PDA ModeImagen PNG (*.png)Contraseña:Pegar texto seleccionadoPrevalidaciónPreferenciasPreferenciasAnteriorRegistro anteriorCampo anteriorImprimirImprimir informeImprimir...PerfilEditor de perfilesPerfil:QuitDelimitador de texto:Registro guardado.Los registros no se han eliminado.Registros eliminados._RelacionadoRelacionado...Atajos en relacionesRecargar/DeshacerEliminar "%s"Eliminar Remove selected profileEliminar registro seleccionadoEliminar registro seleccionado Eliminar de las búsquedas favoritasInformesInformar del errorInforme...VersiónVersión:GuardarGuardar comoGuardar como...Guardar estado de expansión del árbolGuardar ancho/altoGuardar este registroSave your current versionBuscarBuscar %sPreferencias del límite de búsqueda_Límite de búsqueda...Buscar registro See the modified versionSeleccionarSeleccione un colorSeleccionar una versiónSeleccionar todoSeleccionar padreSeleccione su acciónSeleccionar…Seleccionar/Activar fila actualSelecciónMostrar registros activosMuestra las búsquedas favoritasMostrar registros inactivosMostrar como texto planoMostrar versiones...Corrección ortográficaAsunto:Cambiar vistaCambiar vistaAtajos en campos de textoLa acción seleccionada requiere cerrar todas las pestañas.¿Desea continuar?El mismo error ya fue notificado por otro usuario.Para mantenerle informado añadiremos su usuario a la lista de interesados en esta incidencia.Los valores de "%s" no son válidos.Este registro ha sido modificado.¿Desea guardarlo?This record has been modified while you were editing it.Para:Hoy:Conmutar filaConmutar selecciónTraducir vistaTraducciónVista de árbolVerdaderoNo se ha podido comprobar si existe una nueva versión.No se ha podido eliminar el asistente %sNo se ha podido obtener el estado de expansión del árbol de %sNo se ha podido buscar el autocompletado de %sNo se ha podido establecer el idioma %sNo se ha podido establecer el estado de expansión del árbolNo se ha podido escribir el archivo de configuración %s.Recuperar registro seleccionado DesconocidoDesmarcar para eliminaciónDeseleccionar todoNombre de usuario:Usuario:Nombre de usuario:ValorVer _registro...SemanaVista semanal¿Cuál es el nombre de esta exportación?Anchura:AsistenteAhora está trabajando en el registro duplicado.Guardar de todas formasASíDebe elegir un registro.Primero debe elegir un archivo a importar.Debe guardar el registro antes de añadir traducciones.Su selección:_Acciones..._Añadir_Auto-detectar_Cancelar_Limpiar_Cerrar pestaña_Copiar la URL_Eliminar exportación_Eliminar..._Duplicar_Correo electrónico..._Exportar datos..._Importar datos..._NuevoSig_uiente_Notas..._AnteriorIm_primir..._Relacionado..._Recargar/Deshacer_Eliminar_Informes..._Guardar_Guardar exportación_BuscarCambiar vi_stadModo desarrolloretrocederir adelantehRegistra toda la información con nivel INFOmmodularidad, escalabilidad y seguridadaño próximoaño anteriorsIndica un archivo de configuración alternativoIndica el nivel de log: DEBUG, INFO, WARNING, ERROR, CRITICALIndica el usuarioIndica el nombre:puerto del servidorvCréditos de traducciónSatryton-5.0.17/tryton/data/locale/fr/0000755000175000017500000000000013571264253016601 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/fr/LC_MESSAGES/0000755000175000017500000000000013571264253020366 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/fr/LC_MESSAGES/tryton.po0000644000175000017500000011233013463252532022262 0ustar cedced00000000000000# French (France) translations for tryton. # Copyright (C) 2008-2013 B2CK # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2008-2013. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "spécifier un fichier de configuration alternatif" #: tryton/config.py:77 msgid "development mode" msgstr "mode développement" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "logger tout au niveau INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "spécifie le niveau de log : DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "spécifier l'utilisateur de login" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "spécifier le nom du serveur:port" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "Impossible d'écrire le fichier de configuration %s." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Impossible de sélectionner la locale %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Sélectionnez votre action" #: tryton/action/main.py:193 msgid "No action defined." msgstr "Pas d'action définie." #: tryton/common/button.py:54 msgid "By: " msgstr "Par: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Sélection" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 msgid "Cancel" msgstr "Annuler" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "OK" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Votre sélection :" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Sélectionner" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Sauver" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Enregistrer sous..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Toujours ignorer cet avertissement." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Souhaitez-vous continuer ?" #: tryton/common/common.py:643 msgid "No" msgstr "Non" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Oui" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Erreur d'accès concurrent" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" "Cet enregistrement a été modifié pendant que vous étiez en train de " "l'éditer." #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "Annuler la sauvegarde" #: tryton/common/common.py:696 msgid "Compare" msgstr "Comparer" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "Voir la version modifiée" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Écraser" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "Sauver votre version actuelle" #: tryton/common/common.py:729 msgid "Application Error" msgstr "Erreur Applicative" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Rapporter un bogue" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "Fermer" #: tryton/common/common.py:751 msgid "Error: " msgstr "Erreur : " #: tryton/common/common.py:768 #, python-format, python-format msgid "To report bugs you must have an account on %s" msgstr "Pour rapporter un bogue vous devez avoir un compte sur %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Bug Tracker" #: tryton/common/common.py:811 msgid "User:" msgstr "Utilisateur :" #: tryton/common/common.py:819 msgid "Password:" msgstr "Mot de passe :" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Le même bogue a été déjà rapporté par un autre utilisateur.\n" "Pour vous garder informé, votre nom d'utilisateur a été ajouté à la liste de suivi de ce bogue" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Un nouveau bogue a été créé avec l'ID " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Erreur de connexion.\n" "Mauvais nom d'utilisateur ou mot de passe." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Exception :" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "Vérification de l'URL: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "Impossible de vérifier les nouvelles versions" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Un nouvelle version est disponible !" #: tryton/common/common.py:942 msgid "Download" msgstr "Télécharger" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Recherche..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Créer..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "Impossible de rechercher la complétion de %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valeur" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valeur affichée" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Format" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Format d'affichage" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Ouvrir le calendrier" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Format de date" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Format de date affichée" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "y" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Vrai" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "v" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Faux" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Éditer..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Attachements..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notes..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Actions..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Relation..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Rapport..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "E-mail..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Imprimer..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "S" #: tryton/common/timedelta.py:29 msgid "d" msgstr "j" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 msgid "Preferences..." msgstr "Préférences..." #: tryton/gui/main.py:127 msgid "Toolbar" msgstr "Barre d'outils" #: tryton/gui/main.py:128 msgid "Default" msgstr "Défaut" #: tryton/gui/main.py:129 msgid "Text and Icons" msgstr "Textes et Icônes" #: tryton/gui/main.py:130 msgid "Text" msgstr "Textes" #: tryton/gui/main.py:131 msgid "Icons" msgstr "Icônes" #: tryton/gui/main.py:134 msgid "Form" msgstr "Formulaire" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Sauver largeur / hauteur" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Sauver l'état des arbres" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Tabulation rapide" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Vérifier l'orthographe" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "Mode PDA" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Limite la recherche à..." #: tryton/gui/main.py:142 msgid "Email..." msgstr "E-mail..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Vérifier la version" #: tryton/gui/main.py:145 msgid "Options" msgstr "Options" #: tryton/gui/main.py:148 msgid "Keyboard Shortcuts..." msgstr "Raccourcis clavier..." #: tryton/gui/main.py:149 msgid "About..." msgstr "À Propos..." #: tryton/gui/main.py:150 msgid "Help" msgstr "Aide" #: tryton/gui/main.py:153 msgid "Quit" msgstr "Quitter" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Aucun résultat trouvé." #: tryton/gui/main.py:447 msgid "Favorites" msgstr "Favoris" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "Gérer..." #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Actions" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "L'action suivante nécessite de fermer tous les onglets.\n" "Voulez-vous continuer ?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Fermer l'onglet" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "modularité, évolutivité et sécurité" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" "Cédric Krier\n" "Nicolas Évrard" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Attachements (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Éditeur de profil" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "Ajouter un nouveau profile" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "Supprimer le profile sélectionné" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Hôte :" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Base de données :" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Récupération de la liste des bases de données" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Nom d'utilisateur :" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Version du serveur incompatible" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Impossible de se connecter au serveur" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Connexion" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "A_nnuler" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Annuler la connexion au serveur Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onnecter" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Se connecter au serveur Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profil :" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Hôte / Port" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Nom d'utilisateur :" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "E-mail" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Paramètres d'e-mail" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Commande :" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Légende des symboles :" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "À :" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC :" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Sujet :" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Corps :" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Attachement :" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "Ajouter..." #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Attachement(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Note(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Vous devez sélectionner un enregistrement." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID :" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Créé par l'utilisateur :" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Date de création :" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Dernière modification par :" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Date de dernière modification :" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modèle :" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Êtes-vous sûr de vouloir supprimer cet enregistrement ?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Êtes-vous sûr de vouloir supprimer ces enregistrements ?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Enregistrements non supprimés." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Enregistrements supprimés." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Sur les enregistrement(s) dupliqué(s) maintenant." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Enregistrement sauvegardé." #: tryton/gui/window/form.py:485 msgid " of " msgstr " de " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Cet enregistrement a été modifié\n" "voulez-vous le sauvegarder ?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Lancer une action" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Relation" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Ouvrir les enregistrements liés" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Rapport" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Ouvrir un rapport" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Rapport par email" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Imprimer" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Imprimer un rapport" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Copier l'URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Copier l'URL dans le presse-papiers" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Inconnu" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limite" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Limite de recherche" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Limite :" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notes (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Préférences" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Éditer les préférences utilisateur" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Préférence" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Révision" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Sélectionner une révision" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Révision :" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Raccourcis clavier" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Raccourcis des champs texte" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Couper le texte sélectionné" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copier le texte sélectionné" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Coller le texte copié" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Widget suivant" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Widget précédent" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Raccourcis des champs relation" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Créer une nouvelle relation" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Ouvrir/Chercher une relation" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Raccourcis des listes" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Créer une nouvelle ligne" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Ouvrir une relation" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Marquer la ligne pour suppression" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Annuler le marquage de la ligne pour suppression" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Widgets d'édition" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Déplacer le curseur" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Déplacer vers la droite" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Déplacer vers la gauche" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Déplacer vers le haut" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Déplacer vers le bas" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Déplacer vers le haut d'une page" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Déplacer vers le bas d'une page" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Déplacer au dessus" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Déplacer en bas" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Déplacer au parent" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Tout sélectionner" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Désélectionner tout" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Sélectionner le parent" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Sélectionner/Activer la ligne courante" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Basculer la sélection" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Déplier/Replier" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Déplier la ligne" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Replier la ligne" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Basculer la ligne" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Replier toutes les lignes" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Déplier toutes les lignes" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Vue arborescente" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_Changer de vue" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Changer de vue" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Précédent" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Enregistrement précédent" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Sui_vant" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Enregistrement suivant" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Recherche" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nouveau" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Créer un nouvel enregistrement" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Sauver" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Sauver cet enregistrement" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Recharger/Annuler" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Recharger/Annuler" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Dupliquer" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Su_pprimer..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Voir les _Logs..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Afficher les révisions..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "_Pièce jointes..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Ajouter un attachement à l'enregistrement" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notes..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Ajouter une note à l'enregistrement" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Actions..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Relation..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Rapport..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_E-mail..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Imprimer..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Export de données..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Import de données..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Copier l'_URL" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Fermer l'onglet" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Tout les champs" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Ajouter" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Enlever" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Effacer" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Champs sélectionnés" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Paramètres CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Délimiteur :" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Caractère de guillemet :" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codage :" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nom du champ" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "Export CSV: %s" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Sauver l'exportation" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Supprimer l'exportation" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Exportations prédéfinies" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nom" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Ouvrir" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Ajouter les noms des champs" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (string)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (nom de l'enregistrement)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (nom de l'enregistrement)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Quel est le nom de cet export ?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Surcharger la définition « %s » ?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "%d enregistrement sauvé." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "%d enregistrements sauvés." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Échec de l'opération.\n" "Message d'erreur :\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Erreur" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Lien" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Suppression" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Nouveau" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Basculer" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Précédent" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Suivant" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Ajouter" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Supprimer " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Créer un nouvel enregistrement" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Supprimer l'enregistrement sélectionné" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Restaurer l'enregistrement sélectionné" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "Import CSV: %s" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "Détection _automatique" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Fichier à importer :" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Ouvrir..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Lignes à ignorer :" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Vous devez d'abord sélectionner un fichier d'import." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Erreur d'ouverture du fichier CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Erreur lors du traitement du fichier du champ %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "%d enregistrement importé." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "%d enregistrements importés." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Recherche" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Rechercher %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "Impossible de supprimer l'assistant %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Assistant" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Créé par l'utilisateur" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Date de création" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Modifié par l'utilisateur" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Date de modification" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "Impossible d'obtenir l'état de la vue arbre de %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Impossible de définir l'état de la vue arbre" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "« %s » n'est pas valide selon son domaine" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "« %s » est requis" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Les valeurs de « %s » ne sont pas valides" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Pré-validation" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr " :" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Taille de l'image" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Largeur :" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Hauteur :" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "image PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Enregistrer sous" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "Taille de l'image trop grande." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Ouvrir les filtres" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Montrer les marques-pages des filtres" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Supprimer ce marque-page" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Sauver ce filtre" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Montrer les enregistrements actifs" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Montrer les enregistrements inactifs" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nom du marque-page :" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Chercher" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Aujourd'hui" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "revenir" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "avancer" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "année précédente" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "année suivante" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Vue semaine" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Vue mois" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Semaine" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Sélectionner..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Effacer" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Tous les fichiers" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Montrer en text clair" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Ajouter une valeur" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Supprimer « %s »" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Images" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Ajouter un enregistrement existant" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Supprimer l'enregistrement sélectionné" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Ouvrir l'enregistrement " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Effacer le champ " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Chercher un enregistrement" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Supprimer l'enregistrement sélectionné" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Éditer l'enregistrement sélectionné" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Couleur du texte" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Sélectionner une couleur" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Traduction" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Éditer" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Floue" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "" "Vous devez sauvegarder l'enregistrement avant d'ajouter des traductions." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "Pas d'autre langue disponible." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Traduire la vue" tryton-5.0.17/tryton/data/locale/fr/LC_MESSAGES/tryton.mo0000644000175000017500000004516013571264251022266 0ustar cedced00000000000000` )"L]q 7HYu   #-I#[%  .=LU&\      $+>j  ,: IWf x   " 0:?Uow &  )9 ? LV ny  "2E[u ! %7 I T `j        : K T _ h k p }     # !!6!?! Q![!m! |! !!!!!! !!!!!" " "&";"L" S"]" x" " """""" # ## ##-#2# :#E#U#g#x## ####### $ $ *$8$ K$U$ q${$$$$$$$$ % %%(%I7%}% %5 &8V&-&&& &&&& & '''5'$P'%u'''''(( 1( >(I( O(Y( _(m( r( |((((( ((((%)7,)d) t)) ))) ) )) ) ) )))* * * * %* /* :*G* O*Z* `*m* u**** ** **$* * * + +<*+g+ ~++++++E--J-x------.#. @.L.Q.T.Y.\.`.d.{.!...%./ /%/ -/8/@/$\/*/"/// /0#0>0:Q0;00000 11(1 91E1K1Q1`1o1 11&1111122%252O2 `2l2u22?2#2 3!3%?3e3#333*3 4424K4g4444 4-444 5%565 R5`5g5 y55%5*5 5556 6 6*6!161S6 6 666666606 +787O7X7 i7t7{7 77 7777777778#8!98[8y888 8888 88 8!8 9(9=9X9a9v9 99999::!/:Q:U:]:e:|:::::: ::::; ;9;M;_;t; ;;.;;';< <2<B<Y< i< v<< <<<<< <<< ==$=?=[={== =====">(%>-N>|>>> > > >>>>>?1?K? i? s????? ??@,@?@W@r@'@ @"@%@$@$A:AUAmAvAAAAAQAB-BABR+C9~CC CCCCD DD.D.3D&bD2D-D(D.E4BE-wEE0EEE FF-F4FFF NF ZF {F F2FFFF+F5FH4G}G GGGGGG GG H H !H,HCHZHcH lH vH H HHH HHH HHHIII$I&IAI(CIlI|II1ICI!J!*JLJNJlJnJ of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...About...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Application ErrorAre you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancelCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDefaultDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEmail...Encoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFormFormatFuzzyHeight:HelpHost / Database informationHost:IDID:IconsImage SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsKeyboard Shortcuts...Latest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOptionsOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreferences...PreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewTextText Entries ShortcutsText and IconsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To report bugs you must have an account on %sTo:TodayToggle rowToggle selectionToolbarTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: fr Language-Team: fr Plural-Forms: nplurals=2; plural=(n > 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 de « %s » n'est pas valide selon son domaine« %s » est requis%d enregistrement importé.%d enregistrement sauvé.%d enregistrements importés.%d enregistrements sauvés.%s (%s)%s (nom de l'enregistrement)%s (nom de l'enregistrement)%s (string)%s%%, ,…..... :Tout les champsChamps sélectionnésExportations prédéfiniesCréer...Recherche...Un nouvelle version est disponible !_Pièce jointes...À Propos...ActionsActions...AjouterAjouter les noms des champsAjouter une note à l'enregistrementAjouter un attachement à l'enregistrementAjouter un enregistrement existantAjouter un nouveau profileAjouter une valeurAjouter...Tous les fichiersToujours ignorer cet avertissement.Erreur ApplicativeÊtes-vous sûr de vouloir supprimer cet enregistrement ?Êtes-vous sûr de vouloir supprimer ces enregistrements ?Attachement(%d)Attachement :Attachements (%s)Attachements...Corps :Nom du marque-page :Sauver ce filtreBug TrackerPar: CC :Export CSV: %sImport CSV: %sParamètres CSVC_onnecterAnnulerAnnuler la connexion au serveur TrytonAnnuler la sauvegardeVérification de l'URL: %sVérifier la versionEffacerEffacer le champ FermerFermer l'ongletReplier toutes les lignesReplier la ligneCommande :ComparerErreur d'accès concurrentSe connecter au serveur TrytonErreur de connexion. Mauvais nom d'utilisateur ou mot de passe.Copier l'URL dans le presse-papiersCopier l'_URLCopier le texte sélectionnéImpossible de se connecter au serveurCréer un nouvel enregistrementCréer un nouvel enregistrementCréer une nouvelle ligneCréer une nouvelle relationUn nouveau bogue a été créé avec l'ID Date de créationDate de création :Créé par l'utilisateurCréé par l'utilisateur :Couper le texte sélectionnéBase de données :Format de dateDéfautSuppressionSupprimer l'enregistrement sélectionnéDélimiteur :Format d'affichageFormat de date affichéeValeur affichéeSouhaitez-vous continuer ?TéléchargerE-mailRapport par emailE-mail...ÉditerÉditer les préférences utilisateurÉditer l'enregistrement sélectionnéÉditer...Widgets d'éditionE-mailParamètres d'e-mailE-mail...Codage :ErreurErreur d'ouverture du fichier CSVErreur lors du traitement du fichier du champ %s.Erreur : Exception :Déplier toutes les lignesDéplier la ligneDéplier/ReplierFauxTabulation rapideFavorisRécupération de la liste des bases de donnéesNom du champFichier à importer :ChercherCouleur du texteFormulaireFormatFloueHauteur :AideHôte / PortHôte :IDID :IcônesTaille de l'imageTaille de l'image trop grande.ImagesVersion du serveur incompatibleRaccourcis clavierRaccourcis clavier...Date de dernière modification :Dernière modification par :Lancer une actionLégende des symboles :LimiteLimite :Lignes à ignorer :LienRaccourcis des listesConnexionMGérer...Marquer la ligne pour suppressionModèle :Date de modificationModifié par l'utilisateurVue moisDéplacer le curseurDéplacer vers le basDéplacer vers le bas d'une pageDéplacer en basDéplacer vers la gaucheDéplacer au parentDéplacer vers la droiteDéplacer au dessusDéplacer vers le hautDéplacer vers le haut d'une pageNomNouveauSuivantEnregistrement suivantWidget suivantNonPas d'action définie.Pas d'autre langue disponible.Aucun résultat trouvé.Note(%d)Notes (%s)Notes...OKOuvrirOuvrir les filtresOuvrir les enregistrements liésOuvrir une relationOuvrir un rapportOuvrir le calendrierOuvrir l'enregistrement Ouvrir...Ouvrir/Chercher une relationÉchec de l'opération. Message d'erreur : %sOptionsSurcharger la définition « %s » ?Mode PDAimage PNG (*.png)Mot de passe :Coller le texte copiéPré-validationPréférencePréférencesPréférences...PrécédentEnregistrement précédentWidget précédentImprimerImprimer un rapportImprimer...ProfilÉditeur de profilProfil :QuitterCaractère de guillemet :Enregistrement sauvegardé.Enregistrements non supprimés.Enregistrements supprimés.RelationRelation...Raccourcis des champs relationRecharger/AnnulerSupprimer « %s »Supprimer Supprimer le profile sélectionnéSupprimer l'enregistrement sélectionnéSupprimer l'enregistrement sélectionnéSupprimer ce marque-pageRapportRapporter un bogueRapport...RévisionRévision :SauverEnregistrer sousEnregistrer sous...Sauver l'état des arbresSauver largeur / hauteurSauver cet enregistrementSauver votre version actuelleRechercheRechercher %sLimite de rechercheLimite la recherche à...Chercher un enregistrementVoir la version modifiéeSélectionnerSélectionner une couleurSélectionner une révisionTout sélectionnerSélectionner le parentSélectionnez votre actionSélectionner...Sélectionner/Activer la ligne couranteSélectionMontrer les enregistrements actifsMontrer les marques-pages des filtresMontrer les enregistrements inactifsMontrer en text clairAfficher les révisions...Vérifier l'orthographeSujet :BasculerChanger de vueTextesRaccourcis des champs texteTextes et IcônesL'action suivante nécessite de fermer tous les onglets. Voulez-vous continuer ?Le même bogue a été déjà rapporté par un autre utilisateur. Pour vous garder informé, votre nom d'utilisateur a été ajouté à la liste de suivi de ce bogueLes valeurs de « %s » ne sont pas validesCet enregistrement a été modifié voulez-vous le sauvegarder ?Cet enregistrement a été modifié pendant que vous étiez en train de l'éditer.Pour rapporter un bogue vous devez avoir un compte sur %sÀ :Aujourd'huiBasculer la ligneBasculer la sélectionBarre d'outilsTraduire la vueTraductionVue arborescenteVraiImpossible de vérifier les nouvelles versionsImpossible de supprimer l'assistant %sImpossible d'obtenir l'état de la vue arbre de %sImpossible de rechercher la complétion de %sImpossible de sélectionner la locale %sImpossible de définir l'état de la vue arbreImpossible d'écrire le fichier de configuration %s.Restaurer l'enregistrement sélectionnéInconnuAnnuler le marquage de la ligne pour suppressionDésélectionner toutNom d'utilisateur :Utilisateur :Nom d'utilisateur :ValeurVoir les _Logs...SemaineVue semaineQuel est le nom de cet export ?Largeur :AssistantSur les enregistrement(s) dupliqué(s) maintenant.ÉcraserAOuiVous devez sélectionner un enregistrement.Vous devez d'abord sélectionner un fichier d'import.Vous devez sauvegarder l'enregistrement avant d'ajouter des traductions.Votre sélection :_Actions..._AjouterDétection _automatiqueA_nnuler_Effacer_Fermer l'onglet_Copier l'URL_Supprimer l'exportationSu_pprimer..._Dupliquer_E-mail..._Export de données..._Import de données..._NouveauSui_vant_Notes..._Précédent_Imprimer..._Relation..._Recharger/Annuler_Enlever_Rapport..._Sauver_Sauver l'exportation_Recherche_Changer de vuejmode développementreveniravancerhlogger tout au niveau INFOmmodularité, évolutivité et sécuritéannée suivanteannée précédentesspécifier un fichier de configuration alternatifspécifie le niveau de log : DEBUG, INFO, WARNING, ERROR, CRITICALspécifier l'utilisateur de loginspécifier le nom du serveur:portvCédric Krier Nicolas ÉvrardSytryton-5.0.17/tryton/data/locale/bg/0000755000175000017500000000000013571264253016562 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/bg/LC_MESSAGES/0000755000175000017500000000000013571264253020347 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/bg/LC_MESSAGES/tryton.po0000644000175000017500000011503313463252532022246 0ustar cedced00000000000000# Bulgarian (Bulgaria) translations for tryton. # Copyright (C) 2010 B2CK # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2010. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "укажете друг конфигурационен файл" #: tryton/config.py:77 msgid "development mode" msgstr "" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "записване на всичко на ниво INFO " #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:85 msgid "specify the login user" msgstr "укажете потребителското име" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "укажете адреса на сървъра" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Не може да запише конфигурационен файл %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Не може да зададе локални настройки %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Изберете действие" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Не е зададено действие!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Избор:" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "Отказ" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Вашия избор" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Съхраняване" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Запис като ..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Винаги игнорирай това предупреждение." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Грешка при достъп" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Сравняване" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Запис" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Грешка в приложението!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Съобщаване за грешка" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Грешка: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "За да съобщите за грешка трябва да имате сметка на %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "" #: tryton/common/common.py:811 msgid "User:" msgstr "Потребител: " #: tryton/common/common.py:819 msgid "Password:" msgstr "Парола:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Тази грешка е вече съобщена от друг потребител..\n" "За да бъдете информирани потребителя ви е добавен списъка за този проблем" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Създадена е нова грешка с ID" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Грешка при свързване!\n" "Грешно потребителско име или парола!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Грешка:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "" #: tryton/common/completion.py:27 msgid "Create..." msgstr "" #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "Лъжа" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "Нормален" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "Отваряне на календара" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "г" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Истина" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Лъжа" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "Изход..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Прикачен файл:" #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Действия..." #: tryton/common/popup_menu.py:108 #, fuzzy msgid "Relate..." msgstr "Свързани..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Справки..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Email..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Печат..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "Г" #: tryton/common/timedelta.py:27 msgid "M" msgstr "М" #: tryton/common/timedelta.py:28 msgid "w" msgstr "с" #: tryton/common/timedelta.py:29 msgid "d" msgstr "д" #: tryton/common/timedelta.py:30 msgid "h" msgstr "ч" #: tryton/common/timedelta.py:31 msgid "m" msgstr "м" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "Предпочитания..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "Лента с инструменти" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "По подразбиране" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "Текс и икони" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "Текст" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "Икони" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "Форма" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Запазване на ширина/височина" #: tryton/gui/main.py:136 #, fuzzy msgid "Save Tree State" msgstr "Запазване на състояние разгърнато дърво" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Проверка на правопис" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Ограничение при търсене..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "Email..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "Настройки" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "Бързи клавиши..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "Относно..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "Помощ" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "" #: tryton/gui/main.py:447 msgid "Favorites" msgstr "" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Действие" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Следващите действия изискват затваряне на всички прозорци.\n" "Искате ли да продължите?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Затваряне на таб" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Прикачен файл(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Редактор на профили" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Профил" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Хост:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "База данни:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Вземане на списъка с бази данни:" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Потребителско име:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Несъвместима версия на сървъра!" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Не може да се свърже със сървъра!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Потребителско име" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "Отказ" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Отказ от свръзване с Tryton сървъра" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "Свързване" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Свързване с Tryton сървъра" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Профил:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Информация за Хост / База данни" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Потребителско име:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Email" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Настройки на програма за email" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Команден ред:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Лагенда за налични контейнери:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "До" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Относно:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Тяло:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Прикачен файл:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Прикачен файл(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Трябва да изберете един запис!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Потребител създал:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Дата на създаване:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Последно променен от:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Дата на последна промяна:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Модел:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Наистина ли искате да изтриете този запис?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Наистина ли искате да изтриете тези записи?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Записа не е изтрит!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Записите изтрити!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Работите върху дублиран(и) запис(и)!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Записа съхранен!" #: tryton/gui/window/form.py:485 msgid " of " msgstr " от" #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Този запис е променен\n" "искате ли да го запишете ?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Започване на действие" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Свързани" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Отваряне на свързани записи" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Справки" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Отваряне на справка" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Email" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Изращане на справка по Email" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Печат" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Отпечатване на справка" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Неизвестен" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Ограничение" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Настройки на органичения за търсене" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Ограничение:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Настройки" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Редактиране на потребителски настройки" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Настройки" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "Предишен" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "Избор:" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "Предишен" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Бързи клавиши" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Текстови бързи клавиши" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Изрязване на избрания текст" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Копиране на избрания текст" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Поставяне на копирания текст" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Следваща джаджа" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Предишенна джаджа" #: tryton/gui/window/shortcuts.py:41 #, fuzzy msgid "Relation Entries Shortcuts" msgstr "Текстови бързи клавиши" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Създаване на нова връзка" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Отваряне/Търсене на връзка" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Списък бързи клавиши" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Създаване на нов ред" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Отваряне на връзка" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Отбелязване на ред за изтриване" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Изчистване на ред за изтриване" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Превключване на изглед" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "Превключване на изглед" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "Предишен" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Предишен запис" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Следващ" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Следващ запис" #: tryton/gui/window/tabcontent.py:61 #, fuzzy msgid "_Search" msgstr "Търсене" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "Нов" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Създаване на нов запис" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "Съхраняване" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Съхраняване на този запис" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Презареждане/Обратно" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "Презареждане/Обратно" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "Дублиране" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Изтриване..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Преглед на логове" #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 #, fuzzy msgid "A_ttachments..." msgstr "Прикачен файл:" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Добавяне на прикачен файл към записа" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "Действия..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "Свързани..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "Справки..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "Email..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Печат..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Извличане на данни..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Вмъкване на данни..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Затваряне на таб" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Всички полета" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "Добавяне" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "Изтриване" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Изчистване" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV параметри" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Кодиране:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Име на поле" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Запис на извличане" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Изтриване на извличане" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Предварително зададени извличания" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Име" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Отваряне" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Добавяне на имена на полета" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Какво е името на това извличане?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d заспис съхранен!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d записа съхранени!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Операцията неуспешна!\n" "Съобщение за грешка:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Грешка" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Връзка" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Изтриване" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Нов" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Превключване" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Предишен" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Следващ" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Добавяне" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Изтриване " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Създаване на нов запис " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Изтриване на избрания запис " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Възтановяване на избрания запис " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Автоматично разпознаване" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Файл за вмъкване:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Отваряне..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Редове за пропускане:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Първо трябва да изберете файл за вмъкване!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Грешка при отваряне на CSV файл" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Грешка при обработка на файл при поле %s" #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d запис вмъкнат!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d записи вмъкнати!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Търсене" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Помощник" #: tryton/gui/window/view_form/screen/screen.py:206 #, fuzzy msgid "ID" msgstr "д" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "Потребител създал:" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "Дата на създаване:" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "Дата на последна промяна:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "Дата на последна промяна:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "Не може да зададе локални настройки %s" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "Не може да зададе локални настройки %s" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Размер на изображение" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Ширина:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Височина:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG изображение (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Запис като" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Размера на изображението е много голям!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Търсене" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "Тяло:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "Превключване на изглед" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "Превключване на изглед" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Изчистване" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Всички файлове" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Показване само на текст" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Изображения" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 #, fuzzy msgid "Add existing record" msgstr "Съхраняване на този запис" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 #, fuzzy msgid "Remove selected record " msgstr "Изтриване на избрания запис " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Отваряне на запис" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Тъсене на запис" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 #, fuzzy msgid "Remove selected record" msgstr "Изтриване на избрания запис " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Редактиране на избрания запис" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 #, fuzzy msgid "Translation" msgstr "Добавяне на превод" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Редактиране" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Неясно" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Трябва да съхраните записа преди да добавите преводи!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Няма наличен друг език!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Превод на изглед" tryton-5.0.17/tryton/data/locale/bg/LC_MESSAGES/tryton.mo0000644000175000017500000004007513571264251022247 0ustar cedced00000000000000) "'*,>Uo   ' .8#T%x  %4&= d r     7DWw  '. KVe{   -7=&T{       'CI MX"_ !/5 7AX _ ku     & /:CF KX m {   $4D JW`hw      $5O V`v    &:TjzI}  8  "B%]       7 > E R T X h t y     ! !! !+! 1!>!@!Q! Y!d! f!!$! ! !!!<!#":"<"O"Q"S"#)#$"$*$:$ K$W$\$_$ a$$G$$$%%0%D%2U%%C%% %%&F"&Mi&O&'%'@' ['e't' ''''''';' "( 0( >(L(a(w(}(( ((( (+ )6) N)1[);))).)%"*-H*1v*!*"*3*!+ 6+B+9U+ +++++++/+&,/,IF,7,,,3,- $-61-Gh-- -- --- . .:.S.h.. . ..8. ./(/1/:H//./'/(/80V0m0'0 0&0!01 1:1 K1 W1 c1m11 11 1 1111112292<2M2 V2a2j2m2 ~232"2$2313M3g3"p3 353333 44!94 [4*f4 4 4$4 44 44 5 5&5>5S5&b5555555/6D6^6 m6Bw6/667 7'7 67 A7!O7 q7{7 7777+78&%8L8\8*u88;9 :8<:u: z::: : :::%;D-;Ar;;8; <"<2<"I< l<<:< << <<<<=(= 9=D= c=m===%=#=== = > >(>'<>d>w>>*>>>> >>8>.?$1? V? `?n??p?<?4?"@$@7@:@ of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationHost:ID:Image SizeImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:RelateRemove "%s"Remove Remove selected profileRemove this bookmarkReportReport BugReport...SaveSave AsSave As...Save Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUndelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: bg Language-Team: bg Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 от"%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:Всички полетаFields selectedПредварително зададени извличанияCreate...Search...A new version is available!ДействиеДействия...ДобавянеДобавяне на имена на полетаAdd a note to the recordДобавяне на прикачен файл към записаAdd new profileAdd valueAdd...Всички файловеВинаги игнорирай това предупреждение.Наистина ли искате да изтриете този запис?Наистина ли искате да изтриете тези записи?Прикачен файл(%d)Прикачен файл:Прикачен файл:Тяло:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV параметриСвързванеОтказ от свръзване с Tryton сървъраCancel savingCheck URL: %sCheck VersionИзчистванеClear the field CloseЗатваряне на табCollapse all rowsCollapse rowКоманден ред:СравняванеГрешка при достъпСвързване с Tryton сървъраCopy URL into clipboardCopy _URL...Копиране на избрания текстНе може да се свърже със сървъра!Създаване на нов записСъздаване на нов запис Създаване на нов редСъздаване на нова връзкаСъздадена е нова грешка с IDДата на създаване:Потребител създал:Изрязване на избрания текстБаза данни:Date FormatИзтриванеИзтриване на избрания запис Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadEmailИзращане на справка по EmailEmail...РедактиранеРедактиране на потребителски настройкиРедактиране на избрания записEdition WidgetsEmailНастройки на програма за emailКодиране:ГрешкаГрешка при отваряне на CSV файлГрешка при обработка на файл при поле %sГрешка: Грешка:Expand all rowsExpand rowExpand/CollapseЛъжаFast TabbingFavoritesВземане на списъка с бази данни:Име на полеФайл за вмъкване:ТърсенеForegroundНеясноВисочина:Информация за Хост / База данниХост:ID:Размер на изображениеИзображенияНесъвместима версия на сървъра!Бързи клавишиДата на последна промяна:Последно променен от:Започване на действиеЛагенда за налични контейнери:ОграничениеОграничение:Редове за пропускане:ВръзкаСписък бързи клавишиПотребителско имеМManage...Отбелязване на ред за изтриванеМодел:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageИмеНовСледващСледващ записСледваща джаджаNoNo result found.Note(%d)Notes (%s)Notes...OKОтварянеOpen filtersОтваряне на свързани записиОтваряне на връзкаОтваряне на справкаОтваряне...Отваряне/Търсене на връзкаOverride '%s' definition?PDA ModePNG изображение (*.png)Парола:Поставяне на копирания текстPre-validationНастройкиНастройкиПредишенПредишен записПредишенна джаджаПечатОтпечатване на справкаПечат...ПрофилРедактор на профилиПрофил:QuitQuote char:СвързаниRemove "%s"Изтриване Remove selected profileRemove this bookmarkСправкиСъобщаване за грешкаСправки...СъхраняванеЗапис катоЗапис като ...Запазване на ширина/височинаСъхраняване на този записSave your current versionТърсенеSearch %sНастройки на органичения за търсенеОграничение при търсене...Тъсене на записSee the modified versionSelectSelect a colorSelect allSelect parentИзберете действиеSelect...Select/Activate current rowИзбор:Show active recordsShow bookmarks of filtersShow inactive recordsПоказване само на текстShow revisions...Проверка на правописОтносно:ПревключванеТекстови бързи клавишиСледващите действия изискват затваряне на всички прозорци. Искате ли да продължите?Тази грешка е вече съобщена от друг потребител.. За да бъдете информирани потребителя ви е добавен списъка за този проблемThe values of "%s" are not validThis record has been modified while you were editing it.ДоToggle rowToggle selectionПревод на изгледTree viewИстинаUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sНе може да зададе локални настройки %sВъзтановяване на избрания запис НеизвестенИзчистване на ред за изтриванеUnselect allПотребителско име:Потребител: Потребителско име:Преглед на логовеWeekКакво е името на това извличане?Ширина:ПомощникЗаписГYesВашия изборДействия...ДобавянеОтказЗатваряне на таб_Copy URLИзтриване...ДублиранеEmail...Извличане на данни...Вмъкване на данни...НовСледващ_Notes...ПредишенПечат...Свързани...Презареждане/ОбратноИзтриванеСправки...СъхраняванеПревключване на изгледдdevelopment modego backgo forwardчзаписване на всичко на ниво INFO мmodularity, scalability and securitynext yearprevious yearsукажете друг конфигурационен файлspecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALукажете потребителското имеttranslator-creditsсгtryton-5.0.17/tryton/data/locale/lt/0000755000175000017500000000000013571264253016611 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/lt/LC_MESSAGES/0000755000175000017500000000000013571264253020376 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/lt/LC_MESSAGES/tryton.po0000644000175000017500000010650713463252532022303 0ustar cedced00000000000000# Lithuanian (Lithuania) translations for tryton. # Copyright (C) 2011 B2CK # This file is distributed under the same license as the tryton project. # Giedrius Slavinskas , 2011. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "" #: tryton/config.py:77 msgid "development mode" msgstr "" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:85 msgid "specify the login user" msgstr "" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "" #: tryton/config.py:127 #, python-format msgid "Unable to write config file %s." msgstr "" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Nepavyko nustatyti lokalės %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Pasirinkite veiksmą" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Nėra apibrėžtų veiksmų!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Pasirinkimas" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Atsisakyti" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Jūsų pasirinkimas:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Išsaugoti" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Įrašyti kaip..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Daugiau nepaisyti šio pranešimo." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Ar tikrai norite vykdyti?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Lygiagretaus duomenų rašymo klaida" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Palyginti" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Rašyti visvien" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Programos klaida!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Pranešti apie klaidą" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Klaida: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Klaidų pranešimui reikalinga naudotojo paskyra %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Klaidų pėdsekys" #: tryton/common/common.py:811 msgid "User:" msgstr "Naudotojas:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Slaptažodis:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Ta pati klaida jau buvo pranešta kito naudotojo.\n" "Norėdami informuoti apie klaidos tvarkymo eigą, jūsų naudotojo vardas buvo pridėtas prie klaidos pranešimo sąrašo" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Užregistruoti naują klaidą su ID" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Prisijungimo klaida!\n" "Neteisingas naudotojo vardas arba slaptažodis!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Klaida:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Ieškoti..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Sukurti..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "Pridėti reikšmę" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 #, fuzzy msgid "Displayed value" msgstr "Pridėti reikšmę" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "Sta_ndartinis" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "Atverti kalendorių " #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "t" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Tiesa" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "t" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Netiesa" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "Išei_ti..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Priedai..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Veiksmai..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Susiję įrašai..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Ataskaita..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "El. paštas..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Spausdinti..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "Y" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "w" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "Nus_tatymai..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "Įrankių _juosta" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Numatytasis" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_Tekstas ir piktogramos" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Tekstas" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "P_iktogramos" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_Forma" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Įsiminti plotį/aukštį" #: tryton/gui/main.py:136 #, fuzzy msgid "Save Tree State" msgstr "Įsiminti hierarchinio sąrašo išskleistas šakas" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Rašybos klaidų tikrinimas" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Paieškos ribojimas..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_El. paštas..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Parinktys" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Trumpiniai..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_Apie..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Žinynas" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Nerasta rezultatų." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "_Mėgstami" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Veiksmai" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Atliekant šį veiksmą bus uždarytos visos kortelės.\n" "Ar norite tęsti?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Uždaryti kortelę" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Priedai(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Profilių tvarkymas" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profilis" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Serveris:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Duomenų bazė:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Gaunamas duomenų bazių sąrašas" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Naudotojas:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Nesuderinama serverio versija" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Nepavyko prisijungti prie serverio" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Prisijungti" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Atsisakyti" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Atšaukti prisijungimą prie Tryton serverio" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "_Prisijungti" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Prisijungti prie Tryton serverio" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profilis:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Serverio / duomenų bazės duomenys" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Naudotojas:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "El. paštas" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "El. pašto programos nustatymai" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Komandinė eilutė:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Galimos žymekliai:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Kam:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Tema:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Turinys:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Priedas:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Priedai(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Pasirinkite bent vieną įrašą!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Sukūrė naudotojas:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Sukūrimo data:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Paskutinį kartą redagavo:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Paskutinio redagavimo data:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modelis:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Ar tikrai norite ištrinti šį įrašą?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Ar tikrai norite ištrinti šiuos įrašus?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Įrašai nebuvo ištrinti!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Įrašai ištrinti!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Dabar dirbate su įrašo(-ų) kopija(-omis)!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Įrašas išsaugotas!" #: tryton/gui/window/form.py:485 msgid " of " msgstr " iš " #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Šis įrašas buvo pakeistas\n" "Ar norite jį išsaugoti?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Vykdyti veiksmą" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Susijęs" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Atverti susijusius įrašus" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Ataskaitos" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Atverti ataskaitą" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Siuntimas" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Siųsti ataskaitą el. paštu" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Spausdinimas" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Spausdinti ataskaitą" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Nežinomas" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Riba" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Paieškos ribojimo nustatymai" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Riba:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Nustatymai" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Keisti naudotojo nustatymus" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Nustatymai" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "Buvęs" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "Pasirinkimas" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "Buvęs" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Spartieji klavišai" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Teksto laukų trumpiniai" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Iškirpti pažymėtą tekstą" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Kopijuoti pažymėtą tekstą" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Įdėti nukopijuotą tekstą" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Peršokti į kitą lauką" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Grįžti į buvusį lauką" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Sąryšinių laukų trumpiniai" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Kurti naują sąryšį" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Atverti/ieškoti sąryšinio įrašo" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Sąrašo laukų trumpiniai" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Kurti naują eilutę" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Atverti sąryšį" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Pažymėti eilutę ištrinimui" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Nužymėti eilutę ištrinimui" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Trumpiniai pagal laukus" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_Perjungti rodymą" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "_Perjungti rodymą" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Buvęs" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Buvęs įrašas" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Kitas" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Kitas įrašas" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "I_eškoti" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Naujas" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Sukurti naują įrašą" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Saugoti" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Išsaugoti šį įrašą" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Pe_rkrauti/atšaukti" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "Pe_rkrauti/atšaukti" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "Sukurti ko_piją" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Ištrinti..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Žiūrėti _žurnalus..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "P_riedas:" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Prisegti failą prie įrašo" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Veiksmai..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Susiję įrašai..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Ataskaita..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "Siųsti _el. paštu..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Spausdinti..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Eksportuoti duomenis..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importuoti duomenis..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Uždaryti _kortelę" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Galimi laukai" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Pridėti" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Ištrinti" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Valyti" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV parametrai" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Koduotė:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Lauko pavadinimas" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Išsaugoti šabloną" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Ištrinti šabloną" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Išsaugoti eksportavimo šablonai" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Pavadinimas" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Atvėrimas" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Pridėti laukų pavadinimus" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Kokiu pavadinimu išsaugoti šį eksportavimo šabloną?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d įrašas išsaugotas!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d įrašai išsaugoti!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Veiksmas neįvykdytas!\n" "Klaidos pranešimas:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Klaida" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Nuoroda" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Naikinti" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Naujas" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Perjungti" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Buvęs" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Kitas" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Pridėti" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Šalinti " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Sukurti naują įrašą " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Pašalinti pasirinktą įrašą " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Atkurti pasirinktą įrašą " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Aptikti automatiškai" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Importuoti iš failo:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Atverti..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Praleisti eilutes:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Pasirinkite failą iš kurio importuosite!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Klaida atveriant CSV failą" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Klaida apdorojant failą ties lauku %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d įrašas importuotas!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d įrašai importuoti!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Ieškoti" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Vedlys" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "Sukūrė naudotojas:" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "Sukūrimo data:" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "Paskutinio redagavimo data:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "Paskutinio redagavimo data:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "Nepavyko nustatyti lokalės %s" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "Nepavyko nustatyti lokalės %s" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Paveiklėlio dydis" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Plotis:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Aukštis" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG paveikslėlis (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Įrašyti kaip" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Paveikslėlis yra per didelis!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Rodyti filtrų žymeles" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Šalinti šią žymelę" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Sukurti šio filtro žymelę" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Žymelės pavadinimas:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Rasti" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "Turinys:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "Perjungti rodymą" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "Perjungti rodymą" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Valyti" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Visi failai" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Rodyti paprastą tekstą" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Pridėti reikšmę" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Šalinti \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Paveikslėliai" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Pridėti turimą įrašą" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Pašalinti pasirinktą įrašą " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Atverti įrašą " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Ieškoti įrašo " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Pašalinti pasirinktą įrašą" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Keisti pasirinktą įrašą " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Vertimas" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Keisti" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Neaiškus" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Išsaugokite įrašą prieš pridedant vertimą!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Jokia kita kalba nėra prieinama!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Vertimų peržiūra" tryton-5.0.17/tryton/data/locale/lt/LC_MESSAGES/tryton.mo0000644000175000017500000003503713571264251022300 0ustar cedced00000000000000", <=)Bl} !=M T_ct  #%,R am| &  & 4BH^ dn    +?Xh|    /GP W eot & '2 BM] cp   "2L d!r   ( 7D S amu      $,A[d v    ". 5? Z fs   +E LVl|    0J`pI} 8    $ D %_      !! ! %!3! 8!Y!`! g!t!v!z! !!! ! ! ! ! !!!!! " " " "" -":" B"M"S" ["h"j"{" "" ""$" " """<#M# d######k%)q%%%%% %%%%%&(&@&R&e& && &&&&&&'%'8' ?'"K')n'+' '' '''(!(3(8(<(K(Z( i(,v( ( ( ((((() )") 6)$@) e)) ))"))*!*6*#M*q**** **%* * ++/+I+ R+\+z+++ ++ ++ ,,",'>,f,o,w, ,,, ,",,,- - --#&- J-T-W-[-n-}------ ...*.2. M.Y. [.e.. . ... .. . ../ /&/-/3/B/\/_/s/ |/// / //// /$/060?0 Y0g00 0 0000 00 0 11 )131 81D1M1a1 1111%11 22 52 B2M2\2n2222 222332393 H3 S3a3 v33 333334424 84B4I[44 Q58r55 5555 5556%46Z6y6"6 66 6 6 6 7707857n7v7}7777 7 7 77 7 778888P8X8 _8i8q888 8 88 88888 99 929$49 Y9 c9q9s9<99 9:::: of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationHost:IDID:Image SizeImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:RelateRelate...Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...SaveSave AsSave As...Save Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: lt Language-Team: lt Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 iš "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:Galimi laukaiFields selectedIšsaugoti eksportavimo šablonaiSukurti...Ieškoti...A new version is available!P_riedas:VeiksmaiVeiksmai...PridėtiPridėti laukų pavadinimusAdd a note to the recordPrisegti failą prie įrašoPridėti turimą įrašąAdd new profilePridėti reikšmęAdd...Visi failaiDaugiau nepaisyti šio pranešimo.Ar tikrai norite ištrinti šį įrašą?Ar tikrai norite ištrinti šiuos įrašus?Priedai(%d)Priedas:Priedai...Turinys:Žymelės pavadinimas:Sukurti šio filtro žymelęKlaidų pėdsekysBy: CC:CSV Export: %sCSV Import: %sCSV parametrai_PrisijungtiAtšaukti prisijungimą prie Tryton serverioCancel savingCheck URL: %sCheck VersionValytiClear the field CloseUždaryti kortelęCollapse all rowsCollapse rowKomandinė eilutė:PalygintiLygiagretaus duomenų rašymo klaidaPrisijungti prie Tryton serverioCopy URL into clipboardCopy _URL...Kopijuoti pažymėtą tekstąNepavyko prisijungti prie serverioSukurti naują įrašąSukurti naują įrašą Kurti naują eilutęKurti naują sąryšįUžregistruoti naują klaidą su IDSukūrimo data:Sukūrė naudotojas:Iškirpti pažymėtą tekstąDuomenų bazė:Date FormatNaikintiPašalinti pasirinktą įrašą Delimiter:Display formatDisplayed date formatAr tikrai norite vykdyti?DownloadSiuntimasSiųsti ataskaitą el. paštuEl. paštas...KeistiKeisti naudotojo nustatymusKeisti pasirinktą įrašą Trumpiniai pagal laukusEl. paštasEl. pašto programos nustatymaiKoduotė:KlaidaKlaida atveriant CSV failąKlaida apdorojant failą ties lauku %s.Klaida: Klaida:Expand all rowsExpand rowExpand/CollapseNetiesaFast TabbingGaunamas duomenų bazių sąrašasLauko pavadinimasImportuoti iš failo:RastiForegroundNeaiškusAukštisServerio / duomenų bazės duomenysServeris:IDID:Paveiklėlio dydisPaveikslėliaiNesuderinama serverio versijaSpartieji klavišaiPaskutinio redagavimo data:Paskutinį kartą redagavo:Vykdyti veiksmąGalimos žymekliai:RibaRiba:Praleisti eilutes:NuorodaSąrašo laukų trumpiniaiPrisijungtiMManage...Pažymėti eilutę ištrinimuiModelis:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pagePavadinimasNaujasKitasKitas įrašasPeršokti į kitą laukąNoNerasta rezultatų.Note(%d)Notes (%s)Notes...OKAtvėrimasOpen filtersAtverti susijusius įrašusAtverti sąryšįAtverti ataskaitąAtverti...Atverti/ieškoti sąryšinio įrašoOverride '%s' definition?PDA ModePNG paveikslėlis (*.png)Slaptažodis:Įdėti nukopijuotą tekstąPre-validationNustatymaiNustatymaiBuvęsBuvęs įrašasGrįžti į buvusį laukąSpausdinimasSpausdinti ataskaitąSpausdinti...ProfilisProfilių tvarkymasProfilis:QuitQuote char:SusijęsSusiję įrašai...Sąryšinių laukų trumpiniaiŠalinti "%s"Šalinti Remove selected profilePašalinti pasirinktą įrašąPašalinti pasirinktą įrašą Šalinti šią žymelęAtaskaitosPranešti apie klaidąAtaskaita...IšsaugotiĮrašyti kaipĮrašyti kaip...Įsiminti plotį/aukštįIšsaugoti šį įrašąSave your current versionIeškotiSearch %sPaieškos ribojimo nustatymaiPaieškos ribojimas...Ieškoti įrašo See the modified versionSelectSelect a colorSelect allSelect parentPasirinkite veiksmąSelect...Select/Activate current rowPasirinkimasShow active recordsRodyti filtrų žymelesShow inactive recordsRodyti paprastą tekstąShow revisions...Rašybos klaidų tikrinimasTema:PerjungtiTeksto laukų trumpiniaiAtliekant šį veiksmą bus uždarytos visos kortelės. Ar norite tęsti?Ta pati klaida jau buvo pranešta kito naudotojo. Norėdami informuoti apie klaidos tvarkymo eigą, jūsų naudotojo vardas buvo pridėtas prie klaidos pranešimo sąrašoThe values of "%s" are not validThis record has been modified while you were editing it.Kam:Toggle rowToggle selectionVertimų peržiūraVertimasTree viewTiesaUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sNepavyko nustatyti lokalės %sUnable to write config file %s.Atkurti pasirinktą įrašą NežinomasNužymėti eilutę ištrinimuiUnselect allNaudotojas:Naudotojas:Naudotojas:Žiūrėti _žurnalus...WeekKokiu pavadinimu išsaugoti šį eksportavimo šabloną?Plotis:VedlysRašyti visvienYYesJūsų pasirinkimas:_Veiksmai..._Pridėti_AtsisakytiUždaryti _kortelę_Copy URL_Ištrinti...Sukurti ko_pijąSiųsti _el. paštu..._Eksportuoti duomenis..._Importuoti duomenis..._Naujas_Kitas_Notes..._Buvęs_Spausdinti..._Susiję įrašai...Pe_rkrauti/atšaukti_Ištrinti_Ataskaita..._SaugotiI_eškoti_Perjungti rodymąddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswttryton-5.0.17/tryton/data/locale/it_IT/0000755000175000017500000000000013571264253017202 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/it_IT/LC_MESSAGES/0000755000175000017500000000000013571264253020767 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/it_IT/LC_MESSAGES/tryton.po0000644000175000017500000010547313463252532022675 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "indica un altro file di configurazione" #: tryton/config.py:77 msgid "development mode" msgstr "modo sviluppatore" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "registrare tutto a livello INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" "specifica il livello di registrazione: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "specifica l'utente di accesso" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "specifica l'hostname" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Impossibile scrivere il file di configurazione %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Impossibile impostare la localizzazione %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Scegliere un'azione" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Nessuna azione definita!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Selezione" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Cancella" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Selezione:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Salva" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Salva come..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Ignorare sempre l'avviso" #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Procedere?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Eccezione di concorrenza" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Confrontare" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Scrivere comunque" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Errore di applicazione!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Segnala un bug" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Errore:" #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Per segnalare bugs è necessario avere un account in %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Bug Tracker" #: tryton/common/common.py:811 msgid "User:" msgstr "Utente:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Password:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Lo stesso bug è stato già segnalato da altro utente.\n" "Per tua informazione il tuo nome utente è aggiunto alla nosy-list di questo problema" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Creato nuovo bug con ID" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Errore di connessione!\n" "Nome utente o password errati!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Eccezione:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Cerca..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Crea..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valore" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valore visualizzato" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Formato" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Formato di visualizzazione" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Apertura calendario" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Formato data" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Formato data visualizzato" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "a" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "True" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "o" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "False" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Modifica..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Allegati..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Azioni..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Riferire..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Segnala..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "E-Mail" #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Stampa..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "S" #: tryton/common/timedelta.py:29 msgid "d" msgstr "g" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Preferenze" #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_Toolbar" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Default" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_Testo e Icone" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Testo" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_Icone" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_Modulo" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Salva larghezza/altezza" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Salva diagramma ad albero" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Controllo ortogbrafico" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Limite di ricerca..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_Email" #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Options" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Scorciatoie da tastiera" #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_About" #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Help" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Nessun risultato trovato." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "Fa_vorites" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Azione" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "L'azione seguente richiede la chiusura di tutte le finestre.\n" "Vuoi continuare?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Chiudere la scheda" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Allegato(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Editor del profilo" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profilo" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Host:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Database:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Preleva la lista dei database" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Nome utente:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Versione del server incompatibile" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Impossibile connettersi al server" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Accedi" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Cancella" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Cancella la connessione al server Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onnetti" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Connetti il server Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profilo:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Informazione su Host/ database" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "nome utente" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Email" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Impostazioni programma Email" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Riga di comando:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Leggenda dei segnaposto disponibili:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "a:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr ".CC" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Oggetto:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Corpo:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Allegato:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Allegato(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Devi selezionare un record!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Utente di creazione:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Data di creazione:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Ultima modifica a:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Ultima data di modifica:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modello:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Sei sicuro di rimuovere questo record?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Sei sicuro di rimuovere questi records?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Record non rimossi!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Records rimossi!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Attivo ora nel (nei) record duplicato!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Record salvato!" #: tryton/gui/window/form.py:485 msgid " of " msgstr "di" #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Il record è stato modificato\n" " intendi salvarlo?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Lanciare l'azione" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Collegato" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Apri record relazionati" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Rapporto" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Apri rapporto" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-Mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "report E-Mail" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Stampa" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Stampa report" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Sconosciuto" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limite" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Impostazione dei limiti di ricerca" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Limite:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferenze" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Modifica le preferenze dell'utente" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferenza" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Revisione" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Scegli una revisione" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Revisione:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Scorciatoie da tastiera" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Scorciatoie imputazioni di testo" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Taglia testo selezionato" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copia il testo selezionato" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Incolla il testo copiato" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Prossimo oggetto" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Oggetto precedente" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Scorciatoie imputazioni relazionate" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Crea nuova relazione" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Apri/Cerca relazione" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Lista scorciatoie registrazioni" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Crea nuova riga" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Apri relazione" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Seleziona riga da eliminare" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Deseleziona riga da eliminare" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Widget di modifica" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_Cambia vista" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "_Cambia vista" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Precedente" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Record Precedente" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Successivo" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Prossimo Record" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Cerca" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nuovo" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Crea nuovo record" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Salva" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Salva questo record." #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplicato" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Eliimina" #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Visualizza_Log..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Mostra revisioni..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "A_llegati..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Aggiungi un allegato al record" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Azioni..." #: tryton/gui/window/tabcontent.py:123 #, fuzzy msgid "_Relate..." msgstr "Riferire..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Rapporto..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_E-Mail..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Stampa..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Esporta dati" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importa dati" #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Chiudi scheda" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Tutti i campi" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "Profilo" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Rimuovi" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Pulisci" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parametri CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codifica:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nome di campo" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Salva esportazione" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Elimina Esportazione" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "esportazioni predefinite" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nome" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Apri" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Aggiungi_nomi di campo" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (stringa)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Qual è il nome di questa esportazione?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Sostituisci definizione '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d record salvato!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d record salvato!" #: tryton/gui/window/win_export.py:333 #, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Errore" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Elimina" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Nuovo" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Cambia" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Precedente" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Prossimo" #: tryton/gui/window/win_form.py:176 #, fuzzy msgid "Add" msgstr "Profilo" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 #, fuzzy msgid "Create a new record " msgstr "Crea nuovo record" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Elimina il record selezionato " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Non eliminare il record selezionato " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Autorilevamento" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "File da importare:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Apri..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Righe da saltare." #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Devi prima selezionare un file di import!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Errore nell'apertura del file CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Errore nel processare il file nel campo %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr " %d record importati" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr " %d record importati!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Ricerca" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Creazione utente" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Data di creazione" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Utente di modifica" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Data di modifica" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy, python-format msgid "Unable to get view tree state for %s" msgstr "Impossibile configurare la vista ad albero %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Impossibile configurare la vista ad albero" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr "" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Dimensione immagine" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Salva come" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Mostra segnalibri dei filtri" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Rimuovi questo segnalibro" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Memorizza questo filtro" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nome segnalibro:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Trova" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Oggi" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Vista settimanale" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Vista mensile" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Settimana" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Pulisci" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Tutti i files" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Mostra testo semplice" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Aggiungi valore" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Rimuovi \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Immagini" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Aggiungi un record esistente" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 #, fuzzy msgid "Remove selected record " msgstr "Elimina il record selezionato " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Rimuovi i record selezionati" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Modifica il record selezionato " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 #, fuzzy msgid "Translation" msgstr "Traduzione" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Modifica" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Vago" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "E' necessario salvare il record prima di aggiungere le traduzioni!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Nessun altra lingua disponibile!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Traduci vista" tryton-5.0.17/tryton/data/locale/it_IT/LC_MESSAGES/tryton.mo0000644000175000017500000003533613571264251022673 0ustar cedced000000000000000 )"L]eu - 4?Pi  #%. =IX^m &   $: @J \ iw +? Xf u   6? F T^cy & ) 9DT Zg    "3F` x!  " 4 ? KUk z     #& +8 M [gy#   / :FO_o u      %<Q X cm v   1JQ` r }   " 4 C L S Ij } 2!8S!!! !!! !!!!% "1"I"g""" " "" "" "" " "## !#.#0#4# D#P#U# ]# h# r# }# ##### # # # ## ##$ $$$*$ 2$=$ ?$`$$b$ $ $$$<$$%%(%*%,%&)&&&'' ''4'9'<'>'S'j'''' '' '''(2(O(_(o( v((&('( ( ( )))') ?)K)P)T)c) r) )() ) ) ))))** &*3* D*P*i** **!***++4+F+Y+j++ + ++#+ ++,, /,:,C, J,X,_,"h,#, ,,,, ,,!-+$-P- X-c- s-~-- -- --- ----.%.+...2.F.\.!e.....$./ //#/(/H/O/ Q/[/w/// / / /// // 0 0#0+0?0D0J0S0c0t0w00 0000 000 00 1!1)1#>1b111 111 1 1 1122 2 (222:2M2V2 [2 g2 q2#}2 2 2 222233 .3 93 C3N3 T3 _3m33333 3"344-4F4M4\4 q4 |44 44 44445+5?5V5_5 f5M55 b68666 66 6 6667%87*^7*7)7 77 8 8!8 )868=8 O8Y8'k888888 8 88 88 8 8 9 9 9 (969 =9 I9 S9 _9 j9w9 999 9999 9999$9 : #:1:&3:LZ:::::: of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...Add _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUndelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Reload/Undo_Remove_Report..._Save_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: it_IT Language-Team: it_IT Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 di"%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (stringa)%s%%..:Tutti i campiFields selectedesportazioni predefiniteCrea...Cerca...A new version is available!A_llegati...AzioneAzioni...Aggiungi_nomi di campoAdd a note to the recordAggiungi un allegato al recordAggiungi un record esistenteAdd new profileAggiungi valoreAdd...Tutti i filesIgnorare sempre l'avvisoSei sicuro di rimuovere questo record?Sei sicuro di rimuovere questi records?Allegato(%d)Allegato:Allegati...Corpo:Nome segnalibro:Memorizza questo filtroBug TrackerBy: .CCCSV Export: %sCSV Import: %sParametri CSVC_onnettiCancella la connessione al server TrytonCancel savingCheck URL: %sCheck VersionPulisciClear the field CloseChiudere la schedaCollapse all rowsCollapse rowRiga di comando:ConfrontareEccezione di concorrenzaConnetti il server TrytonCopy URL into clipboardCopy _URL...Copia il testo selezionatoImpossibile connettersi al serverCrea nuovo recordCrea nuova rigaCrea nuova relazioneCreato nuovo bug con IDData di creazioneData di creazione:Creazione utenteUtente di creazione:Taglia testo selezionatoDatabase:Formato dataEliminaElimina il record selezionato Delimiter:Formato di visualizzazioneFormato data visualizzatoValore visualizzatoProcedere?DownloadE-Mailreport E-MailE-MailModificaModifica le preferenze dell'utenteModifica il record selezionato Modifica...Widget di modificaEmailImpostazioni programma EmailCodifica:ErroreErrore nell'apertura del file CSVErrore nel processare il file nel campo %s.Errore:Eccezione:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingPreleva la lista dei databaseNome di campoFile da importare:TrovaForegroundFormatoVagoHeight:Informazione su Host/ databaseHost:IDID:Dimensione immagineImage size too large.ImmaginiVersione del server incompatibileScorciatoie da tastieraUltima data di modifica:Ultima modifica a:Lanciare l'azioneLeggenda dei segnaposto disponibili:LimiteLimite:Righe da saltare.LinkLista scorciatoie registrazioniAccediMManage...Seleziona riga da eliminareModello:Data di modificaUtente di modificaVista mensileMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNomeNuovoProssimoProssimo RecordProssimo oggettoNoNessun risultato trovato.Note(%d)Notes (%s)Notes...OKApriOpen filtersApri record relazionatiApri relazioneApri rapportoApertura calendarioOpen the record Apri...Apri/Cerca relazioneOperation failed. Error message: %sSostituisci definizione '%s'?PDA ModePNG image (*.png)Password:Incolla il testo copiatoPre-validationPreferenzaPreferenzePrecedenteRecord PrecedenteOggetto precedenteStampaStampa reportStampa...ProfiloEditor del profiloProfilo:QuitQuote char:CollegatoRiferire...Scorciatoie imputazioni relazionateReload/UndoRimuovi "%s"Remove Remove selected profileRimuovi i record selezionatiRimuovi questo segnalibroRapportoSegnala un bugSegnala...RevisioneRevisione:SalvaSalva comeSalva come...Salva diagramma ad alberoSalva larghezza/altezzaSalva questo record.Save your current versionRicercaSearch %sImpostazione dei limiti di ricercaLimite di ricerca...Search a record See the modified versionSelectSelect a colorScegli una revisioneSelect allSelect parentScegliere un'azioneSelect...Select/Activate current rowSelezioneShow active recordsMostra segnalibri dei filtriShow inactive recordsMostra testo sempliceMostra revisioni...Controllo ortogbraficoOggetto:CambiaScorciatoie imputazioni di testoL'azione seguente richiede la chiusura di tutte le finestre. Vuoi continuare?Lo stesso bug è stato già segnalato da altro utente. Per tua informazione il tuo nome utente è aggiunto alla nosy-list di questo problemaThe values of "%s" are not validThis record has been modified while you were editing it.a:OggiToggle rowToggle selectionTraduci vistaTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sImpossibile impostare la localizzazione %sImpossibile configurare la vista ad alberoNon eliminare il record selezionato SconosciutoDeseleziona riga da eliminareUnselect allnome utenteUtente:Nome utente:ValoreVisualizza_Log...SettimanaVista settimanaleQual è il nome di questa esportazione?Width:WizardScrivere comunqueAYesSelezione:_Azioni...Profilo_Cancella_Chiudi scheda_Copy URL_Eliimina_Duplicato_E-Mail..._Esporta dati_Importa dati_Nuovo_Successivo_Notes..._Precedente_Stampa..._Reload/Undo_Rimuovi_Rapporto..._Salva_Cerca_Cambia vistagmodo sviluppatorego backgo forwardhregistrare tutto a livello INFOmmodularity, scalability and securitynext yearprevious yearsindica un altro file di configurazionespecifica il livello di registrazione: DEBUG, INFO, WARNING, ERROR, CRITICALspecifica l'utente di accessootranslator-creditsSatryton-5.0.17/tryton/data/locale/nl/0000755000175000017500000000000013571264253016603 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/nl/LC_MESSAGES/0000755000175000017500000000000013571264253020370 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/nl/LC_MESSAGES/tryton.po0000644000175000017500000010533313463252532022271 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "specificeer een vervangend configuratiebestand" #: tryton/config.py:77 msgid "development mode" msgstr "" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "logboek bijhouden op INFO niveau" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:85 msgid "specify the login user" msgstr "specificeer de inlog gebruiker" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "Stel de servernaam in" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Kan configuratiebestand %s niet opslaan! " #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Kan omgeving %s niet instellen" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Selecteer je handeling." #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Geen handeling gedefinieerd!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Selectie" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr " _Annuleren" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Uw selectie:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Opslaan" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Opslaan als..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Altijd deze waarschuwing negeren." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Simultaan gebruik" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Vergelijk" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Overschrijven" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Programmafout" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Programmafout melden" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Fout: " #: tryton/common/common.py:768 #, python-format, fuzzy msgid "To report bugs you must have an account on %s" msgstr "" "Om programmafouten aan te melden moet je een account hebben bij %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Foutrapportage" #: tryton/common/common.py:811 msgid "User:" msgstr "Gebruiker:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Wachtwoord:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Dezelfde programmafout was al gemeld door een andere gebruiker.\n" "Om je op de hoogte te houden is je gebuikersnaam toegevoegd aan de lijst van belangstellenden" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Nieuwe foutmelding gemaakt met ID " #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Geen verbinding!\n" "Verkeerde gebruikersnaam of wachtwoord!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Uitzondering:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "" #: tryton/common/completion.py:27 msgid "Create..." msgstr "" #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "Niet waar" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "_Normaal" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "Open de kalender" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Waar" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Niet waar" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "Afsluiten" #: tryton/common/popup_menu.py:89 #, fuzzy msgid "Attachments..." msgstr "Bijlage:" #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 #, fuzzy msgid "Actions..." msgstr "_Acties.." #: tryton/common/popup_menu.py:108 #, fuzzy msgid "Relate..." msgstr "Verwijderen... " #: tryton/common/popup_menu.py:109 #, fuzzy msgid "Report..." msgstr "_Importeer gegevens... " #: tryton/common/popup_menu.py:110 #, fuzzy msgid "E-Mail..." msgstr "E-mail" #: tryton/common/popup_menu.py:111 #, fuzzy msgid "Print..." msgstr "Afdrukken" #: tryton/common/timedelta.py:26 msgid "Y" msgstr "J" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "w" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "u" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Voorkeuren..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_Werkbalk" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Standaard" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_Tekst en pictogrammen" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Tekst" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "Pictogrammen..." #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "Formulier" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Bewaar breedte/hoogte" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Spellingscontrole uitvoeren" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Zoek limiet..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "E-mail" #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Opties" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "Sneltoetsen" #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "I_nfo..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Help" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "" #: tryton/gui/main.py:447 msgid "Favorites" msgstr "" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Actie" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Tabblad sluiten" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Bijlage (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 #, fuzzy msgid "Host:" msgstr "Poort:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Database:" #: tryton/gui/window/dblogin.py:108 #, fuzzy msgid "Fetching databases list" msgstr "Maak een nieuwe database:" #: tryton/gui/window/dblogin.py:122 #, fuzzy msgid "Username:" msgstr "Gebruikersnaam:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 #, fuzzy msgid "Incompatible version of the server" msgstr "Deze versie is onverenigbaar met de server! " #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 #, fuzzy msgid "Could not connect to the server" msgstr "Geen verbinding met de server!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Inlognaam" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr " _Annuleren" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Verbreek verbinding met Tryton server" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "_Verbinden" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Verbind met Tryton server" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Gebruikersnaam:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "E-mail" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "E-mail instellingen " #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Opdrachtregel:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Legenda van beschikbare sjablonen: " #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Aan:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Onderwerp:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Bericht:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Bijlage:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Bijlage (%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Je moet één item selecteren!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Aangemaakt door:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Aanmaakdatum" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Laatste wijziging door:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Laatste wijzigingsdatum:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Model:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Weet je zeker dat je dit item wilt verwijderen?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Weet je zeker dat je deze items wilt verwijderen?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Items niet verwijderd!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Items verwijderd!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Je werkt nu met het gekopieerde item!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Item opgeslagen!" #: tryton/gui/window/form.py:485 msgid " of " msgstr " van " #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Item is aangepast.\n" "Wil je de wijzigingen opslaan?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Relate" msgstr "Aan_maken" #: tryton/gui/window/form.py:560 #, fuzzy msgid "Open related records" msgstr "Item openen" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Report" msgstr "Rapporten" #: tryton/gui/window/form.py:562 #, fuzzy msgid "Open report" msgstr "Item openen" #: tryton/gui/window/form.py:563 #, fuzzy msgid "E-Mail" msgstr "E-mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Afdrukken" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Onbekend" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limiet:" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Zoek limiet instellen" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr " Limiet:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Voorkeuren" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Voorkeuren gebruiker aanpassen" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Voorkeur" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "Vorige" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "Selectie" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "Vorige" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Sneltoetsen" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Sneltoetsen in tekstvakken" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Knip geselecteerde tekst" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Kopieer geselecteerde tekst" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Plak geselecteerde tekst" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Volgend element" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Vorig element" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Relatie sneltoetsen" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Nieuwe relatie aanmaken" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Zoek / open relatie" #: tryton/gui/window/shortcuts.py:44 #, fuzzy msgid "List Entries Shortcuts" msgstr "Sneltoetsen in tekstvakken" #: tryton/gui/window/shortcuts.py:45 #, fuzzy msgid "Create new line" msgstr "Nieuwe relatie aanmaken" #: tryton/gui/window/shortcuts.py:46 #, fuzzy msgid "Open relation" msgstr "Zoek / open relatie" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Versies widgets" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Wijzig beeld" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "Wijzig beeld" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "V_orige" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Vorige item" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Volgende" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Volgende item" #: tryton/gui/window/tabcontent.py:61 #, fuzzy msgid "_Search" msgstr "Zoeken" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nieuw" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Maak een nieuw item" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "Op_slaan" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Bewaar dit item" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Ongedaan maken" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "_Ongedaan maken" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Dupliceren" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Verwijderen... " #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Bekijk logregister" #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 #, fuzzy msgid "A_ttachments..." msgstr "Bijlage:" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Voeg een bijlage aan dit item toe" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Acties.." #: tryton/gui/window/tabcontent.py:123 #, fuzzy msgid "_Relate..." msgstr "Verwijderen... " #: tryton/gui/window/tabcontent.py:129 #, fuzzy msgid "_Report..." msgstr "_Importeer gegevens... " #: tryton/gui/window/tabcontent.py:134 #, fuzzy msgid "_E-Mail..." msgstr "E-mail" #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Afdrukken" #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Exporteer gegevens... " #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importeer gegevens... " #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Tabblad sluiten" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Alle velden" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Toevoegen" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Verwijderen" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Wissen" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV parameters" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codering:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Veldnaam" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Exportgegevens opslaan" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Exportgegevens verwijderen" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Voorgedefinieerde exportinstellingen" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Naam" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Open" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Voeg veldnamen toe" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Wat is de naam voor deze export?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d item opgeslagen!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d items opgeslagen!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Handeling mislukt!\n" "Foutmelding:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Fout" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Koppeling" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Verwijderen" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "_Nieuw" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Omschakelen" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Vorige" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Volgende" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Toevoegen" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 #, fuzzy msgid "Create a new record " msgstr "Maak een nieuw item" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 #, fuzzy msgid "Delete selected record " msgstr "Geselecteerd item verwijderen" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 #, fuzzy msgid "Undelete selected record " msgstr "Geselecteerd item verwijderen" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Automatisch" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Bestand om te importeren:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Openen..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Regels overslaan:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "U moet eerst een import bestand selecteren!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Fout bij openen CSV-bestand" #: tryton/gui/window/win_import.py:138 #, python-format, python-format, python-format, fuzzy, python-format msgid "Error processing the file at field %s." msgstr "Fout bij inlezen van bestand bij veld%s" #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d item geïmporteerd!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d items geïmporteerd!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Zoeken" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Assistent" #: tryton/gui/window/view_form/screen/screen.py:206 #, fuzzy msgid "ID" msgstr " d" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "Aangemaakt door:" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "Aanmaakdatum" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "Laatste wijzigingsdatum:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "Laatste wijzigingsdatum:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "Kan omgeving %s niet instellen" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "Kan omgeving %s niet instellen" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Afbeeldingsgrootte" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Breedte:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Hoogte:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG afbeelding (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Opslaan als" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Afbeelding te groot!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Vind" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "Bericht:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "Wijzig beeld" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "Wijzig beeld" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Wissen" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Alle bestanden" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Afbeeldingen" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 #, fuzzy msgid "Add existing record" msgstr "Bewaar dit item" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 #, fuzzy msgid "Remove selected record " msgstr "Geselecteerd item verwijderen" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Item openen" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 #, fuzzy msgid "Search a record " msgstr "Item zoeken" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 #, fuzzy msgid "Remove selected record" msgstr "Geselecteerd item verwijderen" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 #, fuzzy msgid "Edit selected record " msgstr "Geselecteerd item aanpassen" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 #, fuzzy msgid "Translation" msgstr "Voeg vertaling toe" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Gegevens eerst opslaan voordat u een vertaling toevoegt! " #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Geen andere taal beschikbaar!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Vertaal aanzicht" tryton-5.0.17/tryton/data/locale/nl/LC_MESSAGES/tryton.mo0000644000175000017500000003040113571264251022260 0ustar cedced00000000000000)"L]eu $(9Rr  #% $3 HTY]l{&     " /=E[u    (4 ;FUk{   !, <GW ] j t    $!2TZapu{ }     27; @ LX[l u     &2;K[ anv      #3EVp w     (2F`vI} 8  ).N%i    ! (57; KW\ d o y       & (I$K p z< )     !!!!!#!6!+M!y!!!! !!!!!" %"/"6"!E"/g"1" """"" ## #$#3#B# Q#%\# # # ###### ## $$)$C$ [$h$$$"$ $$$ % % % ,%7%F%\%l%% %%%%%% %%%& &+& ;&F& V& `& m&w&&& &&&&&& & &'' 5'#C'g'o'x' ' '' ''' ' ''' (( ( -(9(A(U(Z(a( j(x(((( (((( ( ((()) &)2)K)Z) c)n) u) ) ) ))))) )) ) )**1*F* N*Z*i*y**** ****++ + )+7+ O+Y+u+~++++++ , ,,I2,|, -8;-t- y--- ----%-.5.>. W.d. t... .. . ... . . . / / /'/ 7/C/[/s/ z/ // // // //// // /0$0 C0 M0[0.]0<000000 of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!ActionAddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCreate a new recordCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEditEdit User PreferencesEdition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationID:Image SizeImagesKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportProfileProfile EditorProfile:QuitQuote char:Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove this bookmarkReport BugSaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnknownUnmark line for deletionUnselect allUser name:User:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Reload/Undo_Remove_Save_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: nl Language-Team: nl Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 van "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:Alle veldenFields selectedVoorgedefinieerde exportinstellingenCreate...Search...A new version is available!ActieToevoegenVoeg veldnamen toeAdd a note to the recordVoeg een bijlage aan dit item toeAdd new profileAdd valueAdd...Alle bestandenAltijd deze waarschuwing negeren.Weet je zeker dat je dit item wilt verwijderen?Weet je zeker dat je deze items wilt verwijderen?Bijlage (%d)Bijlage:Bericht:Bookmark Name:Bookmark this filterFoutrapportageBy: CC:CSV Export: %sCSV Import: %sCSV parameters_VerbindenVerbreek verbinding met Tryton serverCancel savingCheck URL: %sCheck VersionWissenClear the field CloseTabblad sluitenCollapse all rowsCollapse rowOpdrachtregel:VergelijkSimultaan gebruikVerbind met Tryton serverCopy URL into clipboardCopy _URL...Kopieer geselecteerde tekstMaak een nieuw itemNieuwe relatie aanmakenNieuwe foutmelding gemaakt met ID AanmaakdatumAangemaakt door:Knip geselecteerde tekstDatabase:Date FormatVerwijderenDelimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-Mail reportEditVoorkeuren gebruiker aanpassenVersies widgetsE-mailE-mail instellingen Codering:FoutFout bij openen CSV-bestandFout: Uitzondering:Expand all rowsExpand rowExpand/CollapseNiet waarFast TabbingFavoritesVeldnaamBestand om te importeren:VindForegroundFuzzyHoogte:Host / Database informationID:AfbeeldingsgrootteAfbeeldingenSneltoetsenLaatste wijzigingsdatum:Laatste wijziging door:Launch actionLegenda van beschikbare sjablonen: Limiet: Limiet:Regels overslaan:KoppelingInlognaamMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNaam_NieuwVolgendeVolgende itemVolgend elementNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpenen...Zoek / open relatieOverride '%s' definition?PDA ModePNG afbeelding (*.png)Wachtwoord:Plak geselecteerde tekstPre-validationVoorkeurVoorkeurenVorigeVorige itemVorig elementAfdrukkenPrint reportProfileProfile EditorProfile:QuitQuote char:Relatie sneltoetsenRemove "%s"Remove Remove selected profileRemove this bookmarkProgrammafout meldenOpslaanOpslaan alsOpslaan als...Save Tree StateBewaar breedte/hoogteBewaar dit itemSave your current versionZoekenSearch %sZoek limiet instellenZoek limiet...See the modified versionSelectSelect a colorSelect allSelect parentSelecteer je handeling.Select...Select/Activate current rowSelectieShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spellingscontrole uitvoerenOnderwerp:OmschakelenSneltoetsen in tekstvakkenThe following action requires to close all tabs. Do you want to continue?Dezelfde programmafout was al gemeld door een andere gebruiker. Om je op de hoogte te houden is je gebuikersnaam toegevoegd aan de lijst van belangstellendenThe values of "%s" are not validThis record has been modified while you were editing it.Aan:Toggle rowToggle selectionVertaal aanzichtTree viewWaarUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sKan omgeving %s niet instellenOnbekendUnmark line for deletionUnselect allGebruikersnaam:Gebruiker:Bekijk logregisterWeekWat is de naam voor deze export?Breedte:AssistentOverschrijvenJYesUw selectie:_Acties.._Toevoegen _AnnulerenTabblad sluiten_Copy URLVerwijderen... _Dupliceren_Exporteer gegevens... _Importeer gegevens... _Nieuw_Volgende_Notes...V_origeAfdrukken_Ongedaan maken_VerwijderenOp_slaanWijzig beeldddevelopment modego backgo forwardulogboek bijhouden op INFO niveaummodularity, scalability and securitynext yearprevious yearsspecificeer een vervangend configuratiebestandspecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecificeer de inlog gebruikerttranslator-creditswytryton-5.0.17/tryton/data/locale/es/0000755000175000017500000000000013571264253016601 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/es/LC_MESSAGES/0000755000175000017500000000000013571264253020366 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/es/LC_MESSAGES/tryton.po0000644000175000017500000011220513463252532022263 0ustar cedced00000000000000# Spanish (Spain) translations for tryton. # Copyright (C) 2008 igor@tamarapatino.org # Copyright (C) 2009 PEMAS Servicios Profesionales, S.L. # Copyright (C) 2012 Zikzakmedia SL # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2008. # Carlos Perelló Marín , 2008-2009. # Sergi Almacellas Abellana 2012. # Jordi Esteve Cusiné 2012. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "Indica un archivo de configuración alternativo" #: tryton/config.py:77 msgid "development mode" msgstr "Modo desarrollo" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Registra toda la información con nivel INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "Indica el nivel de log: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Indica el usuario" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "Indica el nombre:puerto del servidor" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "No se ha podido escribir el archivo de configuración %s." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "No se ha podido establecer el idioma %s" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Seleccione su acción" #: tryton/action/main.py:193 msgid "No action defined." msgstr "No se ha definido ninguna acción." #: tryton/common/button.py:54 msgid "By: " msgstr "Por: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Selección" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 msgid "Cancel" msgstr "Cancelar" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "Aceptar" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Su selección:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Seleccionar" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Guardar" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Guardar como..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Ignorar siempre esta advertencia." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "¿Desea continuar?" #: tryton/common/common.py:643 msgid "No" msgstr "No" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Sí" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Excepción de concurrencia" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "Este registro ha sido modificado mientras lo editaba." #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "No guardes los cambios" #: tryton/common/common.py:696 msgid "Compare" msgstr "Comparar" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "Mostrar la versión modificada" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Guardar de todas formas" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "Guardar vuestros cambios" #: tryton/common/common.py:729 msgid "Application Error" msgstr "Error de aplicación." #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Informar del error" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "Cerrar" #: tryton/common/common.py:751 msgid "Error: " msgstr "Error: " #: tryton/common/common.py:768 #, python-format, python-format msgid "To report bugs you must have an account on %s" msgstr "Para informar de errores debe tener una cuenta en %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Seguimiento de errores" #: tryton/common/common.py:811 msgid "User:" msgstr "Usuario:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Contraseña:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "El mismo error ya fue notificado por otro usuario.\n" "Para mantenerle informado añadiremos su usuario a la lista de interesados en esta incidencia." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Se creó un nuevo error con identificador " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Error de conexión.\n" "Nombre de usuario o contraseña incorrectos." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Excepción:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "URL de comprobación: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "No se ha podido comprobar si existe una nueva versión." #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Esta disponible una nueva versión!" #: tryton/common/common.py:942 msgid "Download" msgstr "Descargar" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Buscar..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Crear..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "No se ha podido buscar el autocompletado de %s" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Valor" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Valor a mostrar" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Formato" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Format a mostrar" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Abrir el calendario" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Formato fecha" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Formato fecha actual" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "a" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Verdadero" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "v" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Falso" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Editar..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Adjuntos..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notas..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Acciones..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Relacionado..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Informe..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Correo electrónico..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Imprimir..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "A" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "S" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 msgid "Preferences..." msgstr "Preferencias..." #: tryton/gui/main.py:127 msgid "Toolbar" msgstr "Barra de herramientas" #: tryton/gui/main.py:128 msgid "Default" msgstr "Por defecto" #: tryton/gui/main.py:129 msgid "Text and Icons" msgstr "Texto e iconos" #: tryton/gui/main.py:130 msgid "Text" msgstr "Texto" #: tryton/gui/main.py:131 msgid "Icons" msgstr "Iconos" #: tryton/gui/main.py:134 msgid "Form" msgstr "Formulario" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Guardar ancho/alto" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Guardar estado de expansión del árbol" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Tabulación rápida" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Corrección ortográfica" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "Modo PDA" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "_Límite de búsqueda..." #: tryton/gui/main.py:142 msgid "Email..." msgstr "Correo electrónico..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Comprobar versión" #: tryton/gui/main.py:145 msgid "Options" msgstr "Opciones" #: tryton/gui/main.py:148 msgid "Keyboard Shortcuts..." msgstr "Combinaciones de teclas..." #: tryton/gui/main.py:149 msgid "About..." msgstr "Acerca de..." #: tryton/gui/main.py:150 msgid "Help" msgstr "Ayuda" #: tryton/gui/main.py:153 msgid "Quit" msgstr "Salir" #: tryton/gui/main.py:395 msgid "No result found." msgstr "No se han encontrado resultados." #: tryton/gui/main.py:447 msgid "Favorites" msgstr "Favoritos" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "Gestionar..." #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Acción" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "La acción seleccionada requiere cerrar todas las pestañas.\n" "¿Desea continuar?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Cerrar pestaña" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "modularidad, escalabilidad y seguridad" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "Créditos de traducción" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Adjuntos (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Editor de perfiles" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Perfil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "Añadir un nuevo perfil" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "Eliminar el perfil seleccionado" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Servidor:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Base de datos:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Recuperando lista de bases de datos" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Nombre de usuario:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "El cliente no es compatible con la versión del servidor" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "No se ha podido conectar con el servidor" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Usuario" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Cancelar" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Cancelar conexión con el servidor Tryton" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "C_onectar" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Conectar con el servidor Tryton" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Perfil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Información del Servidor / Base de datos" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Nombre de usuario:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Correo electrónico" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Configuración del programa de correo electrónico" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Línea de comando:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Leyenda de palabras clave disponibles:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Para:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Asunto:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Mensaje:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Adjunto:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "Añadir..." #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Adjunto(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Nota(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Debe elegir un registro." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Creado por:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Fecha creación:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Última modificación por:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Última fecha de modificación:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modelo:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "¿Está seguro que quiere eliminar este registro?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "¿Está seguro que quiere eliminar estos registros?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Los registros no se han eliminado." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Registros eliminados." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Ahora está trabajando en el registro duplicado." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Registro guardado." #: tryton/gui/window/form.py:485 msgid " of " msgstr " de " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Este registro ha sido modificado.\n" "¿Desea guardarlo?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Ejecutar acción" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "_Relacionado" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Abrir registros relacionados" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Informes" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Abrir informe" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Email" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Informe por email" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Imprimir" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Imprimir informe" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_Copiar la URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "Copiar la URL al portapapeles" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Desconocido" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Límite" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Preferencias del límite de búsqueda" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Límite:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notas (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Preferencias" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Editar preferencias de usuario" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Preferencias" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Versión" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Seleccionar una versión" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Versión:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Combinaciones de teclas" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Atajos en campos de texto" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Cortar texto seleccionado" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Copiar texto seleccionado" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Pegar texto seleccionado" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Campo siguiente" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Campo anterior" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Atajos en relaciones" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Crear nueva relación" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Abrir/Buscar relación" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Atajos en listas" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Crear nueva línea" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Abrir relación" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Marcar para eliminación" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Desmarcar para eliminación" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Controles de edición" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Mover cursor" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Mover a la derecha" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Mover a la izquierda" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Mover arriba" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Mover abajo" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Mover arriba una página" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Mover abajo una página" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "Mover al principio" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Mover al final" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Mover al padre" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Seleccionar todo" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Deseleccionar todo" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Seleccionar padre" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Seleccionar/Activar fila actual" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Conmutar selección" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Expandir/Contraer" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Expandir fila" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Contraer fila" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Conmutar fila" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Contraer todas las filas" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Expandir todas las filas" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Vista de árbol" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Cambiar vi_sta" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Cambiar vista" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Anterior" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Registro anterior" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Sig_uiente" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Registro siguiente" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Buscar" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Nuevo" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Crear un nuevo registro" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Guardar" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Guardar este registro" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_Recargar/Deshacer" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Recargar/Deshacer" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplicar" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Eliminar..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Ver _registro..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Mostrar versiones..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Adjun_tos..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Añadir un adjunto al registro" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notas..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Añadir una nota al registro" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Acciones..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Relacionado..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Informes..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_Correo electrónico..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "Im_primir..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_Exportar datos..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_Importar datos..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "Copiar _URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_Cerrar pestaña" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Todos los campos" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Añadir" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Eliminar" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Limpiar" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Campos seleccionados" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Parámetros CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Separador de campo:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Delimitador de texto:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Codificación:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Nombre del campo" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "Exportación CSV: %s" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_Guardar exportación" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_Eliminar exportación" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Exportaciones predeterminadas" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Nombre" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Abrir" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Añadir nombres de _campo" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (cadena)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (nombre del modelo)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (nombre del registro)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "¿Cuál es el nombre de esta exportación?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Sobrescribir la definición de '%s'?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "Se ha guardado %d registro." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "Se han guardado %d registros." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Ha fallado la operación.\n" "Mensaje de error:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Error" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Enlace" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Eliminar" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Nuevo" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Cambiar vista" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Anterior" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Siguiente" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Añadir" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Eliminar " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Crear un nuevo registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Eliminar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Recuperar registro seleccionado " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "Importación CSV: %s" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_Auto-detectar" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Archivo a importar:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Abrir..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Líneas a omitir:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Primero debe elegir un archivo a importar." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Error al abrir el archivo CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Se ha producido un error al procesar el archivo en el campo %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "Se ha importado %d registro." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "Se han importado %d registros." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Buscar" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Buscar %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "No se ha podido eliminar el asistente %s" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Asistente" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Creado por:" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Fecha creación:" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Última modificación por:" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Última fecha de modificación:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "No se ha podido obtener el estado de expansión del árbol de %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "No se ha podido establecer el estado de expansión del árbol" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" no es válido según su dominio." #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" es obligatorio." #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Los valores de \"%s\" no son válidos." #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Prevalidación" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Tamaño de la imagen" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Anchura:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Altura:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "Imagen PNG (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Guardar como" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "El tamaño de la imagen es muy grande." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Abrir filtros" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Muestra las búsquedas favoritas" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Eliminar de las búsquedas favoritas" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Guardar como búsqueda favorita" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Mostrar registros activos" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Mostrar registros inactivos" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Nombre de la búsqueda favorita:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Buscar" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Hoy:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "retroceder" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "ir adelante" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "año anterior" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "año próximo" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Vista semanal" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Vista mensual" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Semana" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Seleccionar…" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Limpiar" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Todos los archivos" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Mostrar como texto plano" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Añadir un valor" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Eliminar \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Imágenes" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Añadir un registro existente" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Eliminar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Abrir registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Eliminar el registro " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Buscar registro " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Eliminar registro seleccionado" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Editar registro seleccionado " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Primer plano" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Seleccione un color" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Traducción" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Editar" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Confuso" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "Debe guardar el registro antes de añadir traducciones." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "No hay otro idioma disponible." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Traducir vista" tryton-5.0.17/tryton/data/locale/es/LC_MESSAGES/tryton.mo0000644000175000017500000004443713571264251022274 0ustar cedced00000000000000` )"L]q 7HYu   #-I#[%  .=LU&\      $+>j  ,: IWf x   " 0:?Uow &  )9 ? LV ny  "2E[u ! %7 I T `j        : K T _ h k p }     # !!6!?! Q![!m! |! !!!!!! !!!!!" " "&";"L" S"]" x" " """""" # ## ##-#2# :#E#U#g#x## ####### $ $ *$8$ K$U$ q${$$$$$$$$ % %%(%I7%}% %5 &8V&-&&& &&&& & '''5'$P'%u'''''(( 1( >(I( O(Y( _(m( r( |((((( ((((%)7,)d) t)) ))) ) )) ) ) )))* * * * %* /* :*G* O*Z* `*m* u**** ** **$* * * + +<*+g+ ~++++++F-%K-q------.. 4.@.E.H.M.P.T.V.n.$...#. . // /"/*/D/a//// //!/0103O0 00 0 00 00011121G1 W1a1)j111111122 *282K2T2o2@2222(3@3X3u33*333 3 344 ,4 :4F4%O4u44444 4444 55!15 S5]5s5255555?6D6 L6X6 q6666 6#6666 7 77%7-757);7 e7o7r7v7}7&7 78778/8O8j8&{88888888 88 9959 P9 ^9 k9w999999 99:: :%:8:H:"K:n: :: :::: ::; ;";6;J;S;.j;;$;;; ;; < < %<2<B<K<]<l<u< <<<<<<<"<= =)=8=M= _=m=}==%=$=>> #>.> 7>A> I>V>'f>>>>> >%>? ?5? T?`?t?????? ?@ @;@W@p@@@ @ @@@@O@AA$A4A5-B4cBBB BBBB BB C7C(HC@qC.C'C= D9GD%D DDDDDDEE(E /E*=EhE qE0{EEEEE*E7FFF UFbFkF zFFFFF F FFFGG G +G 5G ?GLG\G oG yGGGGGGG G GG,GH&H =H KHYH/[H=HH$HIIII of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...About...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Application ErrorAre you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancelCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDefaultDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEmail...Encoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFormFormatFuzzyHeight:HelpHost / Database informationHost:IDID:IconsImage SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsKeyboard Shortcuts...Latest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOptionsOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreferences...PreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewTextText Entries ShortcutsText and IconsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To report bugs you must have an account on %sTo:TodayToggle rowToggle selectionToolbarTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: es Language-Team: es Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 de "%s" no es válido según su dominio."%s" es obligatorio.Se ha importado %d registro.Se ha guardado %d registro.Se han importado %d registros.Se han guardado %d registros.%s (%s)%s (nombre del modelo)%s (nombre del registro)%s (cadena)%s%%, ,….....:Todos los camposCampos seleccionadosExportaciones predeterminadasCrear...Buscar...Esta disponible una nueva versión!Adjun_tos...Acerca de...AcciónAcciones...AñadirAñadir nombres de _campoAñadir una nota al registroAñadir un adjunto al registroAñadir un registro existenteAñadir un nuevo perfilAñadir un valorAñadir...Todos los archivosIgnorar siempre esta advertencia.Error de aplicación.¿Está seguro que quiere eliminar este registro?¿Está seguro que quiere eliminar estos registros?Adjunto(%d)Adjunto:Adjuntos (%s)Adjuntos...Mensaje:Nombre de la búsqueda favorita:Guardar como búsqueda favoritaSeguimiento de erroresPor: CC:Exportación CSV: %sImportación CSV: %sParámetros CSVC_onectarCancelarCancelar conexión con el servidor TrytonNo guardes los cambiosURL de comprobación: %sComprobar versiónLimpiarEliminar el registro CerrarCerrar pestañaContraer todas las filasContraer filaLínea de comando:CompararExcepción de concurrenciaConectar con el servidor TrytonError de conexión. Nombre de usuario o contraseña incorrectos.Copiar la URL al portapapelesCopiar _URL...Copiar texto seleccionadoNo se ha podido conectar con el servidorCrear un nuevo registroCrear un nuevo registro Crear nueva líneaCrear nueva relaciónSe creó un nuevo error con identificador Fecha creación:Fecha creación:Creado por:Creado por:Cortar texto seleccionadoBase de datos:Formato fechaPor defectoEliminarEliminar registro seleccionado Separador de campo:Format a mostrarFormato fecha actualValor a mostrar¿Desea continuar?DescargarEmailInforme por emailCorreo electrónico...EditarEditar preferencias de usuarioEditar registro seleccionado Editar...Controles de ediciónCorreo electrónicoConfiguración del programa de correo electrónicoCorreo electrónico...Codificación:ErrorError al abrir el archivo CSVSe ha producido un error al procesar el archivo en el campo %s.Error: Excepción:Expandir todas las filasExpandir filaExpandir/ContraerFalsoTabulación rápidaFavoritosRecuperando lista de bases de datosNombre del campoArchivo a importar:BuscarPrimer planoFormularioFormatoConfusoAltura:AyudaInformación del Servidor / Base de datosServidor:IDID:IconosTamaño de la imagenEl tamaño de la imagen es muy grande.ImágenesEl cliente no es compatible con la versión del servidorCombinaciones de teclasCombinaciones de teclas...Última fecha de modificación:Última modificación por:Ejecutar acciónLeyenda de palabras clave disponibles:LímiteLímite:Líneas a omitir:EnlaceAtajos en listasUsuarioMGestionar...Marcar para eliminaciónModelo:Última fecha de modificación:Última modificación por:Vista mensualMover cursorMover abajoMover abajo una páginaMover al finalMover a la izquierdaMover al padreMover a la derechaMover al principioMover arribaMover arriba una páginaNombreNuevoSiguienteRegistro siguienteCampo siguienteNoNo se ha definido ninguna acción.No hay otro idioma disponible.No se han encontrado resultados.Nota(%d)Notas (%s)Notas...AceptarAbrirAbrir filtrosAbrir registros relacionadosAbrir relaciónAbrir informeAbrir el calendarioAbrir registro Abrir...Abrir/Buscar relaciónHa fallado la operación. Mensaje de error: %sOpcionesSobrescribir la definición de '%s'?Modo PDAImagen PNG (*.png)Contraseña:Pegar texto seleccionadoPrevalidaciónPreferenciasPreferenciasPreferencias...AnteriorRegistro anteriorCampo anteriorImprimirImprimir informeImprimir...PerfilEditor de perfilesPerfil:SalirDelimitador de texto:Registro guardado.Los registros no se han eliminado.Registros eliminados._RelacionadoRelacionado...Atajos en relacionesRecargar/DeshacerEliminar "%s"Eliminar Eliminar el perfil seleccionadoEliminar registro seleccionadoEliminar registro seleccionado Eliminar de las búsquedas favoritasInformesInformar del errorInforme...VersiónVersión:GuardarGuardar comoGuardar como...Guardar estado de expansión del árbolGuardar ancho/altoGuardar este registroGuardar vuestros cambiosBuscarBuscar %sPreferencias del límite de búsqueda_Límite de búsqueda...Buscar registro Mostrar la versión modificadaSeleccionarSeleccione un colorSeleccionar una versiónSeleccionar todoSeleccionar padreSeleccione su acciónSeleccionar…Seleccionar/Activar fila actualSelecciónMostrar registros activosMuestra las búsquedas favoritasMostrar registros inactivosMostrar como texto planoMostrar versiones...Corrección ortográficaAsunto:Cambiar vistaCambiar vistaTextoAtajos en campos de textoTexto e iconosLa acción seleccionada requiere cerrar todas las pestañas. ¿Desea continuar?El mismo error ya fue notificado por otro usuario. Para mantenerle informado añadiremos su usuario a la lista de interesados en esta incidencia.Los valores de "%s" no son válidos.Este registro ha sido modificado. ¿Desea guardarlo?Este registro ha sido modificado mientras lo editaba.Para informar de errores debe tener una cuenta en %sPara:Hoy:Conmutar filaConmutar selecciónBarra de herramientasTraducir vistaTraducciónVista de árbolVerdaderoNo se ha podido comprobar si existe una nueva versión.No se ha podido eliminar el asistente %sNo se ha podido obtener el estado de expansión del árbol de %sNo se ha podido buscar el autocompletado de %sNo se ha podido establecer el idioma %sNo se ha podido establecer el estado de expansión del árbolNo se ha podido escribir el archivo de configuración %s.Recuperar registro seleccionado DesconocidoDesmarcar para eliminaciónDeseleccionar todoNombre de usuario:Usuario:Nombre de usuario:ValorVer _registro...SemanaVista semanal¿Cuál es el nombre de esta exportación?Anchura:AsistenteAhora está trabajando en el registro duplicado.Guardar de todas formasASíDebe elegir un registro.Primero debe elegir un archivo a importar.Debe guardar el registro antes de añadir traducciones.Su selección:_Acciones..._Añadir_Auto-detectar_Cancelar_Limpiar_Cerrar pestaña_Copiar la URL_Eliminar exportación_Eliminar..._Duplicar_Correo electrónico..._Exportar datos..._Importar datos..._NuevoSig_uiente_Notas..._AnteriorIm_primir..._Relacionado..._Recargar/Deshacer_Eliminar_Informes..._Guardar_Guardar exportación_BuscarCambiar vi_stadModo desarrolloretrocederir adelantehRegistra toda la información con nivel INFOmmodularidad, escalabilidad y seguridadaño próximoaño anteriorsIndica un archivo de configuración alternativoIndica el nivel de log: DEBUG, INFO, WARNING, ERROR, CRITICALIndica el usuarioIndica el nombre:puerto del servidorvCréditos de traducciónSatryton-5.0.17/tryton/data/locale/ru/0000755000175000017500000000000013571264253016620 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ru/LC_MESSAGES/0000755000175000017500000000000013571264253020405 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/ru/LC_MESSAGES/tryton.po0000644000175000017500000011614313463252532022307 0ustar cedced00000000000000# Russian (Russia) translations for tryton. # Copyright (C) 2009 B2CK # This file is distributed under the same license as the tryton project. # Dmitry Klimanov , 2010. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "указать альтернативный конфигурационный файл" #: tryton/config.py:77 msgid "development mode" msgstr "режим разработки" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "все сообщения на уровне INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" "указать уровень вывода сообщений: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "указать имя пользователя" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "укажите имя сервера" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Невозможно записать файл конфигурации %s!" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Не удается установить локализацию %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Выберите действие" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Не определены действия!" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Выбор" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "Отмена" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Ваш выбор:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Сохранить" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Сохранить как..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Всегда игнорировать это предупреждение." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Вы хотите продолжить?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Прерывание конкурентных записей" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Сравнить" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Записать все равно" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Ошибка приложения!" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Сообщить об ошибке" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Ошибка: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "" "Вы можете отправить отчет об ошибке если вы зарегистрированны на %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Система сбора ошибок" #: tryton/common/common.py:811 msgid "User:" msgstr "Пользователь:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Пароль:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Эта же ошибка была уже сообщена от другого пользователя.\n" "Чтобы держать вас в курсе ваше имя пользователя будет добавлен в список перечень по этому вопросу" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Создан новый отчет об ошибке с идентификатором" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Ошибка соединения!\n" "Неверное имя пользователя или пароль!" #: tryton/common/common.py:899 msgid "Exception:" msgstr "Исключительная ситуация:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Поиск..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Создать..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 #, fuzzy msgid "Value" msgstr "Добавить значение" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 #, fuzzy msgid "Displayed value" msgstr "Добавить значение" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 #, fuzzy msgid "Format" msgstr "Нормальный" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:63 #, fuzzy msgid "Open the calendar" msgstr "Открыть календарь " #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Истинный" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Ложный" #: tryton/common/popup_menu.py:84 #, fuzzy msgid "Edit..." msgstr "_Выход..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Вложения..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Действия..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Связанные..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Отчет..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "Эл.почта..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Печать..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "Г" #: tryton/common/timedelta.py:27 msgid "M" msgstr "М" #: tryton/common/timedelta.py:28 msgid "w" msgstr "н" #: tryton/common/timedelta.py:29 msgid "d" msgstr "д" #: tryton/common/timedelta.py:30 msgid "h" msgstr "ч" #: tryton/common/timedelta.py:31 msgid "m" msgstr "м" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "Настройки..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "Панель инструментов" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "По умолчанию" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "Текст и Значки" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "Текст" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "Значки" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "Форма" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Сохранить размеры" #: tryton/gui/main.py:136 #, fuzzy msgid "Save Tree State" msgstr "Запомнить состояние дерева" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Проверка орфографии" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Максимальное количество строк..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "Настройки _Эл.почты" #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Параметры" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Быстрые клавиши" #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "О программе" #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "Помощь" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Ничего не найдено." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "Избранное" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Действие" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Данное действие приведет к закрытию всех вкладок.\n" "Продолжить?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Закрыть вкладку" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Вложений (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Редактор профилей" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Профиль" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Сервер:порт" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "База данных:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Получение списка баз данных" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Имя пользователя:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Несовместимая версия сервера" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Не удается подключиться к серверу!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Логин" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "Отмена" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Отмена подключения к серверу" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "Соединение" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Соединение с сервером" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Профиль:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Сервер / база данных" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Имя пользователя:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "Эл.почта" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Настройки программы электронной почты" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Командная строка:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Переменные доступные для подстановки:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "Кому:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "Скрытая копия:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Тема:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Сообщение:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Вложение:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Вложений (%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Вы должны выбрать одну запись!" #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "Номер строки" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Создано пользователем" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Дата создания" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Изменена пользователем:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Дата изменения:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Модель:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Вы уверены что хотите удалить эту запись?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Вы уверены что хотите удалить эти записи?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Записи не удалены!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Записи удалены!" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "Сейчас работает на дублирующихся записях!" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Запись сохранена!" #: tryton/gui/window/form.py:485 msgid " of " msgstr "из" #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Эта запись была изменена\n" "Вы хотите её сохранить?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Выполнить действие" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Связанные" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Открыть связанные записи" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Отчет" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Открыть отчет" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "Эл.почта" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Отправить отчет по Эл.почте" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Печать" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Печать отчета" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Неизвестно" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Ограничение" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Настройки ограничения поиска" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Кол-во записей" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Настройки" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Изменить настройки пользователя" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Настройка" #: tryton/gui/window/revision.py:21 #, fuzzy msgid "Revision" msgstr "Предыдущий" #: tryton/gui/window/revision.py:38 #, fuzzy msgid "Select a revision" msgstr "Выбор" #: tryton/gui/window/revision.py:41 #, fuzzy msgid "Revision:" msgstr "Предыдущий" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Сочетания клавиш быстрого доступа" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Горячие клавиши в текстовых полях" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Вырезать выделенный текст" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Скопировать выделенный текст" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Вставить скопированный текст" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Следующий Widget" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Предыдущий Widget" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Связи записей \"быстрого доступа\"" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Создать новую связь" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Открыть / Поиск связей" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Список горячих клавиш" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Создать новую строку" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Открыть связь" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Отметить линию на удаление" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Убрать отметку на удаление" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Редактируемые поля" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Сменить просмотр" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "Сменить просмотр" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "Предыдущая" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Предыдущая запись" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "Следующая" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Следующая запись" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "Поиск" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "Новый" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Создать новую запись" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "Сохранить" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Сохранить эту запись" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Обновить/Отменить" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "Обновить/Отменить" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "Копировать" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "Удалить..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Просмотр изменений" #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Вложения..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Добавить вложение для этой записи" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "Действия" #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "Связанные..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "Отчет..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "Эл.почта..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "печать" #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Экспорт данных" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Импорт данных" #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Закрыть вкладку" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Все поля" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Добавить" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Удалить" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Очистить" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "Параметры CVS" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Кодировка:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Наименование поля" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Сохранить настройку экспорта" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Удалить настройку экспорта" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Предопределенные экспорты" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Имя" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Открыть" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Добавить имя поля" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Укажите имя для экспорта." #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d запись сохранена!" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d записей сохранено!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Не удалось выполнить операцию!\n" "Сообщение об ошибке:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Ошибка" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Ссылка" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Удалить" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Новый" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Переключить" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Предыдущий" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Следующий" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Добавить" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Удалить " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Создать новую запись " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Удалить выбраную запись " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Восстановить выбраную запись " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Авто-обнаружение" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Файл для импорта:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Открыть..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Строки для пропуска:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Вы должны сначала выбрать файл для импорта!" #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Ошибка открытия файла CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Ошибка при обработке файла на поле %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d запись импортирована!" #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d записей импортировано!" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Поиск" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Мастер" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 #, fuzzy msgid "Creation User" msgstr "Создано пользователем" #: tryton/gui/window/view_form/screen/screen.py:208 #, fuzzy msgid "Creation Date" msgstr "Дата создания" #: tryton/gui/window/view_form/screen/screen.py:209 #, fuzzy msgid "Modification User" msgstr "Дата изменения:" #: tryton/gui/window/view_form/screen/screen.py:210 #, fuzzy msgid "Modification Date" msgstr "Дата изменения:" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy msgid "Unable to get view tree state for %s" msgstr "Не удается установить локализацию %s" #: tryton/gui/window/view_form/screen/screen.py:867 #, fuzzy msgid "Unable to set view tree state" msgstr "Не удается установить локализацию %s" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Размер изображения" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Ширина:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Ввысота:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG изображение (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Сохранить как" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Размер изображения слишком большой!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Показать сохраненные фильтры" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Удалить эту закладку" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Запомнить этот фильтр" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Имя закладки:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Найти" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 #, fuzzy msgid "Today" msgstr "Сообщение:" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 #, fuzzy msgid "Week View" msgstr "Переключить вид" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 #, fuzzy msgid "Month View" msgstr "Переключить вид" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Очистить" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Все фалы" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Показать в виде текста" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Добавить значение" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "Удалить \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Изображения" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Добавить существующую запись" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Удалить выбраную запись " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Открыть запись " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Поиск записи " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Удалить выбраную запись" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Изменить выбранную запись " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Перевод" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Редактировать" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Неточный" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Необходимо сохранить запись перед добавлением перевода!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Отсутствуют другие доступные языки!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Перевод текущего окна" tryton-5.0.17/tryton/data/locale/ru/LC_MESSAGES/tryton.mo0000644000175000017500000004166213571264251022310 0ustar cedced00000000000000!$ ,-)2\mu -= DOSd}  #%B Q]n} &  ' 5CI_ eo    ,@Yi}    0HQ X fpu &  (3 CN^ dq   " 3M e!s   ) 8E T bnv      %-B\e w    #/ 6@ [ gt    ,F MWm}    1KaqI} 8    % E %`      !! !:!A! H!U!W![! k!w!|! ! ! ! ! !!!!! ! ! ! " "" #"."4" <"I"K"\" d"o" q""$" " """<".#E#G#Z#\#^#6%);%e%v%~%% %%%%%%8%&5&J&f&z&&& &&>&6)'`'!p'''J'K'K@(((((((( )&4)[)`){))))5) ) * *%*6*L*R*p* * **<*(*'+ ?+6L+?+&+++&,$=,Vb,,),1,/- F-R-2a- ---'---2.8.K.<f.5.#..G /U/ i/,v/C//./%0 50@0 P0 ]03j0!00 0 001$1<1R1U1#m1161?12,<2#i2F222%3 ,3(93 b3m3 p31z3 3 3 333 34 4 4+434G4 N4Y4l444!44 4444 4.565P5j5(|555"5 56506?6R6e6!z66 6666!6 707 57A7T7;j7777,728&G8 n8"y8 8888!8&9=9 W9 b96l9;999:: +: 6:!D: f:p: ::6::):";%4; Z;d;>{;q;,< H=8i= = ==(== > >>;>%V>B|><>>1? C? P?q? ?#??.? @ @"@B@E@I@\@m@ @@ @@@@@ A $A/A BALA aAnA!AA AA AABB%B -B8B0;BlB$oB B BBUBdC.iCCCCC of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation Date:Creation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFuzzyHeight:Host / Database informationHost:IDID:Image SizeImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:RelateRelate...Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...SaveSave AsSave As...Save Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:Toggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUndelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:View _Logs...WeekWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: ru Language-Team: ru 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) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 из"%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:Все поляFields selectedПредопределенные экспортыСоздать...Поиск...A new version is available!Вложения...ДействиеДействия...ДобавитьДобавить имя поляAdd a note to the recordДобавить вложение для этой записиДобавить существующую записьAdd new profileДобавить значениеAdd...Все фалыВсегда игнорировать это предупреждение.Вы уверены что хотите удалить эту запись?Вы уверены что хотите удалить эти записи?Вложений (%d)Вложение:Вложений (%s)Вложения...Сообщение:Имя закладки:Запомнить этот фильтрСистема сбора ошибокBy: Скрытая копия:CSV Export: %sCSV Import: %sПараметры CVSСоединениеОтмена подключения к серверуCancel savingCheck URL: %sCheck VersionОчиститьClear the field CloseЗакрыть вкладкуCollapse all rowsCollapse rowКомандная строка:СравнитьПрерывание конкурентных записейСоединение с серверомCopy URL into clipboardCopy _URL...Скопировать выделенный текстНе удается подключиться к серверу!Создать новую записьСоздать новую запись Создать новую строкуСоздать новую связьСоздан новый отчет об ошибке с идентификаторомДата созданияСоздано пользователемВырезать выделенный текстБаза данных:Date FormatУдалитьУдалить выбраную запись Delimiter:Display formatDisplayed date formatВы хотите продолжить?DownloadЭл.почтаОтправить отчет по Эл.почтеЭл.почта...РедактироватьИзменить настройки пользователяИзменить выбранную запись Редактируемые поляЭл.почтаНастройки программы электронной почтыКодировка:ОшибкаОшибка открытия файла CSVОшибка при обработке файла на поле %s.Ошибка: Исключительная ситуация:Expand all rowsExpand rowExpand/CollapseЛожныйFast TabbingПолучение списка баз данныхНаименование поляФайл для импорта:НайтиForegroundНеточныйВвысота:Сервер / база данныхСервер:портIDНомер строкиРазмер изображенияИзображенияНесовместимая версия сервераСочетания клавиш быстрого доступаДата изменения:Изменена пользователем:Выполнить действиеПеременные доступные для подстановки:ОграничениеКол-во записейСтроки для пропуска:СсылкаСписок горячих клавишЛогинМManage...Отметить линию на удалениеМодель:Move CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageИмяНовыйСледующийСледующая записьСледующий WidgetNoНичего не найдено.Note(%d)Notes (%s)Notes...OKОткрытьOpen filtersОткрыть связанные записиОткрыть связьОткрыть отчетОткрыть...Открыть / Поиск связейOverride '%s' definition?PDA ModePNG изображение (*.png)Пароль:Вставить скопированный текстPre-validationНастройкаНастройкиПредыдущийПредыдущая записьПредыдущий WidgetПечатьПечать отчетаПечать...ПрофильРедактор профилейПрофиль:QuitQuote char:СвязанныеСвязанные...Связи записей "быстрого доступа"Удалить "%s"Удалить Remove selected profileУдалить выбраную записьУдалить выбраную запись Удалить эту закладкуОтчетСообщить об ошибкеОтчет...СохранитьСохранить какСохранить как...Сохранить размерыСохранить эту записьSave your current versionПоискSearch %sНастройки ограничения поискаМаксимальное количество строк...Поиск записи See the modified versionSelectSelect a colorSelect allSelect parentВыберите действиеSelect...Select/Activate current rowВыборShow active recordsПоказать сохраненные фильтрыShow inactive recordsПоказать в виде текстаShow revisions...Проверка орфографииТема:ПереключитьГорячие клавиши в текстовых поляхДанное действие приведет к закрытию всех вкладок. Продолжить?Эта же ошибка была уже сообщена от другого пользователя. Чтобы держать вас в курсе ваше имя пользователя будет добавлен в список перечень по этому вопросуThe values of "%s" are not validThis record has been modified while you were editing it.Кому:Toggle rowToggle selectionПеревод текущего окнаПереводTree viewИстинныйUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sНе удается установить локализацию %sВосстановить выбраную запись НеизвестноУбрать отметку на удалениеUnselect allИмя пользователя:Пользователь:Имя пользователя:Просмотр измененийWeekУкажите имя для экспорта.Ширина:МастерЗаписать все равноГYesВаш выбор:Действия_ДобавитьОтменаЗакрыть вкладку_Copy URLУдалить...КопироватьЭл.почта...Экспорт данныхИмпорт данныхНовыйСледующая_Notes...ПредыдущаяпечатьСвязанные...Обновить/Отменить_УдалитьОтчет...СохранитьПоискСменить просмотрдрежим разработкиgo backgo forwardчвсе сообщения на уровне INFOмmodularity, scalability and securitynext yearprevious yearsуказать альтернативный конфигурационный файлуказать уровень вывода сообщений: DEBUG, INFO, WARNING, ERROR, CRITICALуказать имя пользователяttranslator-creditsнytryton-5.0.17/tryton/data/locale/tryton.pot0000644000175000017500000007326213463252532020264 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2018 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2018. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: tryton 4.7.dev0\n" "Report-Msgid-Bugs-To: issue_tracker@tryton.org\n" "POT-Creation-Date: 2018-04-14 17:57+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.5.3\n" #: tryton/config.py:75 msgid "specify alternate config file" msgstr "" #: tryton/config.py:78 msgid "development mode" msgstr "" #: tryton/config.py:81 msgid "logging everything at INFO level" msgstr "" #: tryton/config.py:83 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "" #: tryton/config.py:86 msgid "specify the login user" msgstr "" #: tryton/config.py:88 msgid "specify the server hostname:port" msgstr "" #: tryton/config.py:92 msgid "Too much arguments" msgstr "" #: tryton/config.py:95 #, python-format msgid "File \"%s\" not found" msgstr "" #: tryton/config.py:133 #, python-format msgid "Unable to write config file %s." msgstr "" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "" #: tryton/action/main.py:93 tryton/common/button.py:57 msgid ", " msgstr "" #: tryton/action/main.py:95 msgid ",…" msgstr "" #: tryton/action/main.py:96 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:191 msgid "Select your action" msgstr "" #: tryton/action/main.py:197 msgid "No action defined." msgstr "" #: tryton/common/button.py:57 msgid "By: " msgstr "" #: tryton/common/common.py:248 msgid "Tryton Connection" msgstr "" #: tryton/common/common.py:258 msgid "Server:" msgstr "" #: tryton/common/common.py:276 msgid "Port:" msgstr "" #: tryton/common/common.py:348 tryton/gui/window/shortcuts.py:57 msgid "Selection" msgstr "" #: tryton/common/common.py:358 msgid "Your selection:" msgstr "" #: tryton/common/common.py:481 #: tryton/gui/window/view_form/view/form_gtk/binary.py:34 #: tryton/gui/window/view_form/view/form_gtk/binary.py:120 #: tryton/gui/window/view_form/view/graph.py:161 #: tryton/gui/window/view_form/view/list_gtk/widget.py:497 #: tryton/gui/window/win_export.py:307 msgid "Save As..." msgstr "" #: tryton/common/common.py:628 msgid "Always ignore this warning." msgstr "" #: tryton/common/common.py:633 msgid "Do you want to proceed?" msgstr "" #: tryton/common/common.py:652 msgid "Confirmation" msgstr "" #: tryton/common/common.py:763 tryton/common/common.py:1093 msgid "Concurrency Exception" msgstr "" #: tryton/common/common.py:776 msgid "" "Write Concurrency Warning:\n" "\n" "This record has been modified while you were editing it.\n" " Choose:\n" " - \"Cancel\" to cancel saving;\n" " - \"Compare\" to see the modified version;\n" " - \"Write Anyway\" to save your current version." msgstr "" #: tryton/common/common.py:786 msgid "Compare" msgstr "" #: tryton/common/common.py:792 msgid "Write Anyway" msgstr "" #: tryton/common/common.py:821 tryton/gui/window/win_export.py:339 #: tryton/gui/window/win_import.py:114 tryton/gui/window/win_import.py:143 msgid "Error" msgstr "" #: tryton/common/common.py:824 msgid "Report Bug" msgstr "" #: tryton/common/common.py:832 msgid "Application Error." msgstr "" #: tryton/common/common.py:855 msgid "Error: " msgstr "" #: tryton/common/common.py:875 #, python-format msgid "To report bugs you must have an account on %s" msgstr "" #: tryton/common/common.py:905 msgid "Bug Tracker" msgstr "" #: tryton/common/common.py:924 msgid "User:" msgstr "" #: tryton/common/common.py:932 msgid "Password:" msgstr "" #: tryton/common/common.py:987 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" #: tryton/common/common.py:998 msgid "Created new bug with ID " msgstr "" #: tryton/common/common.py:1006 msgid "" "Connection error.\n" "Bad username or password." msgstr "" #: tryton/common/common.py:1011 msgid "Exception:" msgstr "" #: tryton/common/common.py:1038 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:1045 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:1051 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:1053 msgid "Download" msgstr "" #: tryton/common/common.py:1438 msgid "..." msgstr "" #: tryton/common/completion.py:25 msgid "Search..." msgstr "" #: tryton/common/completion.py:27 msgid "Create..." msgstr "" #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:35 tryton/common/datetime_.py:236 #: tryton/common/datetime_.py:387 msgid "Value" msgstr "" #: tryton/common/datetime_.py:36 tryton/common/datetime_.py:237 #: tryton/common/datetime_.py:388 msgid "Displayed value" msgstr "" #: tryton/common/datetime_.py:40 tryton/common/datetime_.py:194 #: tryton/common/datetime_.py:240 tryton/common/datetime_.py:344 msgid "Format" msgstr "" #: tryton/common/datetime_.py:41 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:241 tryton/common/datetime_.py:345 msgid "Display format" msgstr "" #: tryton/common/datetime_.py:64 msgid "Open the calendar" msgstr "" #: tryton/common/datetime_.py:392 tryton/common/datetime_.py:397 msgid "Date Format" msgstr "" #: tryton/common/datetime_.py:393 tryton/common/datetime_.py:398 msgid "Displayed date format" msgstr "" #: tryton/common/domain_parser.py:236 msgid "y" msgstr "" #: tryton/common/domain_parser.py:236 msgid "Yes" msgstr "" #: tryton/common/domain_parser.py:236 tryton/common/domain_parser.py:461 #: tryton/gui/window/view_form/view/screen_container.py:575 msgid "True" msgstr "" #: tryton/common/domain_parser.py:236 msgid "t" msgstr "" #: tryton/common/domain_parser.py:461 #: tryton/gui/window/view_form/view/screen_container.py:575 msgid "False" msgstr "" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "" #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "" #: tryton/common/popup_menu.py:96 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:109 msgid "Actions..." msgstr "" #: tryton/common/popup_menu.py:110 msgid "Relate..." msgstr "" #: tryton/common/popup_menu.py:111 msgid "Report..." msgstr "" #: tryton/common/popup_menu.py:112 msgid "E-Mail..." msgstr "" #: tryton/common/popup_menu.py:113 msgid "Print..." msgstr "" #: tryton/common/timedelta.py:26 msgid "Y" msgstr "" #: tryton/common/timedelta.py:27 msgid "M" msgstr "" #: tryton/common/timedelta.py:28 msgid "w" msgstr "" #: tryton/common/timedelta.py:29 msgid "d" msgstr "" #: tryton/common/timedelta.py:30 msgid "h" msgstr "" #: tryton/common/timedelta.py:31 msgid "m" msgstr "" #: tryton/common/timedelta.py:32 msgid "s" msgstr "" #: tryton/gui/main.py:212 msgid "_Connection" msgstr "" #: tryton/gui/main.py:220 msgid "_User" msgstr "" #: tryton/gui/main.py:234 msgid "_Options" msgstr "" #: tryton/gui/main.py:242 msgid "Fa_vorites" msgstr "" #: tryton/gui/main.py:258 msgid "_Help" msgstr "" #: tryton/gui/main.py:280 tryton/gui/main.py:826 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:48 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:91 #: tryton/gui/window/view_form/view/screen_container.py:144 #: tryton/gui/window/win_search.py:34 msgid "Search" msgstr "" #: tryton/gui/main.py:370 msgid "No result found." msgstr "" #: tryton/gui/main.py:410 msgid "_Connect..." msgstr "" #: tryton/gui/main.py:420 msgid "_Disconnect" msgstr "" #: tryton/gui/main.py:430 msgid "_Quit..." msgstr "" #: tryton/gui/main.py:446 msgid "_Preferences..." msgstr "" #: tryton/gui/main.py:458 msgid "_Menu Reload" msgstr "" #: tryton/gui/main.py:468 msgid "_Menu Toggle" msgstr "" #: tryton/gui/main.py:476 msgid "_Global Search" msgstr "" #: tryton/gui/main.py:492 msgid "_Toolbar" msgstr "" #: tryton/gui/main.py:500 msgid "_Default" msgstr "" #: tryton/gui/main.py:511 msgid "_Text and Icons" msgstr "" #: tryton/gui/main.py:521 msgid "_Icons" msgstr "" #: tryton/gui/main.py:530 msgid "_Text" msgstr "" #: tryton/gui/main.py:538 msgid "_Mode" msgstr "" #: tryton/gui/main.py:546 msgid "_Normal" msgstr "" #: tryton/gui/main.py:555 msgid "_PDA" msgstr "" #: tryton/gui/main.py:562 msgid "_Form" msgstr "" #: tryton/gui/main.py:571 msgid "Save Width/Height" msgstr "" #: tryton/gui/main.py:582 msgid "Save Tree State" msgstr "" #: tryton/gui/main.py:594 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:604 msgid "Spell Checking" msgstr "" #: tryton/gui/main.py:615 msgid "_Previous Tab" msgstr "" #: tryton/gui/main.py:622 msgid "_Next Tab" msgstr "" #: tryton/gui/main.py:629 msgid "Search Limit..." msgstr "" #: tryton/gui/main.py:635 msgid "_Email..." msgstr "" #: tryton/gui/main.py:647 msgid "Check Version" msgstr "" #: tryton/gui/main.py:657 msgid "_Save Options" msgstr "" #: tryton/gui/main.py:671 msgid "_Keyboard Shortcuts..." msgstr "" #: tryton/gui/main.py:681 msgid "_About..." msgstr "" #: tryton/gui/main.py:717 tryton/gui/main.py:739 msgid "Manage Favorites" msgstr "" #: tryton/gui/main.py:879 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" #: tryton/gui/main.py:1135 msgid "Close Tab" msgstr "" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:22 #, python-format msgid "Attachments (%s)" msgstr "" #: tryton/gui/window/dblogin.py:32 msgid "Profile Editor" msgstr "" #: tryton/gui/window/dblogin.py:47 msgid "Profile" msgstr "" #: tryton/gui/window/dblogin.py:53 tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "" #: tryton/gui/window/dblogin.py:59 tryton/gui/window/win_csv.py:79 msgid "_Remove" msgstr "" #: tryton/gui/window/dblogin.py:73 tryton/gui/window/dblogin.py:458 msgid "Host:" msgstr "" #: tryton/gui/window/dblogin.py:84 tryton/gui/window/dblogin.py:470 msgid "Database:" msgstr "" #: tryton/gui/window/dblogin.py:104 msgid "Fetching databases list" msgstr "" #: tryton/gui/window/dblogin.py:120 msgid "Username:" msgstr "" #: tryton/gui/window/dblogin.py:307 tryton/gui/window/dblogin.py:627 msgid "Incompatible version of the server" msgstr "" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:630 msgid "Could not connect to the server" msgstr "" #: tryton/gui/window/dblogin.py:388 msgid "Login" msgstr "" #: tryton/gui/window/dblogin.py:394 msgid "_Cancel" msgstr "" #: tryton/gui/window/dblogin.py:400 msgid "Cancel connection to the Tryton server" msgstr "" #: tryton/gui/window/dblogin.py:402 msgid "C_onnect" msgstr "" #: tryton/gui/window/dblogin.py:408 msgid "Connect the Tryton server" msgstr "" #: tryton/gui/window/dblogin.py:436 msgid "Profile:" msgstr "" #: tryton/gui/window/dblogin.py:442 msgid "Manage profiles" msgstr "" #: tryton/gui/window/dblogin.py:455 msgid "Host / Database information" msgstr "" #: tryton/gui/window/dblogin.py:486 msgid "User name:" msgstr "" #: tryton/gui/window/email.py:16 msgid "Email" msgstr "" #: tryton/gui/window/email.py:26 msgid "Email Program Settings" msgstr "" #: tryton/gui/window/email.py:29 msgid "Command Line:" msgstr "" #: tryton/gui/window/email.py:39 msgid "Legend of Available Placeholders:" msgstr "" #: tryton/gui/window/email.py:46 msgid "To:" msgstr "" #: tryton/gui/window/email.py:50 msgid "CC:" msgstr "" #: tryton/gui/window/email.py:54 msgid "Subject:" msgstr "" #: tryton/gui/window/email.py:58 msgid "Body:" msgstr "" #: tryton/gui/window/email.py:62 msgid "Attachment:" msgstr "" #: tryton/gui/window/form.py:118 #, python-format msgid "Attachment(%d)" msgstr "" #: tryton/gui/window/form.py:144 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:166 msgid "You have to select one record." msgstr "" #: tryton/gui/window/form.py:170 msgid "ID:" msgstr "" #: tryton/gui/window/form.py:171 msgid "Creation User:" msgstr "" #: tryton/gui/window/form.py:172 msgid "Creation Date:" msgstr "" #: tryton/gui/window/form.py:173 msgid "Latest Modification by:" msgstr "" #: tryton/gui/window/form.py:174 msgid "Latest Modification Date:" msgstr "" #: tryton/gui/window/form.py:193 msgid "Model:" msgstr "" #: tryton/gui/window/form.py:265 msgid "Are you sure to remove this record?" msgstr "" #: tryton/gui/window/form.py:267 msgid "Are you sure to remove those records?" msgstr "" #: tryton/gui/window/form.py:270 msgid "Records not removed." msgstr "" #: tryton/gui/window/form.py:272 msgid "Records removed." msgstr "" #: tryton/gui/window/form.py:308 msgid "Working now on the duplicated record(s)." msgstr "" #: tryton/gui/window/form.py:320 msgid "Record saved." msgstr "" #: tryton/gui/window/form.py:437 msgid " of " msgstr "" #: tryton/gui/window/form.py:457 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" #: tryton/gui/window/form.py:511 msgid "Action" msgstr "" #: tryton/gui/window/form.py:511 msgid "Launch action" msgstr "" #: tryton/gui/window/form.py:512 msgid "Relate" msgstr "" #: tryton/gui/window/form.py:512 msgid "Open related records" msgstr "" #: tryton/gui/window/form.py:514 msgid "Report" msgstr "" #: tryton/gui/window/form.py:514 msgid "Open report" msgstr "" #: tryton/gui/window/form.py:515 msgid "E-Mail" msgstr "" #: tryton/gui/window/form.py:515 msgid "E-Mail report" msgstr "" #: tryton/gui/window/form.py:516 msgid "Print" msgstr "" #: tryton/gui/window/form.py:516 msgid "Print report" msgstr "" #: tryton/gui/window/form.py:536 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:539 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:598 #: tryton/gui/window/view_form/view/list_gtk/widget.py:924 msgid "Unknown" msgstr "" #: tryton/gui/window/limit.py:17 msgid "Limit" msgstr "" #: tryton/gui/window/limit.py:27 msgid "Search Limit Settings" msgstr "" #: tryton/gui/window/limit.py:30 msgid "Limit:" msgstr "" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:23 msgid "Preferences" msgstr "" #: tryton/gui/window/preference.py:50 msgid "Edit User Preferences" msgstr "" #: tryton/gui/window/preference.py:77 msgid "Preference" msgstr "" #: tryton/gui/window/revision.py:19 msgid "Revision" msgstr "" #: tryton/gui/window/revision.py:29 msgid "Select a revision" msgstr "" #: tryton/gui/window/revision.py:32 msgid "Revision:" msgstr "" #: tryton/gui/window/shortcuts.py:17 msgid "Keyboard Shortcuts" msgstr "" #: tryton/gui/window/shortcuts.py:28 msgid "Text Entries Shortcuts" msgstr "" #: tryton/gui/window/shortcuts.py:29 msgid "Cut selected text" msgstr "" #: tryton/gui/window/shortcuts.py:30 msgid "Copy selected text" msgstr "" #: tryton/gui/window/shortcuts.py:31 msgid "Paste copied text" msgstr "" #: tryton/gui/window/shortcuts.py:32 msgid "Next widget" msgstr "" #: tryton/gui/window/shortcuts.py:33 msgid "Previous widget" msgstr "" #: tryton/gui/window/shortcuts.py:34 msgid "Relation Entries Shortcuts" msgstr "" #: tryton/gui/window/shortcuts.py:35 msgid "Create new relation" msgstr "" #: tryton/gui/window/shortcuts.py:36 msgid "Open/Search relation" msgstr "" #: tryton/gui/window/shortcuts.py:37 msgid "List Entries Shortcuts" msgstr "" #: tryton/gui/window/shortcuts.py:38 msgid "Create new line" msgstr "" #: tryton/gui/window/shortcuts.py:39 msgid "Open relation" msgstr "" #: tryton/gui/window/shortcuts.py:40 msgid "Mark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:41 msgid "Unmark line for deletion" msgstr "" #: tryton/gui/window/shortcuts.py:44 msgid "Edition Widgets" msgstr "" #: tryton/gui/window/shortcuts.py:47 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:48 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:49 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:50 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:51 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:52 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:53 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:54 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:58 tryton/gui/window/shortcuts.py:59 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:60 tryton/gui/window/shortcuts.py:61 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:63 tryton/gui/window/shortcuts.py:64 #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:67 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:68 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:70 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:71 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:72 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:73 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:41 msgid "_Switch View" msgstr "" #: tryton/gui/window/tabcontent.py:42 msgid "Switch View" msgstr "" #: tryton/gui/window/tabcontent.py:47 msgid "_Previous" msgstr "" #: tryton/gui/window/tabcontent.py:48 msgid "Previous Record" msgstr "" #: tryton/gui/window/tabcontent.py:53 msgid "_Next" msgstr "" #: tryton/gui/window/tabcontent.py:54 msgid "Next Record" msgstr "" #: tryton/gui/window/tabcontent.py:59 msgid "_Search" msgstr "" #: tryton/gui/window/tabcontent.py:65 msgid "_New" msgstr "" #: tryton/gui/window/tabcontent.py:66 msgid "Create a new record" msgstr "" #: tryton/gui/window/tabcontent.py:71 tryton/gui/window/win_form.py:72 msgid "_Save" msgstr "" #: tryton/gui/window/tabcontent.py:72 msgid "Save this record" msgstr "" #: tryton/gui/window/tabcontent.py:77 msgid "_Reload/Undo" msgstr "" #: tryton/gui/window/tabcontent.py:78 msgid "Reload/Undo" msgstr "" #: tryton/gui/window/tabcontent.py:83 msgid "_Duplicate" msgstr "" #: tryton/gui/window/tabcontent.py:88 msgid "_Delete..." msgstr "" #: tryton/gui/window/tabcontent.py:94 msgid "View _Logs..." msgstr "" #: tryton/gui/window/tabcontent.py:97 msgid "Show revisions..." msgstr "" #: tryton/gui/window/tabcontent.py:102 msgid "A_ttachments..." msgstr "" #: tryton/gui/window/tabcontent.py:103 msgid "Add an attachment to the record" msgstr "" #: tryton/gui/window/tabcontent.py:108 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:109 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:114 msgid "_Actions..." msgstr "" #: tryton/gui/window/tabcontent.py:119 msgid "_Relate..." msgstr "" #: tryton/gui/window/tabcontent.py:125 msgid "_Report..." msgstr "" #: tryton/gui/window/tabcontent.py:130 msgid "_E-Mail..." msgstr "" #: tryton/gui/window/tabcontent.py:135 msgid "_Print..." msgstr "" #: tryton/gui/window/tabcontent.py:141 msgid "_Export Data..." msgstr "" #: tryton/gui/window/tabcontent.py:146 msgid "_Import Data..." msgstr "" #: tryton/gui/window/tabcontent.py:150 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:156 msgid "_Close Tab" msgstr "" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "" #: tryton/gui/window/win_csv.py:89 msgid "_Clear" msgstr "" #: tryton/gui/window/win_csv.py:111 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:130 msgid "CSV Parameters" msgstr "" #: tryton/gui/window/win_csv.py:138 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:152 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:161 msgid "Encoding:" msgstr "" #: tryton/gui/window/win_csv.py:197 tryton/gui/window/win_csv.py:201 msgid "Field name" msgstr "" #: tryton/gui/window/win_export.py:28 msgid "Export to CSV" msgstr "" #: tryton/gui/window/win_export.py:39 msgid "Predefined exports" msgstr "" #: tryton/gui/window/win_export.py:46 msgid "Name" msgstr "" #: tryton/gui/window/win_export.py:60 msgid "_Save Export" msgstr "" #: tryton/gui/window/win_export.py:70 msgid "_Delete Export" msgstr "" #: tryton/gui/window/win_export.py:87 msgid "Open" msgstr "" #: tryton/gui/window/win_export.py:88 msgid "Save" msgstr "" #: tryton/gui/window/win_export.py:92 msgid "Add _field names" msgstr "" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (string)" msgstr "" #: tryton/gui/window/win_export.py:109 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:111 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:210 msgid "What is the name of this export?" msgstr "" #: tryton/gui/window/win_export.py:216 #, python-format msgid "Override '%s' definition?" msgstr "" #: tryton/gui/window/win_export.py:333 #, python-format msgid "%d record saved." msgstr "" #: tryton/gui/window/win_export.py:335 #, python-format msgid "%d records saved." msgstr "" #: tryton/gui/window/win_export.py:338 #, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "" #: tryton/gui/window/win_form.py:131 msgid "Add" msgstr "" #: tryton/gui/window/win_form.py:144 msgid "Remove " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:159 msgid "Create a new record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:154 #: tryton/gui/window/win_form.py:171 msgid "Delete selected record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:164 #: tryton/gui/window/win_form.py:185 msgid "Undelete selected record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:61 #: tryton/gui/window/view_form/view/screen_container.py:225 #: tryton/gui/window/win_form.py:200 msgid "Previous" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:75 #: tryton/gui/window/view_form/view/screen_container.py:237 #: tryton/gui/window/win_form.py:214 msgid "Next" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:50 #: tryton/gui/window/win_form.py:227 msgid "Switch" msgstr "" #: tryton/gui/window/win_import.py:25 msgid "Import from CSV" msgstr "" #: tryton/gui/window/win_import.py:32 msgid "_Auto-Detect" msgstr "" #: tryton/gui/window/win_import.py:44 msgid "File to Import:" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:207 #: tryton/gui/window/view_form/view/list_gtk/widget.py:462 #: tryton/gui/window/win_import.py:46 msgid "Open..." msgstr "" #: tryton/gui/window/win_import.py:51 msgid "Lines to Skip:" msgstr "" #: tryton/gui/window/win_import.py:104 msgid "You must select an import file first." msgstr "" #: tryton/gui/window/win_import.py:114 msgid "Error opening CSV file" msgstr "" #: tryton/gui/window/win_import.py:142 #, python-format msgid "Error processing the file at field %s." msgstr "" #: tryton/gui/window/win_import.py:202 #, python-format msgid "%d record imported." msgstr "" #: tryton/gui/window/win_import.py:204 #, python-format msgid "%d records imported." msgstr "" #: tryton/gui/window/win_search.py:75 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:150 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:304 msgid "Wizard" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:197 msgid "ID" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:198 msgid "Creation User" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:199 msgid "Creation Date" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:200 msgid "Modification User" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:201 msgid "Modification Date" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:777 #, python-format msgid "Unable to get view tree state for %s" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:838 msgid "Unable to set view tree state" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1015 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1022 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1026 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1075 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:257 #: tryton/gui/window/view_form/view/form.py:259 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:483 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:485 #: tryton/gui/window/view_form/view/form_gtk/widget.py:155 #: tryton/gui/window/view_form/view/form_gtk/widget.py:157 #: tryton/gui/window/view_form/view/list.py:535 #: tryton/gui/window/view_form/view/list.py:537 msgid ":" msgstr "" #: tryton/gui/window/view_form/view/graph.py:100 msgid "Image Size" msgstr "" #: tryton/gui/window/view_form/view/graph.py:112 msgid "Width:" msgstr "" #: tryton/gui/window/view_form/view/graph.py:120 msgid "Height:" msgstr "" #: tryton/gui/window/view_form/view/graph.py:130 msgid "PNG image (*.png)" msgstr "" #: tryton/gui/window/view_form/view/graph.py:139 msgid "Save As" msgstr "" #: tryton/gui/window/view_form/view/graph.py:151 msgid "Image size too large." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:149 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:380 msgid "Remove this bookmark" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:387 msgid "Bookmark this filter" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:404 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:406 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:487 msgid "Bookmark Name:" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:607 msgid "Find" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:43 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:52 msgid "Clear" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:65 msgid "All files" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:88 msgid "Select" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/char.py:168 msgid "Show plain text" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:371 msgid "Add value" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:497 #, python-format msgid "Remove \"%s\"" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/image.py:49 msgid "Images" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:68 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:109 msgid "Add existing record" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:79 msgid "Remove selected record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:580 msgid "Open the record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:581 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:584 msgid "Search a record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:121 msgid "Remove selected record" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:144 msgid "Edit selected record " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:900 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:87 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:326 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:126 msgid "Translation" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:192 msgid "Edit" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:197 msgid "Fuzzy" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:274 msgid "You need to save the record before adding translations." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "No other language available." msgstr "" #: tryton/plugins/translation/__init__.py:23 msgid "Translate view" msgstr "" tryton-5.0.17/tryton/data/locale/de/0000755000175000017500000000000013571264253016562 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/de/LC_MESSAGES/0000755000175000017500000000000013571264253020347 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/de/LC_MESSAGES/tryton.po0000644000175000017500000011224613463252532022251 0ustar cedced00000000000000# German (Germany) translations for tryton. # Copyright (C) 2008-2014 MBSolutions # This file is distributed under the same license as the tryton project. # Udo Spallek , 2008. # Mathias Behrle , 2008-2014. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "Alternative Konfigurationsdatei angeben" #: tryton/config.py:77 msgid "development mode" msgstr "Entwicklungsmodus" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Allgemeiner Log-Level: INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "Loglevel angeben: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Anmeldename angeben" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "Name des Servers:Ports angeben" #: tryton/config.py:127 #, python-format, python-format, python-format, python-format msgid "Unable to write config file %s." msgstr "Kann Konfigurationsdatei '%s' nicht schreiben." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Kann locale %s nicht setzen." #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr ", " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "%s (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Aktion wählen" #: tryton/action/main.py:193 msgid "No action defined." msgstr "Keine Aktion definiert." #: tryton/common/button.py:54 msgid "By: " msgstr "Von: " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Auswahl" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 msgid "Cancel" msgstr "Abbrechen" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "OK" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Ihre Auswahl:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "Auswählen" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Speichern" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Speichern unter..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Diese Warnung künftig nicht mehr anzeigen." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Fortfahren?" #: tryton/common/common.py:643 msgid "No" msgstr "Nein" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "Ja" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Aktualisierungskonflikt" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" "Dieser Datensatz wurde anderweitig geändert, während Sie ihn bearbeitet " "haben." #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "Speichern abbrechen" #: tryton/common/common.py:696 msgid "Compare" msgstr "Vergleichen" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "Die geänderte Version ansehen" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Überschreiben" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "Ihre aktuelle Version speichern" #: tryton/common/common.py:729 msgid "Application Error" msgstr "Anwendungsfehler" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Fehler melden" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "Schließen" #: tryton/common/common.py:751 msgid "Error: " msgstr "Fehler:" #: tryton/common/common.py:768 #, python-format, python-format msgid "To report bugs you must have an account on %s" msgstr "Um Fehler online melden zu können, benötigen Sie ein Konto auf %s" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Fehler melden" #: tryton/common/common.py:811 msgid "User:" msgstr "Anmeldename:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Passwort:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Derselbe Fehlerbericht wurde bereits von einem anderen Benutzer gemeldet.\n" "Zu Ihrer Information wurde Ihr Benutzername auf der Interessentenliste eingetragen." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Neuer Fehlerbericht angelegt mit ID " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Verbindungsfehler.\n" "Anmeldename oder Passwort fehlerhaft." #: tryton/common/common.py:899 msgid "Exception:" msgstr "Ausnahme:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "Überprüfung der URL: %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "Es war nicht möglich nach einer neuen Version zu suchen" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "Eine neue Version ist verfügbar!" #: tryton/common/common.py:942 msgid "Download" msgstr "Herunterladen" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "Suche..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Erstelle..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "Unmöglich nach einer Vervollständigungn von %s zu suchen" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Wert" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Angezeigter Wert" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Format" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Angezeigtes Format" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Kalender öffnen" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Datumsformat" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Angezeigtes Datumsformat" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "J" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Wahr" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "w" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Falsch" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Bearbeiten..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Anhänge..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "Notizen..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Aktionen..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Beziehungen..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Berichte..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "E-Mail..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Drucken..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "J" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "W" #: tryton/common/timedelta.py:29 msgid "d" msgstr "t" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 msgid "Preferences..." msgstr "Einstellungen..." #: tryton/gui/main.py:127 msgid "Toolbar" msgstr "Werkzeugleiste" #: tryton/gui/main.py:128 msgid "Default" msgstr "Standard" #: tryton/gui/main.py:129 msgid "Text and Icons" msgstr "Text und Symbole" #: tryton/gui/main.py:130 msgid "Text" msgstr "Text" #: tryton/gui/main.py:131 msgid "Icons" msgstr "Symbole" #: tryton/gui/main.py:134 msgid "Form" msgstr "Formular" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Breite/Höhe speichern" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Menüansicht speichern" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "Schneller Feldwechsel mit Tabulatortaste" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Rechtschreibkorrektur" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "PDA Modus" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Suchlimitierung..." #: tryton/gui/main.py:142 msgid "Email..." msgstr "E-Mail..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "Nach neuer Version suchen" #: tryton/gui/main.py:145 msgid "Options" msgstr "Einstellungen" #: tryton/gui/main.py:148 msgid "Keyboard Shortcuts..." msgstr "Schnelltasten..." #: tryton/gui/main.py:149 msgid "About..." msgstr "Über..." #: tryton/gui/main.py:150 msgid "Help" msgstr "Hilfe" #: tryton/gui/main.py:153 msgid "Quit" msgstr "Beenden" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Kein Ergebnis." #: tryton/gui/main.py:447 msgid "Favorites" msgstr "Favoriten" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "Verwalten..." #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Aktion" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "Die folgende Aktion erfordert die Schließung aller Registerkarten.\n" "Fortfahren?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Registerkarte schließen" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "Modularität, Skalierbarkeit und Sicherheit" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" "Mathias Behrle\n" "Clemens Hupka\n" "Korbinian Preisler\n" "Udo Spallek" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, python-format, python-format msgid "Attachments (%s)" msgstr "Anhänge (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Profilbearbeitung" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "Neues Profil hinzufügen" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "Ausgewähltes Profil löschen" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Host:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Datenbank:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Datenbankliste wird abgefragt..." #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Anmeldename:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Inkompatible Serverversion" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Kann nicht zum Server verbinden!" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Anmeldung" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Abbrechen" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "Abbrechen" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "_Verbinden" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Verbindung zum Tryton Server herstellen" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Host-/Datenbankdetails" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Anmeldename:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "E-Mail" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "Einstellungen E-Mail" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Kommandozeile:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Legende der verfügbaren Platzhalter:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "An:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Betreff:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Textkörper:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Anhang:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "Hinzufügen..." #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Anhänge(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "Notiz(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "Ein Datensatz muss ausgewählt werden." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Erstellt von" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Erstellt am" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Zuletzt verändert von" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Zuletzt verändert am" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Modell:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Möchten Sie diesen Datensatz wirklich löschen?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Möchten Sie diese Datensätze wirklich löschen?" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "Die Datensätze wurden nicht gelöscht." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "Die Datensätze wurden gelöscht." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "Sie arbeiten nun an dem/den duplizierten Datensatz/Datensätzen." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "Der Datensatz wurde gespeichert." #: tryton/gui/window/form.py:485 msgid " of " msgstr " von " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Datensatz geändert.\n" "Soll der Datensatz gespeichert werden?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Aktion ausführen" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Beziehung" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Datensätze einer Beziehung öffnen" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Bericht" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Bericht öffnen" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-Mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Bericht per E-Mail senden" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Drucken" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Bericht drucken" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "URL kopieren" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "URL in Zwischenablage kopieren" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Unbekannt" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Limitierung" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Einstellung Suchlimitierung" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Limit:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "Notizen (%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Einstellungen" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Benutzereinstellungen bearbeiten" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Einstellung" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Bearbeitung" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Bearbeitung auswählen" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Bearbeitung:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Schnelltasten" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Schnelltasten für Texteinträge" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Ausgewählten Text ausschneiden" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "Ausgewählten Text kopieren" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Ausgewählten Text einfügen" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Nächstes Widget" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Vorheriges Widget" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Schnelltasten für Einträge in verknüpften Feldern" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Neue Beziehung erstellen" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Beziehung suchen/öffnen" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Schnelltasten für Einträge in Listenfelder" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Neue Zeile erstellen" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Beziehung öffnen" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Zeile zum Löschen markieren" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "Löschmarkierung für Zeile aufheben" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Widgets zur Bearbeitung" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "Cursor bewegen" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "Nach rechts bewegen" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "Nach links bewegen" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "Nach oben bewegen" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "Nach unten bewegen" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "Eine Seite nach oben bewegen" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "Eine Seite nach unten bewegen" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "An den Anfang bewegen" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "Zum Ende bewegen" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "Zum übergeordneten Datensatz bewegen" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "Alle auswählen" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "Auswahl aufheben" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "Übergeordneten Datensatz auswählen" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "Aktuelle Zeile auswählen/aktivieren" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "Auswahl umkehren" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "Ausklappen/Einklappen" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "Zeile ausklappen" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "Zeile einklappen" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "Auswahl für Zeile umkehren" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "Alle Zeilen einklappen" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "Alle Zeilen ausklappen" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "Baumansicht" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_Ansicht wechseln" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "Ansicht wechseln" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Vorheriger" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Vorheriger Datensatz" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Nächster" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Nächster Datensatz" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Suche" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Neu" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Neuen Datensatz erstellen" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Speichern" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Diesen Datensatz speichern" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Neu laden/_Rückgängig" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "Neu laden/Rückgängig" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_Duplizieren" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Löschen..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "_Protokoll ansehen..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Bearbeitungen anzeigen..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "A_nhänge..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Einen Anhang zum Datensatz hinzufügen" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_Notizen..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "Eine Notiz zu einem Datensatz hinzufügen" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Aktion ausführen..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_Beziehung öffnen..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_Bericht öffnen..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_Bericht per E-Mail..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Bericht drucken..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Daten _exportieren..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Daten _importieren..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "_URL kopieren..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Registerkarte schließen" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "Alle Felder" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Hinzufügen" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Entfernen" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_Leeren" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "Ausgewählte Felder" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV Parameter" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "Feldtrenner:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "Anführungszeichen:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Kodierung:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Feldname" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "CSV-Export: %s" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "Exportkonfiguration _speichern" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "Exportkonfiguration _löschen" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Vordefinierte Exporte" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Name" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Öffnen" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Feldnamen _hinzufügen" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (string)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "%s (Bezeichnung des Modells)" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "%s (Bezeichnung des Datensatzes)" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Wie soll der Name des Exports lauten?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "Definition von '%s' nicht berücksichtigen?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, python-format, python-format msgid "%d record saved." msgstr "%d Datensatz gespeichert." #: tryton/gui/window/win_export.py:330 #, python-format, python-format, python-format, python-format msgid "%d records saved." msgstr "%d Datensätze gespeichert." #: tryton/gui/window/win_export.py:333 #, python-format, python-format, python-format, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Operation fehlgeschlagen.\n" "Fehlermeldung:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Fehler" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Verknüpfung" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Löschen" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Neu" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Ansicht wechseln" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Vorheriger" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Nächster" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Hinzufügen" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Entfernen " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Neuen Datensatz erstellen " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Ausgewählte Datensätze löschen " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Löschung der ausgewählten Datensätze rückgängig machen " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "CSV-Import: %s" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_Automatische Erkennung" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Importdatei:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Öffnen..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Zu überspringende Zeilen:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "Zuerst muss eine Importdatei ausgewählt werden." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Fehler beim Öffnen der CSV-Datei" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Fehler bei der Verarbeitung der Datei in Feld %s." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, python-format, python-format msgid "%d record imported." msgstr "%d Datensatz importiert." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, python-format, python-format msgid "%d records imported." msgstr "%d Datensätze importiert." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Suchen" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "Suche %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "Der Assistent %s kann nicht gelöscht werden." #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Wizard" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Erstellt von" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Erstellt am" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Zuletzt verändert von" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Zuletzt verändert am" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, python-format, python-format msgid "Unable to get view tree state for %s" msgstr "Unmöglich den Status für die Baumansicht von %s zu holen." #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "Kann Sicht für den Menübaum nicht anwenden." #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "\"%s\" liegt nicht im gültigen Wertebereich (Domain)." #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "In Feld \"%s\" ist ein Eintrag erforderlich." #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "Die Werte von \"%s\" sind ungültig." #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "Vorvalidierung" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Bildgröße" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Breite:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Höhe:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG Bild (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Speichern unter..." #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "Bild ist zu groß." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "Filter öffnen" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Filterlesezeichen anzeigen" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Dieses Lesezeichen entfernen" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "Diesen Filter als Lesezeichen hinzufügen" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "Aktive Datensätze anzeigen" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "Inaktive Datensätze anzeigen" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Lesezeichenname:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Suchen" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Heute" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "Vorwärts bewegen" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "Rückwärts bewegen" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "Vorheriges Jahr" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "Nächstes Jahr" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Wochenansicht" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Monatsansicht" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Woche" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "Auswählen..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Leeren" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Alle Dateien" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Klartext anzeigen" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Wert hinzufügen" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "\"%s\" entfernen" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Bilder" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Bestehenden Datensatz hinzufügen" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Ausgewählten Datensatz löschen " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "Datensatz öffnen " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "Feld löschen " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Datensatz suchen " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "Ausgewählten Datensatz löschen " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "Ausgewählten Datensatz bearbeiten " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "Vordergrund" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "Eine Farbe auswählen" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Übersetzung" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Bearbeiten" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Unscharf" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "" "Der Datensatz muss gespeichert werden, bevor eine Übersetzung hinzugefügt " "werden kann." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "Keine weiteren Sprachen verfügbar." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Aktuelle Sicht übersetzen" tryton-5.0.17/tryton/data/locale/de/LC_MESSAGES/tryton.mo0000644000175000017500000004500313571264251022243 0ustar cedced00000000000000` )"L]q 7HYu   #-I#[%  .=LU&\      $+>j  ,: IWf x   " 0:?Uow &  )9 ? LV ny  "2E[u ! %7 I T `j        : K T _ h k p }     # !!6!?! Q![!m! |! !!!!!! !!!!!" " "&";"L" S"]" x" " """""" # ## ##-#2# :#E#U#g#x## ####### $ $ *$8$ K$U$ q${$$$$$$$$ % %%(%I7%}% %5 &8V&-&&& &&&& & '''5'$P'%u'''''(( 1( >(I( O(Y( _(m( r( |((((( ((((%)7,)d) t)) ))) ) )) ) ) )))* * * * %* /* :*G* O*Z* `*m* u**** ** **$* * * + +<*+g+ ~++++++F-4L-*-----.. ;. \.h.m.p.u.x.|.~.....!. //$/ +/ 7/C/)Z/&/!//// 0+0?00P010 00 0 0 00)1 *181>1B1Q1 `1 n1 y1 111111 112,2=2 L2X2'p282223 3>3X3w33$3 3 3 3 33 4 '444=4(F4 o4|444 4 444 4 4 5'*5 R5`5x55 5 55!5156 66-6>6T6([6 6 66 66 6666666777"7 *767I7P7 k7y7777%7 778 8,*8 W8a8 c8p8888 88889!9%49Z9n99999 99999#:,: ;: E: R:]:`:h:#w::::: ::+ ; 5;+C; o;y; ;;; ; ;; ;; <<%< 5<@<G<Y<a<i< }<'<!< <<4=6=M=\=m='='=== > > > &> 3>=>P>c>z>>>>>>> ?!? @?K?a?x?$?? ?$???@.@L@^@x@@@@@ @@O@@A"A;BP=BCBBBBB CC 3C @CLC8QC-C;C:C/D-LD.zDCD D$DE -E :E GETEYEoE uE%EEE@EEF F& F04FXeF FF FF GGG 3G@G ^G kGxGGGG G G GGG H %H0H DHOHnHuHHHHHHHH+H II,I'.I7VIIII;IIJ of "%s" is not valid according to its domain"%s" is required%d record imported.%d record saved.%d records imported.%d records saved.%s (%s)%s (model name)%s (record name)%s (string)%s%%, ,….....:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...About...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Application ErrorAre you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancelCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDefaultDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEmail...Encoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFavoritesFetching databases listField nameFile to Import:FindForegroundFormFormatFuzzyHeight:HelpHost / Database informationHost:IDID:IconsImage SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsKeyboard Shortcuts...Latest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOptionsOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreferences...PreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewTextText Entries ShortcutsText and IconsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To report bugs you must have an account on %sTo:TodayToggle rowToggle selectionToolbarTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: de Language-Team: de Plural-Forms: nplurals=2; plural=(n != 1) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 von "%s" liegt nicht im gültigen Wertebereich (Domain).In Feld "%s" ist ein Eintrag erforderlich.%d Datensatz importiert.%d Datensatz gespeichert.%d Datensätze importiert.%d Datensätze gespeichert.%s (%s)%s (Bezeichnung des Modells)%s (Bezeichnung des Datensatzes)%s (string)%s%%, ,….....:Alle FelderAusgewählte FelderVordefinierte ExporteErstelle...Suche...Eine neue Version ist verfügbar!A_nhänge...Über...AktionAktionen...HinzufügenFeldnamen _hinzufügenEine Notiz zu einem Datensatz hinzufügenEinen Anhang zum Datensatz hinzufügenBestehenden Datensatz hinzufügenNeues Profil hinzufügenWert hinzufügenHinzufügen...Alle DateienDiese Warnung künftig nicht mehr anzeigen.AnwendungsfehlerMöchten Sie diesen Datensatz wirklich löschen?Möchten Sie diese Datensätze wirklich löschen?Anhänge(%d)Anhang:Anhänge (%s)Anhänge...Textkörper:Lesezeichenname:Diesen Filter als Lesezeichen hinzufügenFehler meldenVon: CC:CSV-Export: %sCSV-Import: %sCSV Parameter_VerbindenAbbrechenAbbrechenSpeichern abbrechenÜberprüfung der URL: %sNach neuer Version suchenLeerenFeld löschen SchließenRegisterkarte schließenAlle Zeilen einklappenZeile einklappenKommandozeile:VergleichenAktualisierungskonfliktVerbindung zum Tryton Server herstellenVerbindungsfehler. Anmeldename oder Passwort fehlerhaft.URL in Zwischenablage kopieren_URL kopieren...Ausgewählten Text kopierenKann nicht zum Server verbinden!Neuen Datensatz erstellenNeuen Datensatz erstellen Neue Zeile erstellenNeue Beziehung erstellenNeuer Fehlerbericht angelegt mit ID Erstellt amErstellt amErstellt vonErstellt vonAusgewählten Text ausschneidenDatenbank:DatumsformatStandardLöschenAusgewählte Datensätze löschen Feldtrenner:Angezeigtes FormatAngezeigtes DatumsformatAngezeigter WertFortfahren?HerunterladenE-MailBericht per E-Mail sendenE-Mail...BearbeitenBenutzereinstellungen bearbeitenAusgewählten Datensatz bearbeiten Bearbeiten...Widgets zur BearbeitungE-MailEinstellungen E-MailE-Mail...Kodierung:FehlerFehler beim Öffnen der CSV-DateiFehler bei der Verarbeitung der Datei in Feld %s.Fehler:Ausnahme:Alle Zeilen ausklappenZeile ausklappenAusklappen/EinklappenFalschSchneller Feldwechsel mit TabulatortasteFavoritenDatenbankliste wird abgefragt...FeldnameImportdatei:SuchenVordergrundFormularFormatUnscharfHöhe:HilfeHost-/DatenbankdetailsHost:IDID:SymboleBildgrößeBild ist zu groß.BilderInkompatible ServerversionSchnelltastenSchnelltasten...Zuletzt verändert amZuletzt verändert vonAktion ausführenLegende der verfügbaren Platzhalter:LimitierungLimit:Zu überspringende Zeilen:VerknüpfungSchnelltasten für Einträge in ListenfelderAnmeldungMVerwalten...Zeile zum Löschen markierenModell:Zuletzt verändert amZuletzt verändert vonMonatsansichtCursor bewegenNach unten bewegenEine Seite nach unten bewegenZum Ende bewegenNach links bewegenZum übergeordneten Datensatz bewegenNach rechts bewegenAn den Anfang bewegenNach oben bewegenEine Seite nach oben bewegenNameNeuNächsterNächster DatensatzNächstes WidgetNeinKeine Aktion definiert.Keine weiteren Sprachen verfügbar.Kein Ergebnis.Notiz(%d)Notizen (%s)Notizen...OKÖffnenFilter öffnenDatensätze einer Beziehung öffnenBeziehung öffnenBericht öffnenKalender öffnenDatensatz öffnen Öffnen...Beziehung suchen/öffnenOperation fehlgeschlagen. Fehlermeldung: %sEinstellungenDefinition von '%s' nicht berücksichtigen?PDA ModusPNG Bild (*.png)Passwort:Ausgewählten Text einfügenVorvalidierungEinstellungEinstellungenEinstellungen...VorherigerVorheriger DatensatzVorheriges WidgetDruckenBericht druckenDrucken...ProfilProfilbearbeitungProfil:BeendenAnführungszeichen:Der Datensatz wurde gespeichert.Die Datensätze wurden nicht gelöscht.Die Datensätze wurden gelöscht.BeziehungBeziehungen...Schnelltasten für Einträge in verknüpften FeldernNeu laden/Rückgängig"%s" entfernenEntfernen Ausgewähltes Profil löschenAusgewählten Datensatz löschen Ausgewählten Datensatz löschen Dieses Lesezeichen entfernenBerichtFehler meldenBerichte...BearbeitungBearbeitung:SpeichernSpeichern unter...Speichern unter...Menüansicht speichernBreite/Höhe speichernDiesen Datensatz speichernIhre aktuelle Version speichernSuchenSuche %sEinstellung SuchlimitierungSuchlimitierung...Datensatz suchen Die geänderte Version ansehenAuswählenEine Farbe auswählenBearbeitung auswählenAlle auswählenÜbergeordneten Datensatz auswählenAktion wählenAuswählen...Aktuelle Zeile auswählen/aktivierenAuswahlAktive Datensätze anzeigenFilterlesezeichen anzeigenInaktive Datensätze anzeigenKlartext anzeigenBearbeitungen anzeigen...RechtschreibkorrekturBetreff:Ansicht wechselnAnsicht wechselnTextSchnelltasten für TexteinträgeText und SymboleDie folgende Aktion erfordert die Schließung aller Registerkarten. Fortfahren?Derselbe Fehlerbericht wurde bereits von einem anderen Benutzer gemeldet. Zu Ihrer Information wurde Ihr Benutzername auf der Interessentenliste eingetragen.Die Werte von "%s" sind ungültig.Datensatz geändert. Soll der Datensatz gespeichert werden?Dieser Datensatz wurde anderweitig geändert, während Sie ihn bearbeitet haben.Um Fehler online melden zu können, benötigen Sie ein Konto auf %sAn:HeuteAuswahl für Zeile umkehrenAuswahl umkehrenWerkzeugleisteAktuelle Sicht übersetzenÜbersetzungBaumansichtWahrEs war nicht möglich nach einer neuen Version zu suchenDer Assistent %s kann nicht gelöscht werden.Unmöglich den Status für die Baumansicht von %s zu holen.Unmöglich nach einer Vervollständigungn von %s zu suchenKann locale %s nicht setzen.Kann Sicht für den Menübaum nicht anwenden.Kann Konfigurationsdatei '%s' nicht schreiben.Löschung der ausgewählten Datensätze rückgängig machen UnbekanntLöschmarkierung für Zeile aufhebenAuswahl aufhebenAnmeldename:Anmeldename:Anmeldename:Wert_Protokoll ansehen...WocheWochenansichtWie soll der Name des Exports lauten?Breite:WizardSie arbeiten nun an dem/den duplizierten Datensatz/Datensätzen.ÜberschreibenJJaEin Datensatz muss ausgewählt werden.Zuerst muss eine Importdatei ausgewählt werden.Der Datensatz muss gespeichert werden, bevor eine Übersetzung hinzugefügt werden kann.Ihre Auswahl:_Aktion ausführen..._Hinzufügen_Automatische Erkennung_Abbrechen_LeerenRegisterkarte schließenURL kopierenExportkonfiguration _löschen_Löschen..._Duplizieren_Bericht per E-Mail...Daten _exportieren...Daten _importieren..._Neu_Nächster_Notizen..._Vorheriger_Bericht drucken..._Beziehung öffnen...Neu laden/_Rückgängig_Entfernen_Bericht öffnen..._SpeichernExportkonfiguration _speichern_Suche_Ansicht wechselntEntwicklungsmodusVorwärts bewegenRückwärts bewegenhAllgemeiner Log-Level: INFOmModularität, Skalierbarkeit und SicherheitNächstes JahrVorheriges JahrsAlternative Konfigurationsdatei angebenLoglevel angeben: DEBUG, INFO, WARNING, ERROR, CRITICALAnmeldename angebenName des Servers:Ports angebenwMathias Behrle Clemens Hupka Korbinian Preisler Udo SpallekWJtryton-5.0.17/tryton/data/locale/fa/0000755000175000017500000000000013571264253016560 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/fa/LC_MESSAGES/0000755000175000017500000000000013571264253020345 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/fa/LC_MESSAGES/tryton.po0000644000175000017500000011541713463252532022252 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2018 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2018. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "فایل پیکربندی جایگزین را مشخص کنید" #: tryton/config.py:77 msgid "development mode" msgstr "حالت پیشرفته" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "گزارشگیری همه چیز در سطح اطلاعات" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "تعیین سطح گزارش : اشکال زدایی، اطلاعات، هشدار، خطا، بحرانی" #: tryton/config.py:85 msgid "specify the login user" msgstr "تعیین ورود به سیستم کاربر" #: tryton/config.py:87 msgid "specify the server hostname:port" msgstr "تعیین نام میزبان سرور : درگاه" #: tryton/config.py:127 #, python-format msgid "Unable to write config file %s." msgstr "قادر به نوشتن در فایل پیکربندی \"%s\" نیست." #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "قادر به تنظیم محلی: \"%s\" نیست" #: tryton/action/main.py:89 tryton/common/button.py:54 msgid ", " msgstr "، " #: tryton/action/main.py:91 msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "\"%s\" (%s)" #: tryton/action/main.py:187 msgid "Select your action" msgstr "انتخاب اقدام شما" #: tryton/action/main.py:193 msgid "No action defined." msgstr "اقدامی تعریف نشده." #: tryton/common/button.py:54 msgid "By: " msgstr "توسط : " #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "انتخاب" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_انصراف" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "انتخاب شما:" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "انتخاب" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "ذخیره" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "ذخیره با نام..." #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "همیشه این هشدار را نادیده بگیر." #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "آیا می خواهید پردازش شود؟" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "بله" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "همزمانی استثنا" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "مقایسه" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "نوشتن بهرحال" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "خطای برنامه." #: tryton/common/common.py:732 msgid "Report Bug" msgstr "گزارش اشکال(باگ)" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "خطا: " #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "برای گزارش اشکالات باید یک حساب کاربری داشته باشید در \"%s\" " #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "ردیابی اشکال(باگ)" #: tryton/common/common.py:811 msgid "User:" msgstr "کاربر:" #: tryton/common/common.py:819 msgid "Password:" msgstr "کلمه عبور:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "همین اشکال قبلا توسط کاربر دیگری گزارش شده است.\n" "برای نگهداری اطلاعات شما نام کاربریتان به ناز-لیست این شماره افزوده می شود" #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "اشکال(باگ) جدید با شناسه ایجاد شد " #: tryton/common/common.py:894 msgid "" "Connection error.\n" "Bad username or password." msgstr "" "خطای اتصال.\n" " نام کاربری یا کلمه عبور اشتباه." #: tryton/common/common.py:899 msgid "Exception:" msgstr "اعتراض:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "بررسی URL : %s" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "قادر به بررسی نسخه جدید نیست" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "نسخه جدید در دسترس است!" #: tryton/common/common.py:942 msgid "Download" msgstr "دانلود" #: tryton/common/common.py:1323 msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "جستجو..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "ایجاد..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "قادر به جستجو برای تکمیل : \"%s\" نیست" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "مقدار" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "مقدار نمایش داده شده" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "قالب" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "فرمت نمایش" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "بازکردن تقویم" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "فرمت تاریخ" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "فرمت تاریخ تمایش داده شده" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "y" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "درست" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "t" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "غلط" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "ویرایش..." #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "پیوست ها..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "یادداشت ها..." #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "اقدامات..." #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "مرتبط..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "گزارش..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "ایمیل..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "چاپ..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "Y" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "w" #: tryton/common/timedelta.py:29 msgid "d" msgstr "d" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_ظاهر برنامه..." #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_نوارابزار" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_پیش فرض" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "_متن و آیکون ها" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_متن" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "_آیکون ها" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "_فرم" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "ذخیره عرض/ارتفاع" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "ذخیره حالت درختی" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "برگه کردن سریع" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "غلط ‌یاب املایی" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "جستجو محدود..." #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "_ایمیل..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "بررسی نسخه" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_گزینه‌ها" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_میانبرهای صفحه کلید..." #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "_درباره..." #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_راهنما" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "نتیجه ای پیدا نشد." #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "_علاقمندی ها" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "اقدام" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "اقدام زیر نیاز به بستن همه برگه ها دارد.\n" "می خواهید ادامه دهید؟" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "بستن برگه" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "مدولاربودن، مقیاس پذیری و امنیت" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "پرویز همایون نژاد" #: tryton/gui/window/attachment.py:24 #, python-format msgid "Attachments (%s)" msgstr "پیوستها (%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "ویرایشگر پروفایل" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "پروفایل" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "هاست:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "پایگاه داده:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "وارد کردن فهرست های پایگاه داده" #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "نام کاربری:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "نسخه ناسازگار سرور" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "نمی تواند به سرور متصل شود" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "ورود به سیستم" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_انصراف" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "لغو اتصال به سرور تریتون" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "_ارتباط" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "اتصال سرور تریتون" #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "پروفایل:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "اطلاعات میزبان / پایگاه داده" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "نام کاربر:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "ایمیل" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "تنظیمات برنامه ایمیل" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "خط فرمان:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "مشروح متغیرهای موجود:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "به:" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "موضوع :" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "بدنه:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "پیوست:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "پیوست(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "یاداشت(%d)" #: tryton/gui/window/form.py:207 msgid "You have to select one record." msgstr "شما باید یک پرونده را انتخاب کنید." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "شناسه:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "ایجاد کاربر:" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "تاريخ ايجاد:" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "آخرین تغییرات بوسیله:" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "تاریخ آخرین تغییرات:" #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "مدل:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "برای حذف این پرونده اطمینان کامل دارید؟" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "برای حذف این پرونده ها اطمینان کامل دارید؟" #: tryton/gui/window/form.py:317 msgid "Records not removed." msgstr "پرونده ها حذف نشدند." #: tryton/gui/window/form.py:319 msgid "Records removed." msgstr "پرونده ها حذف شدند." #: tryton/gui/window/form.py:356 msgid "Working now on the duplicated record(s)." msgstr "هم اکنون کار بر روی پرونده(ها) تکثیر شده انجام می شود." #: tryton/gui/window/form.py:368 msgid "Record saved." msgstr "پرونده ذخیره شد." #: tryton/gui/window/form.py:485 msgid " of " msgstr " از " #: tryton/gui/window/form.py:505 msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "این پرونده هنوز اصلاح نشده است.\n" "می‌خواهید آن را ذخیره کنید ؟" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "انجام اقدام" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "مرتبط" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "بازکردن پرونده های مرتبط" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "گزارش" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "باز کردن گزارش" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "ایمیل" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "گزارش ایمیل" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "چاپ" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "چاپ گزارش" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "_رونوشت URL" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "کپی URL درون کلیپبورد" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "نامعلوم" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "محدود" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "تنظیمات جستجو محدود" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "محدودیت:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "یادداشت ها(%s)" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "ظاهر برنامه" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "ویرایش ظاهر برنامه کاربر" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "ظاهر" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "تجدید نظر" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "انتخاب یک تجدید نظر" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "تجدید نظر:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "میانبرهای صفحه کلید" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "نوشته های متنی میانبر" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "برش متن انتخابی" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "کپی متن انتخابی" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "چسباندن متن کپی شده" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "ویجت بعدی" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "ویجت قبلی" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "رابطه ها کلید های میانبر" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "ایجاد رابطه جدید" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "بازکردن / ارتباط جستجو" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "فهرست محتوای میانبرهای" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "ایجاد سطر جدید" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "بازکردن رابطه" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "برای حذف سطر را علامتگذاری کنید" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "برای حذف علامت سطر را بردارید" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "ویرایش ویجت ها" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "حرکت مکان نما" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "حرکت به راست" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "حرکت به چپ" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "حرکت به بالا" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "حرکت به پایین" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "حرکت به بالای یک صفحه" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "حرکت به پایین یک صفحه" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "حرکت به بالا" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "حرکت به انتها" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "انتقال به منبع" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "انتخاب همه" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "انتخاب نکردن همه" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "انتخاب منبع" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "انتخاب/فعال کردن ردیف جاری" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "انتخاب زنجیر" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "گشودن - بستن" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "گسترش ردیف" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "بستن ردیف" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "زنجیر ردیف" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "بستن همه ردیف ها" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "گشودن همه ردیف ها" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "نمایش درختی" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "_تعویض نمایه" #: tryton/gui/window/tabcontent.py:44 msgid "Switch View" msgstr "تعویض نمایه" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_قبلی" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "پرونده قبلی" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_بعدی" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "پرونده بعدی" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_جستجو" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_جدید" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "ایجاد پرونده جدید" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_ذخیره" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "ذخیره این پرونده" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "_بارگیری مجدد / واگرد" #: tryton/gui/window/tabcontent.py:80 msgid "Reload/Undo" msgstr "بارگیری مجدد / واگرد" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "_تکثیر" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_حذف..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "_مشاهده گزارشات..." #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "مشاهده تجدیدنظرها..." #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "_پیوست..." #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "پیوست را به پرونده اضافه کنید" #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "_یادداشت ها..." #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "یک یادداشت به پرونده اضافه کنید" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_اقدامات..." #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "_مرتبط..." #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "_گزارش..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "_ایمیل..." #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_چاپ..." #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "_صادرات داده ها..." #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "_واردات داده ها..." #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "_رونوشت URL..." #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "_بستن برگه" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "همه فیلد ها" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_افزودن" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_حذف" #: tryton/gui/window/win_csv.py:85 msgid "_Clear" msgstr "_پاکسازی" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "فیلد های انتخابی" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "مولفه های CSV" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "جدا کننده:" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "کاراکترنقل قول:" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "رمزگذاری:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "نام فیلد" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 msgid "_Save Export" msgstr "_ذخیره استخراج" #: tryton/gui/window/win_export.py:40 msgid "_Delete Export" msgstr "_حذف استخراج" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "استخراج از پیش تعریف شده" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "نام" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "باز کردن" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "_اضافه کردن نام فیلدها" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "متنی %s" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "نام مدل %s" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "نام پرونده %s" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "نام این فایل استخراجی چیست؟" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "بازنویسی %s تعاریف؟" #: tryton/gui/window/win_export.py:328 #, python-format msgid "%d record saved." msgstr "%d پرونده ذخیره شد." #: tryton/gui/window/win_export.py:330 #, python-format msgid "%d records saved." msgstr "%d پرونده های ذخیره شده." #: tryton/gui/window/win_export.py:333 #, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "عملیات ناموفق بود.\n" "پیام خطا:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "خطا" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "پیوند" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 #, fuzzy msgid "New" msgstr "_جدید" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "تعویض" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "قبلی" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "بعدی" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "افزودن" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "حذف " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "ایجاد یک پرونده جدید " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "حذف پرونده انتخابی " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "بازگردانی فایل انتخابی " #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 msgid "_Auto-Detect" msgstr "_شناسایی - خودکار" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "فایل برای واردکردن:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "باز کردن..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "چشم پوشی از سطرهای:" #: tryton/gui/window/win_import.py:101 msgid "You must select an import file first." msgstr "شما باید ابتدا فایل ورودی را انتخاب کنید." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "خطا در بازگشایی فایل CSV" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "خطای پردازش فایل واقع در فیلد : \"%s\"." #: tryton/gui/window/win_import.py:198 #, python-format msgid "%d record imported." msgstr "%d پرونده وارد شد." #: tryton/gui/window/win_import.py:200 #, python-format msgid "%d records imported." msgstr "%d پرونده ها وارد شدند." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "جستجو" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "جستجو %s" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "قادر به حذف دستیار \"%s\" نیست" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "دستیار" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "شناسه" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "ایجاد کاربر" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "تاریخ ایجاد" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "کاربر اصلاح کننده" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "تاریخ اصلاح" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format msgid "Unable to get view tree state for %s" msgstr "قادربه دریافت حالت نمایش درختی نیست برای %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "قادر به تنظیم حالت نمایش درختی نیست" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "با توجه به دامنه : \"%s\" معتبر نیست" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "\"%s\" مورد نیاز است" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "مقادیر \"%s\" معتبر نیستند" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "پیش-اعتبارسنجی" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "اندازه تصویر" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "عرض:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "ارتفاع:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG image (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "ذخیره با نام" #: tryton/gui/window/view_form/view/graph.py:161 msgid "Image size too large." msgstr "اندازه تصویر بیش از حد بزرگ است." #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "بازکردن فیلترها" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "نمایش بوک مارک های فیلترها" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "حذف این بوک مارک" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "بوک مارک این فیلتر" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "نمایش پرونده های فعال" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "نمایش پرونده های غیرفعال" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "نام بوک مارک :" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "یافتن" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "امروز" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "بازگشت" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "برو جلو" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "سال قبل" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "سال بعد" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "نمایش هفته" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "نمایش ماه" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "هفته" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "انتخاب..." #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "پاک کردن" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "همه فایل ها" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "نمایش متن ساده" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "افزودن مقدار" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "حذف \"%s\"" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "تصاویر" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "افزودن پرونده موجود" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "حذف پرونده انتخابی " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 msgid "Open the record " msgstr "بازکردن پرونده " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "پاکسازی فیلد " #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "جستجوی یک پرونده " #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "حذف پرونده انتخابی" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "ویرایش پرونده انتخابی " #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "%s%%" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "پیش زمینه" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "انتخاب یک رنگ" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "ترجمه" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "ویرایش" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "نامانوس" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 msgid "You need to save the record before adding translations." msgstr "قبل از اضافه کردن ترجمه ها شما باید پرونده را ذخیره کنید." #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 msgid "No other language available." msgstr "هیچ زبان دیگری در دسترس نیست." #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "نمایش ترجمه" tryton-5.0.17/tryton/data/locale/fa/LC_MESSAGES/tryton.mo0000644000175000017500000004736413571264251022255 0ustar cedced00000000000000O  )<Mar  '8Ieu |  #0%Tz  !&* Q _ m{   + 8 P]p  %4 F P\c   5=MS jtz&     !,< ALSYa} " !(JPWfk      ) 8 FRZns x     )5G\d#y      - = C P Y a p y ~     !!'!>![!p! w! !! !!! !!!!!" ""+";"P"i"p"" " "" "" ""##1#A#S#b#k# r#~#I#}# ]$5~$8$$$ $%% "% .%8%=%]%$x%%%%%%&8&@& Y& f&q& w&& && & &&&(& & ' ''%.'7T'' '' ''' ' '' ' ' (((.(3( 9( C( M( W( b(o( w(( (( (((( (( (($( ) $)2)4)<R)) ))))))g+8n+++ +',)-, W,a,r, ,,,,,,,,%,3,"-7-)L-v- -- -(-9-5.$H.m.}...8.H.M3// /// //!/0 (04080G0V0 l0,z0 00000 11$1B1T1 e1r1 1N1$1#282/U2 2*222< 3H3^3u333333(34-4.A4%p4.4 4 44 4 5-5-<5j5z5 5&555)5= 6H6 Q6_66666967#7 97D7V7_7 n73|7 7 7 7797 #8"08$S8%x8'88'8 99"9 B9*M9x99 99999 9:(:A:&Z:::::::& ;4;;;D;Z;l;!o;4; ;;;<'<*<:<-X<<<< <<( =52="h====#===>>!>7>I>P> b>l>{>>>>>$>"? 3? >?,L?$y? ? ??"?(?@ 9@D@ b@p@@ @@@@@A.A HA SA$aAA#AA AA#B&B:BPBoB0B B'B0B-CDC$_CC C CC'CoChD)FEmpE8EF F(FAll fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments (%s)Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverConnection error. Bad username or password.Copy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImage size too large.ImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNextNext RecordNext widgetNoNo action defined.No other language available.No result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen the record Open...Open/Search relationOperation failed. Error message: %sOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:Record saved.Records not removed.Records removed.RelateRelate...Relation Entries ShortcutsReload/UndoRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchSwitch ViewText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified do you want to save it?This record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to get view tree state for %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUnable to write config file %s.Undelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWorking now on the duplicated record(s).Write AnywayYYesYou have to select one record.You must select an import file first.You need to save the record before adding translations.Your selection:_Actions..._Add_Auto-Detect_Cancel_Clear_Close Tab_Copy URL_Delete Export_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Save Export_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userspecify the server hostname:portttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: fa Language-Team: fa Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 از با توجه به دامنه : "%s" معتبر نیست"%s" مورد نیاز است%d پرونده وارد شد.%d پرونده ذخیره شد.%d پرونده ها وارد شدند.%d پرونده های ذخیره شده."%s" (%s)نام مدل %sنام پرونده %sمتنی %s%s%%، ,….....:همه فیلد هافیلد های انتخابیاستخراج از پیش تعریف شدهایجاد...جستجو...نسخه جدید در دسترس است!_پیوست...اقداماقدامات...افزودن_اضافه کردن نام فیلدهایک یادداشت به پرونده اضافه کنیدپیوست را به پرونده اضافه کنیدافزودن پرونده موجودAdd new profileافزودن مقدارAdd...همه فایل هاهمیشه این هشدار را نادیده بگیر.برای حذف این پرونده اطمینان کامل دارید؟برای حذف این پرونده ها اطمینان کامل دارید؟پیوست(%d)پیوست:پیوستها (%s)پیوست ها...بدنه:نام بوک مارک :بوک مارک این فیلترردیابی اشکال(باگ)توسط : CC:CSV Export: %sCSV Import: %sمولفه های CSV_ارتباطلغو اتصال به سرور تریتونCancel savingبررسی URL : %sبررسی نسخهپاک کردنپاکسازی فیلد Closeبستن برگهبستن همه ردیف هابستن ردیفخط فرمان:مقایسههمزمانی استثنااتصال سرور تریتونخطای اتصال. نام کاربری یا کلمه عبور اشتباه.کپی URL درون کلیپبورد_رونوشت URL...کپی متن انتخابینمی تواند به سرور متصل شودایجاد پرونده جدیدایجاد یک پرونده جدید ایجاد سطر جدیدایجاد رابطه جدیداشکال(باگ) جدید با شناسه ایجاد شد تاریخ ایجادتاريخ ايجاد:ایجاد کاربرایجاد کاربر:برش متن انتخابیپایگاه داده:فرمت تاریخDeleteحذف پرونده انتخابی جدا کننده:فرمت نمایشفرمت تاریخ تمایش داده شدهمقدار نمایش داده شدهآیا می خواهید پردازش شود؟دانلودایمیلگزارش ایمیلایمیل...ویرایشویرایش ظاهر برنامه کاربرویرایش پرونده انتخابی ویرایش...ویرایش ویجت هاایمیلتنظیمات برنامه ایمیلرمزگذاری:خطاخطا در بازگشایی فایل CSVخطای پردازش فایل واقع در فیلد : "%s".خطا: اعتراض:گشودن همه ردیف هاگسترش ردیفگشودن - بستنغلطبرگه کردن سریعوارد کردن فهرست های پایگاه دادهنام فیلدفایل برای واردکردن:یافتنپیش زمینهقالبنامانوسارتفاع:اطلاعات میزبان / پایگاه دادههاست:شناسهشناسه:اندازه تصویراندازه تصویر بیش از حد بزرگ است.تصاویرنسخه ناسازگار سرورمیانبرهای صفحه کلیدتاریخ آخرین تغییرات:آخرین تغییرات بوسیله:انجام اقداممشروح متغیرهای موجود:محدودمحدودیت:چشم پوشی از سطرهای:پیوندفهرست محتوای میانبرهایورود به سیستمMManage...برای حذف سطر را علامتگذاری کنیدمدل:تاریخ اصلاحکاربر اصلاح کنندهنمایش ماهحرکت مکان نماحرکت به پایینحرکت به پایین یک صفحهحرکت به انتهاحرکت به چپانتقال به منبعحرکت به راستحرکت به بالاحرکت به بالاحرکت به بالای یک صفحهنامبعدیپرونده بعدیویجت بعدیNoاقدامی تعریف نشده.هیچ زبان دیگری در دسترس نیست.نتیجه ای پیدا نشد.یاداشت(%d)یادداشت ها(%s)یادداشت ها...OKباز کردنبازکردن فیلترهابازکردن پرونده های مرتبطبازکردن رابطهباز کردن گزارشبازکردن تقویمبازکردن پرونده باز کردن...بازکردن / ارتباط جستجوعملیات ناموفق بود. پیام خطا: %sبازنویسی %s تعاریف؟PDA ModePNG image (*.png)کلمه عبور:چسباندن متن کپی شدهپیش-اعتبارسنجیظاهرظاهر برنامهقبلیپرونده قبلیویجت قبلیچاپچاپ گزارشچاپ...پروفایلویرایشگر پروفایلپروفایل:Quitکاراکترنقل قول:پرونده ذخیره شد.پرونده ها حذف نشدند.پرونده ها حذف شدند.مرتبطمرتبط...رابطه ها کلید های میانبربارگیری مجدد / واگردحذف "%s"حذف Remove selected profileحذف پرونده انتخابیحذف پرونده انتخابی حذف این بوک مارکگزارشگزارش اشکال(باگ)گزارش...تجدید نظرتجدید نظر:ذخیرهذخیره با نامذخیره با نام...ذخیره حالت درختیذخیره عرض/ارتفاعذخیره این پروندهSave your current versionجستجوجستجو %sتنظیمات جستجو محدودجستجو محدود...جستجوی یک پرونده See the modified versionانتخابانتخاب یک رنگانتخاب یک تجدید نظرانتخاب همهانتخاب منبعانتخاب اقدام شماانتخاب...انتخاب/فعال کردن ردیف جاریانتخابنمایش پرونده های فعالنمایش بوک مارک های فیلترهانمایش پرونده های غیرفعالنمایش متن سادهمشاهده تجدیدنظرها...غلط ‌یاب املاییموضوع :تعویضتعویض نمایهنوشته های متنی میانبراقدام زیر نیاز به بستن همه برگه ها دارد. می خواهید ادامه دهید؟همین اشکال قبلا توسط کاربر دیگری گزارش شده است. برای نگهداری اطلاعات شما نام کاربریتان به ناز-لیست این شماره افزوده می شودمقادیر "%s" معتبر نیستنداین پرونده هنوز اصلاح نشده است. می‌خواهید آن را ذخیره کنید ؟This record has been modified while you were editing it.به:امروززنجیر ردیفانتخاب زنجیرنمایش ترجمهترجمهنمایش درختیدرستقادر به بررسی نسخه جدید نیستقادر به حذف دستیار "%s" نیستقادربه دریافت حالت نمایش درختی نیست برای %sقادر به جستجو برای تکمیل : "%s" نیستقادر به تنظیم محلی: "%s" نیستقادر به تنظیم حالت نمایش درختی نیستقادر به نوشتن در فایل پیکربندی "%s" نیست.بازگردانی فایل انتخابی نامعلومبرای حذف علامت سطر را برداریدانتخاب نکردن همهنام کاربر:کاربر:نام کاربری:مقدار_مشاهده گزارشات...هفتهنمایش هفتهنام این فایل استخراجی چیست؟عرض:دستیارهم اکنون کار بر روی پرونده(ها) تکثیر شده انجام می شود.نوشتن بهرحالYبلهشما باید یک پرونده را انتخاب کنید.شما باید ابتدا فایل ورودی را انتخاب کنید.قبل از اضافه کردن ترجمه ها شما باید پرونده را ذخیره کنید.انتخاب شما:_اقدامات..._افزودن_شناسایی - خودکار_انصراف_پاکسازی_بستن برگه_رونوشت URL_حذف استخراج_حذف..._تکثیر_ایمیل..._صادرات داده ها..._واردات داده ها..._جدید_بعدی_یادداشت ها..._قبلی_چاپ..._مرتبط..._بارگیری مجدد / واگرد_حذف_گزارش..._ذخیره_ذخیره استخراج_جستجو_تعویض نمایهdحالت پیشرفتهبازگشتبرو جلوhگزارشگیری همه چیز در سطح اطلاعاتmمدولاربودن، مقیاس پذیری و امنیتسال بعدسال قبلsفایل پیکربندی جایگزین را مشخص کنیدتعیین سطح گزارش : اشکال زدایی، اطلاعات، هشدار، خطا، بحرانیتعیین ورود به سیستم کاربرتعیین نام میزبان سرور : درگاهtپرویز همایون نژادwytryton-5.0.17/tryton/data/locale/hu_HU/0000755000175000017500000000000013571264253017202 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/hu_HU/LC_MESSAGES/0000755000175000017500000000000013571264253020767 5ustar cedced00000000000000tryton-5.0.17/tryton/data/locale/hu_HU/LC_MESSAGES/tryton.po0000644000175000017500000010674013463252532022673 0ustar cedced00000000000000# Translations template for tryton. # Copyright (C) 2016 Tryton # This file is distributed under the same license as the tryton project. # FIRST AUTHOR , 2016. msgid "" msgstr "Content-Type: text/plain; charset=utf-8\n" #: tryton/config.py:74 msgid "specify alternate config file" msgstr "Alternatív beállítási adatok megadása" #: tryton/config.py:77 msgid "development mode" msgstr "Fejlesztői mód" #: tryton/config.py:80 msgid "logging everything at INFO level" msgstr "Általános belépési szint:INFO" #: tryton/config.py:82 msgid "specify the log level: DEBUG, INFO, WARNING, ERROR, CRITICAL" msgstr "Belépési szint megadása: DEBUG, INFO, WARNING, ERROR, CRITICAL" #: tryton/config.py:85 msgid "specify the login user" msgstr "Bejelentkezési név megadása" #: tryton/config.py:87 #, fuzzy msgid "specify the server hostname:port" msgstr "Szerver név megadása" #: tryton/config.py:127 #, python-format, python-format, fuzzy, python-format msgid "Unable to write config file %s." msgstr "Nem lehet a következő konfigurációs fájlba írni: „%s”" #: tryton/translate.py:185 #, python-format msgid "Unable to set locale %s" msgstr "Nem lehet beállítani a csoportot: %s" #: tryton/action/main.py:89 tryton/common/button.py:54 #, fuzzy msgid ", " msgstr ", " #: tryton/action/main.py:91 #, fuzzy msgid ",…" msgstr ",…" #: tryton/action/main.py:92 #, python-format msgid "%s (%s)" msgstr "" #: tryton/action/main.py:187 msgid "Select your action" msgstr "Válasszon műveletet" #: tryton/action/main.py:193 #, fuzzy msgid "No action defined." msgstr "Nincs megadva művelet" #: tryton/common/button.py:54 msgid "By: " msgstr "" #: tryton/common/common.py:307 tryton/gui/window/shortcuts.py:64 msgid "Selection" msgstr "Kiválasztás" #: tryton/common/common.py:309 tryton/common/common.py:365 #: tryton/common/common.py:368 tryton/common/common.py:642 #: tryton/common/common.py:693 tryton/common/common.py:796 #: tryton/gui/window/email.py:23 tryton/gui/window/limit.py:24 #: tryton/gui/window/preference.py:35 tryton/gui/window/revision.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:149 #: tryton/gui/window/view_form/view/graph.py:106 #: tryton/gui/window/win_csv.py:173 tryton/gui/window/win_form.py:68 #: tryton/gui/window/win_search.py:54 #, fuzzy msgid "Cancel" msgstr "_Mégse" #: tryton/common/common.py:310 tryton/common/common.py:797 #: tryton/gui/window/email.py:28 tryton/gui/window/limit.py:29 #: tryton/gui/window/preference.py:40 tryton/gui/window/revision.py:30 #: tryton/gui/window/shortcuts.py:25 #: tryton/gui/window/view_form/view/form_gtk/widget.py:154 #: tryton/gui/window/view_form/view/graph.py:111 #: tryton/gui/window/win_csv.py:178 tryton/gui/window/win_form.py:97 #: tryton/gui/window/win_search.py:72 msgid "OK" msgstr "" #: tryton/common/common.py:315 msgid "Your selection:" msgstr "Kiválasztva" #: tryton/common/common.py:366 tryton/gui/window/form.py:114 #: tryton/gui/window/view_form/view/form_gtk/binary.py:83 msgid "Select" msgstr "" #: tryton/common/common.py:369 tryton/gui/window/win_export.py:83 msgid "Save" msgstr "Mentés" #: tryton/common/common.py:447 #: tryton/gui/window/view_form/view/form_gtk/binary.py:31 #: tryton/gui/window/view_form/view/form_gtk/binary.py:116 #: tryton/gui/window/view_form/view/graph.py:171 #: tryton/gui/window/view_form/view/list_gtk/widget.py:493 #: tryton/gui/window/win_export.py:305 msgid "Save As..." msgstr "Mentés másként…" #: tryton/common/common.py:592 msgid "Always ignore this warning." msgstr "Ne adja be többet ezt a figyelmeztetést" #: tryton/common/common.py:597 msgid "Do you want to proceed?" msgstr "Akarja folyatni?" #: tryton/common/common.py:643 msgid "No" msgstr "" #: tryton/common/common.py:644 tryton/common/domain_parser.py:239 msgid "Yes" msgstr "" #: tryton/common/common.py:689 tryton/common/common.py:983 msgid "Concurrency Exception" msgstr "Aktualizálási ellentét" #: tryton/common/common.py:691 msgid "This record has been modified while you were editing it." msgstr "" #: tryton/common/common.py:694 msgid "Cancel saving" msgstr "" #: tryton/common/common.py:696 msgid "Compare" msgstr "Összehasonlítás" #: tryton/common/common.py:697 msgid "See the modified version" msgstr "" #: tryton/common/common.py:699 msgid "Write Anyway" msgstr "Felülír" #: tryton/common/common.py:700 msgid "Save your current version" msgstr "" #: tryton/common/common.py:729 #, fuzzy msgid "Application Error" msgstr "Alkalmazási hiba" #: tryton/common/common.py:732 msgid "Report Bug" msgstr "Hibabejelentés" #: tryton/common/common.py:733 tryton/gui/window/dblogin.py:36 msgid "Close" msgstr "" #: tryton/common/common.py:751 msgid "Error: " msgstr "Hiba:" #: tryton/common/common.py:768 #, python-format, fuzzy, python-format msgid "To report bugs you must have an account on %s" msgstr "Az online hibabejelentéshez szükség van %s fiókra" #: tryton/common/common.py:794 msgid "Bug Tracker" msgstr "Hiba bejelentése" #: tryton/common/common.py:811 msgid "User:" msgstr "Felhasználó:" #: tryton/common/common.py:819 msgid "Password:" msgstr "Jelszó:" #: tryton/common/common.py:875 msgid "" "The same bug was already reported by another user.\n" "To keep you informed your username is added to the nosy-list of this issue" msgstr "" "Ez a hiba egy másik felhasználó által már be lett jelentve \n" "Az Ön felhasználóneve az érdekeltségi listára felkerült." #: tryton/common/common.py:886 msgid "Created new bug with ID " msgstr "Új hibabejelentés létesítése ezzel az ID -vel" #: tryton/common/common.py:894 #, fuzzy msgid "" "Connection error.\n" "Bad username or password." msgstr "" "Kapcsolási hiba!\n" "Hibás felhasználónév vagy jelszó " #: tryton/common/common.py:899 msgid "Exception:" msgstr "Kivétel:" #: tryton/common/common.py:926 #, python-format msgid "Check URL: %s" msgstr "" #: tryton/common/common.py:934 msgid "Unable to check for new version" msgstr "" #: tryton/common/common.py:940 msgid "A new version is available!" msgstr "" #: tryton/common/common.py:942 msgid "Download" msgstr "" #: tryton/common/common.py:1323 #, fuzzy msgid "..." msgstr "..." #: tryton/common/completion.py:25 msgid "Search..." msgstr "keresés..." #: tryton/common/completion.py:27 msgid "Create..." msgstr "Készítve..." #: tryton/common/completion.py:70 #, python-format msgid "Unable to search for completion of %s" msgstr "" #: tryton/common/datetime_.py:32 tryton/common/datetime_.py:238 #: tryton/common/datetime_.py:391 msgid "Value" msgstr "Érték" #: tryton/common/datetime_.py:33 tryton/common/datetime_.py:239 #: tryton/common/datetime_.py:392 msgid "Displayed value" msgstr "Megjelenített érték" #: tryton/common/datetime_.py:37 tryton/common/datetime_.py:195 #: tryton/common/datetime_.py:242 tryton/common/datetime_.py:347 msgid "Format" msgstr "Formátum" #: tryton/common/datetime_.py:38 tryton/common/datetime_.py:196 #: tryton/common/datetime_.py:243 tryton/common/datetime_.py:348 msgid "Display format" msgstr "Megjelenítési formátum" #: tryton/common/datetime_.py:63 msgid "Open the calendar" msgstr "Naptár megnyitása" #: tryton/common/datetime_.py:396 tryton/common/datetime_.py:401 msgid "Date Format" msgstr "Dátumformátum" #: tryton/common/datetime_.py:397 tryton/common/datetime_.py:402 msgid "Displayed date format" msgstr "Mutatott dátumformátum" #: tryton/common/domain_parser.py:239 msgid "y" msgstr "J" #: tryton/common/domain_parser.py:239 tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "True" msgstr "Igaz" #: tryton/common/domain_parser.py:239 msgid "t" msgstr "w" #: tryton/common/domain_parser.py:490 #: tryton/gui/window/view_form/view/screen_container.py:567 msgid "False" msgstr "Hamis" #: tryton/common/popup_menu.py:84 msgid "Edit..." msgstr "Szerkesztés…" #: tryton/common/popup_menu.py:89 msgid "Attachments..." msgstr "Mellékletek..." #: tryton/common/popup_menu.py:95 msgid "Notes..." msgstr "" #: tryton/common/popup_menu.py:107 msgid "Actions..." msgstr "Műveletek" #: tryton/common/popup_menu.py:108 msgid "Relate..." msgstr "Kapcsolatok..." #: tryton/common/popup_menu.py:109 msgid "Report..." msgstr "Jelentés..." #: tryton/common/popup_menu.py:110 msgid "E-Mail..." msgstr "E-Mail..." #: tryton/common/popup_menu.py:111 msgid "Print..." msgstr "Nyomtatás..." #: tryton/common/timedelta.py:26 msgid "Y" msgstr "J" #: tryton/common/timedelta.py:27 msgid "M" msgstr "M" #: tryton/common/timedelta.py:28 msgid "w" msgstr "W" #: tryton/common/timedelta.py:29 msgid "d" msgstr "t" #: tryton/common/timedelta.py:30 msgid "h" msgstr "h" #: tryton/common/timedelta.py:31 msgid "m" msgstr "m" #: tryton/common/timedelta.py:32 msgid "s" msgstr "s" #: tryton/gui/main.py:123 #, fuzzy msgid "Preferences..." msgstr "_Beállítások…" #: tryton/gui/main.py:127 #, fuzzy msgid "Toolbar" msgstr "_Eszköztár" #: tryton/gui/main.py:128 #, fuzzy msgid "Default" msgstr "_Alapértelmezett" #: tryton/gui/main.py:129 #, fuzzy msgid "Text and Icons" msgstr "Szöveg és ikonok" #: tryton/gui/main.py:130 #, fuzzy msgid "Text" msgstr "_Szöveg" #: tryton/gui/main.py:131 #, fuzzy msgid "Icons" msgstr "Ikonok" #: tryton/gui/main.py:134 #, fuzzy msgid "Form" msgstr "Űrlap" #: tryton/gui/main.py:135 msgid "Save Width/Height" msgstr "Szélesség/magasság mentése" #: tryton/gui/main.py:136 msgid "Save Tree State" msgstr "Menünézet mentése" #: tryton/gui/main.py:137 msgid "Fast Tabbing" msgstr "" #: tryton/gui/main.py:138 msgid "Spell Checking" msgstr "Helyesírás ellenőrzés" #: tryton/gui/main.py:140 msgid "PDA Mode" msgstr "" #: tryton/gui/main.py:141 msgid "Search Limit..." msgstr "Keresés limit" #: tryton/gui/main.py:142 #, fuzzy msgid "Email..." msgstr "E-mail..." #: tryton/gui/main.py:143 msgid "Check Version" msgstr "" #: tryton/gui/main.py:145 #, fuzzy msgid "Options" msgstr "_Beállítások" #: tryton/gui/main.py:148 #, fuzzy msgid "Keyboard Shortcuts..." msgstr "_Gyorsbillentyűk" #: tryton/gui/main.py:149 #, fuzzy msgid "About..." msgstr "Felett" #: tryton/gui/main.py:150 #, fuzzy msgid "Help" msgstr "_Segítség" #: tryton/gui/main.py:153 msgid "Quit" msgstr "" #: tryton/gui/main.py:395 msgid "No result found." msgstr "Nincs találat" #: tryton/gui/main.py:447 #, fuzzy msgid "Favorites" msgstr "Fa_vorit" #: tryton/gui/main.py:464 tryton/gui/window/dblogin.py:438 #: tryton/gui/window/form.py:139 msgid "Manage..." msgstr "" #: tryton/gui/main.py:541 tryton/gui/window/form.py:559 msgid "Action" msgstr "Művelet" #: tryton/gui/main.py:563 msgid "" "The following action requires to close all tabs.\n" "Do you want to continue?" msgstr "" "A következő művelethez az összes lap bezárása szükséges\n" "Folytatja?" #: tryton/gui/main.py:747 msgid "Close Tab" msgstr "Lap bezárása" #: tryton/gui/window/about.py:37 msgid "modularity, scalability and security" msgstr "" #: tryton/gui/window/about.py:43 msgid "translator-credits" msgstr "" #: tryton/gui/window/attachment.py:24 #, python-format, python-format, fuzzy, python-format msgid "Attachments (%s)" msgstr "Melléklet(%s)" #: tryton/gui/window/dblogin.py:33 msgid "Profile Editor" msgstr "Profilszerkesztő" #: tryton/gui/window/dblogin.py:49 msgid "Profile" msgstr "Profil" #: tryton/gui/window/dblogin.py:58 msgid "Add new profile" msgstr "" #: tryton/gui/window/dblogin.py:63 msgid "Remove selected profile" msgstr "" #: tryton/gui/window/dblogin.py:77 tryton/gui/window/dblogin.py:450 msgid "Host:" msgstr "Host:" #: tryton/gui/window/dblogin.py:88 tryton/gui/window/dblogin.py:462 msgid "Database:" msgstr "Adatbank:" #: tryton/gui/window/dblogin.py:108 msgid "Fetching databases list" msgstr "Adatbanklista lekérdezése..." #: tryton/gui/window/dblogin.py:122 msgid "Username:" msgstr "Felhasználónév:" #: tryton/gui/window/dblogin.py:309 tryton/gui/window/dblogin.py:619 msgid "Incompatible version of the server" msgstr "Inkompatibilis szerververzió" #: tryton/gui/window/dblogin.py:311 tryton/gui/window/dblogin.py:623 msgid "Could not connect to the server" msgstr "Nem sikerült csatlakozni a kiszolgálóhoz" #: tryton/gui/window/dblogin.py:390 msgid "Login" msgstr "Bejelentkezés" #: tryton/gui/window/dblogin.py:396 msgid "_Cancel" msgstr "_Mégse" #: tryton/gui/window/dblogin.py:398 msgid "Cancel connection to the Tryton server" msgstr "_Mégse" #: tryton/gui/window/dblogin.py:400 msgid "C_onnect" msgstr "Kapcsolódik" #: tryton/gui/window/dblogin.py:404 msgid "Connect the Tryton server" msgstr "Kapcsolódás helyreállítása a Tryton szerverhez." #: tryton/gui/window/dblogin.py:432 msgid "Profile:" msgstr "Profil:" #: tryton/gui/window/dblogin.py:447 msgid "Host / Database information" msgstr "Host-/adatbank adatok" #: tryton/gui/window/dblogin.py:478 msgid "User name:" msgstr "Felhasználónév:" #: tryton/gui/window/email.py:19 msgid "Email" msgstr "E-mail" #: tryton/gui/window/email.py:36 msgid "Email Program Settings" msgstr "E-mail beállítások" #: tryton/gui/window/email.py:39 msgid "Command Line:" msgstr "Parancssor:" #: tryton/gui/window/email.py:49 msgid "Legend of Available Placeholders:" msgstr "Az elérhető helyettesítők jelmagyarázata:" #: tryton/gui/window/email.py:56 msgid "To:" msgstr "-hoz, -hez" #: tryton/gui/window/email.py:60 msgid "CC:" msgstr "CC:" #: tryton/gui/window/email.py:64 msgid "Subject:" msgstr "Tárgy:" #: tryton/gui/window/email.py:68 msgid "Body:" msgstr "Szöveg:" #: tryton/gui/window/email.py:72 msgid "Attachment:" msgstr "Melléklet:" #: tryton/gui/window/form.py:135 msgid "Add..." msgstr "" #: tryton/gui/window/form.py:155 #, python-format msgid "Attachment(%d)" msgstr "Melléklet(%d)" #: tryton/gui/window/form.py:185 #, python-format msgid "Note(%d)" msgstr "" #: tryton/gui/window/form.py:207 #, fuzzy msgid "You have to select one record." msgstr "Legalább egy adatot kell kiválasztani." #: tryton/gui/window/form.py:211 msgid "ID:" msgstr "ID:" #: tryton/gui/window/form.py:212 msgid "Creation User:" msgstr "Által létrehozva" #: tryton/gui/window/form.py:213 msgid "Creation Date:" msgstr "Létrehozás dátuma" #: tryton/gui/window/form.py:214 msgid "Latest Modification by:" msgstr "Utolsó módosítás" #: tryton/gui/window/form.py:215 msgid "Latest Modification Date:" msgstr "Módosítás dátuma " #: tryton/gui/window/form.py:234 msgid "Model:" msgstr "Típus:" #: tryton/gui/window/form.py:312 msgid "Are you sure to remove this record?" msgstr "Biztos törölni szeretné?" #: tryton/gui/window/form.py:314 msgid "Are you sure to remove those records?" msgstr "Biztos törölni szeretné?" #: tryton/gui/window/form.py:317 #, fuzzy msgid "Records not removed." msgstr "Adat nincs törölve!" #: tryton/gui/window/form.py:319 #, fuzzy msgid "Records removed." msgstr "Adat törölve" #: tryton/gui/window/form.py:356 #, fuzzy msgid "Working now on the duplicated record(s)." msgstr "A másolaton dolgozik" #: tryton/gui/window/form.py:368 #, fuzzy msgid "Record saved." msgstr "Adat mentve" #: tryton/gui/window/form.py:485 msgid " of " msgstr "-tól" #: tryton/gui/window/form.py:505 #, fuzzy msgid "" "This record has been modified\n" "do you want to save it?" msgstr "" "Adat módosítva\n" "Szeretne menteni?" #: tryton/gui/window/form.py:559 msgid "Launch action" msgstr "Művelet indítása" #: tryton/gui/window/form.py:560 msgid "Relate" msgstr "Kapcsolat" #: tryton/gui/window/form.py:560 msgid "Open related records" msgstr "Kapcsolat adatainak megnyitása" #: tryton/gui/window/form.py:562 msgid "Report" msgstr "Jelentés" #: tryton/gui/window/form.py:562 msgid "Open report" msgstr "Jelentés megnyitása" #: tryton/gui/window/form.py:563 msgid "E-Mail" msgstr "E-mail" #: tryton/gui/window/form.py:563 msgid "E-Mail report" msgstr "Jelentést e-mailon küldeni" #: tryton/gui/window/form.py:564 msgid "Print" msgstr "Nyomtatás" #: tryton/gui/window/form.py:564 msgid "Print report" msgstr "Jelentés nyomtatása" #: tryton/gui/window/form.py:590 msgid "_Copy URL" msgstr "" #: tryton/gui/window/form.py:593 msgid "Copy URL into clipboard" msgstr "" #: tryton/gui/window/form.py:652 #: tryton/gui/window/view_form/view/list_gtk/widget.py:932 msgid "Unknown" msgstr "Ismeretlen" #: tryton/gui/window/limit.py:20 msgid "Limit" msgstr "Korlátozás" #: tryton/gui/window/limit.py:37 msgid "Search Limit Settings" msgstr "Keresési beállítások" #: tryton/gui/window/limit.py:40 msgid "Limit:" msgstr "Korlát:" #: tryton/gui/window/note.py:17 #, python-format msgid "Notes (%s)" msgstr "" #: tryton/gui/window/preference.py:25 msgid "Preferences" msgstr "Beállítások" #: tryton/gui/window/preference.py:58 msgid "Edit User Preferences" msgstr "Felhasználói beállítások szerkesztése" #: tryton/gui/window/preference.py:85 msgid "Preference" msgstr "Beállítások" #: tryton/gui/window/revision.py:21 msgid "Revision" msgstr "Szerkesztés" #: tryton/gui/window/revision.py:38 msgid "Select a revision" msgstr "Szerkesztés kiválasztása" #: tryton/gui/window/revision.py:41 msgid "Revision:" msgstr "Szerkesztés:" #: tryton/gui/window/shortcuts.py:20 msgid "Keyboard Shortcuts" msgstr "Gyorsbillentyűk" #: tryton/gui/window/shortcuts.py:35 msgid "Text Entries Shortcuts" msgstr "Gyorsbillentyű szövegbeíráshoz" #: tryton/gui/window/shortcuts.py:36 msgid "Cut selected text" msgstr "Kijelölt szöveg kiválasztása" #: tryton/gui/window/shortcuts.py:37 msgid "Copy selected text" msgstr "_Kijelölt szöveg másolása" #: tryton/gui/window/shortcuts.py:38 msgid "Paste copied text" msgstr "Kijelölt szöveg beillesztése" #: tryton/gui/window/shortcuts.py:39 msgid "Next widget" msgstr "Következő Widget" #: tryton/gui/window/shortcuts.py:40 msgid "Previous widget" msgstr "Előző Widget" #: tryton/gui/window/shortcuts.py:41 msgid "Relation Entries Shortcuts" msgstr "Gyorsbillentyű az összekötő mezők beírásához" #: tryton/gui/window/shortcuts.py:42 msgid "Create new relation" msgstr "Új kapcsolat létrehozása" #: tryton/gui/window/shortcuts.py:43 msgid "Open/Search relation" msgstr "Kapcsolatok keresése/megnyitása" #: tryton/gui/window/shortcuts.py:44 msgid "List Entries Shortcuts" msgstr "Gyorsbillentyűk lista mezők beírásához" #: tryton/gui/window/shortcuts.py:45 msgid "Create new line" msgstr "Új sor létrehozása" #: tryton/gui/window/shortcuts.py:46 msgid "Open relation" msgstr "Kapcsolat megnyitása" #: tryton/gui/window/shortcuts.py:47 msgid "Mark line for deletion" msgstr "Kijelölés törlésre" #: tryton/gui/window/shortcuts.py:48 msgid "Unmark line for deletion" msgstr "A törlési kijelölés visszavonása" #: tryton/gui/window/shortcuts.py:51 msgid "Edition Widgets" msgstr "Widget szerkesztéshez" #: tryton/gui/window/shortcuts.py:54 msgid "Move Cursor" msgstr "" #: tryton/gui/window/shortcuts.py:55 msgid "Move to right" msgstr "" #: tryton/gui/window/shortcuts.py:56 msgid "Move to left" msgstr "" #: tryton/gui/window/shortcuts.py:57 msgid "Move up" msgstr "" #: tryton/gui/window/shortcuts.py:58 msgid "Move down" msgstr "" #: tryton/gui/window/shortcuts.py:59 msgid "Move up of one page" msgstr "" #: tryton/gui/window/shortcuts.py:60 msgid "Move down of one page" msgstr "" #: tryton/gui/window/shortcuts.py:61 msgid "Move to top" msgstr "" #: tryton/gui/window/shortcuts.py:62 msgid "Move to bottom" msgstr "" #: tryton/gui/window/shortcuts.py:63 msgid "Move to parent" msgstr "" #: tryton/gui/window/shortcuts.py:65 tryton/gui/window/shortcuts.py:66 msgid "Select all" msgstr "" #: tryton/gui/window/shortcuts.py:67 tryton/gui/window/shortcuts.py:68 msgid "Unselect all" msgstr "" #: tryton/gui/window/shortcuts.py:69 msgid "Select parent" msgstr "" #: tryton/gui/window/shortcuts.py:70 tryton/gui/window/shortcuts.py:71 #: tryton/gui/window/shortcuts.py:72 tryton/gui/window/shortcuts.py:73 msgid "Select/Activate current row" msgstr "" #: tryton/gui/window/shortcuts.py:74 msgid "Toggle selection" msgstr "" #: tryton/gui/window/shortcuts.py:75 msgid "Expand/Collapse" msgstr "" #: tryton/gui/window/shortcuts.py:76 msgid "Expand row" msgstr "" #: tryton/gui/window/shortcuts.py:77 msgid "Collapse row" msgstr "" #: tryton/gui/window/shortcuts.py:78 msgid "Toggle row" msgstr "" #: tryton/gui/window/shortcuts.py:79 msgid "Collapse all rows" msgstr "" #: tryton/gui/window/shortcuts.py:80 msgid "Expand all rows" msgstr "" #: tryton/gui/window/shortcuts.py:83 msgid "Tree view" msgstr "" #: tryton/gui/window/tabcontent.py:43 msgid "_Switch View" msgstr "Nézet váltása" #: tryton/gui/window/tabcontent.py:44 #, fuzzy msgid "Switch View" msgstr "Nézet váltása" #: tryton/gui/window/tabcontent.py:49 msgid "_Previous" msgstr "_Előző" #: tryton/gui/window/tabcontent.py:50 msgid "Previous Record" msgstr "Előző adat" #: tryton/gui/window/tabcontent.py:55 msgid "_Next" msgstr "_Következő" #: tryton/gui/window/tabcontent.py:56 msgid "Next Record" msgstr "Következő adat" #: tryton/gui/window/tabcontent.py:61 msgid "_Search" msgstr "_Keresés" #: tryton/gui/window/tabcontent.py:67 msgid "_New" msgstr "_Új" #: tryton/gui/window/tabcontent.py:68 msgid "Create a new record" msgstr "Új bejegyzés létrehozása" #: tryton/gui/window/tabcontent.py:73 tryton/gui/window/win_form.py:85 msgid "_Save" msgstr "_Mentés" #: tryton/gui/window/tabcontent.py:74 msgid "Save this record" msgstr "Bejegyzés mentése" #: tryton/gui/window/tabcontent.py:79 msgid "_Reload/Undo" msgstr "Frissítés/ visszavonás" #: tryton/gui/window/tabcontent.py:80 #, fuzzy msgid "Reload/Undo" msgstr "Frissítés/ visszavonás" #: tryton/gui/window/tabcontent.py:85 msgid "_Duplicate" msgstr "Másolat" #: tryton/gui/window/tabcontent.py:90 msgid "_Delete..." msgstr "_Törlés..." #: tryton/gui/window/tabcontent.py:96 msgid "View _Logs..." msgstr "Napló megtekintése…" #: tryton/gui/window/tabcontent.py:100 msgid "Show revisions..." msgstr "Feldolgozások megtekintése" #: tryton/gui/window/tabcontent.py:105 msgid "A_ttachments..." msgstr "Csatolmány" #: tryton/gui/window/tabcontent.py:106 msgid "Add an attachment to the record" msgstr "Melléklet hozzáadása az üzenethez." #: tryton/gui/window/tabcontent.py:112 msgid "_Notes..." msgstr "" #: tryton/gui/window/tabcontent.py:113 msgid "Add a note to the record" msgstr "" #: tryton/gui/window/tabcontent.py:118 msgid "_Actions..." msgstr "_Műveletek" #: tryton/gui/window/tabcontent.py:123 msgid "_Relate..." msgstr "Kapcsolat megnyitása" #: tryton/gui/window/tabcontent.py:129 msgid "_Report..." msgstr "Jelentés megnyitása..." #: tryton/gui/window/tabcontent.py:134 msgid "_E-Mail..." msgstr "Jelentés per e-mail" #: tryton/gui/window/tabcontent.py:139 msgid "_Print..." msgstr "_Nyomtatás…" #: tryton/gui/window/tabcontent.py:145 msgid "_Export Data..." msgstr "Adat exportálása" #: tryton/gui/window/tabcontent.py:150 msgid "_Import Data..." msgstr "Adat importálása" #: tryton/gui/window/tabcontent.py:155 msgid "Copy _URL..." msgstr "" #: tryton/gui/window/tabcontent.py:161 msgid "_Close Tab" msgstr "Lap bezárása" #: tryton/gui/window/win_csv.py:60 msgid "All fields" msgstr "összes mező" #: tryton/gui/window/win_csv.py:69 msgid "_Add" msgstr "_Hozzáadás" #: tryton/gui/window/win_csv.py:77 msgid "_Remove" msgstr "_Eltávolítás" #: tryton/gui/window/win_csv.py:85 #, fuzzy msgid "_Clear" msgstr "Törlés" #: tryton/gui/window/win_csv.py:105 msgid "Fields selected" msgstr "" #: tryton/gui/window/win_csv.py:124 msgid "CSV Parameters" msgstr "CSV Paraméter" #: tryton/gui/window/win_csv.py:132 msgid "Delimiter:" msgstr "" #: tryton/gui/window/win_csv.py:146 msgid "Quote char:" msgstr "" #: tryton/gui/window/win_csv.py:155 msgid "Encoding:" msgstr "Kódolás:" #: tryton/gui/window/win_csv.py:195 tryton/gui/window/win_csv.py:199 msgid "Field name" msgstr "Mezőnév" #: tryton/gui/window/win_export.py:28 #, python-format msgid "CSV Export: %s" msgstr "" #: tryton/gui/window/win_export.py:32 #, fuzzy msgid "_Save Export" msgstr "Export mentése" #: tryton/gui/window/win_export.py:40 #, fuzzy msgid "_Delete Export" msgstr "Export törlése" #: tryton/gui/window/win_export.py:55 msgid "Predefined exports" msgstr "Előre megadott export" #: tryton/gui/window/win_export.py:62 msgid "Name" msgstr "Név" #: tryton/gui/window/win_export.py:82 msgid "Open" msgstr "Megnyitás" #: tryton/gui/window/win_export.py:87 msgid "Add _field names" msgstr "Mezőnév hozzáadása" #: tryton/gui/window/win_export.py:103 #, python-format msgid "%s (string)" msgstr "%s (string)" #: tryton/gui/window/win_export.py:106 #, python-format msgid "%s (model name)" msgstr "" #: tryton/gui/window/win_export.py:108 #, python-format msgid "%s (record name)" msgstr "" #: tryton/gui/window/win_export.py:207 msgid "What is the name of this export?" msgstr "Mi legyen az export neve?" #: tryton/gui/window/win_export.py:213 #, python-format msgid "Override '%s' definition?" msgstr "'%s' definiálásának figyelembe vétele?" #: tryton/gui/window/win_export.py:328 #, python-format, python-format, fuzzy, python-format msgid "%d record saved." msgstr "%d adat mentve" #: tryton/gui/window/win_export.py:330 #, python-format, python-format, fuzzy, python-format msgid "%d records saved." msgstr "%d adatok mentve!" #: tryton/gui/window/win_export.py:333 #, python-format, python-format, fuzzy, python-format msgid "" "Operation failed.\n" "Error message:\n" "%s" msgstr "" "Sikertelen művelet!\n" "Error message:\n" "%s" #: tryton/gui/window/win_export.py:334 tryton/gui/window/win_import.py:112 #: tryton/gui/window/win_import.py:139 msgid "Error" msgstr "Hiba" #: tryton/gui/window/win_form.py:38 msgid "Link" msgstr "Hivatkozás" #: tryton/gui/window/win_form.py:66 msgid "Delete" msgstr "Töröl" #: tryton/gui/window/win_form.py:78 tryton/gui/window/win_search.py:65 msgid "New" msgstr "Új" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:48 #: tryton/gui/window/win_form.py:140 msgid "Switch" msgstr "Nézet váltása" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:56 #: tryton/gui/window/view_form/view/screen_container.py:222 #: tryton/gui/window/win_form.py:148 msgid "Previous" msgstr "Előző" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:67 #: tryton/gui/window/view_form/view/screen_container.py:231 #: tryton/gui/window/win_form.py:159 msgid "Next" msgstr "Következő" #: tryton/gui/window/win_form.py:176 msgid "Add" msgstr "Hozzáad" #: tryton/gui/window/win_form.py:186 msgid "Remove " msgstr "Mező eltávolítása" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:118 #: tryton/gui/window/win_form.py:198 msgid "Create a new record " msgstr "Új adat létrehozása." #: tryton/gui/window/view_form/view/form_gtk/one2many.py:134 #: tryton/gui/window/win_form.py:208 msgid "Delete selected record " msgstr "Kiválasztott adatok törlése" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:142 #: tryton/gui/window/win_form.py:219 msgid "Undelete selected record " msgstr "Törlés visszavonása" #: tryton/gui/window/win_import.py:26 #, python-format msgid "CSV Import: %s" msgstr "" #: tryton/gui/window/win_import.py:30 #, fuzzy msgid "_Auto-Detect" msgstr "Automatikus felismerés" #: tryton/gui/window/win_import.py:41 msgid "File to Import:" msgstr "Importadatok:" #: tryton/gui/window/view_form/view/form_gtk/binary.py:200 #: tryton/gui/window/view_form/view/list_gtk/widget.py:466 #: tryton/gui/window/win_import.py:43 msgid "Open..." msgstr "Megnyitás..." #: tryton/gui/window/win_import.py:48 msgid "Lines to Skip:" msgstr "Átugrandó sorok:" #: tryton/gui/window/win_import.py:101 #, fuzzy msgid "You must select an import file first." msgstr "Először ki kell jelölni legalább egy fájlt." #: tryton/gui/window/win_import.py:112 msgid "Error opening CSV file" msgstr "Hiba a CSV fájl megnyitásakor" #: tryton/gui/window/win_import.py:138 #, python-format msgid "Error processing the file at field %s." msgstr "Hiba az adat feldolgozásnál a %s mezőben." #: tryton/gui/window/win_import.py:198 #, python-format, python-format, fuzzy, python-format msgid "%d record imported." msgstr "%d adat importálva..." #: tryton/gui/window/win_import.py:200 #, python-format, python-format, fuzzy, python-format msgid "%d records imported." msgstr "%d adat importálva..." #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:344 #: tryton/gui/window/view_form/view/form_gtk/many2many.py:46 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:81 #: tryton/gui/window/view_form/view/screen_container.py:146 #: tryton/gui/window/win_search.py:36 tryton/gui/window/win_search.py:59 msgid "Search" msgstr "Keresés" #: tryton/gui/window/win_search.py:91 #, python-format msgid "Search %s" msgstr "" #: tryton/gui/window/wizard.py:160 #, python-format msgid "Unable to delete wizard %s" msgstr "" #: tryton/gui/window/wizard.py:317 msgid "Wizard" msgstr "Wizard" #: tryton/gui/window/view_form/screen/screen.py:206 msgid "ID" msgstr "ID" #: tryton/gui/window/view_form/screen/screen.py:207 msgid "Creation User" msgstr "Által létrehozva" #: tryton/gui/window/view_form/screen/screen.py:208 msgid "Creation Date" msgstr "Létrehozás dátuma" #: tryton/gui/window/view_form/screen/screen.py:209 msgid "Modification User" msgstr "Által módosítva" #: tryton/gui/window/view_form/screen/screen.py:210 msgid "Modification Date" msgstr "Módosítás dátuma" #: tryton/gui/window/view_form/screen/screen.py:806 #, python-format, python-format, fuzzy, python-format msgid "Unable to get view tree state for %s" msgstr "A menü láthatósága nem állítható be %s" #: tryton/gui/window/view_form/screen/screen.py:867 msgid "Unable to set view tree state" msgstr "A menü láthatósága nem állítható be" #: tryton/gui/window/view_form/screen/screen.py:1054 #, python-format msgid "\"%s\" is not valid according to its domain" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1061 #, python-format msgid "\"%s\" is required" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1065 #, python-format msgid "The values of \"%s\" are not valid" msgstr "" #: tryton/gui/window/view_form/screen/screen.py:1114 msgid "Pre-validation" msgstr "" #: tryton/gui/window/view_form/view/form.py:261 #: tryton/gui/window/view_form/view/form.py:263 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:476 #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:478 #: tryton/gui/window/view_form/view/form_gtk/widget.py:172 #: tryton/gui/window/view_form/view/form_gtk/widget.py:174 #: tryton/gui/window/view_form/view/list.py:530 #: tryton/gui/window/view_form/view/list.py:532 msgid ":" msgstr ":" #: tryton/gui/window/view_form/view/graph.py:102 msgid "Image Size" msgstr "Kép mérete" #: tryton/gui/window/view_form/view/graph.py:121 msgid "Width:" msgstr "Szélesség:" #: tryton/gui/window/view_form/view/graph.py:129 msgid "Height:" msgstr "Magasság:" #: tryton/gui/window/view_form/view/graph.py:140 msgid "PNG image (*.png)" msgstr "PNG Kép (*.png)" #: tryton/gui/window/view_form/view/graph.py:149 msgid "Save As" msgstr "Mentés másként" #: tryton/gui/window/view_form/view/graph.py:161 #, fuzzy msgid "Image size too large." msgstr "Kép túl nagy!" #: tryton/gui/window/view_form/view/screen_container.py:23 msgid ".." msgstr ".." #: tryton/gui/window/view_form/view/screen_container.py:152 msgid "Open filters" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:209 msgid "Show bookmarks of filters" msgstr "Szűrő könyvjelzők megjelenítése" #: tryton/gui/window/view_form/view/screen_container.py:371 msgid "Remove this bookmark" msgstr "Könyvjelző eltávolítása" #: tryton/gui/window/view_form/view/screen_container.py:379 msgid "Bookmark this filter" msgstr "A szűrőt könyvjelzőként hozzáadni" #: tryton/gui/window/view_form/view/screen_container.py:396 msgid "Show active records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:398 msgid "Show inactive records" msgstr "" #: tryton/gui/window/view_form/view/screen_container.py:479 msgid "Bookmark Name:" msgstr "Könyvjelző neve:" #: tryton/gui/window/view_form/view/screen_container.py:599 msgid "Find" msgstr "Keresés" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:22 msgid "Today" msgstr "Ma" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:32 msgid "go back" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:73 msgid "go forward" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:82 msgid "previous year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:96 msgid "next year" msgstr "" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:107 msgid "Week View" msgstr "Heti nézet" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:117 msgid "Month View" msgstr "Havi nézet" #: tryton/gui/window/view_form/view/calendar_gtk/toolbar.py:142 msgid "Week" msgstr "Hét" #: tryton/gui/window/view_form/view/form_gtk/binary.py:39 msgid "Select..." msgstr "" #: tryton/gui/window/view_form/view/form_gtk/binary.py:47 msgid "Clear" msgstr "Törlés" #: tryton/gui/window/view_form/view/form_gtk/binary.py:60 msgid "All files" msgstr "Összes fájl" #: tryton/gui/window/view_form/view/form_gtk/char.py:169 msgid "Show plain text" msgstr "Magyarázat mutatása" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:369 msgid "Add value" msgstr "Érték hozzáadása" #: tryton/gui/window/view_form/view/form_gtk/dictionary.py:490 #, python-format msgid "Remove \"%s\"" msgstr "„%s” eltávolítása" #: tryton/gui/window/view_form/view/form_gtk/image.py:50 msgid "Images" msgstr "Képek" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:66 #: tryton/gui/window/view_form/view/form_gtk/one2many.py:99 msgid "Add existing record" msgstr "Meglévő adat hozzáadása" #: tryton/gui/window/view_form/view/form_gtk/many2many.py:74 msgid "Remove selected record " msgstr "Kijelölt adat törlése" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:305 #: tryton/gui/window/view_form/view/list_gtk/widget.py:582 #, fuzzy msgid "Open the record " msgstr "Adat megnyitása" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:306 #: tryton/gui/window/view_form/view/list_gtk/widget.py:583 msgid "Clear the field " msgstr "" #: tryton/gui/window/view_form/view/form_gtk/many2one.py:309 #: tryton/gui/window/view_form/view/list_gtk/widget.py:586 msgid "Search a record " msgstr "Adat keresése" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:108 msgid "Remove selected record" msgstr "A kiválasztott adat eltávolítása" #: tryton/gui/window/view_form/view/form_gtk/one2many.py:126 msgid "Edit selected record " msgstr "A kiválasztott adat átdolgozása" #: tryton/gui/window/view_form/view/form_gtk/progressbar.py:35 #: tryton/gui/window/view_form/view/list_gtk/widget.py:908 #, python-format msgid "%s%%" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:85 msgid "Foreground" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/richtextbox.py:328 msgid "Select a color" msgstr "" #: tryton/gui/window/view_form/view/form_gtk/widget.py:136 msgid "Translation" msgstr "Fordítás" #: tryton/gui/window/view_form/view/form_gtk/widget.py:209 msgid "Edit" msgstr "Szerkesztés" #: tryton/gui/window/view_form/view/form_gtk/widget.py:214 msgid "Fuzzy" msgstr "Életlen" #: tryton/gui/window/view_form/view/form_gtk/widget.py:285 #, fuzzy msgid "You need to save the record before adding translations." msgstr "Az adatot menteni kell, mielőtt egy fordítást hozzá lehet adni!" #: tryton/gui/window/view_form/view/form_gtk/widget.py:296 #, fuzzy msgid "No other language available." msgstr "Más nyelv nem használható!" #: tryton/plugins/translation/__init__.py:17 #: tryton/plugins/translation/__init__.py:24 msgid "Translate view" msgstr "Nézet elfordítása" tryton-5.0.17/tryton/data/locale/hu_HU/LC_MESSAGES/tryton.mo0000644000175000017500000003621713571264251022672 0ustar cedced000000000000001 ,-)2\mu -= DOSd}  #%B Q]lr &   $28N T^ p } /HXl     %;Kcl s  &C KV fq     "'J]w !   '9 K V bl        &1:= BO d r~   $-=M S`iq    +@ G R\ eot |   9@O a lz    # 2 ; B IY } !!8B!{!! !!! ! !!!!%","D"b""" " "" "" "" " "## #)#+#/# ?#K#P# X# c# m# x# ##### # # # # ## #$$ $$$0$ 8$C$ E$f$$h$ $ $$$<$%%%.%0%2%&)&&''' )'5':'='?'T'k'''' '' ''' (&&(M(i(y(( ()((() )!)1):)'M)u)))))) )) ) ) ))**!*0* B* O*[*n*4** **++,+I+e+{+2++++, , ;,E,U,$], ,,,,,,,, - -+,-&X----- ---,- . &.0. @.K.[. a.n. . .. . .. ..... .//,/=/S/h/.|/ /// /+/ 00 0'0>0F0[0 n0 z0 000 00 0 0001 1 11-1@1C1R1 [1f1o1 r1 }11111 1!1*2E2N2_2h22222 22 22 233!3)3 .3 :3D34S3333*344 <4F4 V4 c4 p4~44444445 5"5;5J5]5v5}55 5 55 55 5 6%6E6[6q6666"6J6/7 787 88 8#848 I8 T8^8c88%8&8*89 49%?9 e9r999999 99 99 ::: : #: /:<:D: S: ]:j:s:::: : :::::;";;; D;N;_;a;r; z;;!;;$; ; ;;*;A<W<v<x<<< of "%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:All fieldsFields selectedPredefined exportsCreate...Search...A new version is available!A_ttachments...ActionActions...AddAdd _field namesAdd a note to the recordAdd an attachment to the recordAdd existing recordAdd new profileAdd valueAdd...All filesAlways ignore this warning.Are you sure to remove this record?Are you sure to remove those records?Attachment(%d)Attachment:Attachments...Body:Bookmark Name:Bookmark this filterBug TrackerBy: CC:CSV Export: %sCSV Import: %sCSV ParametersC_onnectCancel connection to the Tryton serverCancel savingCheck URL: %sCheck VersionClearClear the field CloseClose TabCollapse all rowsCollapse rowCommand Line:CompareConcurrency ExceptionConnect the Tryton serverCopy URL into clipboardCopy _URL...Copy selected textCould not connect to the serverCreate a new recordCreate a new record Create new lineCreate new relationCreated new bug with ID Creation DateCreation Date:Creation UserCreation User:Cut selected textDatabase:Date FormatDeleteDelete selected record Delimiter:Display formatDisplayed date formatDisplayed valueDo you want to proceed?DownloadE-MailE-Mail reportE-Mail...EditEdit User PreferencesEdit selected record Edit...Edition WidgetsEmailEmail Program SettingsEncoding:ErrorError opening CSV fileError processing the file at field %s.Error: Exception:Expand all rowsExpand rowExpand/CollapseFalseFast TabbingFetching databases listField nameFile to Import:FindForegroundFormatFuzzyHeight:Host / Database informationHost:IDID:Image SizeImagesIncompatible version of the serverKeyboard ShortcutsLatest Modification Date:Latest Modification by:Launch actionLegend of Available Placeholders:LimitLimit:Lines to Skip:LinkList Entries ShortcutsLoginMManage...Mark line for deletionModel:Modification DateModification UserMonth ViewMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNameNewNextNext RecordNext widgetNoNo result found.Note(%d)Notes (%s)Notes...OKOpenOpen filtersOpen related recordsOpen relationOpen reportOpen the calendarOpen...Open/Search relationOverride '%s' definition?PDA ModePNG image (*.png)Password:Paste copied textPre-validationPreferencePreferencesPreviousPrevious RecordPrevious widgetPrintPrint reportPrint...ProfileProfile EditorProfile:QuitQuote char:RelateRelate...Relation Entries ShortcutsRemove "%s"Remove Remove selected profileRemove selected recordRemove selected record Remove this bookmarkReportReport BugReport...RevisionRevision:SaveSave AsSave As...Save Tree StateSave Width/HeightSave this recordSave your current versionSearchSearch %sSearch Limit SettingsSearch Limit...Search a record See the modified versionSelectSelect a colorSelect a revisionSelect allSelect parentSelect your actionSelect...Select/Activate current rowSelectionShow active recordsShow bookmarks of filtersShow inactive recordsShow plain textShow revisions...Spell CheckingSubject:SwitchText Entries ShortcutsThe following action requires to close all tabs. Do you want to continue?The same bug was already reported by another user. To keep you informed your username is added to the nosy-list of this issueThe values of "%s" are not validThis record has been modified while you were editing it.To:TodayToggle rowToggle selectionTranslate viewTranslationTree viewTrueUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sUnable to set locale %sUnable to set view tree stateUndelete selected record UnknownUnmark line for deletionUnselect allUser name:User:Username:ValueView _Logs...WeekWeek ViewWhat is the name of this export?Width:WizardWrite AnywayYYesYour selection:_Actions..._Add_Cancel_Close Tab_Copy URL_Delete..._Duplicate_E-Mail..._Export Data..._Import Data..._New_Next_Notes..._Previous_Print..._Relate..._Reload/Undo_Remove_Report..._Save_Search_Switch Viewddevelopment modego backgo forwardhlogging everything at INFO levelmmodularity, scalability and securitynext yearprevious yearsspecify alternate config filespecify the log level: DEBUG, INFO, WARNING, ERROR, CRITICALspecify the login userttranslator-creditswyProject-Id-Version: PROJECT VERSION Report-Msgid-Bugs-To: EMAIL@ADDRESS POT-Creation-Date: 2019-12-02 20:40+0100 PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE Last-Translator: FULL NAME Language: hu_HU Language-Team: hu_HU Plural-Forms: nplurals=1; plural=0 MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit Generated-By: Babel 2.6.0 -tól"%s" is not valid according to its domain"%s" is required%s (%s)%s (model name)%s (record name)%s (string)%s%%..:összes mezőFields selectedElőre megadott exportKészítve...keresés...A new version is available!CsatolmányMűveletMűveletekHozzáadMezőnév hozzáadásaAdd a note to the recordMelléklet hozzáadása az üzenethez.Meglévő adat hozzáadásaAdd new profileÉrték hozzáadásaAdd...Összes fájlNe adja be többet ezt a figyelmeztetéstBiztos törölni szeretné?Biztos törölni szeretné?Melléklet(%d)Melléklet:Mellékletek...Szöveg:Könyvjelző neve:A szűrőt könyvjelzőként hozzáadniHiba bejelentéseBy: CC:CSV Export: %sCSV Import: %sCSV ParaméterKapcsolódik_MégseCancel savingCheck URL: %sCheck VersionTörlésClear the field CloseLap bezárásaCollapse all rowsCollapse rowParancssor:ÖsszehasonlításAktualizálási ellentétKapcsolódás helyreállítása a Tryton szerverhez.Copy URL into clipboardCopy _URL..._Kijelölt szöveg másolásaNem sikerült csatlakozni a kiszolgálóhozÚj bejegyzés létrehozásaÚj adat létrehozása.Új sor létrehozásaÚj kapcsolat létrehozásaÚj hibabejelentés létesítése ezzel az ID -velLétrehozás dátumaLétrehozás dátumaÁltal létrehozvaÁltal létrehozvaKijelölt szöveg kiválasztásaAdatbank:DátumformátumTörölKiválasztott adatok törléseDelimiter:Megjelenítési formátumMutatott dátumformátumMegjelenített értékAkarja folyatni?DownloadE-mailJelentést e-mailon küldeniE-Mail...SzerkesztésFelhasználói beállítások szerkesztéseA kiválasztott adat átdolgozásaSzerkesztés…Widget szerkesztéshezE-mailE-mail beállításokKódolás:HibaHiba a CSV fájl megnyitásakorHiba az adat feldolgozásnál a %s mezőben.Hiba:Kivétel:Expand all rowsExpand rowExpand/CollapseHamisFast TabbingAdatbanklista lekérdezése...MezőnévImportadatok:KeresésForegroundFormátumÉletlenMagasság:Host-/adatbank adatokHost:IDID:Kép méreteKépekInkompatibilis szerververzióGyorsbillentyűkMódosítás dátuma Utolsó módosításMűvelet indításaAz elérhető helyettesítők jelmagyarázata:KorlátozásKorlát:Átugrandó sorok:HivatkozásGyorsbillentyűk lista mezők beírásáhozBejelentkezésMManage...Kijelölés törlésreTípus:Módosítás dátumaÁltal módosítvaHavi nézetMove CursorMove downMove down of one pageMove to bottomMove to leftMove to parentMove to rightMove to topMove upMove up of one pageNévÚjKövetkezőKövetkező adatKövetkező WidgetNoNincs találatNote(%d)Notes (%s)Notes...OKMegnyitásOpen filtersKapcsolat adatainak megnyitásaKapcsolat megnyitásaJelentés megnyitásaNaptár megnyitásaMegnyitás...Kapcsolatok keresése/megnyitása'%s' definiálásának figyelembe vétele?PDA ModePNG Kép (*.png)Jelszó:Kijelölt szöveg beillesztésePre-validationBeállításokBeállításokElőzőElőző adatElőző WidgetNyomtatásJelentés nyomtatásaNyomtatás...ProfilProfilszerkesztőProfil:QuitQuote char:KapcsolatKapcsolatok...Gyorsbillentyű az összekötő mezők beírásához„%s” eltávolításaMező eltávolításaRemove selected profileA kiválasztott adat eltávolításaKijelölt adat törléseKönyvjelző eltávolításaJelentésHibabejelentésJelentés...SzerkesztésSzerkesztés:MentésMentés máskéntMentés másként…Menünézet mentéseSzélesség/magasság mentéseBejegyzés mentéseSave your current versionKeresésSearch %sKeresési beállításokKeresés limitAdat kereséseSee the modified versionSelectSelect a colorSzerkesztés kiválasztásaSelect allSelect parentVálasszon műveletetSelect...Select/Activate current rowKiválasztásShow active recordsSzűrő könyvjelzők megjelenítéseShow inactive recordsMagyarázat mutatásaFeldolgozások megtekintéseHelyesírás ellenőrzésTárgy:Nézet váltásaGyorsbillentyű szövegbeíráshozA következő művelethez az összes lap bezárása szükséges Folytatja?Ez a hiba egy másik felhasználó által már be lett jelentve Az Ön felhasználóneve az érdekeltségi listára felkerült.The values of "%s" are not validThis record has been modified while you were editing it.-hoz, -hezMaToggle rowToggle selectionNézet elfordításaFordításTree viewIgazUnable to check for new versionUnable to delete wizard %sUnable to search for completion of %sNem lehet beállítani a csoportot: %sA menü láthatósága nem állítható beTörlés visszavonásaIsmeretlenA törlési kijelölés visszavonásaUnselect allFelhasználónév:Felhasználó:Felhasználónév:ÉrtékNapló megtekintése…HétHeti nézetMi legyen az export neve?Szélesség:WizardFelülírJYesKiválasztva_Műveletek_Hozzáadás_MégseLap bezárása_Copy URL_Törlés...MásolatJelentés per e-mailAdat exportálásaAdat importálása_Új_Következő_Notes..._Előző_Nyomtatás…Kapcsolat megnyitásaFrissítés/ visszavonás_EltávolításJelentés megnyitása..._Mentés_KeresésNézet váltásatFejlesztői módgo backgo forwardhÁltalános belépési szint:INFOmmodularity, scalability and securitynext yearprevious yearsAlternatív beállítási adatok megadásaBelépési szint megadása: DEBUG, INFO, WARNING, ERROR, CRITICALBejelentkezési név megadásawtranslator-creditsWJtryton-5.0.17/tryton/data/pixmaps/0000755000175000017500000000000013571264253016414 5ustar cedced00000000000000tryton-5.0.17/tryton/data/pixmaps/tryton/0000755000175000017500000000000013571264253017753 5ustar cedced00000000000000tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-create.svg0000644000175000017500000000040713463252532023272 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-translate.svg0000644000175000017500000000067613463252532024034 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-forward.svg0000644000175000017500000000030413463252532023467 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-bold.svg0000644000175000017500000000057313463252532024241 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-clear.svg0000644000175000017500000000037313463252532023117 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-remove.svg0000644000175000017500000000024713463252532023326 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-color-text.svg0000644000175000017500000000043013463252532025411 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-add.svg0000644000175000017500000000027113463252532022556 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-bookmark.svg0000644000175000017500000000032113463252532023627 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton.png0000644000175000017500000010726713354423127022031 0ustar cedced00000000000000PNG  IHDR;sRGBbKGD pHYs B(xtIME 19: IDATxymgY5ΜCZB<9T|T jXZGVkS[)-jJZQ(B"|gӚ^:B y5gu_~?qÁ=zѣǣ =zѣǣ=zB=.lZ>=z=z<ѣG}ѣG=zG=z=zѣ=zѣG>ѣG=ޣG=z|>ѣGcZIZT ![u4Z󖺮x=zxX}!$ix}|IR,#scc!!P5MP5 er`;w}mBV =z,M8vqi\s!B@"{O DJR{ fBk-IfHӴ !,|?g­%$ ѧw#ѣGoԕ%O\~J'sWd8h$AkR%%u`@ BR59$AD)kb`VesAhJ#2~-%EOyǏ#M2RJFDC Zњr:{? C@iE3 qj޵Yv떒 $-Z8p#Kv D|/bޣG've"o}sWԧ^1 w!IvlZ*lmm)iRx𝋽-lmNyraGkM%ix:iS%TU&RJ={O}Syh4b߾} $cbt%w[R| $R@UV8>Dr )Ep>xѣGuk5W?'>L&8,# GJV 99֚$I3Ϲ;;vht:E+J)8i)zR"OK!!HVG*$ i\ʵָmMgH);_e!/p=zx\U<𒗼#/Ah4چ4KHAJeZk!xlUZu]{/ RJVZkF1@`kk m E]4 Ob I2xS748Z,9G4n,KVeRF#&) &Ih,`l[h0FG>v {=zq#_z9_%G.(}++"),84ZsTr!2xe@>H!M]Sבe)BI|HRubw!$ u]w94N(w>b}m}pl6CJ ؝Zh-9u$??}&"Mj6~KѣG0nѣGɈ{g? uD86] +$Q5O]U[꺎er%;[,.xhyYH%iZZ(1e m74@ P5 Z+8EJQ4;R"B(%۱H3&IO|"Ox8oޣG=~4cOpɑ #dc667@i"2U I>tu-BYܾ-mɢz1&R7|Ii\CZQ,ц`HfFUThKLUbZPIb0F2wdYJb F3\eIM5F+㢔m,p6`LolE4%ZIwL&cmux4y/ nXWYx/ѣEa6+:g3ɲbyG|d<4Mb6#M&) i}nڄ,Mc@=ilC}{>Ǚ31k]鷥u9](Uآ 8y48kY\[r۞Ùhu]6%8*fJb}TQ9b1h{Mz?e]x=zx>0ʦO~Ip8auxLb IPB-&1EA$$(˒Xe)[\Rt4M0&n\X8lFSQe[>PU%mTUR,t kł%E5ӕ̸D]TJRy Qom)ԍvt10L|ӟbZx=z88yߺe_p%yEQlF4\zH7W]wA`0@JIQeEb"K}8$ eY\-"3?.R*=Vhm]|x#3<Ύ朏DnM +L& />,I /Ew,q!ek9*@( ." oھ<`k~~£g=zq`s\+^1$diRxp0 ;[ },O;X__Ckӧގv[%.XXg9}=IbB B rBDᗦiH<1ten=>8`6Ɛ9{,'sʲ v>k:j65ibPJHS ٌ|٣ǮwHѣGG:og$kuRt<CU~6 w@@*FsRJ110Lp6f{Yx<&xѣG/dL|7'=,Xķ.a{#Y{A6RlƁ: x6K672oZxu5۬mo}X$ Œq%4CiN$EU-ϣш$IY.VlwZt2AIr{OYK_oZ"ֺc˖$ $Ak,gMijԀ8AD=w=$yJ%Aju"ox)Uѣ\1/,Jԍɇg8S2ɭ,K<$ix2Ulw'51Cʪy-Qg&Hh0)BR)ٳEq,<R. Sl3, b>ߥn dmcJYBsO}VΜ9luSۇ@60N9u4D6\zɥtMZg %8}$0OHa>;Nd:x3NiCffޡ!E:ᝧjJTV4Jk|jUZG=i|@E-;;@hE&(>YVQ-jkI4`OEqv޹Vv 8Iyd돣޻Xطo~k_h=z >xB oYQg=M+q4uC~\VH(ܜs(!m|dZ6mM;nEeB@Кxe]HCo&mtkbX45 dg>'AD{<;.njIwS AQ6H4@ .P HTh{& JDQ\yc!%I*e[6߳>fA*s-B7}?>_X[[ {<^z! ݿ7r~ëPH7;$)_>}|t^}̓CC8yRra=ѣ1><ҼuSs]wrmλև$++"M> pIn9ydTot־X,floos!Ҕ-ۼ\BCQdih2f6eY7Fя|Gv}c6a8ߪ3g΢d{k\r 3$a0weEYPU%!xVU#W $eYZwYW;;k?0_t׾Z~?gu^|=q~?P._x {okj;O|7 {v;' ^ӮyW\~ET|`ggo|?Gˋ ×=+ykaHkkJ)DJɓ'XߠkN:&4傃wiu]uƩSIӄrIUVlllf4t6(V$PUQE "fEU$$yZ粺V%M"@4"JFekk4KI҄@1Գ4n* M\0cDR\z{$IlXֹMZ:hQU mnއ.Tg dG 3:U{^_~g~7菿?B=H/^z`7}|/r ;v_r~?mb%_y3DA|Ƴx3ō~'o(>r^$xeW??f1L 8*؈!b>'IAa rFG2SVłgGpe4)^xԍX DS|9}uC (8!xmĐfYn,ˎ^܊1n(y DK簥籕Nѱ:pzuK`l=8֔UI-֭`۶!fy@s}ϙs 12.΢J5W_%r;.}ρWN^o|؃7o9syW#?s^uUn%Eu ׽1_{a4oοv:^_y7sem:A=Y5s:UYy=/mctg1F`Bgr)JH$a4qinVDi]G!fժ*+(ZӤU[rnj`\rkغJDYRe^1Bjnڬ8GЎuAV0ˣh@(jkIh M R* yCAeUO7Z3nqhR()¹8oxu/$^/y܃u/!TR\{/P|scoo}X=}y_=%/O7颸wg¯|QE/ :ʳLswIh>]֚|?) ]3i±+rYbwwwmghrتAzQ[;,lrb}cM!yeQ uUAbTM|>.KHPYk!Y\gmsh_I{s~|9zyyރ*-|c p b?[?#?47׿{|+~o{=kk=S#<Wa:@KM&ƾM[ I4ilMxHy=TUɓ'llQ h67>lw.ȡ(ռ7lح=f06;ۻآA:)RzÌEbQE%~`38>>!%R.r& "bU"D;ĠG+Vh۹\.Y%i2 L&YFTeGĔ؏0P5咝]nm3)2Iّ꺎gδ4 Zs1pfiq;jkc!V dvc5&MDTZkT!ےF)ݕnj1$A' "MiJoBb>ɱ,EXkIZi'Ηkmxs4{}ݝ狟%:/x U]{{.%˿ |=jƕEw6d F0N Csh%ަjnFoP;|gXr!\c Fـp6=\z2w`>p"Ǫ*=vם~]:KX'Oa6_,˒9<$>D }8ry>@)$Զv5&SSRaCr$)I",7s,_cZEbk{,J|j0_,ٝY 4QVru,c-ۇQUu-uӐѮs(}h?bY|O9Af!. %mMC]U8kqF]uk C:p}fPJ!jTUTHkzܛ&;sRJ&Bm_!_#\;_{a%|k7^@k?L3gN? -%q?IOIO|#G.KpWQđCGrٚ4у[klcYLɒ'f40G:pIHЉa<rwri>OSNrf,gΞeg6c\LB:}epTe=N, dYN8͝w Rb]t+ż%n9,+y6` ]Y8HLxOOO&gǟp^Ǿ뮻 (ڬO{Fӿ=gNǙ+._d$(ccz<2pq gcm-vKkK6< 6'Or]wT5ij9gss_d uSSU[[g"eS5k?iblی*xrU'S4Ŷlw$Y6[,e4eUSVU4 sʪbZ* vvwY8[E6I/~pd'QnUmS ! !H H6ir9p8JNiVUUaC*Պxb1MbMts("$tA{ﱷ@>gQvv/V*s(%Iӄ߾//R~gzCzxC7?_l6,ZxX!{ywɄ,ZJhlgjגvwwQJ1LIIk++c<6HSR08?`c}%egEQ* VqK)1vLKi"ʈ%nm >lk*+# LkqRD@UU4u*Byniub3BsoΩӉ4z,pit26UKNi]v BT+w:Ekڔ4,z9t#WߒOi~X,vE~o:/s^|?og J){xg¿~ww=v꼎~+_|m?OO~mO߫̾q(nϸ]\+o6ov"8|0(ʳ$H u98x J)Q>r5ْUQa.lsT][?GF6!pKY[[pxrUӸH']VAN0,Yj4XPT%J),fӨ a:ښ@`[q%w2.."a-M'8 3˰!49|QfLHr5o+x$d"na ( 8$%x_Ϻ\%}{ϑ#pS{{V*矓WWA>qǹw*_ }n>s)>?=~/kӾzp!M\~.CXլu%߽&s 1kwDZ XszLu]b шMkl-f{5RVU0kKLvgѐ,&1ۑ@ u+84Qj\cbe%5uC4IȒjESD.=u==W E12'cҕ4C+AV/ViBBRὸMe0QU " j+#Nk"I+B+uM_B0? WFkB1 !soϸݟeBAU ~wym?>"Džg?YVԘH&e,7֢,V3] IRRVMSh8Op4"MS$%њp3`@2}YkN8-"(ɺ6f84U;eVQރX6$IN˒N:VuSo)\IY>s$Cflg(;Erc ]EV%UXiѡ-m6xO}6Za$iRt=w%%κhb9:ǸEzL zReYU>Tty?n>?峯_խ2}Bկ| ixg rvC7*lgΞỿfMa rj^q',";Gt4(˒Y6cs>| B,;K,UU\X8׬αZ.qւKNӧcl?mx2+.ȑ>|pRjp0`-+4ŅXP:f6 hakȑìV+@ɸ`V-%ŒbD҂c]w3%$eY\X.V]]Y*,KB CmF4!`h0D)E"\}ڎ gXY-{,8{wkc6 蜡n kksOzf//+?Eu7-^B|ݯG>r.?9?]\ɱˎ%4UY(PV%uU3rr603ee\O|9<yeGPXl/NkkLGS5&)R8%K ,р ANhdj0lwR%jISv)Vs;KS7x먊hXVͲ&)kO^Z|$l=|wFYxQҰFe$iJY5$Ud O Ֆ_@},UQT>7(pv}ʞ UU7>? M6}6ɪbޯum?$I80X[[Gf|iY4g8n5dcc mUYe\X)ٌZra1kc66oLI3u5RI!x&s!0)PFr%9~Q4*+l;zy\bb\E)NȒbYpel U]"{b9=n6yŊb& Yשm=Y,I*wX۴t,O0YH~Tk"TWnrFt{l׀m LcWkg>쿗VOoŌg<y;ˡ{k"Uߔ= 0;v윣tNZC;8uoR`Q8e-=c7iV)TۆloZru4ͺclFb <ØfaFo8z|(KX{a?m(mH2s"-EP:MkP2Vz{V}oڹs)[R s.)Ι/Ѫ)-6~%+9=rc.a>ޛ}ѥ\?kr oyYms=[h$ X+K,XT, N*P6v*WEa0`@F0IH3I3͢^n{wm=Is{Fyo{=ݿS1II/zQ_NБ|yi ZSUCOM{}r:ZnΙFbfSu{Bθl,1T˴]6)+6c94M*fְA@SU J ٪$> ,Nu=a[kqvk'x"I3-)k|h%?8=7M3GiE"Hu8kewg{|}@Cq$HD“&a"\E]5(m Beڀq mW71N"$n9U~M'ePdGV=,_W \?p3ʜ`bj={ӯa1_L_?ЃO y#0|/{a~_7⶞Tּ^K {zZOc9p9cZq|don]ڶ#B(ehfw] XΝ;`>_uEH H2Ϙ͚)|cww٬I8+i]]߲<>f{MeYPr;; c۰L n4+9z՚IxZQ9+TRCqsu-#F-Y.t]_Ho\`u7(Nʒ8Í0ċ YleqC[i.fhGϤ,fD7Fd{|7|ӳo)Ϳ73_/⮻.9o{뙍TnZs٧ݯW^5~!}|髿t֧/x׼F[Xד3LڧĜcY'*փVz&L\|PvUee^Crwж):Z}uLSg%!hBlp]:i}!1B$%kҙDKy Q]ڢ4spp@xD%dIm~2ɚgѤ:ַhXHJb%J8gH!#x$XR oW i-b<l.&wʘ& h9n+_;…;| .|RGGOEWn|3kJH)٬Iu]Kjuݮ-愋98Ur7._‡(~;/| 1αZY\|!$f}8g55ͼ'Xqﹺ${6+u*4峡3gAdTUUIjQX9zBs|D:hn`n{s)X8gk-IH,i9âIwJt ucQ@0 hB92dKI~c CNɴnpZhBFHbb"+ FARYE|_jПut|o毟{-ou_}6G虃T>O=Jf IDATw~}ROO'mm{wmN h<^,1EUݦQt+XJ3K.se^J 3C ٴt_VS814n5;hXY~QҠ5TZ͆C_čIY#'H}bƬc [t5_HE0|]yaMHj'A"JKNx@ C1IZU0Х&(D;/ef(8-OU$ftvZ_[y7[ퟚU7nH<أ_o=75/}w/{MOC ?OHXbfwwWu%^)q>1Q vv888} ?wh%<>$2 mwxxȣ!]BTuN 9^.R5{$"9/fVYE{C:C6mGYr Xg-X#ׂ(d nbѨkj9g$aE,ri]Oe\%Z*ș=bLxߓSf60ƒEH)ڊbb:sSU5]XI(VkLi }.9D/hewBr[IF&US3ꢁIKR.))L}+l Q_ȒsPUr aTIdQFY3YuT,S7HI !)s7Yyͫw; \ =r7vۧ,M,uճ#1~^!7~裏Ly^F۶Eb[z1򗽂*|*\\(j649uca`ny+xߎZvvCS7s]6rH Jm{OL"cҮV;՞} }lWĐd2`݌>(^ Kʉ~h -:>]e[0P; գ#Wt풅EŊZϥB KŘ%KL)nEdcm,kR ӵq")\eY{ F#9(uͪV(elY"E4}9]3 .ӼҐc5ϒe{+rut뺎?]|Xoּ}7Mga]yG}uu6}}2 wOD+qMbv;։A}Yg9:Q8:>Gn1Ũ!yZmf b|$+t /zыH)c+c8wpʵ!a'@>vww"H,1eϬi0b\; rG[MU~A)LɫVg)A( I|Zِ3b\=aeC }7~6ȑkih w +ч{y i’QL IMyιi]3a`Bΐg=+di4^iZ;bJL,giF mt@ z C(d.IJMżś>7~g0vʳ>g/{M3{<iLvםwy?m}׻w2]Qeo…pn_>y衇Z>ZMIn.@G7cb}ku]{44u=Aܪ{}!ٌYm,!DаX찿#h|ְYmlFAы~b6V;}G{SW9vsd/|x;`ZS$D+ᦜ2 Nq1+kd(1 @J`m%5{ '9֓UT4&Sc;1 fMLLI;9LVFq>PI_*#~X2Jw8'4!(c8JZ ^NCTI6xH V;.D4ƐKϯ> ͆fͦݰٴ}Ow7L1bc?Sg~c}͹ o >WkYPx_+_.qE>GyyG?ి׽λ3pb[m]œX3^[gQBPM,)4Ci֫a&`3]߱b>7rn*r,J1a F*EK& Бˢ2}2yu)NWB $2 ?Zrާn*ߗMy^nόR–_QnPrֽ<"뇞n#2$̔+' J0ؕjY+EJvUwq~|76moQ9G}\\Hs|O>W\}n<CM.;+LK?M~=kgr u_:r^=ʕ+(X,yǝEF6둿}lvMӟϚh|K^Z^rC6֫}mKTuD.XbL {!1t-~ph99ue=vwwAXHֽb~כDYvC$d(TRE(Px@ r4 $W!e^sx*9ff u]]OF;4B4͌"%DctӤe'+k(;rg-՚9꺡k;?;G̉9a0Pv2D!xW6d;+55:gb,.Sz e܍1d)%|Om}#S*9!oݙ{__47x_￾7L*MO7ԩSiRwy|fuvm{oOzAz('>7u]hiG];䭒jՔz M3#F9WqHbꇌm9\.98l`S8T&bLd$zJ:Y֊nX,a@~L)lzy?h G/ncY,%*kơh\CfJi]6/Di*L$>⤦5: u ɋ-mH^ 2埠8ݙ ʥ)Tclh3L/ ͚(0ZM17t,oJ50ԉ"'O!KKo{jY=sZE_3#>Ce7lۖfu}['3;㖺ǘ8z ݙgyޗ? `Ɣ iȠj3>ƉyZ|sEmOZ\7F)цnkX7:b\"//xӮ >S]=z]Ԯ{^pQ$1k~Nno; .#p}/^_^ju=.rغr#{ZŹݝ=꺦<1ueq֊X }QwHUTN/_qNK10aƏܶƔ;N)v-ˣcZ+njdBWmE"_4ƞ,W+s\$<ɡ]re@f'2ϥf> _Rd[ʖKꦖ lRlPS1tQigǐAh#p_\f-sANgF4͌fuީT3϶^|ݽh﹡p_1`TOY RbO0\:bd>a|b$e&ҟBO9O5#>ГT1r7ybꋃ[ꑱֲO޴-8?;[Bwoow7/yɳ }Wɫs'>| ` zhvu=LHz"YpU~`ZbggG$\IڵH]+I DP:b˗1pb,Mj="T(v{bN,M%Ҳ"1lr$tj ZU9AdpLۮj0۝G~Z\:,3!%\%kZ㲃pLqƜ4d5/lٌ6lD&g M-Y2rbw %qjSd+EUW&wdy''L2 r)ERT򚗕Vs*r9NNDL0Sve=yI>/zՙo< <ӟ_M=a<=-w@},x_> }:kSUs2 uh, 躡L_*I5 Jx)À}mCVz;F|?`U @v YQUuYd:L*f IZO*dr)b)68d;D}@)a+*|K8|6si$9k!@BQi0P7}bS=ڔ=F}k2GRKOOyɟ+AnM ik3Zn|^B`^xMݿ.6Myb4H>yqEOb~{?nn͙X~s{T!ӷ-<8sw_Q|;`Czrmh.~4;DzX3/rTz62ᙤ)/fvO6@ 0t%f-I# 1@8]g{JD/^w뎡V vYTo~%H#eĞr -MjcrSG׶ !LZ[A-$pKW05& @JE530j*P G@kT"HWe _+Yw䂈,$:0ɠh*qʎxM. /u]\wyΝ;T9ln?O^rsnvo1Oc#'n1&^ҥ|x"Lkc+|%]~BOOo7y'3._;/Y/_˗ow77Mnh)4Mى1~wgY.hYVh xY,D{bb6_@u+lcR9b~f&􁝝9 f.}mQH"3]94 wu)8P8RF13I9S73.(#_2Vkݶ6ȼb \ql6k=`o E` >EКDm˪1J1k 9.'uidZk FR DۖfV3oFq'cI%粫vV5Ti$K$8N6 l_TeTJo[ۺ \vž HHHwww|B^d'S[c@YS׎z-зhr1[%;u1`J[SyL(ЏY%Y) lr.v4 k\mm{\S〰@IHf!rzzN*q4 k@g"Dp$ehq]O ԝ#à IDATuӐ *Hb9$y_kp!e0ҼItLڲBؘK֔3Y&\36齣>P {MP3\tqmk[7P#Lmewo5#LY[,ͨ;n8Z^F51+1()Z18@( ,ňbJaLbHWd#]ZI#Tiw20jSVT#D,+m|/-E"9m1*%YNF"]YMڗ=s\n13Y+2eG_A?CFZ_=)6σ7~Ǚm;+}ᶵlvbBVwr %QJcpS6a6_oZfquӲHbV8>^bYN\ByajUUMƔcaR1d? ԮՒYSW91 CyL+d`V mD/Ľj%وq+r0 .,1 $mB03 [&]SbJU=9&e}'R0}dG;" DZ.SxНs.¢ʧ}o[nv˿Lse~w~kmk[7 \iͦaX[咶 !\[?]WXW\u"͆;/#j]f4ic/v&f nwu5]YV`M+b}2N~ي`3(k;ah; 5!FbAB2]H YB\"H];z!EȲπO"/ ;NZ4|OĮwN!q]kT~jv>y< "}3h)9'a&o? gΰ~˯Dlֶu \i|ܹ2 [sʕ+,KRJ2=Ȕegnw`'/]$?wyutΝ"omd+h۶x 3;C +cC$6 :|L9aX7 ޓܾ͘-DJk`&&ZcdӶ,W+ڡcJ~r']!''b! Qn˺BҘ1I^WMxăV~|t;MuzJj"JAm6}j?X!~B`}77ֶnB]9<̹ _)j6 x|>m7u2>xv8 /y+8 ̍jj&]BB@ᜣ:^u]z|>hϦg,;OcuBdXŬ[1y6 ĸB?G>GۚK2nz{ɞWM9#f5H3Fe d1A22yet:ՍЊvV&PW5˕eSt9X8!⇈JTfZw%p4!LzXS3FyNDw=0,I@)buzbrzWhйS&jFɎ*1ZUFD˪{ѐJ)%yFe1xQ^^T C)$:Yo{uKbռ{~m/޶u=0 l6a(y \}Ο?l6뤹 P&85qU%buSOl%V*tYc@8iC3_fd뺒C^QHJX^۾z|t]GUUU,Gf +zgm Qp`b(mb֚.)k@]q\u=VTUsF%#k% .m9ھg=!x+덲]Frٔ*v*/T]+O6]ciHd^RʟonNP]ym ok[7u|vj#V>qH)*شkT+2#Ue35cCUe-~R" +c o7{>?}񶵭X}0 x^7Ҽ6dSD+UtʑdRMVBqz[.ݣD9?`\ve{5(,? 0ZL 4ut4,ͣ*d`]L:>]}M,׫Q/$"gf7kr l֢ϖ 12|2+EUlKBJԵ+rY0ꋛZ#yb5ui G>g~ {y˿|ֶnrik#;`]Hڹs穚쏏9>>Fei5B0Z56, '̔h!W)kP:i6 F <\&Gk%+P4Z[RRyOMv>*>CZ"b92_@t@L a[zގ)ጄ !r4Mc^M>HI]WfRY\*֪)o2J%r-Y[ W? x񡤷eŕسJ&mR9SӇK6En$Da,)IcC mϳ~իn[ۺeÒ5ik-Ւ gM-.bjm{i9c-^bb#7"fˤ4͌z΂2N]W 8&i>_o6b Z Zc ¹C BU4{Ȓ.& L`sc}BM,„7$:K~-P%>?=fdw#A(J|s䨰Ɣ)]hz3MIdyj!A82dKR|0X4dܔV<o{uo+ֶ>}o4@TsUUR`v:EF@f; 1t11C0k)3NٖPmۣ:LJ,3|C?)?.PLVtmV9g=9Eak!i-vvNs%K\[C2cdz3Ύ(4!TѶ5uDuhjG=@ΈMӠd/Ѧ1ڠ4 '0C= ,M(M2WC{grR޴TU*rJ8[SWSY*OI@Y!=)%Sl{ (I/zX=99h[-}.ޒs"F33ͬ&qj*bA -spwd*(q XS9U>Ґ.B= CѠwS98[dr?CZxROU !Pc&{c4Z2HѬV)ǔHŗ8 !dYAtߖ$f% s^kL\jIbZK FLiaz &‚[)X'X<,׺Y^J(9%JМ09&ޛmmֶ4 =՚ۼBʫ5ԮY',P)Od5 Rh~ClF 3B{ @ Ni3c%X=ah*E׮hcRrbj4G,;h#J41ZӀ&'VI\{8e$C5Ul^%x|@[[L^41$@Vw)VhޙHe̬3fb@\qC\s q  2Fb86ocg2ۂ2#͈ 5U99_D񼺁$nx\|9TR3N#{ ǣzǨmiuŦto۷*c,XgǵW2 =yxsKIy3L͍Ϝ#neZ1;k[fc,s*M] gst]պuW{'nnn7rl$l[]jfccy k{i|IXLJLI0=8oZk~ѣqaGܣ[[ly/<>`7y`!N'!Pb+WWV1BcZ0t!o{9}-77 v{v֦y&ͮ%΋[e"Nl1 =yM3w牾 q` uekZ! ETՈ&Zeu;ӄ۬fqВy8:N)R4=g-7U9UْT5Y8O43M1ƥw1pcGm-Vi"\V 겊Uoh]Mϯ׆=[l q~-kVťBt'P&<< 9xbld4U9uXg5ɶ ? ֶNJsۑJt:qu>PJ^WZ`E[Y.(:6-5Ssm6&:ӄcHK*ȚY)XŎY; aįik-:y^&n2 Vm@[ð`M=۽=q)oL-K[^vkǭ]ƾX(,Uk G݃W|[l|(Am<>V[\КrJԜꬹTwm]K۽!N|PCu\ޓKfoREvÚ%!R{WfV'yuLz.Kk] L<Ԥը5V%y^+fIx͕@* }ߩJйS纭(^mV0ﻅYn?pF;qZJk]*d.Bn:B%MI\.Kzo~y'[[l2O4O-iy2uea9X Da 4G58i" !oHZwbV~ziЭq#봭>O=KZ1U5)e%ٶ˼4y/ծ`heV\k]&8Yw56'd>h[^G2:`cdm/M^R/jKTVW15X^0s;ɽuZ~>/[lo={O}S;"7qݫ,IL)s>i38Ӊ3|@QEj֫Øsϳj x߱UT2SJf^k[^}i2yn45㔳njmro[Z!PRjݯܗRy(Kmݢ=ߔ,zAO)҄o? ?[l%?L9r; 0gqK7G:l$ibxK=Ngn=Z1NQaJ):{M4gGvi1ILx=.e^|YhbDw}[J)5tCL%H~mczݕG*}؄ E 1: u1*~CUT\oiz~ ^ܹ4y]織nUԨv=8+ T󗎇5\(u_%0‡?G/Dl[l_"Rɼ뾉w󛩵p8cbnŇjը]nLl]97Fhjb/<f5soPӓ{mΌѮDuxgu_XUWluMD_ќ5R3/_轹\b-;1e\k<8MHѣG Y!>&\k15X{yƵTˇ`ysʙn5i+RQTd}2c*S.J͔bթ9 Єќs\WhPWtR ߯kbͱ/Eб՗Ų 3.}a:{sko[|x_>[7<~!cĕDg*Ntj)oj'O{ݑ ^y9y)7іK~70N)%51Y 2b\ =έCDOUrXT֪ gmg>Z5 ))G}ɉ \MCLA^ѤVT &8,1V0έUsN_1sY~B-)u}m5#jjg +dg,G ucǴZJjJάu [V~'OOs-LJܝ"1cg_!b#vIsw{x]Ou\]9=xHͅ'Op:8T4tǽT!6_aq |Sגk/ˬB]ww/ȍ^VU/{ZY{G +q~r#gSp#cn0֩ݦq@{*}}ᗪZ-URʽ]v/%[E[SK' |-u^]J70^!3R ww'|XwGvW{LoI7:ۻ#4Mcyݰ!hKxga`z#B%m|R@.*ZƇ0T!İ:<~Lc] 1FJYj)VJt:ru8HJs>Z&Z\Ƒ 8m;mi: T tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-refresh.svg0000644000175000017500000000054013463252532023463 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-unarchive.svg0000644000175000017500000000105613463252532024014 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-menu.svg0000644000175000017500000000030313463252532022766 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-export.svg0000644000175000017500000000051013463252532023343 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-history.svg0000644000175000017500000000056613463252532023536 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-star.svg0000644000175000017500000000043013463252532022774 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-close.svg0000644000175000017500000000037313463252532023136 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-align-justify.svg0000644000175000017500000000034013463252532026076 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-print.svg0000644000175000017500000000044713463252532023167 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-search.svg0000644000175000017500000000060013463252532023267 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-italic.svg0000644000175000017500000000030613463252532024560 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton.ico0000644000175000017500000017233613354423127022016 0ustar cedced00000000000000  -00 %.  8T(d00  F&00 6PNG  IHDR\rfsRGBgAMA a-IDATx XM1U\D2Oi5dL  2e.RDd!u%4 ) q}y=λY.(_|wVNFjFvFvVf,g^degeD zmyye>}T7!OT*@(ʔX|wtJJUUQɁ% ʕ-VړꪪTU՟>PxRj LEHn8 C%Rz{SSS޾sMӟץ.MpJ]7tu_oNC-[VrlHIIx S'Oo킂uABVWhobblrج !(ٕO>ĩOt|.u+B^V+䰉iE3xEI>v2ϼOyeF%ooһgϝ:)u^̙fwtܷ+R!G J~֥{ND"/_ݵ+rPՓoiI]Pviջ7jԘÇ(w )e׍Y=#+6=vjիe9v^4v*tBGtXt7mSSMd)jYO d*.3^~ECzQ<5k~E__\ x_{ކu/A $|AEOO ^^7vm?=>`-W- ;-H~0yh gϜ3cqd ƍ/n-=&-zzX>.Orus%#z4 ڶ9%<Ǐk fw4^֭͑ι<|!IէGAQ555q&iiiuLNK{M Sw2]vO z Am۱g %%w.r];wYnU-b ϢkCR BLj[p` 66zR/p*`nn(Coo>|I$z?|E%>J$ ZA$dƍ9 [rR^}hݪ5QT\M^$.^Q䀪U+H9|A_K<N aWNH#14S&M6yw 77fV>|P§C|k׾X+(( (tܺ})@kǴEo$  \8BԩkBւfmzq/X /s^RP$'Q+SпE/_IaS|ʕ+[v@ Xi/;; <}< |x9m{wۺLt)f`!ӂkC!du0wBX>tNBJ*A:" ϟgZ'J.-cx4g @/a6m Z ˿UV`3ڵՃ?WCy&$J#Ikzyv#k$>S ??3ʔxouLM77ש -?~zM(<}tF ud~0s;M@\XrSR0y<C' Wi\;sı..LΝ _OSeZI>:Ԃ=3Spthή'O)|~[)?qv Aжu[VŅ'~'z!`m`5/x|?:c۝*†A~uW- @C FGF;]5kw`ѱͻ7&p| 4C tM=oG=˵GuC-Zo?(Pnqag柳Co^ ug.d7DEo}.noj5eam">M@"?z7 o ^\k%y' µ7y#fx ίVUgPOeѤPL<ҺU".WSSom\6iJ V,[f2kONsx{Mow|L-Zux<*A`t yy= 'V{V-dgfi0=8,d ggmX8ϮxCѦmLf-G"fs^ͭ"BWn q{ `M6j޾^( *URՠΧ/_K [ݻvuR',RS2^ /ʗ+FYOCpLmsk+ P 9)а&cwnƬiOD6sJ|2i0l=BPUUGXkw2RpIN wLڎ;!~&?Z{ǒad , @p 짋)ȯA&tmb`[V ,  )b7U5&H$M6>,qajb($3 :5ƆJ[XO^T""[vvCVv6 M_Ç`4W * 4k6oa%U ;S@! S'Oc-<~ Vp6 a-+~p=?:a2p`Pc;*UTQmI@*3>^~ЯO?V"5ӫ/ `<?r*07`~05 nZ$𵛘Aix8 zNGaQ['`ƺ8YJLt`iy5XQ@Id|УtAγUO * lQ\~ L=_<typ@A% C.$I:۝`&Aph @n6J!,҂UA soeK 6`񏄃-#=-;Ł=;w|NcVڢQ gQvUJ[Z;#'rʬ5x ~e$`3fϜ#糳[Jv짏e=Ld J. {@MMM6yC]J0jڳLT$^ )܇VJ%hbBV",5~ 6Q*IS&G3 o ^Gho܎0q6&O<s0bu, S:v7{p1+>6U&qC+J}A}Xi M@ QNaD?,(Wΰ>lkJ[W^C #JxJcC)(} \`ȱԉD"8"X K$I7 P5Up{;;vE_/a$ڸ-)'Nq*|GhѼ%lݸf ~*@R ~C`Ŭ|RXq=a$8&H^0e Ũ `(_<3 ^m(z{9s7}T8H^$KcqIE@Qa3AjԨ)q'@dOb!^j- 0v0̜>KIv!??_RL8{Uʺ//@P}LHמ鳧 [k;p-籀H~=;VƊl56 '19-?57%233Q#ܾsKMLu^R. g{ {1՝6aVX" z:uW^A̾=qK8deenwᶗٯ;*DC[639[Eַ¢% !zO `۽:>|,_L! Xk͛`lNexf҂밌 `H Z^K!Nl1E@e{LE6^ȝ$lwzԓq1]PdIf cTZF2 Nl[7IG0oğ/((a#yC1MMs(̙ d{`F H_"A[mcf#&dm^xG9(ˏɇArdvEK歛H˟]a%R1kL'׊MO[u c;Q999$R@$b b4ґ LwGtQge6v^KsK\R67o˗w @ܧf1g'iK9/{R; ز6<do wRwg +#AyJ۟&HU8,\lL -fbt0iDSΰz Qf?@+,x6g]|3 ؾ96i&U;脋@&M(`B&VqIpH êAR}ϳ}q &84Bׄ(ebc=ˏ"@6mZH{AP4eQ2"m1I̟$RWH5{6sShG=$쁵?` aAllTM?<$;ү(ElU~ X_T-  Z-u;芋,4aܦ*Y5y !!<͕-mJNؾcྟ!%` 6&0h [uH:[o a/˂^76F00u2ϒ& [wJ4ylX; 4ѭLv=+M?QQdT}8Me,IX͂B!U3gI0r(^A$ o"%gժ[pC JGt֍YuTз`6;w,Iuq0 2a%&\ Cƺylz uG ;dU`N]Rp.I (cQXkT4+<CfP\JfӨf?,$2q8{ $uܯ>~L=QCظn#'h>vh_APDf{v,0{kՆe[`ϖxKAob|,cUhby{,]u*  k(a 5mZYks~@pHS;>|e+2B.F$DV.:_JC#KIZs/&I˃c$ӂce-_<ӧ0@ٜPA2}ܿ>2;0UOt8+T#*U~C' WZuNA)ǏAPfX{l7Əui_a=5jBP/^dHпί8L40djphS+7cj5ѬpI|!cCc p0=PY<^cvl~E!hE0g#:\D )U4ILf5qq-;A|N"pG EIG(QsLpو rO[ v0` D!? H/ޓJZ@JCx?.DpOSN:\\(ur0)qZ)K B-W,[Y~㼟>~ ('d>/_5"m'|F$RS A?i+ we{mf/THX`8ҪK(y/}@=?Y;vE_ VBO=K-Z|ot~>>;{ u!5jÁD /#F;|Kнoo~}=!zO\<@@! gUJ[Zf7nѮ_>ӟ1 Z^ `9570fLz[ 8Ç όr&/?g|WgϜvwõ3 K_V1l wW]Ȟ]{A <{wyxC(ϩkҀ͚3+c#ZKA!`U˃򈖭*9)nIh9ۀH(>׆BP:MACm$hJ(.?d`KsK\lٶ.Q(iצlX\/.Tb\!No, r%fc;B,.v7IQ?`Ƕ]X=rLsw1@&9C\op<#%WGOAɒ%鍒3mOjj0^|>s$AVIPƅ?o~ͯєdXxSYx%g(Ÿ B(;&֬ ujbAEQr.I-HL>_ . H۷۷8>S"B2ypr \\\qCx̯׿2/"5kBbA(U p8s #IkVG3,W2nʾNJ R 7sȥKr 4hjي&9d8'8s BZ^ bıf ™ ;kp=x)3,,۰lٲ{=}cg/!(7/5ǎW2o$;3K @Vm@aNO`ݻ`77h7о#jo}3ZZuWcCcoO; < }a:_{MdjjB1.lժ5BD)Es1=zzOzz^Z D,Ɔ&JO(,):QLI9{\yqI#ch۶`= nC\V³g"0jfKZ 1#:xzB*^T\]D>֭__ Z4oĔ%8y'c, [:k"~AZ435g9:~SzfCoQ\\(g'7kXbP[6alٷQLb]z]>].]JY@'N6#'”)pUQnnn&-g)s Ҽ#XPYy H ?Pbwoܯ5m*N2n%3Us @c 024Lے>{p{0]v⑁%3] "(֮b2isNa`̠M[Ý),7XZt&Mh݀'%D CBV-[9j6oٶeԌY(,Ek" nPti +=)IG4ѭ{Ԧ]oPX$_7062 ,)S-`|m$ U`0PPP jѺyW/jRx̜Y@BzbӸ c9*%-FG#-:su >n]P:Zt3 nٚ<% Θ5%P0X`^n|[GNwJ˪2&f`anLp@E|X$f>#== @VVV6tB${0 c.&jҠ?QD`#TKֻk׮0qn+)F sKb'1"l×/Yen}SSQ @_|nӧ ;w-Tp֠uڗ/_ȀO |GD$#Cc@O9 ;;>˨TιuV-qX 8zXW 0A###c`ԁ1MQC1vnWphl޺L=dİ!&$5W LD}ڵc T <Գ{O4Я͛7[oIҟץp>ހTz A+ݷ/lÓ1[=?fO ]j^~$/6O0~-Ɇ6իW&%ǏqDP۾(||md?ϬES,RCCوHcs}?[o;?oי}[iջwIݯ{)5'{/)8*PWj5UԬQ ?޾y ߼f^W9O=e ! -\hc3(i>$567HBHIڷ%K#Ǎ0|֪gIÐ#ɇS( B073Kض) @ZZZ; ReJ}L;ҢaÆwd[f|1yˢwE?q={Ph BؠOTDT¶$ ֧ݻیBL¤ZjY ijj)Xwmhկɗ/^R BX,Y2ˆm]̒b~?nM+P B8xLrr8(]F ۛOEB7~gs''J=j.ہ6,Z$ 8رc9~]%z =v6v/X: |Hy]zA1&#+6=+}'IϚ %4f.0LW==渍1&PڶX;=}<o\?j lV˃---/#GNu@f".ڶ9r]Q|x$''ς;"Fh Ls=~܄ſ:/(ʩ:xyyqzzQ|0FݐE2u.7/-==RojkJ>gUiVyotH+fF gTfprZ8D|||M[;?y?ν#G\0tѻ)P6p?f/]0}E6R\7F)&FƇeO ? B .蝻pÙgM]8!'':u+B+W c#dcm۶=@aكԛ׽zRu{Y3M~sOڍ4nsQc uo4l𦎎] !";;5srUddj<jϳ^R9LǏ|yj~AӇO?~XT*ſW,[]re+T-]՚53k֨fY93U՚5j?K^^_ ܑW/dIENDB`(0` %9?9(.2.i$,' &! ' %!                       ! $" & #*#'-)4<8?484?#*$"#"!  !!!!!!!!!!!!!!!!!!!!!!!!   !#$ )$282V).+%!                                    !$(-(&-($                                   #%-(-50_$                       !             $.4.bUjj $!                   joly}z&-(                &!fff -30Y$             &-(Y^[MSO !            $.41R%*'"         284kolFLH  !           "$+& &!!       ?EA{}$+&           ! &!'    '-)UZW             !%"!! CIEZ_[ !          ! !  ptq"         !  9?:jnkFKG9?9,+2-o$*&% !(#!                        !&# &!$+'*1,r:      lpm#)%         !  !          X\Y.50         ! !!!  X]Z"       OTPkol           !!# 283$       #*%         #$!  V[X       .40         !$!(!#w{yy}{     5;7OTQ          #!(#.4.,#    !      afc>D@  !         #.44,$*&}$              !         $$*$}%+'u!#!! !!!!!!!!!!!!!!!!  !#"$*&w6=6!$*&x%!$#                 %&!#)%z4<4"PNG  IHDR\rfsRGBgAMA a(hIDATxxM} H F$JcA!!]"AB.H""$Z)ea(cQAyYxO {)ysgw/h13q܅{2^=uVy^|[Ϟ{(X . TX?+U<  CYr0eFX@`w!\2&$x`hhF a*3;tyO8@BуƍaI W"4 +5̟PE z;'{}BīHۓKL /_7-} nxB穦_ = 01kݹ{:A|Bҥ*3Fmķ+WN9 hؖ zG֭IU)&pˣ?CO *AA*k{+ڵ?#C{U)^h ؃[ׯP)RےAL6aQbbS[ T$`۴ G!=5U}d&IL AK[ ? I%VCM[8p) BCcHL{L ݿz F- r h\SOB#U@8"傦#7f&uPAS1ڹk,Ah;v0\" BȸvK7n߹MIFj72NO=IZ: YN zuٿ jPD W8yn޼A*UΞʳEEGQ>Ӷu;ճ71fM؞ 7$f䈑5J'00{:Br!(060/d_8O@s/3fs! Ct*U’PRe%¦-`9CT >]PBjT{2G V8ʕо;zd&. -EaTY᳀s܁)U TV=QTP@&f޼!X%gPFeN ^ ~j]I#Tg? uG*JgϞ#Cz;޾}K.3 k׿.rO7>իWD۷I kVڢ_'9% r@ˀG#Ǐ^#Fk^ׯ_C(ʍ T+_F/3͛e7 T䘪83x3iڟwh~@LZa}\d_^`Ͼ2 ,rL1`^(0mOS!>a=Z-51?S!m1+e3f$&V/RHQXtpDF-@Rwl~׼Ȁ~aDG`̆td_מf;ѯ KCP 6'r~=dOƐ9czoЀ0?NDz?8r(|sB^.+ }\xcr 6A%i!ݷX kr!#yáoWG^ C=O?YgDA 0x`nӦ] Me%Â0r9zl+ڸlަdff҃^n. ފz..UZNde6UuɒɁ`dw@^.xy'iSd;{8=xTIG0Oᄇ<Zoɟ]udܸq:(c@ r2kLYAoA6?X@d>Y7 6MleytuMo)Щc'ɯkegIGuQpVTR|Ӵ=KR af(}iI EFcdӡM붲uCw: 6f]drp]J, &@ٲz\rU4 lLUJr)SW0n$ך3o6D\N.斠jն9wY1ŹE*_1&|IE : ع&j~AnŲcI ^1l @ȇam#PY62nɟ[|[V(4FJc) mL4 '䥚~5P52UK$;lR1?Yg3omFz)TXTF Ϟ(K+hoi8e1f$ڤ)ɣQA(YTU2%1}Lhݲ .]N7HN{1Оr@Ju^Ǭ`eN`&%>V )[ƌ)RsJ@ j .,J'O}] ===HۺY{xǮ <: mvdx9X4t[vf޻{ %;|[Wd eЭ ]X<3Vǭ%;@ZLE/ >u]k@-7Q{ će cԱ$3{a2VVI[XS;Ta`51k&r39 mIJ ?փQ1LRqkʢ@oW7Ť-<~ &.=HXUS}=5mT[KJŋUm˔.#-< HC?'`b 8vpdٮ0C8yvb׬-=tk2$쾴JQKA!ܼytlMo¸2 ЈG#K!Љ4`LӧOޒ:@΀6BC4!ށ;,Gc?}ԩ$'7(hpӭ ǠOwT4 Zh1UUpmz]5MxIJ 5 j f |q V,] AӧRKȜ`3ʀ[]U6@,%4HŸ1DGjcp׃:B,҂UA :1Q:B(ض}+2i QY߼u3/+ E*`QvaXlNw%J0iGpie$ܥWeB-u6uY{@ $(PR6orʩIaz|0jMڳVT$^.W^:䖠U_=:D 9Xj|kb #=te&ȤW^Ac+Sa$ӧw_~ G>:2`Ip, 4m@#@z0 /mOҩaj4h߶@Y1 C=x942m̤S^}z#bŊöTCP]tm;yS TG!~ l 4~7^ܼ*;tJeǒ l-f ([Vvncv B#@^0mu9pp? 6P_~U+V3kmn 7Pl%KYWhټ Ŭy@Ha$ѧ~}P P g/v^~ؙY{|`k*y(,-%?2ΜEȞ)SV6{ {wke& +0kr P ݻc<o߾ժ~)X 9pLpԵ#_ ^M)P\yۘ06'hU@ZmnߢF,uuqj slUܱ0Vf ڀ'Ns.׫?+U?Lϟ=w׳O6uN0us|"27d,֞=]a/6M-F;) nݡ]Pr\}ǰiKLVvn{ >ɓ'Z~cAwF7`bސF3q~jYx3gπ $,ʷ: -6MlSl&OBuXƎh|ꂖWiE q=  :[,kőįKj?TS;nFC|-@Vǀr(Ulސe .lʹHҦu[9}]yM&|9]\uZƏ];\μ_6ŃAM@ zC1DaI2m?q wwB vsfU$BisK5}6Ǝ-y+V,E?iբ%50w=zD T* fZn70 OGuش)A~ذy@ dAmD\sָ{ @ܧfMabx}-=Z !wQYݵ\LQ =kVCЌi:>I'&E^1{:Ĭ^I {[{?WX><yҘhrha]d]a[ٔ[vM, veXv q5|X UX%%>#`4yl{_ Ta5a$\'!񤼂Ec^@ tR:hf_"BѨ7q 5~?Slg=$ x_jvְ `m\ 89;w{S#}A:nν7zzz=9yP57@VpvYi¸MUbĚB^H۹Fy"jY4n'hT]0KIoRgϝ\HX z_8_L`s&z_z|& kV4y֣+oШM6?St=)V8Q^H[֓0eL80 1C!?Ç~}=IXx~ȴS!N7m?S ;;bdhV2uTR&!5;"=Q@gXnS.Vb8 :nܸSV]vꂳ-u @.+Vh{>1+V˖DRJ"oU@KVʟfaz:YtaoOp.50Κ#cȿ[a}:fIr/(kpk- k), @*sgQRA!͛36ڊb1U!1!Y~Z懆h }K6;! S'E @d )]FeQ1*cM 6%'7̝?J1#$#b+ yx2K[:qɁh|$%1ڑF?5 HS9 0a{IX+"aET::fS=~髱zh$Y8<³$W53)=9p"v7>t CB%+Tk"Ŋ!N>5!O% K"bnc0dPQr},m5)SDH >OO I'cgɯq\c~ S:58 ~ҥ&rPA8/Qz:?LF]\)x _v57&+{6uhAS:R}q$@@pHJ$6xd3&Q[ lBhHuD?G&L6Jz]uw(ٱWsJv?Hz97`?dvOye{Z*ڣ"1$K|J-](Y~\_>idptx2P `V_)ރ5"{t2HR\9ؑ:"9#y,ۣޣGBdZU:"p\gd%](0`)Щc'HٖcJ_3{̜ +TG+m}05`uDeg'rdD1; :U@TlMLxwѷ1˛5iO׈gC"g-~MZժziК #f͒4R )9y](?٦q_Gc1+'L,5 J*{YԸgAʕ*D̸!6a^BqEd XG "|q{Ν?ρ_zǸ~?}J#! 7C5#ݱڟ׀^SWPխ/,EbWM/BBV7Wg*9hצ%Eh?Ss$ q;~-p!`[/wr/C^͛7$AP4 %tSps9 #+alq"`iCSXtu׭#x\B;9ۣUDtٖ:B ٶ}+_C`.%JzuC9==|ǏBy+WE*=$PD< AK0dP_7n FwfaÚx9ZBĒp{T[Cf>lx;ghD@ I'D93Ŗs;J#I}ӤDgdɒsnќYv ޣ4NCtd  'u6.Hq3Fyj4А0A Putjw!B"y!nm,L>Uc:M6{;~70 g? ~j@I?9L!T* LA$Yp8}4\*\rn߾ůs6xƍcf޲2 ܑq;#;1n-ELTN>} NΎ:oIе<[lRJh 'æ- $v`gkی꫙H#G{QGOr)g f%jǡ׭GJQEBVMN2nTs @c׾䩓j`ia @'W> LMMgr<XIXե<~;cWoF1po uP@&v ǿ{u=W& pq PH{d^@P:{fMlj{pw鬘H>z@#:@;[;~g}`ŦA‘TK(&c7ȃKIIa @Sf`-?Geݘ!u6  -6ֶ`og/p@|8LTa id#2GLX"uJ3`ͺ8 f?B% 9 @-ӧ^VSvŘׯa̸ѐs ڹ̛=/ge2d9E+?GZ2G ?": YZXx!7a,ܻI1ŋ /~]zvCP X6MS˔)gQ"Bah2ޮuefhSF&z6&Cp՗xE0leʠ00p>`؜TtE~W<»%i3ĮY o\'2 M 1!)w@O0/Ɇ\~?hݽ=-^zEH_ @F {j^:| o-"#ݸy_8/f=gΞ _~58Pf ʗAl'|jK>7Mx9<}q6:ϙMrw A( ~fƴZ_5jp/Du`@~Yʢ^'0d;_:  eЭ3̙X|vݚ) 8sL5ܥ!%}@i0Ta AhOVDA>sq+<{LML`s|1+ZQcص4 `=-6Ξ=CO /yXX7ndܤ'JRŊp ǧk'L9WFN]q)[J]P νZ) 7nJ$"t ϷdA=χKM$Sn=HMڮ"Cfs '~;NFSp07Uo*MHw7czRpahlj1q_*Ml??Kp}6}dϟ/Ykծ #5n                       Y]Z           ;A=                                 &!              !                                                                      #                                                                                        GLH                                                                       "            FKG                                         픗                           !                                                                                                                     173             fjg                                    )0+                       4:6                              =C@                  PUQ                 INJ                                                              062BHD                                                               AFB                                          KPLgkh                                        fjg                                                                      ( @                                                 +2-                                           LQN;A=                                  psp                         173           =C>                                                              퐓                 6<8                                                                                                                                             ink                                                    mqn                                  JPL                                                                                               퇊                        퍐                     _c`               fjg                                          &                           &                       RWRPNG  IHDR\rfsRGBgAMA a&JIDATx]}վ6KئVBm@qvkкQ[QcRl}kK1JBuS@GЀ@-)$bjT4jJj FLs׻wg~3s܏97!粻HxZ{wyG3'O|裏ĩS{O|ⓟdg?ˎ7N?^,[,=~0W_?Dr>ψ;OL8QG WoookϞ=/* ?/:;;# /7|}3EB@1cFVBPj{ytUn ɳēO>1(o7$ͤ|p++#2*xݭ<}g-5:;;[y"Toz,HsU/ؿTK8D4,mMp ɜ9sZӟ,K]SN[n* (yGDY"褭nZ1aSYY5"PHN8hӳdikn}BJϊϒeq 5kY=K\a %Kկ$Xd,#Jd2ڰ DTf?d/8h(zzzZjQK,L~{?N=,Y/ ,dvvȑ#ЮRdIE svm%ʯdx@DaϒeW 21m+dɊO;E*#?KJ&Mj%%{ ĨQgtqq!?9)l_=* ~ aKPU:?ázr=zTlٲEڵkhx ߿0 P$bC'_zŗ{mo3Di.@@U?2S)Ds=L[o{a3hr1˂?},sNkv@5ĭ2G&?NAKƍ+|>wrko9< ĒWˀ}Yg'w3aAs9sP3x"qL]rVk*b;Qh`je`,_t eUW]%Ԧ3V~wTc"@*kSkFȹMg4-[AE~'_$ݪU{kEe~3@ `wK2*Q_ H4? zy &s2x%8@d,j48P~5Y3~js.ڹuwiR/K9$@Ռ (vi twws&Ў"{+W'Ν $ud !5ݟ8q",:H:>PM7?k}gW'% cG* s|~ߊ{キP^?& `OB9s$qF30ݣ5uһ{ӞGj;vL̞={ˑ?]Q*@ ShW :@kiREfɒ%@ n?F̀,ui{?NMEYm޾}{K3HT,'y\.B<.C+Wr7ӂEn>5  @}5aRQB i ڎ04TrY0w\?XKÇ)SˀM;.jKV|E,W|!좟3k\x{"9w-k VѣG̙3sUJ],X@ IM9'05X@3.^!A^`2#Z%((t@V~Xӧ|$"c߮v\R3p :ӷZe {Al`,pJdۢꫯ.<4`T+\sc8UJ% ʗjY R1nT%eH̛7/w7P)HEE 5w2| .62TT~{zzgY /25UEa{3TVO[\ Ow*gQB 57 l(Pʀ Xd"n VElC[/@ʒ^d Ai7a/5\Thl*?<&yZ+Y5V~W^yt _p:1ڶ\=F^C=lf:o78IimU@z>H0vjC3f+W$Թʕ P3m'5kBa-fed I,@P|gSS,Y2 Au[E݀,ઃ@YB ƕK#`zV#PVbܛǓz- )V}X@@V>R&/^\ H~|۵kW@<zd k PK֠  L6-@3uxĉŸq?yB:uB>|88pՖWfYT9<|Aח:Tu'7tS%ᪿ-}rUX-cY [Eoٳg'Xw}w|0NTs$ `au]#*O8!z衡 ^K az'JuaXRאA@x`,WcGQLZ*kYP䰩3LʃӆVlcgr@STXR@m,QWIE Hvl@e*>bԨ\&*6:DԒ ,x 9&g-vIOTl" "K)isuY+@y͛QXo.m"E@6ʦt&Qm6rJJ߯Z+PKN@S+@m5B.VGl 6X*X)bZz]wu$/AMR6'X`W;w5W3QET,LV+L̲TacM!MtVT֣4f2՞!#`BscLHu}2M/ d ![4`h4M}p>\dME!t*ATXӫ$]@y6մ+Py*J@S_t2e Pb Ij)꺅ЬU떤 314٪@@Baʟ-Y'K +bZgDI-H1P6q^^_r+  sXNB 2,dt;v8SN"d cuuuXp7 yXe-_V(v|*ni C}vCA(+BSӔ\"T  B$W`>A $ MH; "% $˴G@Wz+惓%!ZN},m g?$}&{֭ "}NAu+)=R lYuKKܫEw TOR2VxcxKA.\0LK2)2!! &OM~}yI-r3|>`r=UMXj#Z%UP~1ZLͱA @E)킀u˗_!:*)?PyT FX }0lWPQG7 ^(zI@Ք E3=z4)m\P4"F]@h0KqÆ ʏsucjK1**ct_OfHE4+7,{ !}P5pjٛPeƒgFLL ȞۺNL=^_L@Օ_C%uL R u/lZ*P^oG(z6^~T7 :XAٲeB!jrV3j p=+FTNÕ҇}rlL)Az-T~,NWM5 NʟƢc G&CG~jcǎNNQ<4Е߶ο/`oGJF0PP,K@E8V4K*)mw˽``>h_U3^Az϶`Da*ʶ.*dZ/_j d=)SćY[N[ĩuVJ&QdH-(=2h;œ 3)+*LAݚkmާ.A$$e#>}y={$￧ts=\uZp~g,n^ 4W)R H-Ozլv-dw pb$i <.~@S_6ըm.\QЂ=pDw-&+xfͺқ›H1Ph킸CƲ(O7E{4h \J:<ܻ+QЬ#fΜieq#k~^}7y7N6#dKfGKof  T \Rvϛ70IYE*u>bA [+sBGMū)[Ai@Vb& +|nuX+V/^x TPSMrHY 5d{  cƌ?O6\_$z)єg`,}Cާ؊|G}۟oM`x5pH+%fթX?lzf̚ `.Qܬ~ڵqFഽf~ q f]K@Rd;}EԷ"[D7-ba& ,I=> I,.Ah VNJi(ozdp:9cX˓-"MĊG\@w o'qn_ouM@Ccf+ysdF}6@DžE!S46IYg r#ӑI=z4Yg%."q饗f2gڪR9@cI*iVr&i֯5duQژv(ǵr Gg.ʙYdž5YC|ZyPw__+rڜuwɹqtjnrUCq H ce>'o/$a'cP=j':[S~ّ2WVz1C@,Ur`Vlt]^mwr s/wމ&VgtLZ=$Ɲ\mw81\l ,Q/m6wrR2JT:e^xdUg`.ǨfQftfpBEe`ѓ-_` شiS0{rUn@DEEU_wyg"T1)?+ 5 T=ڔN?J*P]h7{ƍmq,ܲe + SI>PVmHLE0V Dޣh?d DOŶTJ4UV>裬D5 H9\0WRUotRο(G( @ (CzՑ| 2yd'Er4U2bE,oH @ :s@;v,~($ 1* 5vx}Խ.ᒡV+UL6?N%|H/Rbz0h*ӂ'gd MAR>w +Tz/f 7 -2&b { r"VU~KR~c wKmW^-~ >k֕\ϔ6^tܹ3v#Vz/b۶MbԨZ኿:}n{!(ƍСCΑUwX'F F1,$ !?r:E E$R:ԙX+ Fr %^|Eo?JD<:u*5A3_ $9r$ƍ]v7_^ķ~^}"J Vɳ=m_z+Vp +ZZ}]1uh\U0$>|xH2>u^\|x_V&n /xt_^E,@F1P9JȺaG?q>??;48qbHs:XN%]_&:@ &Mj*Z%G_r%1藿;Vۚw-Ľ!Y4_M,dVPPY7iS;/I^A@УH5l)~;@]@# ӧ_Ι1lҲSP?c -}m%l!=v`>~ҥC$ќ9sZ䓢8m!0mڴ`p dF)G]A 3Ђ…^<'m#}.Dv[- T`ڴa3E1̣. -[gb8 '̙3/὿=XUDIYȑ#QMV5`(n!8c q饗fM<%y?$cGM. F@U& r5M"S) ,UYVǏo[4(rM@+9@WB_@y>| @;q+"v/WLnS__U *py}D09x`i:.CR܀S}n&n7T(sL  ;&nF!WM. Pl|"8 LxY$;/|$1(iAKN@໓<7 8hK,w&SҪxbP@BP~ƥٳgVFKki%@J?vJ)Rå5k*WuAd T~jD=|'7jRArdHՈ2T~D2b3@P!oQG{_ˍ'jUAO緊] ;ǏC=߯%@%oVlٲP$6.(vZ'zpZ1(3@%P'姶$ DKBg֭bӦM䬙Uj F; R(̀" ?|qH(ݻwx=y}ow $Z"IݕV#~n„ sύy[ u_o'^{Ԩ>UVGAq}AD.芇qŮ%A?_W(.w}i{:_ϖ@sr ru!* &488hm” `ڽs v %/ͷ=6O.6lPtPT +@;@iUpP*Y e[ ^A@e!֛oiMX|Η}QQ11cƈB*dg.W /zP*ri U~cyXYR?}gJ KXCeF ,C*XyYt?Юs8˺XTFa>b!X&?uZrd3K)v в]$tAt NWءh^XV1&Om; Z-D|޺ @.. 2[{U"U0]暑|\">, Y}VZzcFYv X.i2ij z#j %KBH^xꫯ|pY:o"Tދ/뛾r@Kwx ,CUV~|x" Yrf/.XrTyd| k'O|?SNgW3 8㌡Ƨ>xhqYgn6**IENDB`(0` ʦ @ ` @@ @@@`@@@@`` `@`````` @` @` @` @`@@ @@@`@@@@@ @ @ @@ `@ @ @ @ @@@@ @@@@@`@@@@@@@@@`@` @`@@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@ @` @ ` @@ @@@`@@@@`` `@`````` @` @` @` @` @` @ ` @@ @@@`@@@@`` `@`````` @` @` @`IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII[IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII[IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII[IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIII[[IIIIIIIIIIIIII[IIIIII[IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIII[IIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIII[IIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII( @ʦ @ ` @@ @@@`@@@@`` `@`````` @` @` @` @`@@ @@@`@@@@@ @ @ @@ `@ @ @ @ @@@@ @@@@@`@@@@@@@@@`@` @`@@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@ @` @ ` @@ @@@`@@@@`` `@`````` @` @` @` @` @` @ ` @@ @@@`@@@@`` `@`````` @` @` @`IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIRIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII[IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII[tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-date.svg0000644000175000017500000000040413463252532022741 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-save.svg0000644000175000017500000000041013463252532022757 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-email.svg0000644000175000017500000000040313463252532023112 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-align-left.svg0000644000175000017500000000034213463252532025335 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-archive.svg0000644000175000017500000000057613463252532023457 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-icon.png0000644000175000017500000000142213354423127022741 0ustar cedced00000000000000PNG  IHDR DsRGB8PLTE !"## %!&"' $)"'+%',&).'*/(,0*-1+.3-05.16/4827<68<68=7:>8BF@GKFKOIMPKNQLOSNPTOSVQVZUY]X\_Z]a\_c^`c_beacfaehceidmpknqmpsoqtptvruxtz}y|~{}tRNS@fbKGDH pHYs@ tIME 1NFIDAT8˅V@T wFAE% -lMcgw=" QSB. HyZvYG=jXmEP 8Y` .lcAЫ=l% tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-undo.svg0000644000175000017500000000044413463252532022775 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-copy.svg0000644000175000017500000000043613463252532023003 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-link.svg0000644000175000017500000000055113463252532022764 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton.icns0000644000175000017500000006411213354423127022170 0ustar cedced00000000000000icnshJICN#????il32@ 7O  2zZ-+ "8 !1 K;`v{5b1Wx%c >dFD L$kf g6 !Q@$ tu -=4ﭔ8.T Y1*tc ލo +$ ; яdk 1! 'OQ9k(Rށ 4MTG/"!    "!! !!$!!  !$ !  ;S% " 6}] 1/ !' = ! &6 $ ! O? cy  ~9 f6 $Z z* g $ #B   h  JH $P ) ni j$ : $ &U D) wx 2A 8ﯖ = 3X   \5 #. wf !ޏ! r 0)@ ёgo 5& !+ST !  =n ! -Uބ  " "9QWK3 " !!  " " !! !! " 5M 0yX+)  6 0I9^uz3a/Uv$b<cEC J"ie e4 O?# st +<2ﭓ6,S X/(sa ތn *": Ўbj} / %MO7j&P݀ 3KRE-l8mkMߦN " ki}s*' I[it32 1LN)Cp CU&І8Nj;U|"G,')"SHR_$ދJ}ЬʌQ$ڊvsЉ2݊UWasB(57}5fpJl_p&ׅrZlΟIɅ08Xc'ŅI0مJ 0fDLYKmLrSbNQ\φ@O 0f>'#CQ^J"P_ '݁+qQ0ݜ"]R_֜Lʦ(0Ϝ}KYQǜŅQq'a"HF̅LhFԇMR҅+2 ʌ0q"gv!؆^Ј̗Rr%5!EؖHU*?߉*mfmGۉ 'a1 C)^&=y/Yy9ܟ&G,9ȋgxl_M)%1RʠnݍhUɎ"uԦ͏BZ{SL>FArY#@#m)9Zdc3ˇ43JrC{`ZTqMiKUk.N ز*Ŏu(jhg>,Г~~<Aa"ES$cL-0lnNǽ1m?Qʵ4p S̬.5rL"Vѣi;xf%\֚b@~<(b֐n.WԅҿA!0>NXI7$              6OR.  Gs%  GX  "* !ц!  <ȍ? Y  ' K  1 +  .  & WL  Vb )ߋ  N$ Ѭ  ʌT )ۊ!  x v$  # $щ  7݊ Y  [ dv  F  $ˆ -9 ; : is N o bs *ׅ u] oΟ M "ʅ4 < [g , ƅ M5 څ " N% 4 i H O \ O p P u W e R™ T ` ІD S" %4 i B, (GTaN' S# b% ,݁0 t $# U4 †ޜ &` Vb ֜ P˦ - 4Ϝ O \ TȜ ƅU t #+ d' LJ "ͅ O lJ Շ QV #҅/ 7 %ˌ4 t& j y &؆" ˜ a" ! ш͗ Vu* 9& Iٖ LY . C߉. pi! p" Kۉ% +d6 %G. a* A |3 \| "> #ܟ *K 1 >ɋj {o c Q" #. * 6V ˠ$ "qݍ k# Yʎ& xըΏF ]~ W" PB J Eu\( D( p. >] hf 7 !̇ 87 Nu G} d^ W# tQ lO Yn 2R %ز. Ǝx- m ljC" 1 $ѓš@ E d& IW  )f  "O2  4oq  #RȽ!  6pC  $Tʵ  8s"  %Wͬ2  :uP  &Zңl  ?{i  *`֚e  D@  -e֐q!  2[ՅE  &4CR[M;)              /JM'AoBS$І6NJ9T{ F*%' RGQ]"ދH|ЬɌO"ڊtrЉ0܊TV`r@&35|4eoHj]o$ׅqXj͟Hȅ.6Wb%ąH/مH.eCJWIlKqR`MO[φ>M.e<%!BO\H N]%܁*p~P.ݜ \Q]֜Kʦ&.Μ|IWOǜŅPp%` GD̅JgDԇLQ҅)0ʌ.o eu׆\Ј̗Qq#3CؖGT(>߉(kekEۉ%`/B'\$;x-Wx8ܟ$E*8ȋewj^L'#/Qʠm܍fTȎ tԦ͏@XzRK<D?qW!>!l'8Xca1ˇ21HqBy_YRoLhITj,Mײ(Ŏt&ige=*Г}}:?` CR"aJ+.jmMǽ/l>Oɵ2oR̬,4qK Uѣh9we#[֚`>}:&`֐m,VԅҾ?.=MWH5" t8mk@(^̽g/RREIqt} $[`mlJE+&818-TMUQ¹|kG+ |j8*x` ghPa} t'`s%lE6 J|굀IDv˾V tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-attach.svg0000644000175000017500000000062213463252532023272 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-underline.svg0000644000175000017500000000041113463252532025275 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-bookmark-border.svg0000644000175000017500000000035413463252532025110 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-cancel.svg0000644000175000017500000000050513463252532023253 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-align-right.svg0000644000175000017500000000034113463252532025517 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-note.svg0000644000175000017500000000046313463252532022776 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-log.svg0000644000175000017500000000053613463252532022613 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-delete.svg0000644000175000017500000000034313463252532023270 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-error.svg0000644000175000017500000000036613463252532023164 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-format-align-center.svg0000644000175000017500000000034113463252532025662 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-info.svg0000644000175000017500000000036613463252532022766 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-back.svg0000644000175000017500000000031113463252532022721 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-open.svg0000644000175000017500000000043013463252532022764 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-star-border.svg0000644000175000017500000000052613463252532024255 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-ok.svg0000644000175000017500000000030713463252532022437 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-filter.svg0000644000175000017500000000030413463252532023310 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-public.svg0000644000175000017500000000070213463252532023303 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-import.svg0000644000175000017500000000051213463252532023336 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-exit.svg0000644000175000017500000000047213463252532023002 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-launch.svg0000644000175000017500000000046313463252532023303 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/tryton-warning.svg0000644000175000017500000000031013463252532023465 0ustar cedced00000000000000 tryton-5.0.17/tryton/data/pixmaps/tryton/LICENSE0000644000175000017500000002613513463252532020764 0ustar cedced00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.tryton-5.0.17/tryton/gui/0000755000175000017500000000000013571264253014606 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/0000755000175000017500000000000013571264253016115 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/about.py0000644000175000017500000000321213571264251017575 0ustar cedced00000000000000# -*- coding: utf-8 -*- # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os import gettext from gi.repository import Gtk, GdkPixbuf from tryton.config import PIXMAPS_DIR, CONFIG from tryton.common import get_toplevel_window from tryton import __version__ COPYRIGHT = '''\ Copyright (C) 2004-2019 Tryton. ''' AUTHORS = [ 'Bertrand Chenal ', 'Cédric Krier ', 'Franz Wiesinger', 'Hartmut Goebel', 'Korbinian Preisler ', 'Mathias Behrle ', 'Nicolas Évrard ', 'Sednacom ', 'Udo Spallek ', ] _ = gettext.gettext class About(object): def __init__(self): parent = get_toplevel_window() self.win = Gtk.AboutDialog() self.win.set_transient_for(parent) self.win.set_name(CONFIG['client.title']) self.win.set_version(__version__) self.win.set_comments(_("modularity, scalability and security")) self.win.set_copyright(COPYRIGHT) self.win.set_license_type(Gtk.License.GPL_3_0) self.win.set_website('http://www.tryton.org/') self.win.set_website_label("Tryton") self.win.set_authors(AUTHORS) self.win.set_translator_credits(_('translator-credits')) self.win.set_logo(GdkPixbuf.Pixbuf.new_from_file( os.path.join(PIXMAPS_DIR, 'tryton.png'))) self.win.run() parent.present() self.win.destroy() tryton-5.0.17/tryton/gui/window/attachment.py0000644000175000017500000000617413463252532020624 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Attachment" import os from urllib.request import urlopen from urllib.parse import urlparse, unquote import gettext import webbrowser from functools import partial from tryton.common import RPCExecute, RPCException, file_write, file_open from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_form import WinForm _ = gettext.gettext class Attachment(WinForm): "Attachment window" def __init__(self, record, callback=None): self.resource = '%s,%s' % (record.model_name, record.id) self.attachment_callback = callback title = _('Attachments (%s)') % (record.rec_name()) screen = Screen('ir.attachment', domain=[ ('resource', '=', self.resource), ], mode=['tree', 'form']) super(Attachment, self).__init__(screen, self.callback, view_type='tree', title=title) screen.search_filter() def destroy(self): self.prev_view.save_width_height() super(Attachment, self).destroy() def callback(self, result): if result: self.screen.save_current() if self.attachment_callback: self.attachment_callback() def add_uri(self, uri): data_field = self.screen.group.fields['data'] name_field = self.screen.group.fields[data_field.attrs['filename']] new_record = self.screen.new() uri = unquote(uri) file_name = os.path.basename(urlparse(uri).path) name_field.set_client(new_record, file_name) data_field.set_client(new_record, urlopen(uri).read()) self.screen.display() def add_file(self, filename): self.add_uri('file:///' + filename) @staticmethod def get_attachments(record): attachments = [] context = {} if record and record.id >= 0: context = record.get_context() try: attachments = RPCExecute('model', 'ir.attachment', 'search_read', [ ('resource', '=', '%s,%s' % ( record.model_name, record.id)), ], 0, 20, None, ['rec_name', 'name', 'type', 'link'], context=context) except RPCException: pass for attachment in attachments: name = attachment['rec_name'] callback = getattr( Attachment, 'open_' + attachment['type'], Attachment.open_data) yield name, partial( callback, attachment=attachment, context=context) @staticmethod def open_link(attachment, context): if attachment['link']: webbrowser.open(attachment['link'], new=2) @staticmethod def open_data(attachment, context): try: value, = RPCExecute('model', 'ir.attachment', 'read', [attachment['id']], ['data'], context=context) except RPCException: return filepath = file_write(attachment['name'], value['data']) file_open(filepath) tryton-5.0.17/tryton/gui/window/view_board/0000755000175000017500000000000013571264253020236 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_board/action.py0000644000175000017500000001232613463252532022066 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. 'Action' import gtk import gobject from tryton.gui.window.view_form.screen import Screen import tryton.rpc as rpc import tryton.common as common from tryton.pyson import PYSONDecoder import gettext from tryton.signal_event import SignalEvent from tryton.gui.window.win_form import WinForm from tryton.common import RPCExecute, RPCException from tryton.action import Action as GenericAction _ = gettext.gettext class Action(SignalEvent): def __init__(self, attrs=None, context=None): if context is None: context = {} super(Action, self).__init__() self.name = attrs['name'] self.context = context.copy() try: self.action = RPCExecute('model', 'ir.action.act_window', 'get', self.name) except RPCException: raise view_ids = [] self.action['view_mode'] = None if self.action.get('views', []): view_ids = [x[0] for x in self.action['views']] self.action['view_mode'] = [x[1] for x in self.action['views']] elif self.action.get('view_id', False): view_ids = [self.action['view_id'][0]] if 'view_mode' in attrs: self.action['view_mode'] = attrs['view_mode'] self.action.setdefault('pyson_domain', '[]') self.context.update(rpc.CONTEXT) self.context['_user'] = rpc._USER self.context.update(PYSONDecoder(self.context).decode( self.action.get('pyson_context', '{}'))) eval_ctx = self.context.copy() self.context.update(PYSONDecoder(eval_ctx).decode( self.action.get('pyson_context', '{}'))) self.domain = [] self.update_domain([]) search_context = self.context.copy() search_context['context'] = self.context search_context['_user'] = rpc._USER search_value = PYSONDecoder(search_context).decode( self.action['pyson_search_value'] or '[]') self.widget = gtk.Frame() self.widget.set_border_width(0) vbox = gtk.VBox(homogeneous=False, spacing=3) self.widget.add(vbox) self.title = gtk.Label() self.widget.set_label_widget(self.title) self.widget.set_label_align(0.0, 0.5) self.widget.show_all() self.screen = Screen(self.action['res_model'], mode=self.action['view_mode'], context=self.context, view_ids=view_ids, domain=self.domain, search_value=search_value, row_activate=self.row_activate) vbox.pack_start(self.screen.widget, expand=True, fill=True) self.screen.signal_connect(self, 'record-message', self._active_changed) if attrs.get('string'): self.title.set_text(attrs['string']) else: self.title.set_text(self.action['name']) self.widget.set_size_request(int(attrs.get('width', -1)), int(attrs.get('height', -1))) self.screen.search_filter() def row_activate(self): if not self.screen.current_record: return if (self.screen.current_view.view_type == 'tree' and int(self.screen.current_view.attributes.get( 'keyword_open', 0))): GenericAction.exec_keyword('tree_open', { 'model': self.screen.model_name, 'id': (self.screen.current_record.id if self.screen.current_record else None), 'ids': [r.id for r in self.screen.selected_records], }, context=self.screen.group._context.copy(), warning=False) else: def callback(result): if result: self.screen.current_record.save() else: self.screen.current_record.cancel() WinForm(self.screen, callback) def set_value(self, mode, model_field): self.screen.current_view.set_value() return True def display(self): self.screen.search_filter(self.screen.screen_container.get_text()) def _active_changed(self, *args): self.signal('active-changed') def _get_active(self): if self.screen and self.screen.current_record: return common.EvalEnvironment(self.screen.current_record) active = property(_get_active) def update_domain(self, actions): domain_ctx = self.context.copy() domain_ctx['context'] = domain_ctx domain_ctx['_user'] = rpc._USER for action in actions: if action.active: domain_ctx[action.name] = action.active new_domain = PYSONDecoder(domain_ctx).decode( self.action['pyson_domain']) if self.domain == new_domain: return del self.domain[:] self.domain.extend(new_domain) if hasattr(self, 'screen'): # Catch early update # Using idle_add to prevent corruption of the event who triggered # the update. def display(): if self.screen.widget.props.window: self.display() gobject.idle_add(display) tryton-5.0.17/tryton/gui/window/view_board/__init__.py0000644000175000017500000000025213463252532022343 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .view_board import * tryton-5.0.17/tryton/gui/window/view_board/view_board.py0000644000175000017500000001351113463252532022727 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import xml.dom.minidom from tryton.gui.window.view_form.view.form import Container from tryton.common import node_attributes, IconFactory from .action import Action _ = gettext.gettext class ViewBoard(object): 'View board' def __init__(self, arch, context=None): self.context = context self.actions = [] xml_dom = xml.dom.minidom.parseString(arch) for node in xml_dom.childNodes: if node.nodeType == node.ELEMENT_NODE: break self.attributes = node_attributes(node) self.widget = self.parse(node).table self.widget.show_all() self._active_changed(None) def parse(self, node, container=None): if not container: node_attrs = node_attributes(node) container = Container(int(node_attrs.get('col', 4))) for node in node.childNodes: if node.nodeType != node.ELEMENT_NODE: continue node_attrs = node_attributes(node) for i_field in ('yexpand', 'yfill', 'xexpand', 'xfill', 'colspan', 'position'): if i_field in node_attrs: node_attrs[i_field] = int(node_attrs[i_field]) parser = getattr(self, '_parse_%s' % node.tagName) parser(node, container, node_attrs) return container def _parse_image(self, node, container, attributes): container.add( IconFactory.get_image(attributes['name'], gtk.ICON_SIZE_DIALOG), attributes) def _parse_separator(self, node, container, attributes): vbox = gtk.VBox() if attributes.get('string'): label = gtk.Label(attributes['string']) label.set_alignment(float(attributes.get('xalign', 0.0)), float(attributes.get('yalign', 0.5))) vbox.pack_start(label) vbox.pack_start(gtk.HSeparator()) container.add(vbox, attributes) def _parse_label(self, node, container, attributes): if not attributes.get('string'): container.add(None, attributes) return label = gtk.Label(attributes['string']) label.set_alignment(float(attributes.get('xalign', 0.0)), float(attributes.get('yalign', 0.5))) label.set_angle(int(attributes.get('angle', 0))) attributes.setdefault('xexpand', 0) container.add(label, attributes) def _parse_newline(self, node, container, attributes): container.add_row() def _parse_notebook(self, node, container, attributes): attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) notebook = gtk.Notebook() notebook.set_scrollable(True) container.add(notebook, attributes) self.parse(node, notebook) def _parse_page(self, node, notebook, attributes): tab_box = gtk.HBox(spacing=3) if '_' not in attributes['string']: attributes['string'] = '_' + attributes['string'] label = gtk.Label(attributes['string']) label.set_use_underline(True) tab_box.pack_start(label) if 'icon' in attributes: tab_box.pack_start(IconFactory.get_image( attributes['icon'], gtk.ICON_SIZE_SMALL_TOOLBAR)) tab_box.show_all() viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.add(viewport) scrolledwindow.show_all() notebook.append_page(scrolledwindow, tab_box) container = self.parse(node) viewport.add(container.table) def _parse_group(self, node, container, attributes): group = self.parse(node) group.table.set_homogeneous(attributes.get('homogeneous', False)) frame = gtk.Frame() frame.set_label(attributes.get('string')) if not attributes.get('string'): frame.set_shadow_type(gtk.SHADOW_NONE) frame.set_border_width(0) frame.add(group.table) container.add(frame, attributes) def _parse_paned(self, node, container, attributes, Paned): attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) paned = Paned() if 'position' in attributes: paned.set_position(attributes['position']) container.add(paned, attributes) self.parse(node, paned) def _parse_hpaned(self, node, container, attributes): self._parse_paned(node, container, attributes, gtk.HPaned) def _parse_vpaned(self, node, container, attributes): self._parse_paned(node, container, attributes, gtk.VPaned) def _parse_child(self, node, paned, attributes): container = self.parse(node) if not paned.get_child1(): pack = paned.pack1 else: pack = paned.pack2 pack(container.table, resize=True, shrink=True) def _parse_action(self, node, container, attributes): attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) action = Action(attributes, self.context) action.signal_connect(self, 'active-changed', self._active_changed) self.actions.append(action) container.add(action.widget, attributes) def widget_get(self): return self.widget def reload(self): for action in self.actions: action.display() def _active_changed(self, event_action, *args): for action in self.actions: if action == event_action: continue action.update_domain(self.actions) tryton-5.0.17/tryton/gui/window/note.py0000644000175000017500000000245613463252532017440 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_form import WinForm _ = gettext.gettext class Note(WinForm): "Note window" def __init__(self, record, callback=None): self.resource = '%s,%s' % (record.model_name, record.id) self.note_callback = callback title = _('Notes (%s)') % (record.rec_name()) screen = Screen('ir.note', domain=[ ('resource', '=', self.resource), ], mode=['tree', 'form']) super(Note, self).__init__(screen, self.callback, view_type='tree', title=title) screen.search_filter() def destroy(self): self.prev_view.save_width_height() super(Note, self).destroy() def callback(self, result): if result: unread = self.screen.group.fields['unread'] for record in self.screen.group: if record.loaded or record.id < 0: if 'unread' not in record.modified_fields: unread.set_client(record, False) self.screen.save_current() if self.note_callback: self.note_callback() tryton-5.0.17/tryton/gui/window/window.py0000644000175000017500000000330713463252532017776 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. class Window(object): hide_current = False allow_similar = False def __init__(self, hide_current=False, allow_similar=True): Window.hide_current = hide_current Window.allow_similar = allow_similar def __enter__(self): return self def __exit__(self, type, value, traceback): Window.hide_current = False Window.allow_similar = False @staticmethod def create(model, **attributes): from tryton.gui import Main main = Main() if not Window.allow_similar: for other_page in main.pages: if other_page.compare(model, attributes): main.win_set(other_page) return if model: from .form import Form win = Form(model, **attributes) else: from .board import Board win = Board(model, **attributes) win.icon = attributes.get('icon') main.win_add(win, hide_current=Window.hide_current) @staticmethod def create_wizard(action, data, direct_print=False, email_print=False, email=None, name='', context=None, icon=None, window=False): from tryton.gui import Main from .wizard import WizardForm, WizardDialog if window: win = WizardForm(name=name) win.icon = icon Main().win_add(win, Window.hide_current) else: win = WizardDialog(name=name) win.run(action, data, direct_print=direct_print, email_print=email_print, email=email, context=context) tryton-5.0.17/tryton/gui/window/email.py0000644000175000017500000001016113463252532017552 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from tryton.common import get_toplevel_window, IconFactory from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON, CONFIG from tryton.gui import Main _ = gettext.gettext class Email(object): def __init__(self): self.parent = get_toplevel_window() self.win = gtk.Dialog(_('Email'), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) cancel_button = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) cancel_button.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) cancel_button.set_always_show_image(True) ok_button = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.vbox.set_spacing(3) self.win.vbox.pack_start(gtk.Label( _('Email Program Settings')), expand=False, fill=True) self.win.vbox.pack_start(gtk.HSeparator()) hbox = gtk.HBox(spacing=3) label = gtk.Label(_('Command Line:')) hbox.pack_start(label, expand=True, fill=True) self.entry = gtk.Entry() self.entry.set_property('activates_default', True) self.entry.set_width_chars(50) self.entry.set_text(CONFIG['client.email']) label.set_mnemonic_widget(label) hbox.pack_start(self.entry, expand=True, fill=True) self.win.vbox.pack_start(hbox, expand=True, fill=True) label = gtk.Label(_('Legend of Available Placeholders:')) label.set_alignment(0.0, 0.5) label.set_padding(0, 10) self.win.vbox.pack_start(label, expand=False, fill=True) hbox = gtk.HBox(spacing=3) vboxl = gtk.VBox(homogeneous=True, spacing=3) label = gtk.Label(_('To:')) label.set_alignment(0, 0) label.set_padding(10, 0) vboxl.pack_start(label, expand=False, fill=False) label = gtk.Label(_('CC:')) label.set_alignment(0, 0) label.set_padding(10, 0) vboxl.pack_start(label, expand=False, fill=False) label = gtk.Label(_('Subject:')) label.set_alignment(0, 0) label.set_padding(10, 0) vboxl.pack_start(label, expand=False, fill=False) label = gtk.Label(_('Body:')) label.set_alignment(0, 0) label.set_padding(10, 0) vboxl.pack_start(label, expand=False, fill=False) label = gtk.Label(_('Attachment:')) label.set_alignment(0, 0) label.set_padding(10, 0) vboxl.pack_start(label, expand=False, fill=False) vboxr = gtk.VBox(homogeneous=True, spacing=3) label = gtk.Label(' ${to}') label.set_alignment(0, 0) vboxr.pack_start(label, expand=False, fill=False) label = gtk.Label(' ${cc}') label.set_alignment(0, 0) vboxr.pack_start(label, expand=False, fill=False) label = gtk.Label(' ${subject}') label.set_alignment(0, 0) vboxr.pack_start(label, expand=False, fill=False) label = gtk.Label(' ${body}') label.set_alignment(0, 0) vboxr.pack_start(label, expand=False, fill=False) label = gtk.Label(' ${attachment}') label.set_alignment(0, 0) vboxr.pack_start(label, expand=False, fill=False) hbox.pack_start(vboxl, expand=False, fill=False) hbox.pack_start(vboxr, expand=False, fill=False) self.win.vbox.pack_start(hbox, expand=True, fill=True) self.win.show_all() def run(self): "Run the window" res = self.win.run() if res == gtk.RESPONSE_OK: CONFIG['client.email'] = self.entry.get_text() CONFIG.save() self.parent.present() self.win.destroy() return res tryton-5.0.17/tryton/gui/window/nomodal.py0000644000175000017500000000221213463252532020112 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import tryton.common as common class NoModal(object): def __init__(self): self.parent = common.get_toplevel_window() self.sensible_widget = common.get_sensible_widget(self.parent) self.page = None self.parent_focus = [] focus = self.parent.get_focus() while focus: self.parent_focus.append(focus) focus = focus.get_parent() def register(self): from tryton.gui.main import Main main = Main() self.page = main.get_page() if not self.page: self.page = main self.page.dialogs.append(self) self.sensible_widget.props.sensitive = False def destroy(self): if not self.page: return self.page.dialogs.remove(self) self.parent.present() self.sensible_widget.props.sensitive = True for focus in self.parent_focus: if focus and focus.is_ancestor(self.parent): focus.grab_focus() break tryton-5.0.17/tryton/gui/window/wizard.py0000644000175000017500000003331713463252532017773 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import logging import gettext import gtk import pango from gi.repository import Gtk from tryton.signal_event import SignalEvent import tryton.common as common from tryton.gui.window.view_form.screen import Screen from tryton.gui import Main from tryton.exceptions import TrytonServerError from tryton.gui.window.nomodal import NoModal from tryton.common.button import Button from tryton.common import RPCExecute, RPCException, RPCContextReload from tryton.common import TRYTON_ICON from .infobar import InfoBar from .tabcontent import TabContent _ = gettext.gettext logger = logging.getLogger(__name__) class Wizard(InfoBar): def __init__(self, name=''): super(Wizard, self).__init__() self.widget = gtk.VBox(spacing=3) self.toolbar_box = None self.widget.show() self.name = name or '' self.id = None self.ids = None self.action = None self.action_id = None self.direct_print = False self.email_print = False self.email = False self.context = None self.states = {} self.response2state = {} self.__processing = False self.__waiting_response = False self.session_id = None self.start_state = None self.end_state = None self.screen = None self.screen_state = None self.state = None def run(self, action, data, direct_print=False, email_print=False, email=None, context=None): self.action = action self.action_id = data.get('action_id') self.id = data.get('id') self.ids = data.get('ids') self.model = data.get('model') self.direct_print = direct_print self.email_print = email_print self.email = email self.context = context.copy() if context is not None else {} self.context['active_id'] = self.id self.context['active_ids'] = self.ids self.context['active_model'] = self.model self.context['action_id'] = self.action_id def callback(result): try: result = result() except RPCException: self.destroy() return self.session_id, self.start_state, self.end_state = result self.state = self.start_state self.process() RPCExecute('wizard', action, 'create', callback=callback) def process(self): from tryton.action import Action if self.__processing or self.__waiting_response: return self.__processing = True ctx = self.context.copy() if self.screen: data = { self.screen_state: self.screen.get_on_change_value(), } else: data = {} def callback(result): try: result = result() except RPCException as rpc_exception: if (not isinstance(rpc_exception.exception, TrytonServerError) or not self.screen): self.state = self.end_state self.end() self.__processing = False return if 'view' in result: self.clean() view = result['view'] self.update(view['fields_view'], view['buttons']) self.screen.new(default=False) self.screen.current_record.set_default(view['defaults']) self.update_buttons(self.screen.current_record) self.screen.set_cursor() self.screen_state = view['state'] self.__waiting_response = True else: self.state = self.end_state def execute_actions(): for action in result.get('actions', []): for k, v in [ ('direct_print', self.direct_print), ('email_print', self.email_print), ('email', self.email), ]: action[0].setdefault(k, v) context = self.context.copy() # Remove wizard keys added by run del context['active_id'] del context['active_ids'] del context['active_model'] del context['action_id'] Action._exec_action(*action, context=context) if self.state == self.end_state: self.end(lambda *a: execute_actions()) else: execute_actions() self.__processing = False RPCExecute('wizard', self.action, 'execute', self.session_id, data, self.state, context=ctx, callback=callback) def destroy(self, action=None): if self.screen: self.screen.destroy() def end(self, callback=None): def end_callback(action): self.destroy(action=action()) if callback: callback() try: RPCExecute('wizard', self.action, 'delete', self.session_id, process_exception=False, callback=end_callback) except Exception: logger.warn( _("Unable to delete wizard %s") % self.session_id, exc_info=True) def clean(self): for widget in self.widget.get_children(): self.widget.remove(widget) self.states = {} def response(self, widget, response): self.__waiting_response = False state = self.response2state.get(response, self.end_state) self.screen.current_view.set_value() if (not self.screen.current_record.validate() and state != self.end_state): self.screen.display(set_cursor=True) self.message_info(self.screen.invalid_message(), gtk.MESSAGE_ERROR) return self.message_info() self.state = state self.process() def _get_button(self, definition): button = Button(definition) self.states[definition['state']] = button response = len(self.states) self.response2state[response] = definition['state'] button.show() return button def _record_changed(self, screen, record): self.update_buttons(record) def update_buttons(self, record): for button in self.states.values(): button.state_set(record) def update(self, view, buttons): tooltips = common.Tooltips() for button in buttons: self._get_button(button) self.screen = Screen(view['model'], mode=[], context=self.context) self.screen.add_view(view) self.screen.switch_view() self.screen.widget.show() self.screen.signal_connect(self, 'group-changed', self._record_changed) title = gtk.Label() title.modify_font(pango.FontDescription("bold 14")) title.set_label(common.ellipsize(self.name, 80)) tooltips.set_tip(title, self.name) title.set_padding(20, 4) title.set_alignment(0.0, 0.5) title.set_max_width_chars(1) title.set_ellipsize(pango.ELLIPSIZE_END) title.set_size_request(0, -1) # Allow overflow title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) title.show() hbox = gtk.HBox() hbox.pack_start(title, expand=True, fill=True) hbox.show() frame = gtk.Frame() frame.set_shadow_type(gtk.SHADOW_ETCHED_IN) frame.add(hbox) frame.show() eb = gtk.EventBox() eb.add(frame) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff")) eb.show() self.widget.pack_start(eb, expand=False, fill=True, padding=3) if self.toolbar_box: self.widget.pack_start(self.toolbar_box, False, True) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) viewport.add(self.screen.widget) viewport.show() self.scrolledwindow = gtk.ScrolledWindow() self.scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.scrolledwindow.add(viewport) self.scrolledwindow.show() self.widget.pack_start(self.scrolledwindow, expand=True, fill=True) self.create_info_bar() self.widget.pack_start(self.info_bar, False, True) class WizardForm(Wizard, TabContent, SignalEvent): "Wizard" def __init__(self, name=''): super(WizardForm, self).__init__(name=name) self.toolbar_box = gtk.HBox() self.hbuttonbox = gtk.HButtonBox() self.hbuttonbox.set_spacing(5) self.hbuttonbox.set_layout(gtk.BUTTONBOX_END) self.hbuttonbox.show() self.widget.pack_start(self.toolbar_box, False, True) self.dialogs = [] self.handlers = { 'but_close': self.sig_close } def clean(self): super(WizardForm, self).clean() for button in self.hbuttonbox.get_children(): self.hbuttonbox.remove(button) def _get_button(self, state): button = super(WizardForm, self)._get_button(state) response = len(self.states) button.connect('clicked', self.response, response) self.hbuttonbox.pack_start(button) return button def update(self, view, buttons): super(WizardForm, self).update(view, buttons) self.widget.pack_start(self.hbuttonbox, expand=False, fill=True) def sig_close(self): if self.end_state in self.states: self.states[self.end_state].clicked() return self.state == self.end_state def destroy(self, action=None): if self.toolbar_box.get_children(): toolbar = self.toolbar_box.get_children()[0] self.toolbar_box.remove(toolbar) super(WizardForm, self).destroy(action=action) if action == 'reload menu': RPCContextReload(Main().sig_win_menu) elif action == 'reload context': RPCContextReload() def end(self, callback=None): super(WizardForm, self).end(callback=callback) Main()._win_del(self.widget) def set_cursor(self): if self.screen: self.screen.set_cursor() class WizardDialog(Wizard, NoModal): def __init__(self, name=''): if not name: name = _('Wizard') Wizard.__init__(self, name=name) NoModal.__init__(self) self.dia = gtk.Dialog(self.name, self.parent, gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.dia) self.dia.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dia.set_icon(TRYTON_ICON) self.dia.set_deletable(False) self.dia.connect('delete-event', lambda *a: True) self.dia.connect('close', self.close) self.dia.connect('response', self.response) self.accel_group = gtk.AccelGroup() self.dia.add_accel_group(self.accel_group) self.dia.vbox.pack_start(self.widget, expand=True, fill=True) self.register() def clean(self): super(WizardDialog, self).clean() hbuttonbox = self.dia.get_action_area() for button in hbuttonbox.get_children(): hbuttonbox.remove(button) def _get_button(self, definition): button = super(WizardDialog, self)._get_button(definition) response = len(self.states) self.dia.add_action_widget(button, response) if definition['default']: button.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) button.get_style_context().add_class( Gtk.STYLE_CLASS_SUGGESTED_ACTION) button.set_can_default(True) button.grab_default() self.dia.set_default_response(response) return button def update(self, view, buttons): super(WizardDialog, self).update(view, buttons) current_view = self.screen.current_view self.scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER) if current_view.scroll: current_view.scroll.set_policy( gtk.POLICY_NEVER, gtk.POLICY_NEVER) self.show() def destroy(self, action=None): super(WizardDialog, self).destroy(action=action) self.dia.destroy() NoModal.destroy(self) main = Main() if self.parent == main.window: current_form = main.get_page() if current_form: for dialog in current_form.dialogs: dialog.show() if self.page.dialogs: dialog = self.page.dialogs[-1] else: dialog = self.page screen = getattr(dialog, 'screen', None) if self.sensible_widget == main.window: screen = main.menu_screen if screen: if (screen.current_record and self.sensible_widget != main.window): if screen.model_name == self.model: ids = self.ids else: # Wizard run from a children record so reload parent record ids = [screen.current_record.id] screen.reload(ids, written=True) if action: screen.client_action(action) def close(self, widget, event=None): widget.emit_stop_by_name('close') if self.end_state in self.states: self.states[self.end_state].clicked() return True def show(self): self.dia.set_default_size(200, -1) self.dia.show() def hide(self): self.dia.hide() tryton-5.0.17/tryton/gui/window/win_search.py0000644000175000017500000001333513463252532020613 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import tryton.common as common from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main from tryton.gui.window.nomodal import NoModal from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_form import WinForm _ = gettext.gettext class WinSearch(NoModal): def __init__(self, model, callback, sel_multi=True, context=None, domain=None, order=None, view_ids=None, views_preload=None, new=True, title=''): NoModal.__init__(self) if view_ids is None: view_ids = [] if views_preload is None: views_preload = {} self.domain = domain or [] self.context = context or {} self.order = order self.view_ids = view_ids self.views_preload = views_preload self.sel_multi = sel_multi self.callback = callback self.title = title self.win = gtk.Dialog(_('Search'), self.parent, gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) self.win.set_icon(TRYTON_ICON) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_default_response(gtk.RESPONSE_APPLY) self.win.connect('response', self.response) parent_allocation = self.parent.get_allocation() width, height = parent_allocation.width, parent_allocation.height if self.parent != self.sensible_widget: width = max(width - 150, 0) self.win.set_default_size(min(600, width), min(400, height)) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) self.but_cancel = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) self.but_cancel.set_image(common.IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) self.but_cancel.set_always_show_image(True) self.but_find = self.win.add_button( set_underline(_("Search")), gtk.RESPONSE_APPLY) self.but_find.set_image(common.IconFactory.get_image( 'tryton-search', gtk.ICON_SIZE_BUTTON)) self.but_find.set_always_show_image(True) if new and common.MODELACCESS[model]['create']: self.but_new = self.win.add_button( set_underline(_("New")), gtk.RESPONSE_ACCEPT) self.but_new.set_image(common.IconFactory.get_image( 'tryton-create', gtk.ICON_SIZE_BUTTON)) self.but_new.set_always_show_image(True) self.but_new.set_accel_path('/Form/New', self.accel_group) self.but_ok = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) self.but_ok.set_image(common.IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) self.but_ok.set_always_show_image(True) self.but_ok.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) hbox = gtk.HBox() hbox.show() self.win.vbox.pack_start(hbox, expand=False, fill=True) self.win.vbox.pack_start(gtk.HSeparator(), expand=False, fill=True) self.screen = Screen(model, domain=domain, mode=['tree'], order=order, context=context, view_ids=view_ids, views_preload=views_preload, row_activate=self.sig_activate, readonly=True) self.view = self.screen.current_view # Prevent to set tree_state self.screen.tree_states_done.add(id(self.view)) sel = self.view.treeview.get_selection() self.win.set_title(_('Search %s') % self.title) if not sel_multi: sel.set_mode(gtk.SELECTION_SINGLE) else: sel.set_mode(gtk.SELECTION_MULTIPLE) self.win.vbox.pack_start(self.screen.widget, expand=True, fill=True) self.screen.widget.show() self.model_name = model self.register() def sig_activate(self, *args): self.view.treeview.emit_stop_by_name('row_activated') self.win.response(gtk.RESPONSE_OK) return True def destroy(self): self.screen.destroy() self.win.destroy() NoModal.destroy(self) def show(self): self.win.show() def hide(self): self.win.hide() def response(self, win, response_id): res = None if response_id == gtk.RESPONSE_OK: res = [r.id for r in self.screen.selected_records] elif response_id == gtk.RESPONSE_APPLY: self.screen.search_filter(self.screen.screen_container.get_text()) return elif response_id == gtk.RESPONSE_ACCEPT: # Remove first tree view as mode if form only view_ids = self.view_ids[1:] screen = Screen(self.model_name, domain=self.domain, context=self.context, order=self.order, mode=['form'], view_ids=view_ids, views_preload=self.views_preload) def callback(result): if result: record = screen.current_record res = [(record.id, record.value.get('rec_name', ''))] self.callback(res) else: self.callback(None) self.destroy() WinForm( screen, callback, new=True, save_current=True, title=self.title) return if res: group = self.screen.group res = [(id_, group.get(id_).value.get('rec_name', '')) for id_ in res] self.callback(res) self.destroy() tryton-5.0.17/tryton/gui/window/preference.py0000644000175000017500000000731713463252532020612 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Preference" import gettext import gtk import copy import tryton.rpc as rpc from tryton.common import RPCExecute, RPCException, IconFactory from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main from tryton.gui.window.nomodal import NoModal from tryton.gui.window.view_form.screen import Screen _ = gettext.gettext class Preference(NoModal): "Preference window" def __init__(self, user, callback): NoModal.__init__(self) self.callback = callback self.win = gtk.Dialog(_('Preferences'), self.parent, gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_icon(TRYTON_ICON) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) self.but_cancel = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) self.but_cancel.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) self.but_cancel.set_always_show_image(True) self.but_ok = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) self.but_ok.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) self.but_ok.set_always_show_image(True) self.but_ok.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) self.win.set_default_response(gtk.RESPONSE_OK) self.win.connect('response', self.response) try: view = RPCExecute('model', 'res.user', 'get_preferences_fields_view') except RPCException: self.win.destroy() self.win = None return title = gtk.Label(_('Edit User Preferences')) title.show() self.win.vbox.pack_start(title, expand=False, fill=True) self.screen = Screen('res.user', mode=[]) # Reset readonly set automaticly by MODELACCESS self.screen.readonly = False self.screen.group.readonly = False self.screen.group.skip_model_access = True self.screen.add_view(view) self.screen.switch_view() self.screen.new(default=False) try: preferences = RPCExecute('model', 'res.user', 'get_preferences', False) except RPCException: self.win.destroy() self.win = None return self.screen.current_record.cancel() self.screen.current_record.set(preferences) self.screen.current_record.id = rpc._USER self.screen.current_record.validate(softvalidation=True) self.screen.display(set_cursor=True) self.screen.widget.show() self.win.vbox.pack_start(self.screen.widget) self.win.set_title(_('Preference')) width, height = self.parent.get_size() self.win.set_default_size(width, height) self.register() self.win.show() def response(self, win, response_id): if response_id == gtk.RESPONSE_OK: if self.screen.current_record.validate(): vals = copy.copy(self.screen.get()) try: RPCExecute('model', 'res.user', 'set_preferences', vals) except RPCException: return self.parent.present() self.destroy() self.callback() def destroy(self): self.screen.destroy() self.win.destroy() NoModal.destroy(self) tryton-5.0.17/tryton/gui/window/view_form/0000755000175000017500000000000013571264253020112 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/screen/0000755000175000017500000000000013571264253021371 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/screen/__init__.py0000644000175000017500000000024613463252532023501 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .screen import * tryton-5.0.17/tryton/gui/window/view_form/screen/screen.py0000644000175000017500000014100413563616132023220 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Screen" import copy import functools import gobject import datetime import calendar import json import collections import urllib.parse import xml.dom.minidom import gettext import logging from operator import itemgetter import gtk from tryton.gui.window.view_form.model.group import Group from tryton.gui.window.view_form.view.screen_container import ScreenContainer from tryton.gui.window.view_form.view import View from tryton.signal_event import SignalEvent from tryton.config import CONFIG from tryton.jsonrpc import JSONEncoder from tryton.common.domain_parser import DomainParser from tryton.common import RPCExecute, RPCException, MODELACCESS, \ node_attributes, sur, RPCContextReload, warning from tryton.action import Action from tryton.pyson import PYSONDecoder _ = gettext.gettext logger = logging.getLogger(__name__) class Screen(SignalEvent): "Screen" # Width of tree columns per model # It is shared with all connection but it is the price for speed. tree_column_width = collections.defaultdict(lambda: {}) def __init__(self, model_name, **attributes): context = attributes.get('context', {}) self.limit = attributes.get('limit', CONFIG['client.limit']) self.offset = 0 super(Screen, self).__init__() self.readonly = attributes.get('readonly', False) if not (MODELACCESS[model_name]['write'] or MODELACCESS[model_name]['create']): self.readonly = True self.search_count = 0 if not attributes.get('row_activate'): self.row_activate = self.default_row_activate else: self.row_activate = attributes['row_activate'] self.domain = attributes.get('domain', []) self.context_domain = attributes.get('context_domain') self.size_limit = None self.views_preload = attributes.get('views_preload', {}) self.model_name = model_name self.views = [] self.view_ids = attributes.get('view_ids', [])[:] self.parent = None self.parent_name = None self.exclude_field = attributes.get('exclude_field') self.filter_widget = None self.tree_states = collections.defaultdict( lambda: collections.defaultdict(lambda: None)) self.tree_states_done = set() self.__group = None self.new_group(context or {}) self.__current_record = None self.current_record = None self.screen_container = ScreenContainer(attributes.get('tab_domain')) self.screen_container.alternate_view = attributes.get( 'alternate_view', False) self.widget = self.screen_container.widget_get() self.context_screen = None if attributes.get('context_model'): self.context_screen = Screen( attributes['context_model'], mode=['form'], context=context) self.context_screen.new() context_widget = self.context_screen.widget def walk_descendants(widget): yield widget if not hasattr(widget, 'get_children'): return for child in widget.get_children(): for widget in walk_descendants(child): yield widget for widget in reversed(list(walk_descendants(context_widget))): if isinstance(widget, gtk.Entry): widget.connect_after( 'activate', self.screen_container.activate) elif isinstance(widget, gtk.CheckButton): widget.connect_after( 'toggled', self.screen_container.activate) def remove_bin(widget): assert isinstance(widget, (gtk.ScrolledWindow, gtk.Viewport)) parent = widget.get_parent() parent.remove(widget) child = widget.get_child() while isinstance(child, (gtk.ScrolledWindow, gtk.Viewport)): child = child.get_child() child.get_parent().remove(child) parent.add(child) return child # Remove first level Viewport and ScrolledWindow to fill the Vbox for widget in [ self.context_screen.screen_container.viewport, self.context_screen.current_view.widget.get_children()[0], ]: remove_bin(widget) self.screen_container.filter_vbox.pack_start( context_widget, expand=False, fill=True) self.screen_container.filter_vbox.reorder_child( context_widget, 0) self.context_screen.widget.show() self.__current_view = 0 self.search_value = attributes.get('search_value') self.fields_view_tree = {} self.order = self.default_order = attributes.get('order') self.view_to_load = [] self._domain_parser = {} self.pre_validate = False mode = attributes.get('mode') if mode is None: mode = ['tree', 'form'] self.view_to_load = mode[:] if self.view_ids or self.view_to_load: self.switch_view() self.count_tab_domain() def __repr__(self): return '' % (self.model_name, id(self)) def search_active(self, active=True): if active and not self.parent: self.screen_container.set_screen(self) self.screen_container.show_filter() else: self.screen_container.hide_filter() @property def domain_parser(self): view_id = self.current_view.view_id if self.current_view else None if view_id in self._domain_parser: return self._domain_parser[view_id] if view_id not in self.fields_view_tree: try: self.fields_view_tree[view_id] = view_tree = RPCExecute( 'model', self.model_name, 'fields_view_get', False, 'tree', context=self.context) except RPCException: view_tree = { 'fields': {}, } else: view_tree = self.fields_view_tree[view_id] fields = copy.deepcopy(view_tree['fields']) for name, props in fields.items(): if props['type'] not in ('selection', 'reference'): continue if isinstance(props['selection'], (tuple, list)): continue props['selection'] = self.get_selection(props) if 'arch' in view_tree: # Filter only fields in XML view xml_dom = xml.dom.minidom.parseString(view_tree['arch']) root_node, = xml_dom.childNodes ofields = collections.OrderedDict() for node in root_node.childNodes: if node.nodeName != 'field': continue attributes = node_attributes(node) name = attributes['name'] # If a field is defined multiple times in the XML, # take only the first definition if name in ofields: continue ofields[name] = fields[name] for attr in ['string', 'factor']: if attributes.get(attr): ofields[name][attr] = attributes[attr] fields = ofields if 'active' in view_tree['fields']: self.screen_container.but_active.show() else: self.screen_container.but_active.hide() # Add common fields for name, string, type_ in ( ('id', _('ID'), 'integer'), ('create_uid', _('Creation User'), 'many2one'), ('create_date', _('Creation Date'), 'datetime'), ('write_uid', _('Modification User'), 'many2one'), ('write_date', _('Modification Date'), 'datetime'), ): if name not in fields: fields[name] = { 'string': string, 'name': name, 'type': type_, } if type_ == 'datetime': fields[name]['format'] = '"%H:%M:%S"' domain_parser = DomainParser(fields, self.context) self._domain_parser[view_id] = domain_parser return domain_parser def get_selection(self, props): try: change_with = props.get('selection_change_with') if change_with: selection = RPCExecute('model', self.model_name, props['selection'], dict((p, None) for p in change_with)) else: selection = RPCExecute('model', self.model_name, props['selection']) except RPCException: selection = [] selection.sort(key=itemgetter(1)) return selection def search_prev(self, search_string): if self.limit: self.offset -= self.limit self.search_filter(search_string=search_string) def search_next(self, search_string): if self.limit: self.offset += self.limit self.search_filter(search_string=search_string) def search_complete(self, search_string): return list(self.domain_parser.completion(search_string)) def search_filter(self, search_string=None, only_ids=False): if self.context_screen and not only_ids: context_record = self.context_screen.current_record if not context_record.validate(): self.clear() self.context_screen.display(set_cursor=True) return False context = self.local_context context.update(self.context_screen.get_on_change_value()) self.new_group(context) domain = self.search_domain(search_string, True) if self.context_domain: decoder = PYSONDecoder(self.context) domain = ['AND', domain, decoder.decode(self.context_domain)] tab_domain = self.screen_container.get_tab_domain() if tab_domain: domain = ['AND', domain, tab_domain] context = self.context if self.screen_container.but_active.get_active(): context['active_test'] = False try: ids = RPCExecute('model', self.model_name, 'search', domain, self.offset, self.limit, self.order, context=context) except RPCException: ids = [] if not only_ids: if self.limit is not None and len(ids) == self.limit: try: self.search_count = RPCExecute('model', self.model_name, 'search_count', domain, context=context) except RPCException: self.search_count = 0 else: self.search_count = len(ids) self.screen_container.but_prev.set_sensitive(bool(self.offset)) if (self.limit is not None and len(ids) == self.limit and self.search_count > self.limit + self.offset): self.screen_container.but_next.set_sensitive(True) else: self.screen_container.but_next.set_sensitive(False) if only_ids: return ids self.clear() self.load(ids) self.count_tab_domain() return bool(ids) def search_domain(self, search_string=None, set_text=False): domain = [] # Test first parent to avoid calling unnecessary domain_parser if not self.parent and self.domain_parser: if search_string is not None: domain = self.domain_parser.parse(search_string) else: domain = self.search_value self.search_value = None if set_text: self.screen_container.set_text( self.domain_parser.string(domain)) else: domain = [('id', 'in', [x.id for x in self.group])] if domain: if self.domain: domain = ['AND', domain, self.domain] else: domain = self.domain if self.screen_container.but_active.get_active(): if domain: domain = [domain, ('active', '=', False)] else: domain = [('active', '=', False)] if self.current_view and self.current_view.view_type == 'calendar': if domain: domain = ['AND', domain, self.current_view.current_domain()] else: domain = self.current_view.current_domain() return domain def count_tab_domain(self): def set_tab_counter(count, idx): try: count = count() except RPCException: count = None self.screen_container.set_tab_counter(count, idx) screen_domain = self.search_domain(self.screen_container.get_text()) for idx, (name, domain, count) in enumerate( self.screen_container.tab_domain): if not count: continue domain = ['AND', domain, screen_domain] set_tab_counter(lambda: None, idx) RPCExecute('model', self.model_name, 'search_count', domain, context=self.context, callback=functools.partial(set_tab_counter, idx=idx)) @property def context(self): context = self.group.context if self.context_screen: context['context_model'] = self.context_screen.model_name return context @property def local_context(self): context = self.group.local_context if self.context_screen: context['context_model'] = self.context_screen.model_name return context def __get_group(self): return self.__group def __set_group(self, group): fields = {} fields_views = {} if self.group is not None: self.group.signal_unconnect(self) for name, field in self.group.fields.items(): fields[name] = field.attrs fields_views[name] = field.views self.tree_states_done.clear() self.__group = group self.parent = group.parent self.parent_name = group.parent_name if self.parent: self.filter_widget = None if len(group): self.current_record = group[0] else: self.current_record = None self.__group.signal_connect(self, 'group-cleared', self._group_cleared) self.__group.signal_connect(self, 'group-list-changed', self._group_list_changed) self.__group.signal_connect(self, 'record-modified', self._record_modified) self.__group.signal_connect(self, 'group-changed', self._group_changed) self.__group.add_fields(fields) for name, views in fields_views.items(): self.__group.fields[name].views.update(views) self.__group.exclude_field = self.exclude_field group = property(__get_group, __set_group) def new_group(self, context=None): context = context if context is not None else self.context self.group = Group(self.model_name, {}, domain=self.domain, context=context, readonly=self.readonly) def _group_cleared(self, group, signal): for view in self.views: if view.view_type == 'tree': view.display(force=True) def _group_list_changed(self, group, signal): for view in self.views: if hasattr(view, 'group_list_changed'): view.group_list_changed(group, signal) def _record_modified(self, group, signal): self.signal('record-modified', signal) def _group_changed(self, group, record): if not self.parent: self.display() self.signal('group-changed', record) def __get_current_record(self): if (self.__current_record is not None and self.__current_record.group is None): self.__current_record = None return self.__current_record def __set_current_record(self, record): self.__current_record = record if record: try: pos = self.group.index(record) + self.offset + 1 except ValueError: # XXX offset? pos = record.get_index_path() else: pos = 0 self.signal('record-message', (pos, len(self.group) + self.offset, self.search_count, record and record.id)) attachment_count = 0 if record and record.attachment_count > 0: attachment_count = record.attachment_count self.signal('attachment-count', attachment_count) unread_note = 0 if record and record.unread_note > 0: unread_note = record.unread_note self.signal('unread-note', unread_note) # update attachment-count after 1 second gobject.timeout_add(1000, self.update_attachment, record) gobject.timeout_add(1000, self.update_note, record) return True current_record = property(__get_current_record, __set_current_record) def update_attachment(self, record): if record != self.current_record: return False if record and self.signal_connected('attachment-count'): attachment_count = record.get_attachment_count() self.signal('attachment-count', attachment_count) return False def update_note(self, record): if record != self.current_record: return False if record and self.signal_connected('unread-note'): unread_note = record.get_unread_note() self.signal('unread-note', unread_note) return False def destroy(self): self.screen_container.destroy() for view in self.views: view.destroy() del self.views[:] super(Screen, self).destroy() self.group.signal_unconnect(self) self.group.destroy() def default_row_activate(self): if (self.current_view.view_type == 'tree' and int(self.current_view.attributes.get('keyword_open', 0))): return Action.exec_keyword('tree_open', { 'model': self.model_name, 'id': self.current_record.id if self.current_record else None, 'ids': [r.id for r in self.selected_records], }, context=self.local_context, warning=False) else: if not self.modified(): self.switch_view(view_type='form') return True @property def number_of_views(self): return len(self.views) + len(self.view_to_load) def switch_view(self, view_type=None, view_id=None): if view_id is not None: view_id = int(view_id) if self.current_view: self.current_view.set_value() if (self.current_record and self.current_record not in self.current_record.group): self.current_record = None fields = self.current_view.get_fields() if (self.current_record and self.current_view.editable and not self.current_record.validate(fields)): self.screen_container.set(self.current_view.widget) self.set_cursor() self.current_view.display() return def found(): if not self.current_view: return False elif not view_type and view_id is None: return False elif view_id is not None: return self.current_view.view_id == view_id else: return self.current_view.view_type == view_type while not found(): if len(self.view_to_load): self.load_view_to_load() self.__current_view = len(self.views) - 1 elif (view_id is not None and view_id not in {v.view_id for v in self.views}): self.add_view_id(view_id, view_type) self.__current_view = len(self.views) - 1 break else: self.__current_view = ((self.__current_view + 1) % len(self.views)) if not view_type and view_id is None: break if view_type and not view_id and not len(self.view_to_load): break self.screen_container.set(self.current_view.widget) self.display() # Postpone set of the cursor to ensure widgets are allocated gobject.idle_add(self.set_cursor) def load_view_to_load(self): if len(self.view_to_load): if self.view_ids: view_id = self.view_ids.pop(0) else: view_id = None view_type = self.view_to_load.pop(0) self.add_view_id(view_id, view_type) def add_view_id(self, view_id, view_type): if view_id and str(view_id) in self.views_preload: view = self.views_preload[str(view_id)] elif not view_id and view_type in self.views_preload: view = self.views_preload[view_type] else: try: view = RPCExecute('model', self.model_name, 'fields_view_get', view_id, view_type, context=self.context) except RPCException: return return self.add_view(view) def add_view(self, view): arch = view['arch'] fields = view['fields'] view_id = view['view_id'] xml_dom = xml.dom.minidom.parseString(arch) root, = xml_dom.childNodes if root.tagName == 'tree': self.fields_view_tree[view_id] = view # Ensure that loading is always lazy for fields on form view # and always eager for fields on tree or graph view if root.tagName == 'form': loading = 'lazy' else: loading = 'eager' for field in fields: if field not in self.group.fields or loading == 'eager': fields[field]['loading'] = loading else: fields[field]['loading'] = \ self.group.fields[field].attrs['loading'] self.group.add_fields(fields) for field in fields: self.group.fields[field].views.add(view_id) view = View.parse(self, xml_dom, view.get('field_childs')) view.view_id = view_id self.views.append(view) return view def new(self, default=True, rec_name=None): previous_view = self.current_view if self.current_view.view_type == 'calendar': selected_date = self.current_view.get_selected_date() if self.current_view and not self.current_view.editable: self.switch_view('form') if self.current_view.view_type != 'form': return None if self.current_record: group = self.current_record.group else: group = self.group record = group.new(default, rec_name=rec_name) group.add(record, self.new_model_position()) if previous_view.view_type == 'calendar': previous_view.set_default_date(record, selected_date) self.current_record = record self.display() # Postpone set of the cursor to ensure widgets are allocated gobject.idle_add(self.set_cursor, True) return self.current_record def new_model_position(self): position = -1 if (self.current_view and self.current_view.view_type == 'tree' and self.current_view.attributes.get('editable') == 'top'): position = 0 return position def set_on_write(self, func_name): if func_name: self.group.on_write.add(func_name) def cancel_current(self, initial_value=None): if self.current_record: self.current_record.cancel() if self.current_record.id < 0: if initial_value is not None: self.current_record.reset(initial_value) else: self.remove(records=[self.current_record]) def save_current(self): if not self.current_record: if self.current_view.view_type == 'tree' and len(self.group): self.current_record = self.group[0] else: return True self.current_view.set_value() saved = False record_id = None fields = self.current_view.get_fields() path = self.current_record.get_path(self.group) if self.current_view.view_type == 'tree': # False value must be not saved saved = all((x is 0 or x > 0 for x in self.group.save())) record_id = self.current_record.id if self.current_record else None elif self.current_record.validate(fields): record_id = self.current_record.save(force_reload=True) # False value must be not saved saved = record_id is 0 or record_id > 0 else: self.set_cursor() self.current_view.display() return False if path and record_id: path = path[:-1] + ((path[-1][0], record_id),) self.current_record = self.group.get_by_path(path) self.display() self.signal('record-saved') return saved def __get_current_view(self): if not len(self.views): return None return self.views[self.__current_view] current_view = property(__get_current_view) def set_cursor(self, new=False, reset_view=True): current_view = self.current_view if not current_view: return elif current_view.view_type in ('tree', 'form'): current_view.set_cursor(new=new, reset_view=reset_view) def get(self): if not self.current_record: return None self.current_view.set_value() return self.current_record.get() def get_on_change_value(self): if not self.current_record: return None self.current_view.set_value() return self.current_record.get_on_change_value() def modified(self): if self.current_view.view_type != 'tree': if self.current_record: if self.current_record.modified or self.current_record.id < 0: return True else: for record in self.group: if record.modified or record.id < 0: return True if self.current_view.modified: return True return False def reload(self, ids, written=False): self.group.reload(ids) if written: self.group.written(ids) if self.parent: self.parent.root_parent.reload() self.display() def unremove(self): records = self.selected_records for record in records: self.group.unremove(record) def remove(self, delete=False, remove=False, force_remove=False, records=None): records = records or self.selected_records if not records: return if delete: # Must delete children records before parent records.sort(key=lambda r: r.depth, reverse=True) if not self.group.delete(records): return False top_record = records[0] top_group = top_record.group idx = top_group.index(top_record) path = top_record.get_path(self.group) for record in records: # set current model to None to prevent __select_changed # to save the previous_model as it can be already deleted. self.current_record = None record.group.remove(record, remove=remove, signal=False, force_remove=force_remove) # send record-changed only once record.signal('record-changed') if delete: for record in records: if record in record.group.record_deleted: record.group.record_deleted.remove(record) if record in record.group.record_removed: record.group.record_removed.remove(record) if record.parent: # Save parent without deleted children record.parent.save(force_reload=False) record.destroy() if idx > 0: record = top_group[idx - 1] path = path[:-1] + ((path[-1][0], record.id,),) else: path = path[:-1] if path: self.current_record = self.group.get_by_path(path) elif len(self.group): self.current_record = self.group[0] self.set_cursor() self.display() return True def copy(self): ids = [r.id for r in self.selected_records] try: new_ids = RPCExecute('model', self.model_name, 'copy', ids, {}, context=self.context) except RPCException: return False self.load(new_ids) return True def set_tree_state(self): view = self.current_view if view.view_type not in ('tree', 'form'): return if id(view) in self.tree_states_done: return if view.view_type == 'form' and self.tree_states_done: return if (view.view_type == 'tree' and not view.attributes.get('tree_state', False)): # Mark as done to not set later when the view_type change self.tree_states_done.add(id(view)) parent = self.parent.id if self.parent else None if parent is not None and parent < 0: return expanded_nodes, selected_nodes = [], [] timestamp = self.parent._timestamp if self.parent else None state = self.tree_states[parent][view.children_field] if state: state_timestamp, expanded_nodes, selected_nodes = state if (timestamp != state_timestamp and view.view_type != 'form'): state = None if state is None and CONFIG['client.save_tree_state']: json_domain = self.get_tree_domain(parent) try: expanded_nodes, selected_nodes = RPCExecute('model', 'ir.ui.view_tree_state', 'get', self.model_name, json_domain, view.children_field) expanded_nodes = json.loads(expanded_nodes) selected_nodes = json.loads(selected_nodes) except RPCException: logger.warn( _('Unable to get view tree state for %s') % self.model_name) self.tree_states[parent][view.children_field] = ( timestamp, expanded_nodes, selected_nodes) if view.view_type == 'tree': view.expand_nodes(expanded_nodes) view.select_nodes(selected_nodes) else: if selected_nodes: record = None for node in selected_nodes[0]: new_record = self.group.get(node) if node < 0 and -node < len(self.group): # Negative id is the index of the new record new_record = self.group[-node] if not new_record: break else: record = new_record if record and record != self.current_record: self.current_record = record # Force a display of the view to synchronize the # widgets with the new record view.display() self.tree_states_done.add(id(view)) def save_tree_state(self, store=True): parent = self.parent.id if self.parent else None timestamp = self.parent._timestamp if self.parent else None for view in self.views: if view.view_type == 'form': for widgets in view.widgets.values(): for widget in widgets: if hasattr(widget, 'screen'): widget.screen.save_tree_state(store) if len(self.views) == 1 and self.current_record: path = self.current_record.id if path < 0: path = -self.current_record.group.index( self.current_record) self.tree_states[parent][view.children_field] = ( timestamp, [], [[path]]) elif view.view_type == 'tree': paths = view.get_expanded_paths() selected_paths = view.get_selected_paths() self.tree_states[parent][view.children_field] = ( timestamp, paths, selected_paths) if (store and int(view.attributes.get('tree_state', False)) and CONFIG['client.save_tree_state']): json_domain = self.get_tree_domain(parent) json_paths = json.dumps(paths, separators=(',', ':')) json_selected_path = json.dumps( selected_paths, separators=(',', ':')) try: RPCExecute('model', 'ir.ui.view_tree_state', 'set', self.model_name, json_domain, view.children_field, json_paths, json_selected_path, process_exception=False) except Exception: logger.warn( _('Unable to set view tree state'), exc_info=True) def get_tree_domain(self, parent): if parent: domain = (self.domain + [(self.exclude_field, '=', parent)]) else: domain = self.domain json_domain = json.dumps( domain, cls=JSONEncoder, separators=(',', ':')) return json_domain def load(self, ids, set_cursor=True, modified=False): self.tree_states.clear() self.tree_states_done.clear() self.group.load(ids, modified=modified) self.current_view.reset() if ids and self.current_view.view_type != 'calendar': self.display(ids[0]) else: self.current_record = None self.display() if set_cursor: self.set_cursor() def display(self, res_id=None, set_cursor=False): if res_id: self.current_record = self.group.get(res_id) else: if (self.current_record and self.current_record in self.current_record.group): pass elif self.group and self.current_view.view_type != 'calendar': self.current_record = self.group[0] else: self.current_record = None if self.views: self.search_active(self.current_view.view_type in ('tree', 'graph', 'calendar')) for view in self.views: # Always display tree view to update model # because view can be used even if it is not shown # like for save_tree_state if (view == self.current_view or view.view_type == 'tree' or view.widget.get_parent()): view.display() self.current_view.widget.set_sensitive( bool(self.group or (self.current_view.view_type != 'form') or self.current_record)) if set_cursor: self.set_cursor(reset_view=False) self.set_tree_state() # Force record-message signal self.current_record = self.current_record def display_next(self): view = self.current_view view.set_value() self.set_cursor(reset_view=False) if view.view_type == 'tree' and len(self.group): range_ = view.treeview.get_visible_range() if range_: start, end = range_ vadjustment = view.treeview.get_vadjustment() vadjustment.props.value = min( vadjustment.props.value + vadjustment.props.page_increment, vadjustment.props.upper) model = view.treeview.get_model() iter_ = model.get_iter(end) self.current_record = model.get_value(iter_, 0) elif (view.view_type == 'form' and self.current_record and self.current_record.group): group = self.current_record.group record = self.current_record while group: children = record.children_group(view.children_field) if children: record = children[0] break idx = group.index(record) + 1 if idx < len(group): record = group[idx] break parent = record.parent if not parent or record.model_name != parent.model_name: break next = parent.next.get(id(parent.group)) while not next: parent = parent.parent if not parent: break next = parent.next.get(id(parent.group)) if not next: break record = next break self.current_record = record elif view.view_type == 'calendar': record = self.current_record goocalendar = view.widgets.get('goocalendar') if goocalendar: date = goocalendar.selected_date year = date.year month = date.month start = datetime.datetime(year, month, 1) nb_days = calendar.monthrange(year, month)[1] delta = datetime.timedelta(days=nb_days) end = start + delta events = goocalendar.event_store.get_events(start, end) events.sort() if not record: if events: self.current_record = events[0].record else: self.current_record = None else: for idx, event in enumerate(events): if event.record == record: next_id = idx + 1 if next_id < len(events): self.current_record = events[next_id].record break else: self.current_record = self.group[0] if len(self.group) else None self.set_cursor(reset_view=False) view.display() def display_prev(self): view = self.current_view view.set_value() self.set_cursor(reset_view=False) if view.view_type == 'tree' and len(self.group): range_ = view.treeview.get_visible_range() if range_: start, end = range_ vadjustment = view.treeview.get_vadjustment() vadjustment.props.value = min( vadjustment.props.value - vadjustment.props.page_increment, vadjustment.props.lower) model = view.treeview.get_model() iter_ = model.get_iter(start) self.current_record = model.get_value(iter_, 0) elif (view.view_type == 'form' and self.current_record and self.current_record.group): group = self.current_record.group record = self.current_record idx = group.index(record) - 1 if idx >= 0: record = group[idx] children = True while children: children = record.children_group(view.children_field) if children: record = children[-1] else: parent = record.parent if parent and record.model_name == parent.model_name: record = parent self.current_record = record elif view.view_type == 'calendar': record = self.current_record goocalendar = view.widgets.get('goocalendar') if goocalendar: date = goocalendar.selected_date year = date.year month = date.month start = datetime.datetime(year, month, 1) nb_days = calendar.monthrange(year, month)[1] delta = datetime.timedelta(days=nb_days) end = start + delta events = goocalendar.event_store.get_events(start, end) events.sort() if not record: if events: self.current_record = events[0].record else: self.current_record = None else: for idx, event in enumerate(events): if event.record == record: prev_id = idx - 1 if prev_id >= 0: self.current_record = events[prev_id].record break else: self.current_record = self.group[-1] if len(self.group) else None self.set_cursor(reset_view=False) view.display() def invalid_message(self, record=None): if record is None: record = self.current_record domain_string = _('"%s" is not valid according to its domain') domain_parser = DomainParser( {n: f.attrs for n, f in record.group.fields.items()}) fields = [] for field, invalid in sorted(record.invalid_fields.items()): string = record.group.fields[field].attrs['string'] if invalid == 'required' or invalid == [[field, '!=', None]]: fields.append(_('"%s" is required') % string) elif invalid == 'domain': fields.append(domain_string % string) elif invalid == 'children': fields.append(_('The values of "%s" are not valid') % string) else: if domain_parser.stringable(invalid): fields.append(domain_parser.string(invalid)) else: fields.append(domain_string % string) if len(fields) > 5: fields = fields[:5] + ['...'] return '\n'.join(fields) @property def selected_records(self): return self.current_view.selected_records def clear(self): self.current_record = None self.group.clear() def on_change(self, fieldname, attr): self.current_record.on_change(fieldname, attr) self.display() def get_buttons(self): 'Return active buttons for the current view' def is_active(record, button): if button.attrs.get('type', 'class') == 'instance': return False states = record.expr_eval(button.attrs.get('states', {})) return not (states.get('invisible') or states.get('readonly')) if not self.selected_records: return [] buttons = self.current_view.get_buttons() for record in self.selected_records: buttons = [b for b in buttons if is_active(record, b)] if not buttons: break return buttons def button(self, button): 'Execute button on the selected records' self.current_view.set_value() fields = self.current_view.get_fields() for record in self.selected_records: domain = record.expr_eval( button.get('states', {})).get('pre_validate', []) if not record.validate(fields, pre_validate=domain): warning(self.invalid_message(record), _('Pre-validation')) self.display(set_cursor=True) if domain: # Reset valid state with normal domain record.validate(fields) return if button.get('confirm', False) and not sur(button['confirm']): return if button.get('type', 'class') == 'class': if not self.current_record.save(force_reload=False): return if button.get('type', 'class') == 'class': self._button_class(button) else: self._button_instance(button) def _button_instance(self, button): record = self.current_record args = record.expr_eval(button.get('change', [])) values = record._get_on_change_args(args) try: changes = RPCExecute('model', self.model_name, button['name'], values, context=self.context) except RPCException: return record.set_on_change(changes) record.signal('record-changed') def _button_class(self, button): ids = [r.id for r in self.selected_records] context = self.context context['_timestamp'] = {} for record in self.selected_records: context['_timestamp'].update(record.get_timestamp()) try: action = RPCExecute('model', self.model_name, button['name'], ids, context=context) except RPCException: action = None self.reload(ids, written=True) if isinstance(action, str): self.client_action(action) elif action: Action.execute(action, { 'model': self.model_name, 'id': self.current_record.id, 'ids': ids, }, context=self.context, keyword=True) def client_action(self, action): access = MODELACCESS[self.model_name] if action == 'new': if access['create']: self.new() elif action == 'delete': if access['delete']: self.remove(delete=not self.parent, force_remove=not self.parent) elif action == 'remove': if access['write'] and access['read'] and self.parent: self.remove(remove=True) elif action == 'copy': if access['create']: self.copy() elif action == 'next': self.display_next() elif action == 'previous': self.display_prev() elif action == 'close': from tryton.gui import Main Main().sig_win_close() elif action.startswith('switch'): self.switch_view(*action.split(None, 2)[1:]) elif action == 'reload': if (self.current_view.view_type in ['tree', 'graph', 'calendar'] and not self.parent): self.search_filter() elif action == 'reload menu': from tryton.gui import Main RPCContextReload(Main().sig_win_menu) elif action == 'reload context': RPCContextReload() def get_url(self, name=''): query_string = [] if self.domain: query_string.append(('domain', json.dumps( self.domain, cls=JSONEncoder, separators=(',', ':')))) context = self.local_context # Avoid rpc context if context: query_string.append(('context', json.dumps( context, cls=JSONEncoder, separators=(',', ':')))) if self.context_screen: query_string.append( ('context_model', self.context_screen.model_name)) if name: query_string.append( ('name', json.dumps(name, separators=(',', ':')))) path = [CONFIG['login.db'], 'model', self.model_name] view_ids = [v.view_id for v in self.views] + self.view_ids if self.current_view.view_type != 'form': if self.search_value: search_value = self.search_value else: search_string = self.screen_container.get_text() search_value = self.domain_parser.parse(search_string) if search_value: query_string.append(('search_value', json.dumps( search_value, cls=JSONEncoder, separators=(',', ':')))) elif self.current_record and self.current_record.id > -1: path.append(str(self.current_record.id)) i = view_ids.index(self.current_view.view_id) view_ids = view_ids[i:] + view_ids[:i] if view_ids: query_string.append(('views', json.dumps( view_ids, separators=(',', ':')))) query_string = urllib.parse.urlencode(query_string) return urllib.parse.urlunparse(('tryton', CONFIG['login.host'], '/'.join(path), query_string, '', '')) tryton-5.0.17/tryton/gui/window/view_form/model/0000755000175000017500000000000013571264253021212 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/model/field.py0000644000175000017500000011433013566557275022666 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os from itertools import chain import tempfile import logging import locale from tryton.common import \ domain_inversion, eval_domain, localize_domain, \ merge, inverse_leaf, filter_leaf, prepare_reference_domain, \ extract_reference_models, concat, simplify, unique_value, \ EvalEnvironment import tryton.common as common import datetime import decimal from decimal import Decimal import math from tryton.common import RPCExecute, RPCException from tryton.common.htmltextbuffer import guess_decode from tryton.pyson import PYSONDecoder from tryton.config import CONFIG logger = logging.getLogger(__name__) class Field(object): ''' get: return the values to write to the server get_client: return the value for the client widget (form_gtk) set: save the value from the server set_client: save the value from the widget ''' _default = None @staticmethod def get_field(ctype): return TYPES.get(ctype, CharField) def __init__(self, attrs): self.attrs = attrs self.name = attrs['name'] self.views = set() def sig_changed(self, record): record.on_change([self.name]) record.on_change_with([self.name]) record.autocomplete_with(self.name) record.set_field_context() def domains_get(self, record, pre_validate=None): screen_domain = domain_inversion( [record.group.domain4inversion, pre_validate or []], self.name, EvalEnvironment(record)) if isinstance(screen_domain, bool) and not screen_domain: screen_domain = [('id', '=', None)] elif isinstance(screen_domain, bool) and screen_domain: screen_domain = [] attr_domain = record.expr_eval(self.attrs.get('domain', [])) return screen_domain, attr_domain def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) return concat(localize_domain(screen_domain), attr_domain) def validation_domains(self, record, pre_validate=None): return concat(*self.domains_get(record, pre_validate)) def get_context(self, record, record_context=None, local=False): if record_context is not None: context = record_context.copy() else: context = record.get_context(local=local) context.update(record.expr_eval(self.attrs.get('context', {}))) return context def get_search_context(self, record): context = self.get_context(record) context.update(record.expr_eval(self.attrs.get('search_context', {}))) return context def get_search_order(self, record): order = record.expr_eval(self.attrs.get('search_order', None)) return order def _is_empty(self, record): return not self.get_eval(record) def check_required(self, record): state_attrs = self.get_state_attrs(record) if bool(int(state_attrs.get('required') or 0)): if (self._is_empty(record) and not bool(int(state_attrs.get('readonly') or 0))): return False return True def validate(self, record, softvalidation=False, pre_validate=None): if self.attrs.get('readonly'): return True invalid = False self.get_state_attrs(record)['domain_readonly'] = False domain = simplify(self.validation_domains(record, pre_validate)) if not softvalidation: if not self.check_required(record): invalid = 'required' if isinstance(domain, bool): if not domain: invalid = 'domain' elif domain == [('id', '=', None)]: invalid = 'domain' else: unique, leftpart, value = unique_value(domain) if unique: # If the inverted domain is so constraint that only one value # is possible we should use it. But we must also pay attention # to the fact that the original domain might be a 'OR' domain # and thus not preventing the modification of fields. if value is False: # XXX to remove once server domains are fixed value = None setdefault = True if record.group.domain: original_domain = merge(record.group.domain) else: original_domain = merge(domain) domain_readonly = original_domain[0] == 'AND' if '.' in leftpart: recordpart, localpart = leftpart.split('.', 1) constraintfields = set() if domain_readonly: for leaf in localize_domain(original_domain[1:]): constraintfields.add(leaf[0]) if localpart != 'id' or recordpart not in constraintfields: setdefault = False if setdefault and not pre_validate: self.set_client(record, value) self.get_state_attrs(record)['domain_readonly'] = ( domain_readonly) if not eval_domain(domain, EvalEnvironment(record)): invalid = domain self.get_state_attrs(record)['invalid'] = invalid return not invalid def set(self, record, value): record.value[self.name] = value def get(self, record): return record.value.get(self.name, self._default) def get_eval(self, record): return self.get(record) def get_on_change_value(self, record): return self.get_eval(record) def set_client(self, record, value, force_change=False): previous_value = self.get(record) self.set(record, value) if previous_value != self.get(record): record.modified_fields.setdefault(self.name) record.signal('record-modified') self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') elif force_change: self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') def get_client(self, record): return self.get(record) def set_default(self, record, value): self.set(record, value) record.modified_fields.setdefault(self.name) def set_on_change(self, record, value): record.modified_fields.setdefault(self.name) self.set(record, value) def state_set(self, record, states=('readonly', 'required', 'invisible')): state_changes = record.expr_eval(self.attrs.get('states', {})) for key in states: if key == 'readonly' and self.attrs.get(key, False): continue if key in state_changes: self.get_state_attrs(record)[key] = state_changes[key] elif key in self.attrs: self.get_state_attrs(record)[key] = self.attrs[key] if (record.group.readonly or self.get_state_attrs(record).get('domain_readonly')): self.get_state_attrs(record)['readonly'] = True def get_state_attrs(self, record): if self.name not in record.state_attrs: record.state_attrs[self.name] = self.attrs.copy() if record.group.readonly or record.readonly: record.state_attrs[self.name]['readonly'] = True return record.state_attrs[self.name] def get_timestamp(self, record): return {} class CharField(Field): _default = '' def get(self, record): return super(CharField, self).get(record) or self._default def set_client(self, record, value, force_change=False): if isinstance(value, bytes): try: value = guess_decode(value) except UnicodeDecodeError: logger.warning( "The encoding can not be guessed for field '%(name)s'", {'name': self.name}) value = None super().set_client(record, value, force_change) class SelectionField(Field): _default = None def get_client(self, record): return record.value.get(self.name) class DateTimeField(Field): _default = None def set_client(self, record, value, force_change=False): if isinstance(value, datetime.time): current_value = self.get_client(record) if current_value: value = datetime.datetime.combine( current_value.date(), value) else: value = None elif value and not isinstance(value, datetime.datetime): current_value = self.get_client(record) if current_value: time = current_value.time() else: time = datetime.time() value = datetime.datetime.combine(value, time) if value: value = common.untimezoned_date(value) super(DateTimeField, self).set_client(record, value, force_change=force_change) def get_client(self, record): value = super(DateTimeField, self).get_client(record) if value: return common.timezoned_date(value) def date_format(self, record): context = self.get_context(record) return common.date_format(context.get('date_format')) def time_format(self, record): return record.expr_eval(self.attrs['format']) class DateField(Field): _default = None def set_client(self, record, value, force_change=False): if isinstance(value, datetime.datetime): assert(value.time() == datetime.time()) value = value.date() super(DateField, self).set_client(record, value, force_change=force_change) def date_format(self, record): context = self.get_context(record) return common.date_format(context.get('date_format')) class TimeField(Field): _default = None def _is_empty(self, record): return self.get(record) is None def set_client(self, record, value, force_change=False): if isinstance(value, datetime.datetime): value = value.time() super(TimeField, self).set_client(record, value, force_change=force_change) def time_format(self, record): return record.expr_eval(self.attrs['format']) class TimeDeltaField(Field): _default = None def _is_empty(self, record): return self.get(record) is None def converter(self, group): return group.context.get(self.attrs.get('converter')) def set_client(self, record, value, force_change=False): if isinstance(value, str): value = common.timedelta.parse(value, self.converter(record.group)) super(TimeDeltaField, self).set_client( record, value, force_change=force_change) def get_client(self, record): value = super(TimeDeltaField, self).get_client(record) return common.timedelta.format(value, self.converter(record.group)) class FloatField(Field): _default = None def _is_empty(self, record): return self.get(record) is None def get(self, record): return record.value.get(self.name, self._default) def digits(self, record, factor=1): digits = record.expr_eval(self.attrs.get('digits')) if not digits or any(d is None for d in digits): return shift = int(round(math.log(abs(factor), 10))) return (digits[0] + shift, digits[1] - shift) def convert(self, value): try: return locale.atof(value) except ValueError: return self._default def set_client(self, record, value, force_change=False, factor=1): if isinstance(value, str): value = self.convert(value) if value is not None: # Keep the same type if isinstance(value, int): value //= factor else: value /= factor super(FloatField, self).set_client(record, value, force_change=force_change) def get_client(self, record, factor=1): value = record.value.get(self.name) if value is not None: digits = self.digits(record, factor=factor) if digits: p = int(digits[1]) else: d = value * factor if not isinstance(d, Decimal): d = Decimal(repr(d)) p = -int(d.as_tuple().exponent) return locale.format('%.*f', (p, value * factor), True) else: return '' class NumericField(FloatField): def convert(self, value): try: return locale.atof(value, Decimal) except decimal.InvalidOperation: return self._default def set_client(self, record, value, force_change=False, factor=1): return super(NumericField, self).set_client(record, value, force_change=force_change, factor=Decimal(str(factor))) def get_client(self, record, factor=1): return super(NumericField, self).get_client(record, factor=Decimal(str(factor))) class IntegerField(FloatField): def convert(self, value): try: return locale.atoi(value) except ValueError: return self._default def set_client(self, record, value, force_change=False, factor=1): return super(IntegerField, self).set_client(record, value, force_change=force_change, factor=int(factor)) def get_client(self, record, factor=1): return super(IntegerField, self).get_client(record, factor=int(factor)) class BooleanField(Field): _default = False def set_client(self, record, value, force_change=False): value = bool(value) super(BooleanField, self).set_client(record, value, force_change=force_change) def get(self, record): return bool(record.value.get(self.name)) def get_client(self, record): return bool(record.value.get(self.name)) class M2OField(Field): ''' internal = (id, name) ''' _default = None def _is_empty(self, record): return self.get(record) is None def get_client(self, record): rec_name = record.value.get(self.name + '.rec_name') if rec_name is None: self.set(record, self.get(record)) rec_name = record.value.get(self.name + '.rec_name') or '' return rec_name def set_client(self, record, value, force_change=False): if isinstance(value, (tuple, list)): value, rec_name = value else: if value == self.get(record): rec_name = record.value.get(self.name + '.rec_name', '') else: rec_name = '' record.value[self.name + '.rec_name'] = rec_name super(M2OField, self).set_client(record, value, force_change=force_change) def set(self, record, value): rec_name = record.value.get(self.name + '.rec_name') or '' if not rec_name and value is not None and value >= 0: try: result, = RPCExecute('model', self.attrs['relation'], 'read', [value], ['rec_name']) except RPCException: return rec_name = result['rec_name'] or '' record.value[self.name + '.rec_name'] = rec_name record.value[self.name] = value def get_context(self, record, record_context=None, local=False): context = super(M2OField, self).get_context( record, record_context=record_context, local=local) if self.attrs.get('datetime_field'): context['_datetime'] = record.get_eval( )[self.attrs.get('datetime_field')] return context def validation_domains(self, record, pre_validate=None): screen_domain, attr_domain = self.domains_get(record, pre_validate) return screen_domain def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) return concat(localize_domain(inverse_leaf(screen_domain), self.name), attr_domain) def get_on_change_value(self, record): if record.parent_name == self.name and record.parent: return record.parent.get_on_change_value( skip={record.group.child_name}) return super(M2OField, self).get_on_change_value(record) class O2OField(M2OField): pass class O2MField(Field): ''' internal = Group of the related objects ''' _default = None def __init__(self, attrs): super(O2MField, self).__init__(attrs) def _group_changed(self, group, record): if not record.parent: return # Store parent as it could be removed by validation parent = record.parent parent.modified_fields.setdefault(self.name) self.sig_changed(parent) parent.validate(softvalidation=True) parent.signal('record-changed') def _group_list_changed(self, group, signal): if group.model_name == group.parent.model_name: group.parent.group.signal('group-list-changed', signal) def _group_cleared(self, group, signal): if group.model_name == group.parent.model_name: group.parent.signal('group-cleared') def _record_modified(self, group, record): if not record.parent: return record.parent.signal('record-modified') def _set_default_value(self, record, fields=None): if record.value.get(self.name) is not None: return from .group import Group parent_name = self.attrs.get('relation_field', '') fields = fields or {} context = record.expr_eval(self.attrs.get('context', {})) group = Group(self.attrs['relation'], fields, parent=record, parent_name=parent_name, child_name=self.name, context=context, parent_datetime_field=self.attrs.get('datetime_field')) if not fields and record.model_name == self.attrs['relation']: group.fields = record.group.fields record.value[self.name] = group self._connect_value(group) def _connect_value(self, group): group.signal_connect(group, 'group-changed', self._group_changed) group.signal_connect(group, 'group-list-changed', self._group_list_changed) group.signal_connect(group, 'group-cleared', self._group_cleared) group.signal_connect(group, 'record-modified', self._record_modified) def get_client(self, record): self._set_default_value(record) return record.value.get(self.name) def get(self, record): if record.value.get(self.name) is None: return [] record_removed = record.value[self.name].record_removed record_deleted = record.value[self.name].record_deleted result = [] parent_name = self.attrs.get('relation_field', '') to_add = [] to_create = [] to_write = [] for record2 in record.value[self.name]: if record2 in record_removed or record2 in record_deleted: continue if record2.id >= 0: if record2.modified: values = record2.get() values.pop(parent_name, None) if values: to_write.extend(([record2.id], values)) to_add.append(record2.id) else: values = record2.get() values.pop(parent_name, None) to_create.append(values) if to_add: result.append(('add', to_add)) if to_create: result.append(('create', to_create)) if to_write: result.append(('write',) + tuple(to_write)) if record_removed: result.append(('remove', [x.id for x in record_removed])) if record_deleted: result.append(('delete', [x.id for x in record_deleted])) return result def get_timestamp(self, record): if record.value.get(self.name) is None: return {} result = {} record_modified = (r for r in record.value[self.name] if r.modified) for record2 in chain(record_modified, record.value[self.name].record_removed, record.value[self.name].record_deleted): result.update(record2.get_timestamp()) return result def get_eval(self, record): if record.value.get(self.name) is None: return [] record_removed = record.value[self.name].record_removed record_deleted = record.value[self.name].record_deleted return [x.id for x in record.value[self.name] if x not in record_removed and x not in record_deleted] def get_on_change_value(self, record): result = [] if record.value.get(self.name) is None: return [] for record2 in record.value[self.name]: if not (record2.deleted or record2.removed): result.append( record2.get_on_change_value( skip={self.attrs.get('relation_field', '')})) return result def _set_value(self, record, value, default=False, modified=False): self._set_default_value(record) group = record.value[self.name] if value is None: value = [] if not value or isinstance(value[0], int): mode = 'list ids' else: mode = 'list values' if mode == 'list values': context = self.get_context(record) field_names = set(f for v in value for f in v if f not in group.fields and '.' not in f) if field_names: try: fields = RPCExecute('model', self.attrs['relation'], 'fields_get', list(field_names), context=context) except RPCException: return group.load_fields(fields) if mode == 'list ids': for old_record in group: if old_record.id not in value: group.remove(old_record, remove=True, signal=False) group.load(value, modified=modified) else: for vals in value: new_record = record.value[self.name].new(default=False) if default: # Don't validate as parent will validate new_record.set_default(vals, signal=False, validate=False) group.add(new_record, signal=False) else: new_record.set(vals, signal=False) group.append(new_record) # Trigger signal only once with the last record new_record.signal('record-changed') def set(self, record, value, _default=False): group = record.value.get(self.name) fields = {} if group is not None: fields = group.fields.copy() # Unconnect to prevent infinite loop group.signal_unconnect(group) group.destroy() elif record.model_name == self.attrs['relation']: fields = record.group.fields if fields: fields = dict((fname, field.attrs) for fname, field in fields.items()) record.value[self.name] = None self._set_default_value(record, fields=fields) group = record.value[self.name] group.signal_unconnect(group) self._set_value(record, value, default=_default) self._connect_value(group) def set_client(self, record, value, force_change=False): # domain inversion could try to set None as value if value is None: value = [] # domain inversion could try to set id as value if isinstance(value, int): value = [value] previous_ids = self.get_eval(record) # The order of the ids is not significant modified = set(previous_ids) != set(value) self._set_value(record, value, modified=modified) if modified: record.modified_fields.setdefault(self.name) record.signal('record-modified') self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') elif force_change: self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') def set_default(self, record, value): self.set(record, value, _default=True) record.modified_fields.setdefault(self.name) def set_on_change(self, record, value): record.modified_fields.setdefault(self.name) self._set_default_value(record) if isinstance(value, (list, tuple)): self._set_value(record, value, modified=True) return if value and (value.get('add') or value.get('update')): context = self.get_context(record) fields = record.value[self.name].fields values = chain(value.get('update', []), (d for _, d in value.get('add', []))) field_names = set(f for v in values for f in v if f not in fields and f != 'id' and '.' not in f) if field_names: try: fields = RPCExecute('model', self.attrs['relation'], 'fields_get', list(field_names), context=context) except RPCException: return else: fields = {} to_remove = [] for record2 in record.value[self.name]: if not record2.id: to_remove.append(record2) if value and value.get('remove'): for record_id in value['remove']: record2 = record.value[self.name].get(record_id) if record2 is not None: to_remove.append(record2) for record2 in to_remove: record.value[self.name].remove(record2, signal=False, force_remove=False) if value and (value.get('add') or value.get('update', [])): record.value[self.name].add_fields(fields) for index, vals in value.get('add', []): new_record = record.value[self.name].new(default=False) record.value[self.name].add(new_record, index, signal=False) new_record.set_on_change(vals) for vals in value.get('update', []): if 'id' not in vals: continue record2 = record.value[self.name].get(vals['id']) if record2 is not None: record2.set_on_change(vals) def validation_domains(self, record, pre_validate=None): screen_domain, attr_domain = self.domains_get(record, pre_validate) return screen_domain def validate(self, record, softvalidation=False, pre_validate=None): invalid = False ldomain = localize_domain(domain_inversion( record.group.clean4inversion(pre_validate or []), self.name, EvalEnvironment(record)), self.name) if isinstance(ldomain, bool): if ldomain: ldomain = [] else: ldomain = [('id', '=', None)] for record2 in record.value.get(self.name, []): if not record2.loaded and record2.id >= 0 and not pre_validate: continue if not record2.validate(softvalidation=softvalidation, pre_validate=ldomain): invalid = 'children' test = super(O2MField, self).validate(record, softvalidation, pre_validate) if test and invalid: self.get_state_attrs(record)['invalid'] = invalid return False return test def state_set(self, record, states=('readonly', 'required', 'invisible')): self._set_default_value(record) super(O2MField, self).state_set(record, states=states) def get_removed_ids(self, record): return [x.id for x in record.value[self.name].record_removed] def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) # Forget screen_domain because it only means at least one record # and not all records return attr_domain class M2MField(O2MField): def get_on_change_value(self, record): return self.get_eval(record) class ReferenceField(Field): _default = None def _is_empty(self, record): result = super(ReferenceField, self)._is_empty(record) if not result and (record.value[self.name] is None or record.value[self.name][1] < 0): result = True return result def get_client(self, record): if record.value.get(self.name): model, _ = record.value[self.name] name = record.value.get(self.name + '.rec_name') or '' return model, name else: return None def get(self, record): if (record.value.get(self.name) and record.value[self.name][0] and record.value[self.name][1] is not None and record.value[self.name][1] >= -1): return ','.join(map(str, record.value[self.name])) return None def set_client(self, record, value, force_change=False): if value: if isinstance(value, str): value = value.split(',') ref_model, ref_id = value if isinstance(ref_id, (tuple, list)): ref_id, rec_name = ref_id else: if ref_id: try: ref_id = int(ref_id) except ValueError: pass if '%s,%s' % (ref_model, ref_id) == self.get(record): rec_name = record.value.get(self.name + '.rec_name', '') else: rec_name = '' record.value[self.name + '.rec_name'] = rec_name value = (ref_model, ref_id) super(ReferenceField, self).set_client(record, value, force_change=force_change) def set(self, record, value): if not value: record.value[self.name] = self._default return if isinstance(value, str): ref_model, ref_id = value.split(',') if not ref_id: ref_id = None else: try: ref_id = int(ref_id) except ValueError: pass else: ref_model, ref_id = value rec_name = record.value.get(self.name + '.rec_name') or '' if ref_model and ref_id is not None and ref_id >= 0: if not rec_name and ref_id >= 0: try: result, = RPCExecute('model', ref_model, 'read', [ref_id], ['rec_name']) except RPCException: return rec_name = result['rec_name'] elif ref_model: rec_name = '' else: rec_name = str(ref_id) record.value[self.name] = ref_model, ref_id record.value[self.name + '.rec_name'] = rec_name def get_context(self, record, record_context=None, local=False): context = super(ReferenceField, self).get_context( record, record_context, local=local) if self.attrs.get('datetime_field'): context['_datetime'] = record.get_eval( )[self.attrs.get('datetime_field')] return context def get_on_change_value(self, record): if record.parent_name == self.name and record.parent: return record.parent.model_name, record.parent.get_on_change_value( skip={record.group.child_name}) return super(ReferenceField, self).get_on_change_value(record) def validation_domains(self, record, pre_validate=None): screen_domain, attr_domain = self.domains_get(record, pre_validate) return screen_domain def domain_get(self, record): if record.value.get(self.name): model = record.value[self.name][0] else: model = None screen_domain, attr_domain = self.domains_get(record) screen_domain = prepare_reference_domain(screen_domain, self.name) return concat(localize_domain( filter_leaf(screen_domain, self.name, model), strip_target=True), attr_domain) def get_models(self, record): screen_domain, attr_domain = self.domains_get(record) return extract_reference_models( concat(screen_domain, attr_domain), self.name) class _FileCache(object): def __init__(self, path): self.path = path class BinaryField(Field): _default = None def get(self, record): result = record.value.get(self.name, self._default) if isinstance(result, _FileCache): try: with open(result.path, 'rb') as fp: result = fp.read() except IOError: result = self.get_data(record) return result def get_client(self, record): return self.get(record) def set_client(self, record, value, force_change=False): _, filename = tempfile.mkstemp(prefix='tryton_') data = value or b'' if isinstance(data, str): data = data.encode('utf-8') with open(filename, 'wb') as fp: fp.write(data) self.set(record, _FileCache(filename)) record.modified_fields.setdefault(self.name) record.signal('record-modified') self.sig_changed(record) record.validate(softvalidation=True) record.signal('record-changed') def get_size(self, record): result = record.value.get(self.name) or 0 if isinstance(result, _FileCache): result = os.stat(result.path).st_size elif isinstance(result, (str, bytes)): result = len(result) return result def get_data(self, record): if not isinstance(record.value.get(self.name), (str, bytes, _FileCache)): if record.id < 0: return b'' context = record.get_context() try: values, = RPCExecute('model', record.model_name, 'read', [record.id], [self.name], context=context) except RPCException: return b'' _, filename = tempfile.mkstemp(prefix='tryton_') data = values[self.name] or b'' if isinstance(data, str): data = data.encode('utf-8') with open(filename, 'wb') as fp: fp.write(data) self.set(record, _FileCache(filename)) return self.get(record) class DictField(Field): _default = {} def __init__(self, attrs): super(DictField, self).__init__(attrs) self.keys = {} def get(self, record): return super(DictField, self).get(record) or self._default def get_client(self, record): return super(DictField, self).get_client(record) or self._default def validation_domains(self, record, pre_validate=None): screen_domain, attr_domain = self.domains_get(record, pre_validate) return screen_domain def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) return concat(localize_domain(screen_domain), attr_domain) def date_format(self, record): context = self.get_context(record) return common.date_format(context.get('date_format')) def time_format(self, record): return '%X' def add_keys(self, keys, record): schema_model = self.attrs['schema_model'] context = self.get_context(record) domain = self.domain_get(record) batchlen = min(10, CONFIG['client.limit']) for i in range(0, len(keys), batchlen): sub_keys = keys[i:i + batchlen] try: key_ids = RPCExecute('model', schema_model, 'search', [('name', 'in', sub_keys), domain], 0, CONFIG['client.limit'], None, context=context) except RPCException: key_ids = [] if not key_ids: continue try: values = RPCExecute('model', schema_model, 'get_keys', key_ids, context=context) except RPCException: values = [] if not values: continue self.keys.update({k['name']: k for k in values}) def add_new_keys(self, key_ids, record): schema_model = self.attrs['schema_model'] context = self.get_context(record) try: new_fields = RPCExecute('model', schema_model, 'get_keys', key_ids, context=context) except RPCException: new_fields = [] new_keys = [] for new_field in new_fields: name = new_field['name'] new_keys.append(name) self.keys[name] = new_field return new_keys def validate(self, record, softvalidation=False, pre_validate=None): valid = super(DictField, self).validate( record, softvalidation, pre_validate) if self.attrs.get('readonly'): return valid decoder = PYSONDecoder() field_value = self.get_eval(record) domain = [] for key in field_value: if key not in self.keys: continue key_domain = self.keys[key].get('domain') if key_domain: domain.append(decoder.decode(key_domain)) valid_value = eval_domain(domain, field_value) if not valid_value: self.get_state_attrs(record)['invalid'] = 'domain' return valid and valid_value TYPES = { 'char': CharField, 'integer': IntegerField, 'biginteger': IntegerField, 'float': FloatField, 'numeric': NumericField, 'many2one': M2OField, 'many2many': M2MField, 'one2many': O2MField, 'reference': ReferenceField, 'selection': SelectionField, 'boolean': BooleanField, 'datetime': DateTimeField, 'date': DateField, 'time': TimeField, 'timestamp': DateTimeField, 'timedelta': TimeDeltaField, 'one2one': O2OField, 'binary': BinaryField, 'dict': DictField, } tryton-5.0.17/tryton/gui/window/view_form/model/__init__.py0000644000175000017500000000022013354423127023311 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. tryton-5.0.17/tryton/gui/window/view_form/model/record.py0000644000175000017500000005734113563614150023050 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from tryton.signal_event import SignalEvent import tryton.common as common from tryton.pyson import PYSONDecoder from . import field as fields from tryton.common import RPCExecute, RPCException from tryton.config import CONFIG class Record(SignalEvent): id = -1 def __init__(self, model_name, obj_id, group=None): super(Record, self).__init__() self.model_name = model_name if obj_id is None: self.id = Record.id else: self.id = obj_id if self.id < 0: Record.id -= 1 self._loaded = set() self.group = group if group is not None: assert model_name == group.model_name self.state_attrs = {} self.modified_fields = {} self._timestamp = None self.attachment_count = -1 self.unread_note = -1 self.button_clicks = {} self.next = {} # Used in Group list self.value = {} self.autocompletion = {} self.exception = False self.destroyed = False def __getitem__(self, name): if name not in self._loaded and self.id >= 0: id2record = { self.id: self, } if name == '*': loading = 'eager' views = set() for field in self.group.fields.values(): if field.attrs.get('loading', 'eager') == 'lazy': loading = 'lazy' views |= field.views # Set a valid name for next loaded check for fname, field in self.group.fields.items(): if field.attrs.get('loading', 'eager') == loading: name = fname break else: loading = self.group.fields[name].attrs.get('loading', 'eager') views = self.group.fields[name].views if loading == 'eager': fields = ((fname, field) for fname, field in self.group.fields.items() if field.attrs.get('loading', 'eager') == 'eager') else: fields = self.group.fields.items() fnames = [fname for fname, field in fields if fname not in self._loaded and (not views or (views & field.views))] fnames.extend(('%s.rec_name' % fname for fname in fnames[:] if self.group.fields[fname].attrs['type'] in ('many2one', 'one2one', 'reference'))) if 'rec_name' not in fnames: fnames.append('rec_name') fnames.append('_timestamp') record_context = self.get_context() if loading == 'eager': limit = int(CONFIG['client.limit'] / len(fnames)) def filter_group(record): return name not in record._loaded and record.id >= 0 def filter_parent_group(record): return (filter_group(record) and record.id not in id2record and ((record.group == self.group) # Don't compute context for same group or (record.get_context() == record_context))) if self.parent and self.parent.model_name == self.model_name: group = sum(self.parent.group.children, []) filter_ = filter_parent_group else: group = self.group filter_ = filter_group if self in group: idx = group.index(self) length = len(group) n = 1 while len(id2record) < limit and (idx - n >= 0 or idx + n < length) and n < 2 * limit: if idx - n >= 0: record = group[idx - n] if filter_(record): id2record[record.id] = record if idx + n < length: record = group[idx + n] if filter_(record): id2record[record.id] = record n += 1 ctx = record_context.copy() ctx.update(dict(('%s.%s' % (self.model_name, fname), 'size') for fname, field in self.group.fields.items() if field.attrs['type'] == 'binary' and fname in fnames)) exception = False try: values = RPCExecute('model', self.model_name, 'read', list(id2record.keys()), fnames, context=ctx) except RPCException: values = [{'id': x} for x in id2record] default_values = dict((f, None) for f in fnames) for value in values: value.update(default_values) self.exception = exception = True id2value = dict((value['id'], value) for value in values) for id, record in id2record.items(): if not record.exception: record.exception = exception value = id2value.get(id) if record and not record.destroyed and value: for key in record.modified_fields: value.pop(key, None) record.set(value, signal=False) return self.group.fields[name] def __repr__(self): return '' % (self.id, self.model_name, id(self)) @property def modified(self): return bool(self.modified_fields) @property def parent(self): return self.group.parent @property def parent_name(self): return self.group.parent_name @property def root_parent(self): parent = self while parent.parent: parent = parent.parent return parent @property def depth(self): parent = self.parent i = 0 while parent: i += 1 parent = parent.parent return i def set_modified(self, value): if value: self.signal('record-modified') def children_group(self, field_name): if not field_name: return [] self._check_load([field_name]) group = self.value.get(field_name) if group is None: return None if id(group.fields) != id(self.group.fields): self.group.fields.update(group.fields) group.fields = self.group.fields group.on_write = self.group.on_write group.readonly = self.group.readonly group._context.update(self.group._context) return group def get_path(self, group): path = [] i = self child_name = '' while i: path.append((child_name, i.id)) if i.group is group: break child_name = i.group.child_name i = i.parent path.reverse() return tuple(path) def get_index_path(self, group=None): path = [] record = self while record: path.append(record.group.index(record)) if record.group is group: break record = record.parent path.reverse() return tuple(path) def get_removed(self): if self.group is not None: return self in self.group.record_removed return False removed = property(get_removed) def get_deleted(self): if self.group is not None: return self in self.group.record_deleted return False deleted = property(get_deleted) def get_readonly(self): return self.deleted or self.removed or self.exception readonly = property(get_readonly) def fields_get(self): return self.group.fields def _check_load(self, fields=None): if fields is not None: if not self.get_loaded(fields): self.reload(fields) return True return False if not self.loaded: self.reload() return True return False def get_loaded(self, fields=None): if fields: return set(fields) <= (self._loaded | set(self.modified_fields)) return set(self.group.fields.keys()) == self._loaded loaded = property(get_loaded) def get(self): value = {} for name, field in self.group.fields.items(): if (field.attrs.get('readonly') and not isinstance(field, fields.O2MField)): continue if field.name not in self.modified_fields and self.id >= 0: continue value[name] = field.get(self) # Sending an empty x2MField breaks ModelFieldAccess.check if isinstance(field, fields.O2MField) and not value[name]: del value[name] return value def get_eval(self): value = {} for name, field in self.group.fields.items(): if name not in self._loaded and self.id >= 0: continue value[name] = field.get_eval(self) value['id'] = self.id return value def get_on_change_value(self, skip=None): value = {} for name, field in self.group.fields.items(): if skip and name in skip: continue if (self.id >= 0 and (name not in self._loaded or name not in self.modified_fields)): continue value[name] = field.get_on_change_value(self) value['id'] = self.id return value def cancel(self): self._loaded.clear() self.modified_fields.clear() self._timestamp = None self.button_clicks.clear() def get_timestamp(self): result = {self.model_name + ',' + str(self.id): self._timestamp} for name, field in self.group.fields.items(): if name in self._loaded: result.update(field.get_timestamp(self)) return result def pre_validate(self): if not self.modified_fields: return True values = self._get_on_change_args(self.modified_fields) try: RPCExecute('model', self.model_name, 'pre_validate', values, context=self.get_context()) except RPCException: return False return True def save(self, force_reload=True): if self.id < 0 or self.modified: if self.id < 0: value = self.get() try: res, = RPCExecute('model', self.model_name, 'create', [value], context=self.get_context()) except RPCException: return False old_id = self.id self.id = res self.group.id_changed(old_id) elif self.modified: value = self.get() if value: context = self.get_context() context = context.copy() context['_timestamp'] = self.get_timestamp() try: RPCExecute('model', self.model_name, 'write', [self.id], value, context=context) except RPCException: return False self.cancel() if force_reload: self.reload() if self.group: self.group.written(self.id) if self.parent: self.parent.modified_fields.pop(self.group.child_name, None) self.parent.save(force_reload=force_reload) return self.id def default_get(self, rec_name=None): if len(self.group.fields): context = self.get_context() context.setdefault('default_rec_name', rec_name) try: vals = RPCExecute('model', self.model_name, 'default_get', list(self.group.fields.keys()), context=context) except RPCException: return if (self.parent and self.parent_name in self.group.fields): parent_field = self.group.fields[self.parent_name] if isinstance(parent_field, fields.ReferenceField): vals[self.parent_name] = ( self.parent.model_name, self.parent.id) elif (self.group.fields[self.parent_name].attrs['relation'] == self.group.parent.model_name): vals[self.parent_name] = self.parent.id self.set_default(vals) return vals def rec_name(self): try: return RPCExecute('model', self.model_name, 'read', [self.id], ['rec_name'], context=self.get_context())[0]['rec_name'] except RPCException: return '' def validate(self, fields=None, softvalidation=False, pre_validate=None): if isinstance(fields, list) and fields: self._check_load(fields) elif fields is None: self._check_load() res = True for field_name, field in self.group.fields.items(): if fields is not None and field_name not in fields: continue if field.attrs.get('readonly'): continue if field_name == self.group.exclude_field: continue if not field.validate(self, softvalidation, pre_validate): res = False return res def _get_invalid_fields(self): fields = {} for fname, field in self.group.fields.items(): invalid = field.get_state_attrs(self).get('invalid') if invalid: fields[fname] = invalid return fields invalid_fields = property(_get_invalid_fields) def get_context(self, local=False): if not local: return self.group.context else: return self.group.local_context def set_default(self, val, signal=True, validate=True): fieldnames = [] for fieldname, value in list(val.items()): if fieldname not in self.group.fields: continue if fieldname == self.group.exclude_field: continue if isinstance(self.group.fields[fieldname], (fields.M2OField, fields.ReferenceField)): field_rec_name = fieldname + '.rec_name' if field_rec_name in val: self.value[field_rec_name] = val[field_rec_name] elif field_rec_name in self.value: del self.value[field_rec_name] self.group.fields[fieldname].set_default(self, value) self._loaded.add(fieldname) fieldnames.append(fieldname) self.on_change(fieldnames) self.on_change_with(fieldnames) if validate: self.validate(softvalidation=True) if signal: self.signal('record-changed') def set(self, val, signal=True, validate=True): later = {} fieldnames = [] for fieldname, value in val.items(): if fieldname == '_timestamp': # Always keep the older timestamp if not self._timestamp: self._timestamp = value continue if fieldname not in self.group.fields: if fieldname == 'rec_name': self.value['rec_name'] = value continue if isinstance(self.group.fields[fieldname], fields.O2MField): later[fieldname] = value continue if isinstance(self.group.fields[fieldname], (fields.M2OField, fields.ReferenceField)): field_rec_name = fieldname + '.rec_name' if field_rec_name in val: self.value[field_rec_name] = val[field_rec_name] elif field_rec_name in self.value: del self.value[field_rec_name] self.group.fields[fieldname].set(self, value) self._loaded.add(fieldname) fieldnames.append(fieldname) for fieldname, value in later.items(): self.group.fields[fieldname].set(self, value) self._loaded.add(fieldname) if validate: self.validate(fieldnames, softvalidation=True) if signal: self.signal('record-changed') def set_on_change(self, values): for fieldname, value in list(values.items()): if fieldname not in self.group.fields: continue if isinstance(self.group.fields[fieldname], (fields.M2OField, fields.ReferenceField)): field_rec_name = fieldname + '.rec_name' if field_rec_name in values: self.value[field_rec_name] = values[field_rec_name] elif field_rec_name in self.value: del self.value[field_rec_name] self.group.fields[fieldname].set_on_change(self, value) def reload(self, fields=None): if self.id < 0: return if not fields: self['*'] else: for field in fields: self[field] self.validate(fields or []) def reset(self, value): self.cancel() self.set(value, signal=False) if self.parent: self.parent.on_change([self.group.child_name]) self.parent.on_change_with([self.group.child_name]) self.signal('record-changed') def expr_eval(self, expr): if not isinstance(expr, str): return expr if not expr: return elif expr == '[]': return [] elif expr == '{}': return {} ctx = self.get_eval() ctx['context'] = self.get_context() ctx['active_model'] = self.model_name ctx['active_id'] = self.id if self.parent and self.parent_name: ctx['_parent_' + self.parent_name] = \ common.EvalEnvironment(self.parent) val = PYSONDecoder(ctx).decode(expr) return val def _get_on_change_args(self, args): res = {} values = common.EvalEnvironment(self, 'on_change') for arg in args: scope = values for i in arg.split('.'): if i not in scope: break scope = scope[i] else: res[arg] = scope res['id'] = self.id return res def on_change(self, fieldnames): values = {} for fieldname in fieldnames: on_change = self.group.fields[fieldname].attrs.get('on_change') if not on_change: continue values.update(self._get_on_change_args(on_change)) if values: try: changes = RPCExecute('model', self.model_name, 'on_change', values, fieldnames, context=self.get_context()) except RPCException: return for change in changes: self.set_on_change(change) def on_change_with(self, field_names): field_names = set(field_names) fieldnames = set() values = {} later = set() for fieldname in self.group.fields: on_change_with = self.group.fields[fieldname].attrs.get( 'on_change_with') if not on_change_with: continue if not field_names & set(on_change_with): continue if fieldnames & set(on_change_with): later.add(fieldname) continue fieldnames.add(fieldname) values.update(self._get_on_change_args(on_change_with)) if isinstance(self.group.fields[fieldname], (fields.M2OField, fields.ReferenceField)): field_rec_name = fieldname + '.rec_name' if field_rec_name in self.value: del self.value[field_rec_name] if fieldnames: try: result = RPCExecute('model', self.model_name, 'on_change_with', values, list(fieldnames), context=self.get_context()) except RPCException: return self.set_on_change(result) for fieldname in later: on_change_with = self.group.fields[fieldname].attrs.get( 'on_change_with') values = self._get_on_change_args(on_change_with) try: result = RPCExecute('model', self.model_name, 'on_change_with_' + fieldname, values, context=self.get_context()) except RPCException: return self.group.fields[fieldname].set_on_change(self, result) def autocomplete_with(self, field_name): for fieldname, fieldinfo in self.group.fields.items(): autocomplete = fieldinfo.attrs.get('autocomplete', []) if field_name not in autocomplete: continue self.do_autocomplete(fieldname) def do_autocomplete(self, fieldname): self.autocompletion[fieldname] = [] autocomplete = self.group.fields[fieldname].attrs['autocomplete'] args = self._get_on_change_args(autocomplete) try: res = RPCExecute('model', self.model_name, 'autocomplete_' + fieldname, args, context=self.get_context()) except RPCException: # ensure res is a list res = [] self.autocompletion[fieldname] = res def set_field_context(self): from .group import Group for name, field in self.group.fields.items(): value = self.value.get(name) if not isinstance(value, Group): continue context = field.attrs.get('context') if context: value.context = self.expr_eval(context) def get_attachment_count(self, reload=False): if self.id < 0: return 0 if self.attachment_count < 0 or reload: try: self.attachment_count = RPCExecute('model', 'ir.attachment', 'search_count', [ ('resource', '=', '%s,%s' % (self.model_name, self.id)), ], context=self.get_context()) except RPCException: return 0 return self.attachment_count def get_unread_note(self, reload=False): if self.id < 0: return 0 if self.unread_note < 0 or reload: try: self.unread_note = RPCExecute('model', 'ir.note', 'search_count', [ ('resource', '=', '%s,%s' % (self.model_name, self.id)), ('unread', '=', True), ], context=self.get_context()) except RPCException: return 0 return self.unread_note def get_button_clicks(self, name): if self.id < 0: return clicks = self.button_clicks.get(name) if clicks is not None: return clicks try: clicks = RPCExecute('model', 'ir.model.button.click', 'get_click', self.model_name, name, self.id) self.button_clicks[name] = clicks except RPCException: return return clicks def destroy(self): for v in self.value.values(): if hasattr(v, 'destroy'): v.destroy() super(Record, self).destroy() self.destroyed = True tryton-5.0.17/tryton/gui/window/view_form/model/group.py0000644000175000017500000004313613563614150022723 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .record import Record from .field import Field, M2OField, ReferenceField from tryton import rpc from tryton.signal_event import SignalEvent from tryton.common.domain_inversion import is_leaf from tryton.common import RPCExecute, RPCException, MODELACCESS class Group(SignalEvent, list): def __init__(self, model_name, fields, ids=None, parent=None, parent_name='', child_name='', context=None, domain=None, readonly=False, parent_datetime_field=None): super(Group, self).__init__() if domain is None: domain = [] self.__domain = domain self.__domain4inversion = None self.lock_signal = False self.parent = parent self.parent_name = parent_name or '' self.children = [] self.child_name = child_name self.parent_datetime_field = parent_datetime_field self._context = context or {} self.model_name = model_name self.fields = {} self.load_fields(fields) self.current_idx = None self.load(ids) self.record_deleted, self.record_removed = [], [] self.on_write = set() self.__readonly = readonly self.__id2record = {} self.__field_childs = None self.exclude_field = None self.skip_model_access = False if self.parent and self.parent.model_name == model_name: self.parent.group.children.append(self) @property def readonly(self): # Must skip res.user for Preference windows if (self.context.get('_datetime') or (not (MODELACCESS[self.model_name]['write'] or MODELACCESS[self.model_name]['create']) and not self.skip_model_access)): return True return self.__readonly @readonly.setter def readonly(self, value): self.__readonly = value @property def domain(self): if self.parent and self.child_name: field = self.parent.group.fields[self.child_name] return [self.__domain, field.domain_get(self.parent)] return self.__domain def clean4inversion(self, domain): "This method will replace non relevant fields for domain inversion" if domain in ([], ()): return [] head, tail = domain[0], domain[1:] if head in ('AND', 'OR'): pass elif is_leaf(head): field = head[0] if (field in self.fields and self.fields[field].attrs.get('readonly')): head = [] else: head = self.clean4inversion(head) return [head] + self.clean4inversion(tail) def __get_domain4inversion(self): domain = self.domain if (self.__domain4inversion is None or self.__domain4inversion[0] != domain): self.__domain4inversion = ( domain, self.clean4inversion(domain)) domain, domain4inversion = self.__domain4inversion return domain4inversion domain4inversion = property(__get_domain4inversion) def insert(self, pos, record): assert record.group is self if pos >= 1: self.__getitem__(pos - 1).next[id(self)] = record if pos < self.__len__(): record.next[id(self)] = self.__getitem__(pos) else: record.next[id(self)] = None super(Group, self).insert(pos, record) self.__id2record[record.id] = record if not self.lock_signal: self.signal('group-list-changed', ('record-added', record)) def append(self, record): assert record.group is self if self.__len__() >= 1: self.__getitem__(self.__len__() - 1).next[id(self)] = record record.next[id(self)] = None super(Group, self).append(record) self.__id2record[record.id] = record if not self.lock_signal: self.signal('group-list-changed', ('record-added', record)) def _remove(self, record): idx = self.index(record) if idx >= 1: if idx + 1 < self.__len__(): self.__getitem__(idx - 1).next[id(self)] = \ self.__getitem__(idx + 1) else: self.__getitem__(idx - 1).next[id(self)] = None self.signal('group-list-changed', ('record-removed', record)) super(Group, self).remove(record) del self.__id2record[record.id] def clear(self): # Use reversed order to minimize the cursor reposition as the cursor # has more chances to be on top of the list. for record in reversed(self[:]): self.signal('group-list-changed', ('record-removed', record)) record.destroy() self.pop() self.__id2record = {} self.record_removed, self.record_deleted = [], [] def move(self, record, pos): if self.__len__() > pos >= 0: idx = self.index(record) self._remove(record) if pos > idx: pos -= 1 self.insert(pos, record) else: self._remove(record) self.append(record) def __setitem__(self, i, value): super(Group, self).__setitem__(i, value) if not self.lock_signal: self.signal('group-list-changed', ('record-changed', i)) def __repr__(self): return '' % (self.model_name, id(self)) def load_fields(self, fields): for name, attr in fields.items(): field = Field.get_field(attr['type']) attr['name'] = name self.fields[name] = field(attr) def save(self): saved = [] for record in self: saved.append(record.save(force_reload=False)) if self.record_deleted: for record in self.record_deleted: self._remove(record) record.destroy() self.delete(self.record_deleted) del self.record_deleted[:] return saved def delete(self, records): if not records: return root_group = self.root_group assert all(r.model_name == self.model_name for r in records) assert all(r.group.root_group == root_group for r in records) records = [r for r in records if r.id >= 0] ctx = self.context ctx['_timestamp'] = {} for rec in records: ctx['_timestamp'].update(rec.get_timestamp()) record_ids = set(r.id for r in records) reload_ids = set(root_group.on_write_ids(list(record_ids))) reload_ids -= record_ids reload_ids = list(reload_ids) try: RPCExecute('model', self.model_name, 'delete', list(record_ids), context=ctx) except RPCException: return False if reload_ids: root_group.reload(reload_ids) return True @property def root_group(self): root = self parent = self.parent while parent: root = parent.group parent = parent.parent return root def written(self, ids): if isinstance(ids, int): ids = [ids] ids = [x for x in self.on_write_ids(ids) or [] if x not in ids] if not ids: return self.root_group.reload(ids) return ids def reload(self, ids): for child in self.children: child.reload(ids) for id_ in ids: record = self.get(id_) if record and not record.modified: record.cancel() def on_write_ids(self, ids): if not self.on_write: return [] res = [] for fnct in self.on_write: try: res += RPCExecute('model', self.model_name, fnct, ids, context=self.context) except RPCException: return [] return list({}.fromkeys(res)) def load(self, ids, modified=False): if not ids: return True if len(ids) > 1: self.lock_signal = True new_records = [] for id in ids: new_record = self.get(id) if not new_record: new_record = Record(self.model_name, id, group=self) self.append(new_record) new_record.signal_connect(self, 'record-changed', self._record_changed) new_record.signal_connect(self, 'record-modified', self._record_modified) new_records.append(new_record) # Remove previously removed or deleted records for record in self.record_removed[:]: if record.id in ids: self.record_removed.remove(record) for record in self.record_deleted[:]: if record.id in ids: self.record_deleted.remove(record) if self.lock_signal: self.lock_signal = False self.signal('group-cleared') if new_records and modified: for record in new_records: record.modified_fields.setdefault('id') new_records[0].signal('record-modified') new_records[0].signal('record-changed') self.current_idx = 0 return True @property def context(self): return self._get_context(local=False) @property def local_context(self): return self._get_context(local=True) def _get_context(self, local=False): if not local: ctx = rpc.CONTEXT.copy() else: ctx = {} if self.parent: parent_context = self.parent.get_context(local=local) ctx.update(parent_context) if self.child_name in self.parent.group.fields: field = self.parent.group.fields[self.child_name] ctx.update(field.get_context( self.parent, parent_context, local=local)) ctx.update(self._context) if self.parent_datetime_field: ctx['_datetime'] = self.parent.get_eval( )[self.parent_datetime_field] return ctx @context.setter def context(self, value): self._context = value.copy() def add(self, record, position=-1, signal=True): if record.group is not self: record.signal_unconnect(record.group) record.group = self record.signal_connect(self, 'record-changed', self._record_changed) record.signal_connect(self, 'record-modified', self._record_modified) if position == -1: self.append(record) else: self.insert(position, record) for record_rm in self.record_removed: if record_rm.id == record.id: self.record_removed.remove(record) for record_del in self.record_deleted: if record_del.id == record.id: self.record_deleted.remove(record) self.current_idx = position record.modified_fields.setdefault('id') record.signal('record-modified') if signal: self.signal('group-changed', record) # Set parent field to trigger on_change if self.parent and self.parent_name in self.fields: field = self.fields[self.parent_name] if isinstance(field, (M2OField, ReferenceField)): value = self.parent.id, '' if isinstance(field, ReferenceField): value = self.parent.model_name, value field.set_client(record, value) return record def set_sequence(self, field='sequence'): changed = False prev = None for record in self: # Assume not loaded records are correctly ordered # as far as we do not change any previous records. if record.get_loaded([field]) or changed or record.id < 0: if prev: index = prev[field].get(prev) else: index = None update = False value = record[field].get(record) if value is None: if index: update = True elif prev and record.id >= 0: update = record.id < prev.id elif value == index: if prev and record.id >= 0: update = record.id < prev.id elif value <= (index or 0): update = True if update: if index is None: index = 0 index += 1 record.signal_unconnect(self, 'record-changed') try: record[field].set_client(record, index) finally: record.signal_connect(self, 'record-changed', self._record_changed) changed = record prev = record if changed: self.signal('group-changed', changed) def new(self, default=True, obj_id=None, rec_name=None): record = Record(self.model_name, obj_id, group=self) if default: record.default_get(rec_name=rec_name) record.signal_connect(self, 'record-changed', self._record_changed) record.signal_connect(self, 'record-modified', self._record_modified) return record def unremove(self, record, signal=True): if record in self.record_removed: self.record_removed.remove(record) if record in self.record_deleted: self.record_deleted.remove(record) if signal: record.signal('record-changed', record.parent) def remove(self, record, remove=False, modified=True, signal=True, force_remove=False): idx = self.index(record) if self[idx].id >= 0: if remove: if self[idx] in self.record_deleted: self.record_deleted.remove(self[idx]) self.record_removed.append(self[idx]) else: if self[idx] in self.record_removed: self.record_removed.remove(self[idx]) self.record_deleted.append(self[idx]) if record.parent: record.parent.modified_fields.setdefault('id') record.parent.signal('record-modified') if modified: record.modified_fields.setdefault('id') record.signal('record-modified') if self[idx].id < 0 or force_remove: self._remove(self[idx]) if len(self): self.current_idx = min(idx, len(self) - 1) else: self.current_idx = None if signal: record.signal('record-changed', record.parent) def _record_changed(self, record, signal_data): self.signal('group-changed', record) def _record_modified(self, record, signal_data): self.signal('record-modified', record) def prev(self): if len(self) and self.current_idx is not None: self.current_idx = (self.current_idx - 1) % len(self) elif len(self): self.current_idx = 0 else: return None return self[self.current_idx] def __next__(self): if len(self) and self.current_idx is not None: self.current_idx = (self.current_idx + 1) % len(self) elif len(self): self.current_idx = 0 else: return None return self[self.current_idx] def add_fields(self, fields): to_add = {} for name, attr in fields.items(): if name not in self.fields: to_add[name] = attr else: self.fields[name].attrs.update(attr) self.load_fields(to_add) if not len(self): return True new = [] for record in self: if record.id < 0: new.append(record) if len(new) and len(to_add): try: values = RPCExecute('model', self.model_name, 'default_get', list(to_add.keys()), context=self.context) except RPCException: return False for record in new: record.set_default(values, signal=False) # Trigger signal only once with the last record record.signal('record-changed') def get(self, id): 'Return record with the id' return self.__id2record.get(id) def id_changed(self, old_id): 'Update index for old id' record = self.__id2record[old_id] self.__id2record[record.id] = record del self.__id2record[old_id] def destroy(self): if self.parent: try: self.parent.group.children.remove(self) except ValueError: pass # One2Many connect the group to itself to send signals to the parent # but as we are destroying the group, we do not need to notify the # parent otherwise it will trigger unnecessary display. self.signal_unconnect(self) self.clear() super(Group, self).destroy() def get_by_path(self, path): 'return record by path' group = self record = None for child_name, id_ in path: record = group.get(id_) if not record: return None if not child_name: continue record[child_name] group = record.value.get(child_name) if not isinstance(group, Group): return None return record tryton-5.0.17/tryton/gui/window/view_form/view/0000755000175000017500000000000013571264253021064 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/view/list_gtk/0000755000175000017500000000000013571264253022704 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/view/list_gtk/widget.py0000644000175000017500000010432013524765775024556 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime import os import gtk import gettext import webbrowser from functools import wraps, partial import gobject from tryton.gui.window.win_search import WinSearch from tryton.gui.window.win_form import WinForm from tryton.gui.window.view_form.screen import Screen from tryton.common import file_selection, file_open, file_write import tryton.common as common from tryton.common.cellrendererbutton import CellRendererButton from tryton.common.cellrenderertext import CellRendererText, \ CellRendererTextCompletion from tryton.common.cellrenderertoggle import CellRendererToggle from tryton.common.cellrenderercombo import CellRendererCombo from tryton.common.cellrendererinteger import CellRendererInteger from tryton.common.cellrendererfloat import CellRendererFloat from tryton.common.cellrendererbinary import CellRendererBinary from tryton.common.cellrendererclickablepixbuf import \ CellRendererClickablePixbuf from tryton.common import data2pixbuf from tryton.common.completion import get_completion, update_completion from tryton.common.selection import SelectionMixin, PopdownMixin from tryton.common.datetime_ import CellRendererDate, CellRendererTime from tryton.common.datetime_strftime import datetime_strftime from tryton.common.domain_parser import quote from tryton.config import CONFIG _ = gettext.gettext def send_keys(renderer, editable, position, treeview): editable.connect('key_press_event', treeview.on_keypressed) editable.editing_done_id = editable.connect('editing_done', treeview.on_editing_done) if isinstance(editable, (gtk.ComboBoxEntry, gtk.ComboBox)): def changed(combobox): # "changed" signal is also triggered by text editing # so only trigger editing-done if a row is active if combobox.get_active_iter(): treeview.on_editing_done(combobox) editable.connect('changed', changed) def realized(func): "Decorator for treeview realized" @wraps(func) def wrapper(self, *args, **kwargs): if (hasattr(self.view.treeview, 'get_realized') and not self.view.treeview.get_realized()): return return func(self, *args, **kwargs) return wrapper class CellCache(list): methods = ('set_active', 'set_sensitive', 'set_property') def apply(self, cell): for method, args, kwargs in self: getattr(cell, method)(*args, **kwargs) def decorate(self, cell): def decorate(func): @wraps(func) def wrapper(*args, **kwargs): self.append((func.__name__, args, kwargs)) return func(*args, **kwargs) wrapper.previous = func return wrapper for method in self.methods: if getattr(cell, method, None): setattr(cell, method, decorate(getattr(cell, method))) cell.decorated = True return cell def undecorate(self, cell): for method in self.methods: if getattr(cell, method, None): setattr(cell, method, getattr(cell, method).previous) del cell.decorated @classmethod def cache(cls, func): @wraps(func) def wrapper(self, column, cell, store, iter): if not hasattr(self, 'display_counters'): self.display_counters = {} if not hasattr(self, 'cell_caches'): self.cell_caches = {} record = store.get_value(iter, 0) counter = self.view.treeview.display_counter if (self.display_counters.get(record.id) != counter): if getattr(cell, 'decorated', None): func(self, column, cell, store, iter) else: cache = cls() cache.decorate(cell) func(self, column, cell, store, iter) cache.undecorate(cell) self.cell_caches[record.id] = cache self.display_counters[record.id] = counter else: self.cell_caches[record.id].apply(cell) return wrapper class Cell(object): pass class Affix(Cell): def __init__(self, view, attrs, protocol=None): super(Affix, self).__init__() self.attrs = attrs self.protocol = protocol self.icon = attrs.get('icon') if protocol: self.renderer = CellRendererClickablePixbuf() self.renderer.connect('clicked', self.clicked) if not self.icon: self.icon = 'tryton-public' elif self.icon: self.renderer = gtk.CellRendererPixbuf() else: self.renderer = gtk.CellRendererText() self.view = view @realized @CellCache.cache def setter(self, column, cell, store, iter_): record = store.get_value(iter_, 0) field = record[self.attrs['name']] field.state_set(record, states=('invisible',)) invisible = field.get_state_attrs(record).get('invisible', False) cell.set_property('visible', not invisible) if self.icon: if self.icon in record.group.fields: value = record[self.icon].get_client(record) or '' else: value = self.icon pixbuf = common.IconFactory.get_pixbuf(value, gtk.ICON_SIZE_BUTTON) cell.set_property('pixbuf', pixbuf) else: text = self.attrs.get('string', '') if not text: text = field.get_client(record) or '' cell.set_property('text', text) def clicked(self, renderer, path): store = self.view.treeview.get_model() record = store.get_value(store.get_iter(path), 0) value = record[self.attrs['name']].get(record) if value: if self.protocol == 'email': value = 'mailto:%s' % value elif self.protocol == 'callto': value = 'callto:%s' % value elif self.protocol == 'sip': value = 'sip:%s' % value webbrowser.open(value, new=2) class GenericText(Cell): align = 0 editable = None def __init__(self, view, attrs, renderer=None): super(GenericText, self).__init__() self.attrs = attrs if renderer is None: renderer = CellRendererText self.renderer = renderer() self.renderer.connect('editing-started', self.editing_started) if not isinstance(self.renderer, CellRendererBinary): self.renderer.connect_after('editing-started', send_keys, view.treeview) self.renderer.set_property('yalign', 0) self.view = view @property def field_name(self): return self.attrs['name'] @property def model_name(self): return self.view.screen.model_name @realized @CellCache.cache def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) text = self.get_textual_value(record) if isinstance(cell, CellRendererToggle): cell.set_active(bool(text)) else: cell.set_sensitive(not (record.deleted or record.removed)) if isinstance(cell, (CellRendererText, CellRendererDate, CellRendererCombo)): cell.set_property('strikethrough', record.deleted) cell.set_property('text', text) field = record[self.attrs['name']] editable = getattr(self.view.treeview, 'editable', False) states = ('invisible',) if editable: states = ('readonly', 'required', 'invisible') field.state_set(record, states=states) invisible = field.get_state_attrs(record).get('invisible', False) cell.set_property('visible', not invisible) # Sometimes, the treeview with fixed height mode computes a too big # height for not visible cell with text # We can force an empty text because not visible cell can not be edited # and so value_from_text is never called. if invisible and not isinstance(cell, CellRendererToggle): cell.set_property('text', '') if editable: readonly = self.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False)) if invisible: readonly = True if isinstance(cell, CellRendererToggle): cell.set_property('activatable', not readonly) elif isinstance(cell, (gtk.CellRendererProgress, CellRendererButton, gtk.CellRendererPixbuf)): pass else: cell.set_property('editable', not readonly) else: if isinstance(cell, CellRendererToggle): cell.set_property('activatable', False) cell.set_property('xalign', self.align) def open_remote(self, record, create, changed=False, text=None, callback=None): raise NotImplementedError def get_textual_value(self, record): if not record: return '' return record[self.attrs['name']].get_client(record) def value_from_text(self, record, text, callback=None): field = record[self.attrs['name']] field.set_client(record, text) if callback: callback() def editing_started(self, cell, editable, path): def remove(editable): self.editable = None self.editable = editable editable.connect('remove-widget', remove) return False def _get_record_field(self, path): store = self.view.treeview.get_model() record = store.get_value(store.get_iter(path), 0) field = record.group.fields[self.attrs['name']] return record, field class Char(GenericText): @realized @CellCache.cache def setter(self, column, cell, store, iter_): super(Char, self).setter(column, cell, store, iter_) cell.set_property('single-paragraph-mode', True) class Text(GenericText): pass class Int(GenericText): align = 1 def __init__(self, view, attrs, renderer=None): if renderer is None: renderer = CellRendererInteger super(Int, self).__init__(view, attrs, renderer=renderer) self.factor = float(attrs.get('factor', 1)) def get_textual_value(self, record): if not record: return '' return record[self.attrs['name']].get_client( record, factor=self.factor) def value_from_text(self, record, text, callback=None): field = record[self.attrs['name']] field.set_client(record, text, factor=self.factor) if callback: callback() class Boolean(GenericText): align = 0.5 def __init__(self, view, attrs=None, renderer=None): if renderer is None: renderer = CellRendererToggle super(Boolean, self).__init__(view, attrs, renderer=renderer) self.renderer.connect('toggled', self._sig_toggled) def _sig_toggled(self, renderer, path): store = self.view.treeview.get_model() record = store.get_value(store.get_iter(path), 0) field = record[self.attrs['name']] if not self.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False)): value = record[self.attrs['name']].get_client(record) record[self.attrs['name']].set_client(record, int(not value)) self.view.treeview.set_cursor(path) return True class URL(Char): @realized @CellCache.cache def setter(self, column, cell, store, iter): super(URL, self).setter(column, cell, store, iter) record = store.get_value(iter, 0) field = record[self.attrs['name']] field.state_set(record, states=('readonly',)) readonly = field.get_state_attrs(record).get('readonly', False) cell.set_property('visible', not readonly) class Date(GenericText): def __init__(self, view, attrs, renderer=None): if renderer is None: renderer = CellRendererDate super(Date, self).__init__(view, attrs, renderer=renderer) @realized def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) field = record[self.attrs['name']] self.renderer.props.format = self.get_format(record, field) super(Date, self).setter(column, cell, store, iter) def get_format(self, record, field): if field and record: return field.date_format(record) else: return '%x' def get_textual_value(self, record): if not record: return '' value = record[self.attrs['name']].get_client(record) if value: return datetime_strftime(value, self.renderer.props.format) else: return '' class Time(Date): def __init__(self, view, attrs, renderer=None): if renderer is None: renderer = CellRendererTime super(Time, self).__init__(view, attrs, renderer=renderer) def get_format(self, record, field): if field and record: return field.time_format(record) else: return '%X' def get_textual_value(self, record): if not record: return '' value = record[self.attrs['name']].get_client(record) if value is not None: if isinstance(value, datetime.datetime): value = value.time() return value.strftime(self.renderer.props.format) else: return '' class TimeDelta(GenericText): align = 1 class Float(Int): def __init__(self, view, attrs, renderer=None): if renderer is None: renderer = CellRendererFloat super(Float, self).__init__(view, attrs, renderer=renderer) @realized def setter(self, column, cell, store, iter): super(Float, self).setter(column, cell, store, iter) record = store.get_value(iter, 0) field = record[self.attrs['name']] digits = field.digits(record, factor=self.factor) cell.digits = digits class Binary(GenericText): align = 0.5 def __init__(self, view, attrs, renderer=None): self.filename = attrs.get('filename') if renderer is None: renderer = partial(CellRendererBinary, bool(self.filename)) super(Binary, self).__init__(view, attrs, renderer=renderer) self.renderer.connect( 'select', lambda *args: gobject.idle_add(self.select_binary, *args)) self.renderer.connect( 'open', lambda *args: gobject.idle_add(self.open_binary, *args)) self.renderer.connect( 'save', lambda *args: gobject.idle_add(self.save_binary, *args)) self.renderer.connect('clear', self.clear_binary) def get_textual_value(self, record): pass def value_from_text(self, record, text, callback=None): if callback: callback() @realized @CellCache.cache def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) field = record[self.attrs['name']] if hasattr(field, 'get_size'): size = field.get_size(record) else: size = len(field.get(record)) cell.set_property('size', common.humanize(size) if size else '') states = ('invisible',) if getattr(self.view.treeview, 'editable', False): states = ('readonly', 'required', 'invisible') field.state_set(record, states=states) invisible = field.get_state_attrs(record).get('invisible', False) cell.set_property('visible', not invisible) if getattr(self.view.treeview, 'editable', False): readonly = self.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False)) if invisible: readonly = True cell.set_property('editable', not readonly) def select_binary(self, renderer, path): record, field = self._get_record_field(path) filename = '' filename = file_selection(_('Open...')) if filename: field.set_client(record, open(filename, 'rb').read()) if self.filename: filename_field = record.group.fields[self.filename] filename_field.set_client(record, os.path.basename(filename)) def open_binary(self, renderer, path): if not self.filename: return record, field = self._get_record_field(path) filename_field = record.group.fields.get(self.filename) filename = filename_field.get(record) if not filename: return file_path = file_write(filename, self.get_data(record, field)) root, type_ = os.path.splitext(filename) if type_: type_ = type_[1:] file_open(file_path, type_) def save_binary(self, renderer, path): filename = '' record, field = self._get_record_field(path) if self.filename: filename_field = record.group.fields.get(self.filename) filename = filename_field.get(record) filename = file_selection(_('Save As...'), filename=filename, action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: with open(filename, 'wb') as fp: fp.write(self.get_data(record, field)) def get_data(self, record, field): if hasattr(field, 'get_data'): data = field.get_data(record) else: data = field.get(record) if isinstance(data, str): data = data.encode('utf-8') return data def clear_binary(self, renderer, path): record, field = self._get_record_field(path) if self.filename: filename_field = record.group.fields[self.filename] filename_field.set_client(record, None) field.set_client(record, None) class Image(GenericText): align = 0.5 def __init__(self, view, attrs=None, renderer=None): if renderer is None: renderer = gtk.CellRendererPixbuf super(Image, self).__init__(view, attrs, renderer) self.renderer.set_fixed_size(self.attrs.get('width', -1), self.attrs.get('height', -1)) @realized @CellCache.cache def setter(self, column, cell, store, iter_): record = store.get_value(iter_, 0) field = record[self.field_name] value = field.get_client(record) if isinstance(value, int): if value > CONFIG['image.max_size']: value = None else: value = field.get_data(record) pixbuf = data2pixbuf(value) width = self.attrs.get('width', -1) height = self.attrs.get('height', -1) if pixbuf and (width != -1 or height != -1): pixbuf = common.resize_pixbuf(pixbuf, width, height) cell.set_property('pixbuf', pixbuf) def get_textual_value(self, record): if not record: return '' return str(record[self.attrs['name']].get_size(record)) class M2O(GenericText): def __init__(self, view, attrs, renderer=None): if renderer is None and int(attrs.get('completion', 1)): renderer = partial(CellRendererTextCompletion, self.set_completion) super(M2O, self).__init__(view, attrs, renderer=renderer) def value_from_text(self, record, text, callback=None): field = record.group.fields[self.attrs['name']] if not text: field.set_client(record, (None, '')) if callback: callback() return field = record[self.attrs['name']] win = self.search_remote(record, field, text, callback=callback) if len(win.screen.group) == 1: win.response(None, gtk.RESPONSE_OK) else: win.show() def editing_started(self, cell, editable, path): super(M2O, self).editing_started(cell, editable, path) record, field = self._get_record_field(path) def changed(editable): text = editable.get_text() if field.get_client(record) != text: field.set_client(record, (None, '')) if field.get(record): icon1, tooltip1 = 'tryton-open', _("Open the record ") icon2, tooltip2 = 'tryton-clear', _("Clear the field ") else: icon1, tooltip1 = None, '' icon2, tooltip2 = 'tryton-search', _("Search a record ") for pos, icon, tooltip in [ (gtk.ENTRY_ICON_PRIMARY, icon1, tooltip1), (gtk.ENTRY_ICON_SECONDARY, icon2, tooltip2)]: if icon: pixbuf = common.IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_MENU) else: pixbuf = None editable.set_icon_from_pixbuf(pos, pixbuf) editable.set_icon_tooltip_text(pos, tooltip) def icon_press(editable, icon_pos, event): value = field.get(record) if icon_pos == gtk.ENTRY_ICON_SECONDARY and value: field.set_client(record, (None, '')) editable.set_text('') elif value: self.open_remote(record, create=False, changed=False) else: self.open_remote( record, create=False, changed=True, text=editable.get_text()) editable.connect('icon-press', icon_press) editable.connect('changed', changed) changed(editable) return False def open_remote(self, record, create=True, changed=False, text=None, callback=None): field = record.group.fields[self.attrs['name']] relation = field.attrs['relation'] access = common.MODELACCESS[relation] if (create and not (self.attrs.get('create', True) and access['create'])): return elif not access['read']: return domain = field.domain_get(record) context = field.get_context(record) if create: obj_id = None elif not changed: obj_id = field.get(record) else: self.search_remote(record, field, text, callback=callback).show() return screen = Screen(relation, domain=domain, context=context, mode=['form'], view_ids=self.attrs.get('view_ids', '').split(','), exclude_field=field.attrs.get('relation_field')) def open_callback(result): if result: value = (screen.current_record.id, screen.current_record.rec_name()) field.set_client(record, value, force_change=True) if callback: callback() if obj_id: screen.load([obj_id]) WinForm(screen, open_callback, save_current=True, title=field.attrs.get('string')) else: WinForm(screen, open_callback, new=True, save_current=True, title=field.attrs.get('string'), rec_name=text) def search_remote(self, record, field, text, callback=None): relation = field.attrs['relation'] domain = field.domain_get(record) context = field.get_search_context(record) order = field.get_search_order(record) access = common.MODELACCESS[relation] create_access = self.attrs.get('create', True) and access['create'] def search_callback(found): value = None if found: value = found[0] field.set_client(record, value) if callback: callback() win = WinSearch(relation, search_callback, sel_multi=False, context=context, domain=domain, order=order, view_ids=self.attrs.get('view_ids', '').split(','), new=create_access, title=self.attrs.get('string')) win.screen.search_filter(quote(text)) return win def set_completion(self, entry, path): if entry.get_completion(): entry.set_completion(None) access = common.MODELACCESS[self.attrs['relation']] completion = get_completion( search=access['read'], create=self.attrs.get('create', True) and access['create']) completion.connect('match-selected', self._completion_match_selected, path) completion.connect('action-activated', self._completion_action_activated, path) entry.set_completion(completion) entry.connect('key-press-event', self._key_press, path) entry.connect('changed', self._update_completion, path) def _key_press(self, entry, event, path): record, field = self._get_record_field(path) if (field.get(record) is not None and event.keyval in (gtk.keysyms.Delete, gtk.keysyms.BackSpace)): entry.set_text('') field.set_client(record, None) return False def _completion_match_selected(self, completion, model, iter_, path): record, field = self._get_record_field(path) rec_name, record_id = model.get(iter_, 0, 1) field.set_client(record, (record_id, rec_name)) completion.get_entry().set_text(rec_name) completion_model = completion.get_model() completion_model.clear() completion_model.search_text = rec_name return True def _update_completion(self, entry, path): record, field = self._get_record_field(path) if field.get(record) is not None: return model = field.attrs['relation'] update_completion(entry, record, field, model) def _completion_action_activated(self, completion, index, path): record, field = self._get_record_field(path) entry = completion.get_entry() entry.handler_block(entry.editing_done_id) def callback(): entry.handler_unblock(entry.editing_done_id) entry.set_text(field.get_client(record)) if index == 0: self.open_remote(record, create=False, changed=True, text=entry.get_text(), callback=callback) elif index == 1: self.open_remote(record, create=True, callback=callback) else: entry.handler_unblock(entry.editing_done_id) class O2O(M2O): pass class O2M(GenericText): align = 0.5 def get_textual_value(self, record): return '( ' + str(len(record[self.attrs['name']] .get_eval(record))) + ' )' def value_from_text(self, record, text, callback=None): if callback: callback() def open_remote(self, record, create=True, changed=False, text=None, callback=None): group = record.value[self.attrs['name']] field = record.group.fields[self.attrs['name']] relation = field.attrs['relation'] context = field.get_context(record) access = common.MODELACCESS[relation] if not access['read']: return screen = Screen(relation, mode=['tree', 'form'], view_ids=self.attrs.get('view_ids', '').split(','), exclude_field=field.attrs.get('relation_field')) screen.pre_validate = bool(int(self.attrs.get('pre_validate', 0))) screen.group = group def open_callback(result): if callback: callback() WinForm(screen, open_callback, view_type='tree', context=context, title=field.attrs.get('string')) class M2M(O2M): def open_remote(self, record, create=True, changed=False, text=None, callback=None): group = record.value[self.attrs['name']] field = record.group.fields[self.attrs['name']] relation = field.attrs['relation'] context = field.get_context(record) domain = field.domain_get(record) screen = Screen(relation, mode=['tree', 'form'], view_ids=self.attrs.get('view_ids', '').split(','), exclude_field=field.attrs.get('relation_field')) screen.group = group def open_callback(result): if callback: callback() WinForm(screen, open_callback, view_type='tree', domain=domain, context=context, title=field.attrs.get('string')) class Selection(GenericText, SelectionMixin, PopdownMixin): def __init__(self, *args, **kwargs): if 'renderer' not in kwargs: kwargs['renderer'] = CellRendererCombo super(Selection, self).__init__(*args, **kwargs) self.init_selection() # Use a variable let Python holding reference when calling set_property model = self.get_popdown_model(self.selection)[0] self.renderer.set_property('model', model) self.renderer.set_property('text-column', 0) def get_textual_value(self, record): field = record[self.attrs['name']] self.update_selection(record, field) value = field.get(record) text = dict(self.selection).get(value, '') if value and not text: text = self.get_inactive_selection(value) return text def value_from_text(self, record, text, callback=None): if callback: callback() def editing_started(self, cell, editable, path): super(Selection, self).editing_started(cell, editable, path) store = self.view.treeview.get_model() record = store.get_value(store.get_iter(path), 0) field = record[self.attrs['name']] def set_value(*a): return self.set_value(editable, record, field) editable.get_child().connect('activate', set_value) editable.get_child().connect('focus-out-event', set_value) editable.connect('changed', set_value) self.update_selection(record, field) self.set_popdown(self.selection, editable) value = field.get(record) if not self.set_popdown_value(editable, value): self.get_inactive_selection(value) self.set_popdown_value(editable, value) return False def set_value(self, editable, record, field): value = self.get_popdown_value(editable) if 'relation' in self.attrs and value: value = (value, editable.get_active_text()) field.set_client(record, value) return False class Reference(GenericText, SelectionMixin): def __init__(self, view, attrs, renderer=None): super(Reference, self).__init__(view, attrs, renderer=renderer) self.init_selection() def get_textual_value(self, record): field = record[self.attrs['name']] self.update_selection(record, field) value = field.get_client(record) if not value: model, name = '', '' else: model, name = value if model: return dict(self.selection).get(model, model) + ',' + name else: return name def value_from_text(self, record, text, callback=None): if callback: callback() class ProgressBar(object): align = 0.5 orientations = { 'left_to_right': gtk.PROGRESS_LEFT_TO_RIGHT, 'right_to_left': gtk.PROGRESS_RIGHT_TO_LEFT, 'bottom_to_top': gtk.PROGRESS_BOTTOM_TO_TOP, 'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM, } def __init__(self, view, attrs): super(ProgressBar, self).__init__() self.view = view self.attrs = attrs self.renderer = gtk.CellRendererProgress() orientation = self.orientations.get(self.attrs.get('orientation', 'left_to_right'), gtk.PROGRESS_LEFT_TO_RIGHT) if hasattr(self.renderer, 'set_orientation'): self.renderer.set_orientation(orientation) else: self.renderer.set_property('orientation', orientation) self.renderer.set_property('yalign', 0) @realized @CellCache.cache def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) field = record[self.attrs['name']] field.state_set(record, states=('invisible',)) invisible = field.get_state_attrs(record).get('invisible', False) cell.set_property('visible', not invisible) text = self.get_textual_value(record) if text: text = _('%s%%') % text cell.set_property('text', text) value = field.get(record) or 0.0 cell.set_property('value', value * 100) def open_remote(self, record, create, changed=False, text=None, callback=None): raise NotImplementedError def get_textual_value(self, record): return record[self.attrs['name']].get_client(record, factor=100) or '' def value_from_text(self, record, text, callback=None): field = record[self.attrs['name']] field.set_client(record, float(text)) if callback: callback() class Button(object): def __init__(self, view, attrs): super(Button, self).__init__() self.attrs = attrs self.renderer = CellRendererButton(attrs.get('string', _('Unknown'))) self.view = view self.renderer.connect('clicked', self.button_clicked) self.renderer.set_property('yalign', 0) @realized @CellCache.cache def setter(self, column, cell, store, iter): record = store.get_value(iter, 0) states = record.expr_eval(self.attrs.get('states', {})) invisible = states.get('invisible', False) cell.set_property('visible', not invisible) readonly = states.get('readonly', False) cell.set_property('sensitive', not readonly) parent = record.parent if record else None while parent: if parent.modified: cell.set_property('sensitive', False) break parent = parent.parent # TODO icon def button_clicked(self, widget, path): if not path: return True store = self.view.treeview.get_model() record = store.get_value(store.get_iter(path), 0) state_changes = record.expr_eval( self.attrs.get('states', {})) if state_changes.get('invisible') \ or state_changes.get('readonly'): return True widget.handler_block_by_func(self.button_clicked) try: self.view.screen.button(self.attrs) finally: widget.handler_unblock_by_func(self.button_clicked) tryton-5.0.17/tryton/gui/window/view_form/view/list_gtk/editabletree.py0000644000175000017500000002552613463252532025716 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import gobject from itertools import islice, cycle from tryton.common import MODELACCESS from tryton.common.datetime_ import Date, Time _ = gettext.gettext class TreeView(gtk.TreeView): display_counter = 0 def __init__(self, view): super(TreeView, self).__init__() self.view = view def next_column(self, path, column=None, editable=True, _sign=1): columns = self.get_columns() if column is None: column = columns[-1 if _sign > 0 else 0] model = self.get_model() record = model.get_value(model.get_iter(path), 0) if _sign < 0: columns.reverse() current_idx = columns.index(column) + 1 for column in islice(cycle(columns), current_idx, len(columns) + current_idx): if not column.name: continue widget = self.view.get_column_widget(column) field = record[column.name] field.state_set(record, states=('readonly', 'invisible')) invisible = field.get_state_attrs(record).get('invisible', False) if not column.get_visible(): invisible = True if editable: readonly = widget.attrs.get('readonly', field.get_state_attrs(record).get('readonly', False)) else: readonly = False if not (invisible or readonly): return column def prev_column(self, path, column=None, editable=True): return self.next_column(path, column=column, editable=editable, _sign=-1) class EditableTreeView(TreeView): leaving_record_events = (gtk.keysyms.Up, gtk.keysyms.Down, gtk.keysyms.Return) leaving_events = leaving_record_events + (gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab, gtk.keysyms.KP_Enter) def __init__(self, position, view): super(EditableTreeView, self).__init__(view) self.editable = position def on_quit_cell(self, current_record, column, value, callback=None): field = current_record[column.name] widget = self.view.get_column_widget(column) # The value has not changed and is valid ... do nothing. if value == widget.get_textual_value(current_record) \ and field.validate(current_record): if callback: callback() return widget.value_from_text(current_record, value, callback=callback) def on_open_remote(self, current_record, column, create, value, entry=None, callback=None): widget = self.view.get_column_widget(column) if value != widget.get_textual_value(current_record) or not value: changed = True else: changed = False try: widget.open_remote(current_record, create, changed, value, callback=callback) except NotImplementedError: pass def on_create_line(self): access = MODELACCESS[self.view.screen.model_name] model = self.get_model() limit = (self.view.screen.size_limit is not None and (len(model) >= self.view.screen.size_limit >= 0)) if not access['create'] or limit: return if self.editable == 'top': method = model.prepend else: method = model.append new_record = model.group.new() res = method(new_record) sequence = self.view.attributes.get('sequence') if sequence: model.group.set_sequence(field=sequence) return res def set_cursor(self, path, focus_column=None, start_editing=False): self.grab_focus() if focus_column: widget = self.view.get_column_widget(focus_column) if isinstance(widget.renderer, gtk.CellRendererToggle): start_editing = False self.scroll_to_cell(path, focus_column, use_align=False) super(EditableTreeView, self).set_cursor(path, focus_column, start_editing) def set_value(self): path, column = self.get_cursor() if not path or not column or not column.name: return True for renderer in column.get_cell_renderers(): if renderer.props.editing: widget = self.view.get_column_widget(column) self.on_editing_done(widget.editable) return True def on_keypressed(self, entry, event): path, column = self.get_cursor() model = self.get_model() record = model.get_value(model.get_iter(path), 0) self.display_counter += 1 # Force a display leaving = False if event.keyval == gtk.keysyms.Right: if isinstance(entry, gtk.Entry): if entry.get_position() >= \ len(entry.get_text()) \ and not entry.get_selection_bounds(): leaving = True else: leaving = True elif event.keyval == gtk.keysyms.Left: if isinstance(entry, gtk.Entry): if entry.get_position() <= 0 \ and not entry.get_selection_bounds(): leaving = True else: leaving = True if event.keyval in self.leaving_events or leaving: if isinstance(entry, (Date, Time)): entry.activate() txt = entry.props.value elif isinstance(entry, gtk.Entry): txt = entry.get_text() else: txt = entry.get_active_text() keyval = event.keyval entry.handler_block(entry.editing_done_id) def callback(): entry.handler_unblock(entry.editing_done_id) field = record[column.name] # Must wait the edited entry came back in valid state if field.validate(record): if (keyval in (gtk.keysyms.Tab, gtk.keysyms.KP_Enter) or (keyval == gtk.keysyms.Right and leaving)): gobject.idle_add(self.set_cursor, path, self.next_column(path, column), True) elif (keyval == gtk.keysyms.ISO_Left_Tab or (keyval == gtk.keysyms.Left and leaving)): gobject.idle_add(self.set_cursor, path, self.prev_column(path, column), True) elif keyval in self.leaving_record_events: fields = list(self.view.widgets.keys()) if not record.validate(fields): invalid_fields = record.invalid_fields col = None for col in self.get_columns(): if col.name in invalid_fields: break gobject.idle_add(self.set_cursor, path, col, True) return if ((self.view.screen.pre_validate and not record.pre_validate()) or (not self.view.screen.parent and not record.save())): gobject.idle_add(self.set_cursor, path, column, True) return entry.handler_block(entry.editing_done_id) if keyval == gtk.keysyms.Up: self._key_up(path, model, column) elif keyval == gtk.keysyms.Down: self._key_down(path, model, column) elif keyval == gtk.keysyms.Return: if self.editable == 'top': new_path = self._key_up(path, model) else: new_path = self._key_down(path, model) gobject.idle_add(self.set_cursor, new_path, self.next_column(new_path), True) entry.handler_unblock(entry.editing_done_id) else: gobject.idle_add(self.set_cursor, path, column, True) self.on_quit_cell(record, column, txt, callback=callback) return True elif event.keyval in (gtk.keysyms.F3, gtk.keysyms.F2): if isinstance(entry, gtk.Entry): value = entry.get_text() else: value = entry.get_active_text() entry.handler_block(entry.editing_done_id) def callback(): widget = self.view.get_column_widget(column) value = widget.get_textual_value(record) if isinstance(entry, gtk.Entry): entry.set_text(value) else: entry.set_active_text(value) entry.handler_unblock(entry.editing_done_id) self.on_open_remote(record, column, create=(event.keyval == gtk.keysyms.F3), value=value, callback=callback) else: field = record[column.name] if isinstance(entry, gtk.Entry): entry.set_max_length(int(field.attrs.get('size', 0))) record.modified_fields.setdefault(column.name) return False return True def _key_down(self, path, model, column=None): if path[0] == len(model) - 1 and self.editable == 'bottom': self.on_create_line() new_path = (path[0] + 1) % len(model) if not column: column = self.next_column(new_path) self.set_cursor(new_path, column, True) self.scroll_to_cell(new_path) return new_path def _key_up(self, path, model, column=None): if path[0] == 0 and self.editable == 'top': self.on_create_line() new_path = 0 else: new_path = (path[0] - 1) % len(model) if not column: column = self.next_column(new_path) self.set_cursor(new_path, column, True) self.scroll_to_cell(new_path) return new_path def on_editing_done(self, entry): path, column = self.get_cursor() if not path: return True model = self.get_model() record = model.get_value(model.get_iter(path), 0) if isinstance(entry, (Date, Time)): entry.activate() self.on_quit_cell(record, column, entry.props.value) elif isinstance(entry, gtk.Entry): self.on_quit_cell(record, column, entry.get_text()) elif isinstance(entry, (gtk.ComboBoxEntry, gtk.ComboBox)): self.on_quit_cell(record, column, entry.get_active_text()) tryton-5.0.17/tryton/gui/window/view_form/view/list_gtk/__init__.py0000644000175000017500000000022013354423127025003 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/0000755000175000017500000000000013571264253023032 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/pie.py0000644000175000017500000001601613463252532024162 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # This code is inspired by the pycha project # (http://www.lorenzogil.com/projects/pycha/) import math import locale import datetime import cairo from .graph import Graph, Area import tryton.common as common import tryton.rpc as rpc class Pie(Graph): def _getDatasKeys(self): return list(self.datas.keys()) def drawLegend(self, cr, width, height): pass def drawAxis(self, cr, width, height): cr.set_source_rgb(*common.hex2rgb('#000000')) for slice in self.slices: normalisedAngle = slice.normalisedAngle() labelx = self.centerx + \ math.sin(normalisedAngle) * (self.radius + 10) labely = self.centery - \ math.cos(normalisedAngle) * (self.radius + 10) label = '%s (%s%%)' % (self.labels[slice.xname], locale.format('%.2f', slice.fraction * 100)) extents = cr.text_extents(label) labelWidth = extents[2] labelHeight = extents[3] x = y = 0 if normalisedAngle <= math.pi * 0.5: x = labelx y = labely - labelHeight elif math.pi / 2 < normalisedAngle <= math.pi: x = labelx y = labely elif math.pi < normalisedAngle <= math.pi * 1.5: x = labelx - labelWidth y = labely else: x = labelx - labelWidth y = labely - labelHeight cr.move_to(x, y) cr.show_text(label) def drawLines(self, cr, width, height): pass def updateArea(self, cr, width, height): width = width - self.leftPadding - self.rightPadding height = height - self.topPadding - self.bottomPadding self.area = Area(self.leftPadding, self.topPadding, width, height) self.centerx = self.area.x + self.area.w * 0.5 self.centery = self.area.y + self.area.h * 0.5 self.radius = min(self.area.w * 0.4, self.area.h * 0.4) def updateGraph(self): self.sum = 0.0 for xkey in self.datas.keys(): key = self.yfields[0].get('key', self.yfields[0]['name']) if self.datas[xkey][key] > 0: self.sum += self.datas[xkey][key] fraction = angle = 0.0 self.slices = [] for xkey in self.datas.keys(): key = self.yfields[0].get('key', self.yfields[0]['name']) value = self.datas[xkey][key] if value > 0: angle += fraction fraction = value / self.sum slice = Slice(xkey, fraction, value, angle) self.slices.append(slice) def drawGraph(self, cr, width, height): cr.set_line_join(cairo.LINE_JOIN_ROUND) cr.save() for slice in self.slices: if slice.isBigEnough(): if bool(int(self.yfields[0].get('fill', 1))): color = self.colorScheme[slice.xname] if slice.highlight: color = common.highlight_rgb(*color) cr.set_source_rgba(*color) slice.draw(cr, self.centerx, self.centery, self.radius) cr.fill() cr.set_source_rgb(*common.hex2rgb( self.attrs.get('background', '#f5f5f5'))) slice.draw(cr, self.centerx, self.centery, self.radius) cr.set_line_width(2) cr.stroke() cr.restore() def motion(self, widget, event): super(Pie, self).motion(widget, event) if not getattr(self, 'area', None): return d = (event.x - self.centerx) ** 2 + (event.y - self.centery) ** 2 if d > self.radius ** 2: self.popup.hide() for slice in self.slices: if slice.highlight: self.queue_draw() slice.highlight = False return self.popup.show() if event.y == self.centery: angle = math.pi / 2 else: angle = math.atan((event.x - self.centerx) / (self.centery - event.y)) if event.x >= self.centerx: if event.y <= self.centery: pass else: angle += math.pi else: if event.y < self.centery: angle += 2 * math.pi else: angle += math.pi for slice in self.slices: if slice.startAngle <= angle <= slice.endAngle: if not slice.highlight: slice.highlight = True if 'timedelta' in self.yfields[0]: converter = self.yfields[0].get('timedelta') if converter: converter = rpc.CONTEXT.get(converter) value = common.timedelta.format( datetime.timedelta( seconds=slice.fraction * self.sum), converter) sum = common.timedelta.format( datetime.timedelta(seconds=self.sum), converter) else: value = locale.format('%.2f', slice.fraction * self.sum) sum = locale.format('%.2f', self.sum) label = '%s (%s%%)\n%s/%s' % (self.labels[slice.xname], locale.format('%.2f', slice.fraction * 100), value, sum) self.popup.set_text(label) self.queue_draw() else: if slice.highlight: slice.highlight = False self.queue_draw() def action(self): super(Pie, self).action() for slice in self.slices: if slice.highlight: ids = self.ids[slice.xname] self.action_keyword(ids) class Slice(object): def __init__(self, xname, fraction, value, angle): self.xname = xname self.fraction = fraction self.value = value self.startAngle = 2 * angle * math.pi self.endAngle = 2 * (angle + fraction) * math.pi self.highlight = False def isBigEnough(self): return abs(self.startAngle - self.endAngle) > 0.001 def draw(self, cr, centerx, centery, radius): cr.new_path() cr.move_to(centerx, centery) cr.arc(centerx, centery, radius, self.startAngle - (math.pi / 2), self.endAngle - (math.pi / 2)) cr.line_to(centerx, centery) cr.close_path() def normalisedAngle(self): normalisedAngle = (self.startAngle + self.endAngle) / 2 if normalisedAngle > 2 * math.pi: normalisedAngle -= 2 * math.pi elif normalisedAngle < 0: normalisedAngle += 2 * math.pi return normalisedAngle tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/__init__.py0000644000175000017500000000024513354423127025140 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from parser import * tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/line.py0000644000175000017500000002407713463252532024342 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # This code is inspired by the pycha project # (http://www.lorenzogil.com/projects/pycha/) import locale import math import datetime import cairo from .graph import Graph import tryton.common as common import tryton.rpc as rpc class Line(Graph): def updateGraph(self): yfield2attrs = {} for yfield in self.yfields: yfield2attrs[yfield.get('key', yfield['name'])] = yfield self.points = [] i = 0 keys = list(self.datas.keys()) keys.sort() for xfield in keys: j = 0 for yfield in self.datas[xfield]: xval = i yval = self.datas[xfield][yfield] x = (xval - self.minxval) * self.xscale y = 1.0 - (yval - self.minyval) * self.yscale if self.xrange == 0: x = 1.0 if (not bool(int(yfield2attrs[yfield].get('empty', 1))) and yval == 0): continue point = Point(x, y, xval, yval, xfield, yfield) if (0.0 <= point.x <= 1.0) and (0.0 <= point.y <= 1.0): self.points.append(point) j += 1 i += 1 def drawGraph(self, cr, width, height): key2fill = {} key2interpolation = {} for yfield in self.yfields: key = yfield.get('key', yfield['name']) key2fill[key] = bool(int(yfield.get('fill', 0))) key2interpolation[key] = yfield.get('interpolation', 'linear') def preparePath(key): interpolation = key2interpolation[key] points = (p for p in self.points if p.yname == key) zero = 1.0 + self.minyval * self.yscale cr.new_path() cr.move_to(self.area.x, zero * self.area.h + self.area.y) if interpolation == 'linear': for point in points: cr.line_to(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y) else: previous = Point(0, zero, None, None, None, None) def breakage(previous, point): if interpolation == 'constant-center': return previous.x + ((point.x - previous.x) / 2.0) elif interpolation == 'constant-left': return point.x elif interpolation == 'constant-right': return previous.x for point in points: cr.line_to( breakage(previous, point) * self.area.w + self.area.x, previous.y * self.area.h + self.area.y) cr.line_to( breakage(previous, point) * self.area.w + self.area.x, point.y * self.area.h + self.area.y) cr.line_to(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y) previous = point cr.line_to(breakage(previous, Point(1, zero, None, None, None, None)) * self.area.w + self.area.x, previous.y * self.area.h + self.area.y) cr.line_to(self.area.w + self.area.x, zero * self.area.h + self.area.y) cr.move_to(self.area.x, zero * self.area.h + self.area.y) if key2fill[key]: cr.close_path() else: cr.set_source_rgb(*self.colorScheme[key]) cr.stroke() cr.save() cr.set_line_width(2) if self._getDatasKeys(): transparency = 0.8 / len(self._getDatasKeys()) for key in self._getDatasKeys(): if key2fill[key]: cr.save() r, g, b = self.colorScheme[key] preparePath(key) cr.set_source_rgb(r, g, b) cr.stroke_preserve() cr.restore() # Add soft transparency the area when line is filled cr.set_source_rgba(r, g, b, transparency) cr.fill() # Add gradient top to bottom linear = cairo.LinearGradient( width / 2, 0, width / 2, height) linear.add_color_stop_rgba( 0, r * 0.65, g * 0.65, b * 0.65, transparency) linear.add_color_stop_rgba(1, r, g, b, 0.1) cr.set_source(linear) preparePath(key) cr.fill() else: preparePath(key) for point in self.points: cr.set_source_rgb(*self.colorScheme[point.yname]) cr.move_to(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y) cr.arc(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y, 3, 0, 2 * math.pi) cr.fill() cr.restore() def drawLegend(self, cr, widht, height): super(Line, self).drawLegend(cr, widht, height) cr.save() for point in self.points: if point.highlight: cr.set_line_width(2) cr.set_source_rgb(*common.hex2rgb('#000000')) cr.move_to(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y) cr.arc(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y, 3, 0, 2 * math.pi) cr.stroke() cr.set_source_rgb(*common.highlight_rgb( *self.colorScheme[point.yname])) cr.arc(point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y, 3, 0, 2 * math.pi) cr.fill() cr.restore() def motion(self, widget, event): if not getattr(self, 'area', None): return nearest = None for point in self.points: x = point.x * self.area.w + self.area.x y = point.y * self.area.h + self.area.y l = (event.x - x) ** 2 + (event.y - y) ** 2 if not nearest or l < nearest[1]: nearest = (point, l) dia = self.area.w ** 2 + self.area.h ** 2 keys2txt = {} for yfield in self.yfields: keys2txt[yfield.get('key', yfield['name'])] = yfield['string'] highlight = False draw_points = [] yfields_timedelta = {x.get('key', x['name']): x.get('timedelta') for x in self.yfields if 'timedelta' in x} for point in self.points: if point == nearest[0] and nearest[1] < dia / 100: if not point.highlight: point.highlight = True label = keys2txt[point.yname] label += '\n' if point.yval in yfields_timedelta: converter = None if yfields_timedelta[point.yname]: converter = rpc.CONTEXT.get( yfields_timedelta[point.yname]) label += common.timedelta.format(point.yval, converter) else: label += locale.format('%.2f', point.yval, True) label += '\n' label += str(self.labels[point.xname]) self.popup.set_text(label) draw_points.append(point) else: if point.highlight: point.highlight = False draw_points.append(point) if point.highlight: self.popup.set_position(self, point.x * self.area.w + self.area.x, point.y * self.area.h + self.area.y) highlight = True if highlight: self.popup.show() else: self.popup.hide() if draw_points: minx = self.area.w + self.area.x miny = self.area.h + self.area.y maxx = maxy = 0.0 for point in draw_points: x = self.area.w * point.x + self.area.x y = self.area.h * point.y + self.area.y minx = min(x - 5, minx) miny = min(y - 5, miny) maxx = max(x + 5, maxx) maxy = max(y + 5, maxy) self.queue_draw_area(int(minx - 1), int(miny - 1), int(maxx - minx + 1), int(maxy - miny + 1)) def updateXY(self): super(Line, self).updateXY() if self.xrange != 0: self.xrange -= 1 if self.xrange == 0: self.xscale = 1.0 else: self.xscale = 1.0 / self.xrange def drawAxis(self, cr, width, height): super(Line, self).drawAxis(cr, width, height) self.drawLine(cr, 1.0, 0) def action(self): super(Line, self).action() for point in self.points: if point.highlight: ids = self.ids[point.xname] self.action_keyword(ids) def YLabels(self): ylabels = super(Line, self).YLabels() if all('timedelta' in f for f in self.yfields): converter = {f.get('timedelta') for f in self.yfields} if len(converter) == 1: converter = rpc.CONTEXT.get(converter.pop()) return [ (x[0], common.timedelta.format( datetime.timedelta(seconds=locale.atof(x[1])), converter)) for x in ylabels] return ylabels class Point(object): def __init__(self, x, y, xval, yval, xname, yname): self.x, self.y = x, y self.xval, self.yval = xval, yval self.xname = xname self.yname = yname self.highlight = False tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/bar.py0000644000175000017500000002100713463252532024145 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # This code is inspired by the pycha project # (http://www.lorenzogil.com/projects/pycha/) import locale import math import datetime import cairo from .graph import Graph import tryton.common as common import tryton.rpc as rpc class Bar(Graph): def __init__(self, *args, **kwargs): super(Bar, self).__init__(*args, **kwargs) self.bars = [] def drawGraph(self, cr, width, height): def drawBar(bar): cr.set_line_width(0.5) x = self.area.w * bar.x + self.area.x y = self.area.h * bar.y + self.area.y w = self.area.w * bar.w h = self.area.h * bar.h if w < 1 or h < 1: return # don't draw too small self.drawRectangle(cr, x, y, w, h) r, g, b = self.colorScheme[bar.yname] if bar.highlight: r, g, b = common.highlight_rgb(r, g, b) cr.set_source(self.sourceRectangle(x, y, w, h, r, g, b)) cr.fill_preserve() cr.stroke() cr.save() for bar in self.bars: drawBar(bar) cr.restore() def drawRectangle(self, cr, x, y, w, h): radius = 2.5 cr.arc(x + radius, y + radius, radius, 0, 2 * math.pi) cr.arc(x + w - radius, y + radius, radius, 0, 2 * math.pi) cr.arc(x + w - radius, y + h - radius, radius, 0, 2 * math.pi) cr.arc(x + radius, y + h - radius, radius, 0, 2 * math.pi) cr.rectangle(x + radius, y, w - radius * 2, h) cr.rectangle(x, y + radius, w, h - radius * 2) def sourceRectangle(self, x, y, w, h, r, g, b): linear = cairo.LinearGradient((x + w) / 2, y, (x + w) / 2, y + h) linear.add_color_stop_rgb(0, 3.5 * r / 5.0, 3.5 * g / 5.0, 3.5 * b / 5.0) linear.add_color_stop_rgb(1, r, g, b) return linear def motion(self, widget, event): super(Bar, self).motion(widget, event) if not getattr(self, 'area', None): return def intersect(bar, event): x = self.area.w * bar.x + self.area.x y = self.area.h * bar.y + self.area.y w = self.area.w * bar.w h = self.area.h * bar.h if x <= event.x <= x + w and y <= event.y <= y + h: return True return False highlight = False draw_bars = [] yfields_timedelta = {x.get('key', x['name']): x.get('timedelta') for x in self.yfields if 'timedelta' in x} for bar in self.bars: if intersect(bar, event): if not bar.highlight: bar.highlight = True if bar.yname in yfields_timedelta: converter = None if yfields_timedelta[bar.yname]: converter = rpc.CONTEXT.get( yfields_timedelta[bar.yname]) label = common.timedelta.format( datetime.timedelta(seconds=bar.yval), converter) else: label = locale.format('%.2f', bar.yval, True) label += '\n' label += str(self.labels[bar.xname]) self.popup.set_text(label) draw_bars.append(bar) else: if bar.highlight: bar.highlight = False draw_bars.append(bar) if bar.highlight: highlight = True if highlight: self.popup.show() else: self.popup.hide() if draw_bars: minx = self.area.w + self.area.x miny = self.area.h + self.area.y maxx = maxy = 0.0 for bar in draw_bars: x = self.area.w * bar.x + self.area.x y = self.area.h * bar.y + self.area.y minx = int(min(x, minx)) miny = int(min(y, miny)) maxx = int(max(x + self.area.w * bar.w, maxx)) maxy = int(max(y + self.area.h * bar.h, maxy)) self.queue_draw_area(minx - 1, miny - 1, maxx - minx + 2, maxy - miny + 2) def action(self): super(Bar, self).action() for bar in self.bars: if bar.highlight: ids = self.ids[bar.xname] self.action_keyword(ids) class VerticalBar(Bar): 'Vertical Bar Graph' def updateGraph(self): barWidth = self.xscale * 0.9 barMargin = self.xscale * (1.0 - 0.9) / 2 self.bars = [] i = 0 keys = list(self.datas.keys()) keys.sort() for xfield in keys: j = 0 barWidthForSet = barWidth / len(self.datas[xfield]) for yfield in self._getDatasKeys(): xval = i yval = self.datas[xfield][yfield] x = (xval - self.minxval) * self.xscale + \ barMargin + (j * barWidthForSet) y = 1.0 - (yval - self.minyval) * self.yscale w = barWidthForSet h = yval * self.yscale if h < 0: h = abs(h) y -= h rect = Rect(x, y, w, h, xval, yval, xfield, yfield) if (0.0 <= rect.x <= 1.0) and (0.0 <= rect.y <= 1.0): self.bars.append(rect) j += 1 i += 1 def XLabels(self): xlabels = super(VerticalBar, self).XLabels() return [(x[0] + (self.xscale / 2), x[1]) for x in xlabels] def YLabels(self): ylabels = super(VerticalBar, self).YLabels() if all('timedelta' in f for f in self.yfields): converter = {f.get('timedelta') for f in self.yfields} if len(converter) == 1: converter = rpc.CONTEXT.get(converter.pop()) else: converter = None return [ (x[0], common.timedelta.format( datetime.timedelta(seconds=locale.atof(x[1])), converter)) for x in ylabels] return ylabels class HorizontalBar(Bar): 'Horizontal Bar Graph' def updateGraph(self): barWidth = self.xscale * 0.9 barMargin = self.xscale * (1.0 - 0.9) / 2 self.bars = [] i = 0 keys = list(self.datas.keys()) keys.sort() for xfield in keys: j = 0 barWidthForSet = barWidth / len(self.datas[xfield]) for yfield in self._getDatasKeys(): xval = i yval = self.datas[xfield][yfield] x = - self.minyval * self.yscale y = (xval - self.minxval) * self.xscale + \ barMargin + (j * barWidthForSet) w = yval * self.yscale h = barWidthForSet if w < 0: w = abs(w) x -= w rect = Rect(x, y, w, h, xval, yval, xfield, yfield) if (0.0 <= rect.x <= 1.0) and (0.0 <= rect.y <= 1.0): self.bars.append(rect) j += 1 i += 1 def YLabels(self): xlabels = super(HorizontalBar, self).XLabels() return [(1 - (x[0] + (self.xscale / 2)), x[1]) for x in xlabels] def XLabels(self): ylabels = super(HorizontalBar, self).YLabels() if all('timedelta' in f for f in self.yfields): converter = {f.get('timedelta') for f in self.yfields} if len(converter) == 1: converter = rpc.CONTEXT.get(converter.pop()) else: converter = None return [ (x[0], common.timedelta.format( datetime.timedelta(seconds=locale.atof(x[1])), converter)) for x in ylabels] return [(x[0], x[1]) for x in ylabels] def _getLegendPosition(self, width, height): return self.area.x + self.area.w * 0.95 - width, \ self.area.y + self.area.h * 0.05 def drawLines(self, cr, width, height): for w, label in self.XLabels(): self.drawLine(cr, w, 0) class Rect(object): def __init__(self, x, y, w, h, xval, yval, xname, yname): self.x, self.y, self.w, self.h = x, y, w, h self.xval, self.yval = xval, yval self.yname = yname self.xname = xname self.highlight = False tryton-5.0.17/tryton/gui/window/view_form/view/graph_gtk/graph.py0000644000175000017500000003702713463252532024513 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. # This code is inspired by the pycha project # (http://www.lorenzogil.com/projects/pycha/) import gtk from functools import reduce from tryton.common import hex2rgb, generateColorscheme, \ COLOR_SCHEMES, datetime_strftime from tryton.pyson import PYSONDecoder import locale import math import datetime from dateutil.relativedelta import relativedelta import tryton.rpc as rpc import cairo from tryton.action import Action from tryton.gui.window import Window class Popup(object): def __init__(self, widget): self.win = gtk.Window(gtk.WINDOW_POPUP) self.win.set_name('gtk-tooltips') self.win.set_resizable(False) self.win.set_border_width(1) self.win.set_transient_for(widget.window) self.label = gtk.Label() self.win.add(self.label) self.win.connect('enter-notify-event', self.enter) def set_text(self, text): self.label.set_text(text) def set_position(self, widget, x, y): widget_x, widget_y = widget.window.get_origin() allocation = widget.get_allocation() width, height = allocation.width, allocation.height popup_width, popup_height = self.win.get_size() if x < popup_width // 2: x = popup_width // 2 if x > width - popup_width // 2: x = width - popup_width // 2 pos_x = widget_x + x - popup_width // 2 if pos_x < 0: pos_x = 0 if y < popup_height + 5: y = popup_height + 5 if y > height: y = height pos_y = widget_y + y - popup_height - 5 if pos_y < 0: pos_y = 0 self.win.move(int(pos_x), int(pos_y)) def show(self): self.win.show_all() def hide(self): self.win.hide() def destroy(self): self.win.destroy() def enter(self, widget, event): self.win.hide() class Graph(gtk.DrawingArea): 'Graph' __gsignals__ = {"draw": "override"} def __init__(self, view, xfield, yfields): super(Graph, self).__init__() self.view = view self.xfield = xfield self.yfields = yfields self.datas = {} self.topPadding = 15 self.bottomPadding = 15 self.rightPadding = 30 self.leftPadding = 30 self.set_events(gtk.gdk.POINTER_MOTION_MASK) self.connect('motion-notify-event', self.motion) self.connect('leave-notify-event', self.leave) self.popup = Popup(self) @property def attrs(self): return self.view.attributes @property def model(self): return self.view.screen.model_name def destroy(self): self.popup.destroy() super(Graph, self).destroy() def motion(self, widget, event): self.popup.set_position(self, event.x, event.y) def leave(self, widget, event): self.popup.hide() def do_draw(self, cr): cr = self.window.cairo_create() width = self.get_allocated_width() height = self.get_allocated_height() self.updateArea(cr, width, height) self.drawBackground(cr, width, height) self.drawLines(cr, width, height) self.drawGraph(cr, width, height) self.drawAxis(cr, width, height) self.drawLegend(cr, width, height) def export_png(self, filename, width, height): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) cx = cairo.Context(surface) self.updateArea(cx, width, height) self.drawBackground(cx, width, height) self.drawLines(cx, width, height) self.drawGraph(cx, width, height) self.drawAxis(cx, width, height) self.drawLegend(cx, width, height) surface.write_to_png(filename) self.queue_draw() def action(self): self.popup.hide() def action_keyword(self, ids): if not ids: return ctx = self.group._context.copy() if 'active_ids' in ctx: del ctx['active_ids'] if 'active_id' in ctx: del ctx['active_id'] event = gtk.get_current_event() allow_similar = False if (event.state & gtk.gdk.CONTROL_MASK or event.state & gtk.gdk.MOD1_MASK): allow_similar = True with Window(hide_current=True, allow_similar=allow_similar): return Action.exec_keyword('graph_open', { 'model': self.model, 'id': ids[0], 'ids': ids, }, context=ctx, warning=False) def drawBackground(self, cr, width, height): # Fill the background cr.save() r, g, b = hex2rgb(self.attrs.get('background', '#d5d5d5')) linear = cairo.LinearGradient(width // 2, 0, width // 2, height) linear.add_color_stop_rgb(0, 1, 1, 1) linear.add_color_stop_rgb(1, r, g, b) cr.set_source(linear) cr.rectangle(0, 0, width, height) cr.fill() cr.stroke() cr.restore() def drawGraph(self, cr, width, height): pass def YLabels(self): ylabels = [] if self.yrange == 0.0: base = 1 else: base = 10 ** int(math.log(self.yrange, 10)) for i in range(int(self.yrange / base) + 1): val = int(self.minyval / base) * base + i * base h = (val - self.minyval) * self.yscale label = locale.format('%.2f', val, True) ylabels.append((h, label)) return ylabels def XLabels(self): xlabels = [] i = 0.0 keys = list(self.datas.keys()) keys.sort() for key in keys: if self.xrange == 0: w = 1.0 else: w = i / self.xrange xlabels.append((w, str(self.labels[key]))) i += 1 return xlabels def drawAxis(self, cr, width, height): cr.set_source_rgb(*hex2rgb('#000000')) cr.set_line_width(0.5) # Y axis def drawYLabel(h, label): x = self.area.x y = self.area.y + self.area.h - h * self.area.h cr.new_path() cr.move_to(x, y) cr.line_to(x - 3.0, y) cr.close_path() cr.stroke() extends = cr.text_extents(label) labelWidth = extends[2] labelHeight = extends[3] if labelWidth <= self.area.x: cr.move_to(x - 3.0 - labelWidth - 5, y + labelHeight / 2.0) cr.show_text(label) for h, label in self.YLabels(): drawYLabel(h, label) cr.new_path() cr.move_to(self.area.x, self.area.y) cr.line_to(self.area.x, self.area.y + self.area.h) cr.close_path() cr.stroke() # X axis def drawXLabel(w, label): x = self.area.x + w * self.area.w y = self.area.y + self.area.h cr.new_path() cr.move_to(x, y) cr.line_to(x, y + 3.0) cr.close_path() cr.stroke() extends = cr.text_extents(label) labelWidth = extends[2] labelHeight = extends[3] if labelWidth <= self.xscale * self.area.w: cr.move_to(x - labelWidth / 2.0, y + labelHeight + 5) cr.show_text(label) for w, label in self.XLabels(): drawXLabel(w, label) cr.new_path() cr.move_to(self.area.x, self.area.y + self.area.h) cr.line_to(self.area.x + self.area.w, self.area.y + self.area.h) cr.close_path() cr.stroke() def drawLines(self, cr, width, height): for h, label in self.YLabels(): self.drawLine(cr, 0, h) def drawLine(self, cr, x, y): if x: x1 = x2 = self.area.x + x * self.area.w y1 = self.area.y y2 = y1 + self.area.h else: y1 = y2 = self.area.y + self.area.h - y * self.area.h x1 = self.area.x x2 = x1 + self.area.w cr.save() cr.set_source_rgb(*hex2rgb('#A0A0A0')) cr.set_line_width(0.3) cr.new_path() cr.set_dash([5.0, 4.0]) cr.move_to(x1, y1) cr.line_to(x2, y2) cr.close_path() cr.stroke() cr.restore() def drawLegend(self, cr, width, height): if not int(self.attrs.get('legend', 1)): return padding = 4 bullet = 15 width = 0 height = padding keys = self._getDatasKeys() if not keys: return keys2txt = {} for yfield in self.yfields: keys2txt[yfield.get('key', yfield['name'])] = yfield['string'] for key in keys: extents = cr.text_extents(keys2txt[key]) width = max(extents[2], width) height += max(extents[3], bullet) + padding width = padding + bullet + padding + width + padding pos_x, pos_y = self._getLegendPosition(width, height) cr.save() cr.rectangle(pos_x, pos_y, width, height) cr.set_source_rgba(1, 1, 1, 0.8) cr.fill_preserve() cr.set_line_width(0.5) cr.set_source_rgb(*hex2rgb('#000000')) cr.stroke() def drawKey(key, x, y, text_height): cr.rectangle(x, y, bullet, bullet) cr.set_source_rgb(*self.colorScheme[key]) cr.fill_preserve() cr.set_source_rgb(0, 0, 0) cr.stroke() cr.move_to(x + bullet + padding, y + bullet / 2.0 + text_height / 2.0) cr.show_text(keys2txt[key]) cr.set_line_width(0.5) x = pos_x + padding y = pos_y + padding for key in keys: extents = cr.text_extents(keys2txt[key]) drawKey(key, x, y, extents[3]) y += max(extents[3], bullet) + padding cr.restore() def _getLegendPosition(self, width, height): return self.area.x + self.area.w * 0.05, \ self.area.y + self.area.h * 0.05 def display(self, group): self.updateDatas(group) self.setColorScheme() self.updateXY() self.updateGraph() self.queue_draw() def updateDatas(self, group): self.datas = {} self.labels = {} self.ids = {} self.group = group minx = None maxx = None for model in group: x = model[self.xfield['name']].get(model) if not minx: minx = x if not maxx: maxx = x if minx is None and maxx is None: if isinstance(x, datetime.datetime): minx, maxx = datetime.datetime.min, datetime.datetime.max elif isinstance(x, datetime.date): minx, maxx = datetime.date.min, datetime.date.max elif isinstance(x, datetime.timedelta): minx, maxx = datetime.timedelta.min, datetime.timedelta.max try: minx = min(minx, x) maxx = max(maxx, x) except TypeError: continue self.labels[x] = model[self.xfield['name']].get_client(model) self.ids.setdefault(x, []) self.ids[x].append(model.id) self.datas.setdefault(x, {}) for yfield in self.yfields: key = yfield.get('key', yfield['name']) self.datas[x].setdefault(key, 0.0) if yfield.get('domain'): context = rpc.CONTEXT.copy() context['context'] = context.copy() context['_user'] = rpc._USER for field in model.group.fields: context[field] = model[field].get(model) if not PYSONDecoder(context).decode(yfield['domain']): continue if yfield['name'] == '#': self.datas[x][key] += 1 else: value = model[yfield['name']].get(model) if isinstance(value, datetime.timedelta): value = value.total_seconds() self.datas[x][key] += float(value or 0) date_format = self.view.screen.context.get('date_format', '%x') datetime_format = date_format + ' %X' if isinstance(minx, datetime.datetime): date = minx while date <= maxx: self.labels[date] = datetime_strftime(date, datetime_format) self.datas.setdefault(date, {}) for yfield in self.yfields: self.datas[date].setdefault( yfield.get('key', yfield['name']), 0.0) date += relativedelta(days=1) elif isinstance(minx, datetime.date): date = minx while date <= maxx: self.labels[date] = datetime_strftime(date, date_format) self.datas.setdefault(date, {}) for yfield in self.yfields: self.datas[date].setdefault( yfield.get('key', yfield['name']), 0.0) date += relativedelta(days=1) def updateArea(self, cr, width, height): maxylabel = '' for value, label in self.YLabels(): if len(maxylabel) < len(label): maxylabel = label extends = cr.text_extents(maxylabel) yLabelWidth = extends[2] maxxlabel = '' for value, label in self.XLabels(): if len(maxxlabel) < len(label): maxxlabel = label extends = cr.text_extents(maxxlabel) xLabelHeight = extends[3] if yLabelWidth > width / 3.0: yLabelWidth = 0 width = width - self.leftPadding - yLabelWidth - self.rightPadding height = height - self.topPadding - self.bottomPadding - xLabelHeight self.area = Area(self.leftPadding + yLabelWidth, self.topPadding, width, height) def updateXY(self): self.maxxval = len(self.datas) self.minxval = 0.0 self.xrange = self.maxxval - self.minxval if self.xrange == 0: self.xscale = 1.0 else: self.xscale = 1.0 / self.xrange if not list(self.datas.values()): self.maxyval = 0.0 self.minyval = 0.0 else: self.maxyval = max([reduce(lambda x, y: max(x, y), x.values()) for x in self.datas.values()]) self.minyval = min([reduce(lambda x, y: min(x, y), x.values()) for x in self.datas.values()]) if self.minyval > 0: self.minyval = 0.0 self.yrange = self.maxyval - self.minyval if self.yrange == 0: self.yscale = 1.0 else: self.yscale = 1.0 / self.yrange def updateGraph(self): pass def setColorScheme(self): keys = self._getDatasKeys() color = self.attrs.get('color', 'blue') r, g, b = hex2rgb(COLOR_SCHEMES.get(color, color)) maxcolor = max(max(r, g), b) self.colorScheme = generateColorscheme(color, keys, maxcolor / (len(keys) or 1)) for yfield in self.yfields: if yfield.get('color'): self.colorScheme[yfield.get('key', yfield['name'])] = hex2rgb( COLOR_SCHEMES.get(yfield['color'], yfield['color'])) def _getDatasKeys(self): return [x.get('key', x['name']) for x in self.yfields] class Area(object): def __init__(self, x, y, w, h): self.x, self.y, self.w, self.h = x, y, w, h tryton-5.0.17/tryton/gui/window/view_form/view/calendar_gtk/0000755000175000017500000000000013571264253023502 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/view/calendar_gtk/dates_period.py0000644000175000017500000000163613354423127026520 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime class DatesPeriod(): """ This class represents a period of time between two dates or two datetimes. """ def __init__(self, start, end): assert type(start) == type(end) self.start = start self.end = end def is_in(self, period): return self.start >= period.start and self.end <= period.end def get_dates(self, format_datetime=False): if not format_datetime: return self.start, self.end midnight = datetime.time(0) start = datetime.datetime.combine(self.start, midnight) end = datetime.datetime.combine(self.end, midnight) return start, end def __str__(self): string = self.start.__str__() + ' => ' + self.end.__str__() return string tryton-5.0.17/tryton/gui/window/view_form/view/calendar_gtk/calendar_.py0000644000175000017500000001066013463252532025764 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import calendar import datetime import goocalendar from .dates_period import DatesPeriod class Calendar_(goocalendar.Calendar): 'Calendar' def __init__(self, attrs, screen, fields, event_store=None): super(Calendar_, self).__init__( event_store, attrs.get('mode', 'month')) self.attrs = attrs self.screen = screen self.fields = fields self.event_store = event_store self.current_domain_period = self.get_displayed_period() def set_default_date(self, record, selected_date): dtstart = self.attrs['dtstart'] record[dtstart].set(record, datetime.datetime.combine(selected_date, datetime.time(0))) record.on_change([dtstart]) record.on_change_with([dtstart]) def get_displayed_period(self): cal = calendar.Calendar(self.firstweekday) if self.view == 'week': week = goocalendar.util.my_weekdatescalendar(cal, self.selected_date) first_date = week[0] last_date = week[6] last_date += datetime.timedelta(1) elif self.view == 'month': weeks = goocalendar.util.my_monthdatescalendar(cal, self.selected_date) first_date = weeks[0][0] last_date = weeks[5][6] last_date += datetime.timedelta(1) displayed_period = DatesPeriod(first_date, last_date) return displayed_period def update_domain(self): displayed_period = self.get_displayed_period() if not displayed_period.is_in(self.current_domain_period): self.current_domain_period = displayed_period return True return False def current_domain(self): first_datetime, last_datetime = \ self.current_domain_period.get_dates(True) dtstart = self.attrs['dtstart'] dtend = self.attrs.get('dtend') or dtstart domain = ['OR', ['AND', (dtstart, '>=', first_datetime), (dtstart, '<', last_datetime)], ['AND', (dtend, '>=', first_datetime), (dtend, '<', last_datetime)], ['AND', (dtstart, '<', first_datetime), (dtend, '>', last_datetime)]] return domain def get_colors(self, record): text_color = None if self.attrs.get('color'): text_color = record[self.attrs['color']].get(record) bg_color = 'lightblue' if self.attrs.get('background_color'): bg_color = record[self.attrs['background_color']].get( record) return text_color, bg_color def display(self, group): dtstart = self.attrs['dtstart'] dtend = self.attrs.get('dtend') if self.screen.current_record: record = self.screen.current_record date = record[dtstart].get(record) if date: # select the day of the current record self.select(date) if self._event_store: self._event_store.clear() else: event_store = goocalendar.EventStore() self.event_store = event_store for record in group: if not record[dtstart].get(record): continue start = record[dtstart].get_client(record) if dtend: end = record[dtend].get_client(record) else: end = None midnight = datetime.time(0) all_day = False if not isinstance(start, datetime.datetime): start = datetime.datetime.combine(start, midnight) if end and not isinstance(end, datetime.datetime): end = datetime.datetime.combine(end, midnight) all_day = True elif not end: all_day = True # Skip invalid event if end is not None and start > end: continue text_color, bg_color = self.get_colors(record) label = '\n'.join(record[attrs['name']].get_client(record) for attrs in self.fields).rstrip() event = goocalendar.Event(label, start, end, text_color=text_color, bg_color=bg_color, all_day=all_day) event.record = record self._event_store.add(event) self.grab_focus(self.get_root_item()) tryton-5.0.17/tryton/gui/window/view_form/view/calendar_gtk/__init__.py0000644000175000017500000000022013354423127025601 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. tryton-5.0.17/tryton/gui/window/view_form/view/calendar_gtk/toolbar.py0000644000175000017500000002150013463252532025511 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime import calendar import gettext import gtk from tryton.gui import Main from tryton.common.datetime_ import popup_position, popup_show, popup_hide _ = gettext.gettext class Toolbar(gtk.Toolbar): def __init__(self, goocalendar): super(Toolbar, self).__init__() self.goocalendar = goocalendar self.accel_group = Main().accel_group today_button = gtk.ToolButton() today_button.set_label(_('Today')) today_button.set_homogeneous(False) today_button.connect("clicked", self.on_today_button_clicked) today_button.add_accelerator("clicked", self.accel_group, gtk.keysyms.t, gtk.gdk.MODIFIER_MASK, gtk.ACCEL_VISIBLE) self.insert(today_button, -1) arrow_left = gtk.Arrow(gtk.ARROW_LEFT, gtk.SHADOW_NONE) go_back = gtk.ToolButton() go_back.set_icon_widget(arrow_left) go_back.set_label(_("go back")) go_back.set_expand(False) go_back.set_homogeneous(False) go_back.connect("clicked", self.on_go_back_clicked) self.insert(go_back, -1) self.current_page_label = gtk.Label("") self.current_page = gtk.ToggleToolButton() self.current_page.set_label_widget(self.current_page_label) self.current_page.connect("clicked", self.on_current_page_clicked) self.insert(self.current_page, -1) self.__cal_popup = gtk.Window(gtk.WINDOW_POPUP) self.__cal_popup.set_events( self.__cal_popup.get_events() | gtk.gdk.KEY_PRESS_MASK) self.__cal_popup.set_resizable(False) self.__cal_popup.connect('delete-event', self.on_cal_popup_closed) self.__cal_popup.connect( 'key-press-event', self.on_cal_popup_key_pressed) self.__cal_popup.connect( 'button-press-event', self.on_cal_popup_button_pressed) gtkcal = gtk.Calendar() gtkcal.connect('day-selected', self.on_gtkcal_day_selected) gtkcal.connect( 'day-selected-double-click', self.on_gtkcal_day_selected_double_click) gtkcal.set_display_options( gtk.CALENDAR_SHOW_HEADING | gtk.CALENDAR_SHOW_WEEK_NUMBERS | gtk.CALENDAR_SHOW_DAY_NAMES) gtkcal.set_no_show_all(True) self.__cal_popup.add(gtkcal) gtkcal.show() self.gtkcal = gtkcal self.goocalendar.connect('day-selected', self.on_goocalendar_day_selected) arrow_right = gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_NONE) go_forward = gtk.ToolButton() go_forward.set_icon_widget(arrow_right) go_forward.set_label(_("go forward")) go_forward.set_expand(False) go_forward.set_homogeneous(False) go_forward.connect("clicked", self.on_go_forward_clicked) self.insert(go_forward, -1) arrow_left = gtk.Arrow(gtk.ARROW_LEFT, gtk.SHADOW_NONE) previous_year = gtk.ToolButton() previous_year.set_icon_widget(arrow_left) previous_year.set_label(_("previous year")) previous_year.set_expand(False) previous_year.set_homogeneous(False) previous_year.connect("clicked", self.on_previous_year_clicked) self.insert(previous_year, -1) self.current_year_label = gtk.Label("") current_year = gtk.ToolItem() current_year.add(self.current_year_label) self.insert(current_year, -1) arrow_right = gtk.Arrow(gtk.ARROW_RIGHT, gtk.SHADOW_NONE) next_year = gtk.ToolButton() next_year.set_icon_widget(arrow_right) next_year.set_label(_("next year")) next_year.set_expand(False) next_year.set_homogeneous(False) next_year.connect("clicked", self.on_next_year_clicked) self.insert(next_year, -1) blank_widget = gtk.ToolItem() blank_widget.set_expand(True) self.insert(blank_widget, -1) week_button = gtk.RadioToolButton() week_button.set_label(_('Week View')) week_button.connect("clicked", self.on_week_button_clicked) week_button.add_accelerator("clicked", self.accel_group, gtk.keysyms.w, gtk.gdk.MODIFIER_MASK, gtk.ACCEL_VISIBLE) self.insert(week_button, -1) if hasattr(gtk.RadioToolButton, 'new_from_widget'): month_button = gtk.RadioToolButton.new_from_widget(week_button) else: month_button = gtk.RadioToolButton(week_button) month_button.set_label_widget(gtk.Label(_('Month View'))) month_button.connect("clicked", self.on_month_button_clicked) month_button.add_accelerator("clicked", self.accel_group, gtk.keysyms.m, gtk.gdk.MODIFIER_MASK, gtk.ACCEL_VISIBLE) self.insert(month_button, -1) buttons = { 'month': month_button, 'week': week_button } buttons[self.goocalendar.view].set_active(True) self.update_displayed_date() self.set_style(gtk.TOOLBAR_ICONS) def update_displayed_date(self): date = self.goocalendar.selected_date year = date.timetuple()[0] month = date.timetuple()[1] day = date.timetuple()[2] self.current_year_label.set_text(str(year)) if self.goocalendar.view == "month": new_label = calendar.month_name[month] self.current_page_label.set_text(new_label) elif self.goocalendar.view == "week": week_number = datetime.date(year, month, day).isocalendar()[1] new_label = _('Week') + ' ' + str(week_number) new_label += ' (' + calendar.month_name[month] + ')' self.current_page_label.set_text(new_label) def on_today_button_clicked(self, widget): self.goocalendar.select(datetime.date.today()) def on_go_back_clicked(self, widget): self.goocalendar.previous_page() def on_current_page_clicked(self, widget): if widget.get_active(): self.__cal_popup.set_transient_for(widget.get_toplevel()) popup_position(widget, self.__cal_popup) popup_show(self.__cal_popup) def on_cal_popup_closed(self, widget): self.cal_popup_hide() return True def on_cal_popup_key_pressed(self, widget, event): if event.keyval != gtk.keysyms.Escape: return False widget.stop_emission('key-press-event') self.cal_popup_hide() return True def on_cal_popup_button_pressed(self, widget, event): child = event.window if child != widget.window: while child: if child == widget.window: return False child = child.get_parent() self.cal_popup_hide() return True def cal_popup_hide(self): popup_hide(self.__cal_popup) self.current_page.set_active(False) def on_gtkcal_day_selected(self, gtkcal): year, month, day = gtkcal.get_date() month += 1 # months go from 1 to 12 instead of from 0 to 11 self.goocalendar.select(datetime.date(year, month, day)) def on_gtkcal_day_selected_double_click(self, gtkcal): self.cal_popup_hide() def on_goocalendar_day_selected(self, goocalendar, day): # months go from 0 to 11 in gtk.Calendar instead of 1 to 12 new_date = self.goocalendar.selected_date self.gtkcal.select_month(new_date.month - 1, new_date.year) self.gtkcal.handler_block_by_func(self.on_gtkcal_day_selected) self.gtkcal.select_day(new_date.day) self.gtkcal.handler_unblock_by_func(self.on_gtkcal_day_selected) def on_go_forward_clicked(self, widget): self.goocalendar.next_page() def on_previous_year_clicked(self, widget): date = datetime.datetime.combine(self.goocalendar.selected_date, datetime.time(0)) year, month, day = date.timetuple()[:3] year -= 1 cal = calendar.Calendar(self.goocalendar.firstweekday) next_month_days = [d for d in cal.itermonthdays(year, month)] if day not in next_month_days: day = max(next_month_days) self.goocalendar.select(datetime.datetime(year, month, day)) def on_next_year_clicked(self, widget): date = datetime.datetime.combine(self.goocalendar.selected_date, datetime.time(0)) year, month, day = date.timetuple()[:3] year += 1 cal = calendar.Calendar(self.goocalendar.firstweekday) next_month_days = [d for d in cal.itermonthdays(year, month)] if day not in next_month_days: day = max(next_month_days) self.goocalendar.select(datetime.datetime(year, month, day)) def on_week_button_clicked(self, widget): self.goocalendar.set_view("week") def on_month_button_clicked(self, widget): self.goocalendar.set_view("month") tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/0000755000175000017500000000000013571264253022674 5ustar cedced00000000000000tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/widget.py0000644000175000017500000002462613463252532024540 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import gettext import tryton.common as common from tryton.common import RPCExecute, RPCException from tryton.common import TRYTON_ICON from tryton.common.underline import set_underline from tryton.common.widget_style import widget_class from tryton.gui import Main from tryton.gui.window.nomodal import NoModal _ = gettext.gettext class Widget(object): expand = False def __init__(self, view, attrs): super(Widget, self).__init__() self.view = view self.attrs = attrs self.widget = None self.mnemonic_widget = None self.visible = True self._readonly = False @property def field_name(self): return self.attrs['name'] @property def model_name(self): return self.view.screen.model_name @property def record(self): return self.view.screen.current_record @property def field(self): if self.record: return self.record.group.fields[self.field_name] def destroy(self): pass def sig_activate(self, widget=None): # emulate a focus_out so that the onchange is called if needed self._focus_out() def _readonly_set(self, readonly): self._readonly = readonly def _required_set(self, required): pass def _invisible_widget(self): return self.widget @property def _invalid_widget(self): return self.widget @property def _required_widget(self): return self.widget @property def modified(self): return False def send_modified(self, *args): def send(value): if not self.widget.props.window: return if self.record and self.get_value() == value: self.record.signal('record-modified') def get_value(): if not self.widget.props.window: return gobject.timeout_add(300, send, self.get_value()) # Wait the current event is finished to retreive the value gobject.idle_add(get_value) return False def invisible_set(self, value): widget = self._invisible_widget() if value and value != '0': self.visible = False widget.hide() else: self.visible = True widget.show() def _focus_out(self, *args): if not self.field: return False if not self.visible: return False self.set_value(self.record, self.field) def display(self, record, field): if not field: self._readonly_set(self.attrs.get('readonly', True)) self.invisible_set(self.attrs.get('invisible', False)) self._required_set(False) return states = field.get_state_attrs(record) readonly = self.attrs.get('readonly', states.get('readonly', False)) if self.view.screen.readonly: readonly = True self._readonly_set(readonly) widget_class(self.widget, 'readonly', readonly) self._required_set(not readonly and states.get('required', False)) widget_class( self._required_widget, 'required', not readonly and states.get('required', False)) invalid = states.get('invalid', False) widget_class(self._invalid_widget, 'invalid', not readonly and invalid) self.invisible_set(self.attrs.get( 'invisible', states.get('invisible', False))) def set_value(self, record, field): pass class TranslateDialog(NoModal): def __init__(self, widget, languages, readonly): NoModal.__init__(self) self.widget = widget self.win = gtk.Dialog(_('Translation'), self.parent, gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_icon(TRYTON_ICON) self.win.connect('response', self.response) parent_allocation = self.parent.get_allocation() self.win.set_default_size(-1, min(400, parent_allocation.height)) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) cancel_button = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) cancel_button.set_image(common.IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) cancel_button.set_always_show_image(True) ok_button = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(common.IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) ok_button.add_accelerator( 'clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) tooltips = common.Tooltips() self.widgets = {} table = gtk.Table(len(languages), 4) table.set_homogeneous(False) table.set_col_spacings(3) table.set_row_spacings(2) table.set_border_width(1) for i, language in enumerate(languages): label = language['name'] + _(':') label = gtk.Label(label) label.set_alignment(1.0, 0.0 if self.widget.expand else 0.5) table.attach(label, 0, 1, i, i + 1, xoptions=gtk.FILL, xpadding=2) context = dict( language=language['code'], fuzzy_translation=False, ) try: value = RPCExecute('model', self.widget.record.model_name, 'read', [self.widget.record.id], [self.widget.field_name], context={'language': language['code']} )[0][self.widget.field_name] except RPCException: return context['fuzzy_translation'] = True try: fuzzy_value = RPCExecute('model', self.widget.record.model_name, 'read', [self.widget.record.id], [self.widget.field_name], context=context)[0][self.widget.field_name] except RPCException: return if fuzzy_value is None: fuzzy_value = '' widget = self.widget.translate_widget() label.set_mnemonic_widget(widget) self.widget.translate_widget_set(widget, fuzzy_value) self.widget.translate_widget_set_readonly(widget, True) yopt = 0 if self.widget.expand: yopt = gtk.EXPAND | gtk.FILL table.attach(widget, 1, 2, i, i + 1, yoptions=yopt) editing = gtk.CheckButton() editing.connect('toggled', self.editing_toggled, widget) editing.props.sensitive = not readonly tooltips.set_tip(editing, _('Edit')) table.attach(editing, 2, 3, i, i + 1, xoptions=gtk.FILL) fuzzy = gtk.CheckButton() fuzzy.set_active(value != fuzzy_value) fuzzy.props.sensitive = False tooltips.set_tip(fuzzy, _('Fuzzy')) table.attach(fuzzy, 4, 5, i, i + 1, xoptions=gtk.FILL) self.widgets[language['code']] = (widget, editing, fuzzy) tooltips.enable() vbox = gtk.VBox() vbox.pack_start(table, self.widget.expand, True) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) viewport.add(vbox) scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC) scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) scrolledwindow.add(viewport) self.win.vbox.pack_start(scrolledwindow, True, True) self.win.show_all() self.register() self.show() def editing_toggled(self, editing, widget): self.widget.translate_widget_set_readonly(widget, not editing.get_active()) def response(self, win, response): if response == gtk.RESPONSE_OK: for code, widget in self.widgets.items(): widget, editing, fuzzy = widget if not editing.get_active(): continue value = self.widget.translate_widget_get(widget) context = dict( language=code, fuzzy_translation=False, ) try: RPCExecute('model', self.widget.record.model_name, 'write', [self.widget.record.id], { self.widget.field_name: value, }, context=context) except RPCException: pass self.widget.record.cancel() self.widget.view.display() self.destroy() def destroy(self): self.win.destroy() NoModal.destroy(self) def show(self): self.win.show() def hide(self): self.win.hide() class TranslateMixin: def translate_button(self): button = gtk.Button() button.set_image(common.IconFactory.get_image( 'tryton-translate', gtk.ICON_SIZE_SMALL_TOOLBAR)) button.set_relief(gtk.RELIEF_NONE) button.connect('clicked', self.translate) return button def translate(self, *args): self.view.set_value() if self.record.id < 0 or self.record.modified: common.message( _('You need to save the record before adding translations.')) return try: lang_ids = RPCExecute('model', 'ir.lang', 'search', [ ('translatable', '=', True), ]) except RPCException: return if not lang_ids: common.message(_('No other language available.')) return try: languages = RPCExecute('model', 'ir.lang', 'read', lang_ids, ['code', 'name']) except RPCException: return TranslateDialog(self, languages, self._readonly) def translate_widget(self): raise NotImplemented def translate_widget_set(self, widget, value): raise NotImplemented def translate_widget_get(self, widget): raise NotImplemented def translate_widget_set_readonly(self, widget, value): raise NotImplemented tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/selection.py0000644000175000017500000000707713463252532025243 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject from .widget import Widget from tryton.common.selection import SelectionMixin, selection_shortcuts, \ PopdownMixin from tryton.config import CONFIG class Selection(Widget, SelectionMixin, PopdownMixin): def __init__(self, view, attrs): super(Selection, self).__init__(view, attrs) self.widget = gtk.HBox(spacing=3) self.entry = gtk.ComboBoxEntry() child = self.mnemonic_widget = self.entry.get_child() child.set_property('activates_default', True) child.set_max_length(int(attrs.get('size', 0))) child.set_width_chars(10) selection_shortcuts(self.entry) child.connect('activate', lambda *a: self._focus_out()) child.connect('focus-out-event', lambda *a: self._focus_out()) self.entry.connect('changed', self.changed) self.entry.connect('move-active', self._move_active) self.entry.connect( 'scroll-event', lambda c, e: c.emit_stop_by_name('scroll-event')) self.widget.pack_start(self.entry) self.widget.set_focus_chain([child]) self.selection = attrs.get('selection', [])[:] self.attrs = attrs self.init_selection() self.set_popdown(self.selection, self.entry) def changed(self, combobox): def focus_out(): if combobox.props.window: self._focus_out() # Must be deferred because it triggers a display of the form gobject.idle_add(focus_out) def _move_active(self, combobox, scroll_type): if not combobox.get_child().get_editable(): combobox.emit_stop_by_name('move-active') def _readonly_set(self, value): super(Selection, self)._readonly_set(value) self.entry.get_child().set_editable(not value) self.entry.set_button_sensitivity( gtk.SENSITIVITY_OFF if value else gtk.SENSITIVITY_AUTO) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() def get_value(self): if not self.entry.get_child(): # entry is destroyed return return self.get_popdown_value(self.entry) @property def modified(self): if self.record and self.field: return self.field.get(self.record) != self.get_value() return False def set_value(self, record, field): value = self.get_value() if 'relation' in self.attrs and value: value = (value, self.get_popdown_text(self.entry)) field.set_client(record, value) def display(self, record, field): self.update_selection(record, field) self.set_popdown(self.selection, self.entry) if not field: self.entry.set_active(-1) # When setting no item GTK doesn't clear the entry self.entry.get_child().set_text('') return super(Selection, self).display(record, field) value = field.get(record) if isinstance(value, (list, tuple)): # Compatibility with Many2One value = value[0] self.entry.handler_block_by_func(self.changed) if not self.set_popdown_value(self.entry, value): text = self.get_inactive_selection(value) self.set_popdown(self.selection[:] + [(value, text)], self.entry) self.set_popdown_value(self.entry, value) self.entry.handler_unblock_by_func(self.changed) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/many2many.py0000644000175000017500000002555513463252532025172 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk from tryton.gui.window.view_form.screen import Screen from .widget import Widget from tryton.gui.window.win_search import WinSearch from tryton.gui.window.win_form import WinForm import tryton.common as common import gettext from tryton.common.completion import get_completion, update_completion from tryton.common.domain_parser import quote from tryton.common.underline import set_underline _ = gettext.gettext class Many2Many(Widget): expand = True def __init__(self, view, attrs): super(Many2Many, self).__init__(view, attrs) self.widget = gtk.Frame() self.widget.set_shadow_type(gtk.SHADOW_NONE) self.widget.get_accessible().set_name(attrs.get('string', '')) vbox = gtk.VBox(homogeneous=False, spacing=5) self.widget.add(vbox) self._readonly = True self._required = False self._position = 0 hbox = gtk.HBox(homogeneous=False, spacing=0) hbox.set_border_width(2) self.title = gtk.Label(set_underline(attrs.get('string', ''))) self.title.set_use_underline(True) self.title.set_alignment(0.0, 0.5) hbox.pack_start(self.title, expand=True, fill=True) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) tooltips = common.Tooltips() self.wid_text = gtk.Entry() self.wid_text.set_placeholder_text(_('Search')) self.wid_text.set_property('width_chars', 13) self.wid_text.connect('focus-out-event', self._focus_out) self.focus_out = True hbox.pack_start(self.wid_text, expand=True, fill=True) if int(self.attrs.get('completion', 1)): self.wid_completion = get_completion( create=self.attrs.get('create', True) and common.MODELACCESS[self.attrs['relation']]['create']) self.wid_completion.connect('match-selected', self._completion_match_selected) self.wid_completion.connect('action-activated', self._completion_action_activated) self.wid_text.set_completion(self.wid_completion) self.wid_text.connect('changed', self._update_completion) else: self.wid_completion = None self.but_add = gtk.Button() tooltips.set_tip(self.but_add, _('Add existing record')) self.but_add.connect('clicked', self._sig_add) self.but_add.add(common.IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_add.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_add, expand=False, fill=False) self.but_remove = gtk.Button() tooltips.set_tip(self.but_remove, _('Remove selected record ')) self.but_remove.connect('clicked', self._sig_remove) self.but_remove.add(common.IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_remove.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_remove, expand=False, fill=False) hbox.set_focus_chain([self.wid_text]) tooltips.enable() frame = gtk.Frame() frame.add(hbox) frame.set_shadow_type(gtk.SHADOW_OUT) vbox.pack_start(frame, expand=False, fill=True) self.screen = Screen(attrs['relation'], view_ids=attrs.get('view_ids', '').split(','), mode=['tree'], views_preload=attrs.get('views', {}), row_activate=self._on_activate, limit=None) self.screen.signal_connect(self, 'record-message', self._sig_label) vbox.pack_start(self.screen.widget, expand=True, fill=True) self.title.set_mnemonic_widget( self.screen.current_view.mnemonic_widget) self.screen.widget.connect('key_press_event', self.on_keypress) self.wid_text.connect('key_press_event', self.on_keypress) def on_keypress(self, widget, event): editable = self.wid_text.get_editable() activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab] remove_keys = [gtk.keysyms.Delete, gtk.keysyms.KP_Delete] if not self.wid_completion: activate_keys.append(gtk.keysyms.Return) if widget == self.screen.widget: if event.keyval == gtk.keysyms.F3 and editable: self._sig_add() return True elif event.keyval == gtk.keysyms.F2: self._sig_edit() return True elif event.keyval in remove_keys and editable: self._sig_remove() return True elif widget == self.wid_text: if event.keyval == gtk.keysyms.F3: self._sig_new() return True elif event.keyval == gtk.keysyms.F2: self._sig_add() return True elif event.keyval in activate_keys and self.wid_text.get_text(): self._sig_add() self.wid_text.grab_focus() return False def destroy(self): self.wid_text.disconnect_by_func(self._focus_out) self.screen.destroy() def _sig_add(self, *args): if not self.focus_out: return domain = self.field.domain_get(self.record) add_remove = self.record.expr_eval(self.attrs.get('add_remove')) if add_remove: domain = [domain, add_remove] context = self.field.get_search_context(self.record) order = self.field.get_search_order(self.record) value = self.wid_text.get_text() self.focus_out = False def callback(result): self.focus_out = True if result: ids = [x[0] for x in result] self.screen.load(ids, modified=True) self.screen.display(res_id=ids[0]) self.screen.set_cursor() self.wid_text.set_text('') win = WinSearch(self.attrs['relation'], callback, sel_multi=True, context=context, domain=domain, order=order, view_ids=self.attrs.get('view_ids', '').split(','), views_preload=self.attrs.get('views', {}), new=self.attrs.get('create', True), title=self.attrs.get('string')) win.screen.search_filter(quote(value)) if len(win.screen.group) == 1: win.response(None, gtk.RESPONSE_OK) else: win.show() def _sig_remove(self, *args): self.screen.remove(remove=True) def _on_activate(self): self._sig_edit() def _get_screen_form(self): domain = self.field.domain_get(self.record) add_remove = self.record.expr_eval(self.attrs.get('add_remove')) if add_remove: domain = [domain, add_remove] context = self.field.get_context(self.record) # Remove the first tree view as mode is form only view_ids = self.attrs.get('view_ids', '').split(',')[1:] return Screen(self.attrs['relation'], domain=domain, view_ids=view_ids, mode=['form'], views_preload=self.attrs.get('views', {}), context=context) def _sig_edit(self): if not self.screen.current_record: return # Create a new screen that is not linked to the parent otherwise on the # save of the record will trigger the save of the parent screen = self._get_screen_form() screen.load([self.screen.current_record.id]) def callback(result): if result: screen.current_record.save() # Force a reload on next display self.screen.current_record.cancel() # Force a display to clear the CellCache self.screen.display() WinForm(screen, callback, title=self.attrs.get('string')) def _sig_new(self): screen = self._get_screen_form() def callback(result): self.focus_out = True if result: record = screen.current_record self.screen.load([record.id], modified=True) self.wid_text.set_text('') self.wid_text.grab_focus() self.focus_out = False WinForm(screen, callback, new=True, save_current=True, title=self.attrs.get('string'), rec_name=self.wid_text.get_text()) def _readonly_set(self, value): self._readonly = value self._set_button_sensitive() self.wid_text.set_sensitive(not value) self.wid_text.set_editable(not value) self._set_label_state() def _required_set(self, value): self._required = value self._set_label_state() def _set_label_state(self): common.apply_label_attributes( self.title, self._readonly, self._required) def _set_button_sensitive(self): if self.record and self.field: field_size = self.record.expr_eval(self.attrs.get('size')) m2m_size = len(self.field.get_eval(self.record)) size_limit = (field_size is not None and m2m_size >= field_size >= 0) else: size_limit = False self.but_add.set_sensitive(bool( not self._readonly and not size_limit)) self.but_remove.set_sensitive(bool( not self._readonly and self._position)) def _sig_label(self, screen, signal_data): self._position = signal_data[0] self._set_button_sensitive() def display(self, record, field): super(Many2Many, self).display(record, field) if field is None: self.screen.new_group() self.screen.current_record = None self.screen.parent = None self.screen.display() return False new_group = field.get_client(record) if id(self.screen.group) != id(new_group): self.screen.group = new_group self.screen.display() return True def set_value(self, record, field): self.screen.current_view.set_value() return True def _completion_match_selected(self, completion, model, iter_): record_id, = model.get(iter_, 1) self.screen.load([record_id], modified=True) self.wid_text.set_text('') self.wid_text.grab_focus() completion_model = self.wid_completion.get_model() completion_model.clear() completion_model.search_text = self.wid_text.get_text() return True def _update_completion(self, widget): if self._readonly: return if not self.record: return model = self.attrs['relation'] update_completion(self.wid_text, self.record, self.field, model) def _completion_action_activated(self, completion, index): if index == 0: self._sig_add() self.wid_text.grab_focus() elif index == 1: self._sig_new() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/one2one.py0000644000175000017500000000032313354423127024605 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .many2one import Many2One class One2One(Many2One): pass tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/timedelta.py0000644000175000017500000000335113463252532025215 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk from tryton.config import CONFIG from tryton.common.entry_position import reset_position from .widget import Widget class TimeDelta(Widget): def __init__(self, view, attrs): super(TimeDelta, self).__init__(view, attrs) self.widget = gtk.HBox() self.entry = self.mnemonic_widget = gtk.Entry() self.entry.set_alignment(1.0) self.entry.set_property('activates_default', True) self.entry.connect('activate', self.sig_activate) self.entry.connect('focus-out-event', lambda x, y: self._focus_out()) self.entry.connect('key-press-event', self.send_modified) self.widget.pack_start(self.entry) @property def modified(self): if self.record and self.field: value = self.entry.get_text() return self.field.get_client(self.record) != value return False def set_value(self, record, field): value = self.entry.get_text() return field.set_client(record, value) def get_value(self): return self.entry.get_text() def display(self, record, field): super(TimeDelta, self).display(record, field) if not field: value = '' else: value = field.get_client(record) self.entry.set_text(value) reset_position(self.entry) def _readonly_set(self, value): super(TimeDelta, self)._readonly_set(value) self.entry.set_editable(not value) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/state_widget.py0000644000175000017500000000722213463252532025731 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import tryton.common as common class StateMixin(object): def __init__(self, *args, **kwargs): self.attrs = kwargs.pop('attrs') super(StateMixin, self).__init__(*args, **kwargs) def state_set(self, record): if record: state_changes = record.expr_eval(self.attrs.get('states', {})) else: state_changes = {} if state_changes.get('invisible', self.attrs.get('invisible')): self.hide() else: self.show() class Label(StateMixin, gtk.Label): def state_set(self, record): super(Label, self).state_set(record) if 'name' in self.attrs and record: field = record.group.fields[self.attrs['name']] else: field = None if not self.attrs.get('string', True) and field: if record: text = field.get_client(record) or '' else: text = '' self.set_text(text) if record: state_changes = record.expr_eval(self.attrs.get('states', {})) else: state_changes = {} required = ((field and field.attrs.get('required')) or state_changes.get('required')) readonly = ((field and field.attrs.get('readonly')) or state_changes.get('readonly', not bool(field))) common.apply_label_attributes(self, readonly, required) class VBox(StateMixin, gtk.VBox): pass class Image(StateMixin, gtk.Image): def state_set(self, record): super(Image, self).state_set(record) if not record: return name = self.attrs['name'] if name in record.group.fields: field = record.group.fields[name] name = field.get(record) self.set_from_pixbuf(common.IconFactory.get_pixbuf( name, gtk.ICON_SIZE_DIALOG)) class Frame(StateMixin, gtk.Frame): def __init__(self, label=None, attrs=None): if not label: # label must be None to have no label widget label = None super(Frame, self).__init__(label=label, attrs=attrs) if not label: self.set_shadow_type(gtk.SHADOW_NONE) self.set_border_width(0) class ScrolledWindow(StateMixin, gtk.ScrolledWindow): def state_set(self, record): # Force to show first to ensure it is displayed in the Notebook self.show() super(ScrolledWindow, self).state_set(record) class Notebook(StateMixin, gtk.Notebook): def state_set(self, record): super(Notebook, self).state_set(record) if record: state_changes = record.expr_eval(self.attrs.get('states', {})) else: state_changes = {} if state_changes.get('readonly', self.attrs.get('readonly')): for widgets in self.widgets.values(): for widget in widgets: widget._readonly_set(True) class Alignment(gtk.Alignment): def __init__(self, widget, attrs): super(Alignment, self).__init__( float(attrs.get('xalign', 0.0)), float(attrs.get('yalign', 0.5)), float(attrs.get('xexpand', 1.0)), float(attrs.get('yexpand', 1.0))) self.add(widget) widget.connect('show', lambda *a: self.show()) widget.connect('hide', lambda *a: self.hide()) class Expander(StateMixin, gtk.Expander): def __init__(self, label=None, attrs=None): if not label: label = None super(Expander, self).__init__(label=label, attrs=attrs) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/image.py0000644000175000017500000000747113463252532024336 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import urllib.request from tryton.common import resize_pixbuf, data2pixbuf from tryton.config import CONFIG from .widget import Widget from .binary import BinaryMixin _ = gettext.gettext class Image(BinaryMixin, Widget): def __init__(self, view, attrs): super(Image, self).__init__(view, attrs) self.height = int(attrs.get('height', 100)) self.width = int(attrs.get('width', 300)) self.widget = gtk.VBox(spacing=3) self.event = gtk.EventBox() self.event.drag_dest_set(gtk.DEST_DEFAULT_ALL, [ gtk.TargetEntry.new('text/plain', 0, 0), gtk.TargetEntry.new('text/uri-list', 0, 1), gtk.TargetEntry.new("image/x-xpixmap", 0, 2)], gtk.gdk.ACTION_MOVE) self.event.connect('drag_motion', self.drag_motion) self.event.connect('drag_data_received', self.drag_data_received) self.image = gtk.Image() self.event.add(self.image) self.widget.pack_start(self.event, expand=True, fill=True) toolbar = self.toolbar() # Set button attributes even if not display if not attrs.get('readonly'): alignment = gtk.Alignment(xalign=0.5, yalign=0.5) alignment.add(toolbar) self.widget.pack_start(alignment, expand=False, fill=False) self._readonly = False self.update_img() @property def filters(self): filters = super(Image, self).filters filter_image = gtk.FileFilter() filter_image.set_name(_('Images')) for mime in ("image/png", "image/jpeg", "image/gif"): filter_image.add_mime_type(mime) for pat in ("*.png", "*.jpg", "*.gif", "*.tif", "*.xpm"): filter_image.add_pattern(pat) filters.insert(0, filter_image) return filters def _readonly_set(self, value): self._readonly = value self.but_select.set_sensitive(not value) self.but_clear.set_sensitive(not value) def clear(self, widget=None): super(Image, self).clear(widget=widget) self.update_img() def drag_motion(self, widget, context, x, y, timestamp): if self._readonly: return False context.drag_status(gtk.gdk.ACTION_COPY, timestamp) return True def drag_data_received(self, widget, context, x, y, selection, info, timestamp): if self._readonly: return if info == 0: uri = selection.get_text().split('\n')[0] if uri: self.field.set_client( self.record, urllib.request.urlopen(uri).read()) self.update_img() elif info == 1: uri = selection.data.split('\r\n')[0] if uri: self.field.set_client( self.record, urllib.request.urlopen(uri).read()) self.update_img() elif info == 2: data = selection.get_pixbuf() if data: self.field.set_client(self.record, data) self.update_img() def update_img(self): value = None if self.field: value = self.field.get_client(self.record) if isinstance(value, int): if value > CONFIG['image.max_size']: value = False else: value = self.field.get_data(self.record) pixbuf = data2pixbuf(value) if pixbuf: pixbuf = resize_pixbuf(pixbuf, self.width, self.height) self.image.set_from_pixbuf(pixbuf) return bool(value) def display(self, record, field): super(Image, self).display(record, field) value = self.update_img() self.update_buttons(bool(value)) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/reference.py0000644000175000017500000001217313463252532025205 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from .many2one import Many2One from tryton.common.selection import SelectionMixin, PopdownMixin, \ selection_shortcuts from tryton.config import CONFIG _ = gettext.gettext class Reference(Many2One, SelectionMixin, PopdownMixin): def __init__(self, view, attrs): super(Reference, self).__init__(view, attrs) self.widget_combo = gtk.ComboBoxEntry() child = self.widget_combo.get_child() child.connect('activate', lambda *a: self._focus_out()) child.connect('focus-out-event', lambda *a: self._focus_out()) child.get_accessible().set_name(attrs.get('string', '')) self.widget_combo.connect('changed', self.sig_changed_combo) self.widget_combo.connect('move-active', self._move_active) self.widget_combo.connect( 'scroll-event', lambda c, e: c.emit_stop_by_name('scroll-event')) selection_shortcuts(self.widget_combo) self.widget_combo.set_focus_chain([child]) self.widget.pack_start(self.widget_combo, expand=False, fill=True) self.widget.pack_start(gtk.Label('-'), expand=False, fill=False) self.init_selection() self.set_popdown(self.selection, self.widget_combo) self.widget.set_focus_chain([self.widget_combo, self.wid_text]) def get_model(self): active = self.widget_combo.get_active() if active < 0: return '' else: model = self.widget_combo.get_model() return model[active][1] def get_empty_value(self): for name, model in self.widget_combo.get_model(): if model in (None, ''): return model, name return '', '' def _move_active(self, combobox, scroll_type): if not combobox.get_child().get_editable(): combobox.emit_stop_by_name('move-active') def _set_button_sensitive(self): super(Reference, self)._set_button_sensitive() self.widget_combo.get_child().set_editable(not self._readonly) self.widget_combo.set_button_sensitivity( gtk.SENSITIVITY_OFF if self._readonly else gtk.SENSITIVITY_AUTO) if self._readonly and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() @property def modified(self): if self.record and self.field: try: model, name = self.field.get_client(self.record) except (ValueError, TypeError): model, name = self.get_empty_value() return (model != self.get_model() or name != self.wid_text.get_text()) return False def has_target(self, value): if value is None: return False model, value = value.split(',') if not value: value = None else: try: value = int(value) except ValueError: value = None result = model == self.get_model() and value >= 0 return result def value_from_id(self, id_, str_=None): if str_ is None: str_ = '' return self.get_model(), (id_, str_) @staticmethod def id_from_value(value): _, value = value.split(',') return int(value) def sig_changed_combo(self, *args): if not self.changed: return self.wid_text.set_text('') model = self.get_model() if model: value = (model, (-1, '')) else: value = ('', '') self.field.set_client(self.record, value) def set_value(self, record, field): if not self.get_model(): value = self.wid_text.get_text() if not value: field.set_client(record, None) else: field.set_client(record, ('', value)) return else: try: model, name = field.get_client(record) except (ValueError, TypeError): model, name = self.get_empty_value() if (model != self.get_model() or name != self.wid_text.get_text()): field.set_client(record, None) self.set_text(None) def set_text(self, value): if value: model, value = value else: model, value = None, None super(Reference, self).set_text(value) self.widget_combo.handler_block_by_func(self.sig_changed_combo) if not self.set_popdown_value(self.widget_combo, model): text = self.get_inactive_selection(model) self.set_popdown( self.selection[:] + [(model, text)], self.widget_combo) self.set_popdown_value(self.widget_combo, value) self.widget_combo.handler_unblock_by_func(self.sig_changed_combo) def display(self, record, field): self.update_selection(record, field) self.set_popdown(self.selection, self.widget_combo) super(Reference, self).display(record, field) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/dictionary.py0000644000175000017500000004411213463252532025412 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of this # repository contains the full copyright notices and license terms. import operator import gobject import gtk import locale import decimal import gettext from decimal import Decimal from .widget import Widget from tryton.gui.window.win_search import WinSearch from tryton.common import Tooltips, timezoned_date, untimezoned_date, \ IconFactory from tryton.common.selection import selection_shortcuts from tryton.common.completion import get_completion, update_completion from tryton.common.datetime_ import Date, DateTime from tryton.common.domain_parser import quote from tryton.common.entry_position import reset_position from tryton.common.underline import set_underline from tryton.common.domain_inversion import eval_domain from tryton.common.widget_style import widget_class from tryton.pyson import PYSONDecoder _ = gettext.gettext class DictEntry(object): expand = True fill = True def __init__(self, name, parent_widget): self.name = name self.definition = parent_widget.field.keys[name] self.parent_widget = parent_widget self.widget = self.create_widget() def create_widget(self): widget = gtk.Entry() widget.connect('key-press-event', self.parent_widget.send_modified) widget.connect('focus-out-event', lambda w, e: self.parent_widget._focus_out()) widget.props.activates_default = True widget.connect('activate', self.parent_widget.sig_activate) return widget def modified(self, value): return self.get_value() != value.get(self.name) def get_value(self): return self.widget.get_text() def set_value(self, value): self.widget.set_text(value or '') reset_position(self.widget) def set_readonly(self, readonly): self.widget.set_editable(not readonly) class DictBooleanEntry(DictEntry): def create_widget(self): widget = gtk.CheckButton() widget.connect('toggled', self.parent_widget.sig_activate) widget.connect('focus-out-event', lambda w, e: self.parent_widget._focus_out()) return widget def get_value(self): return self.widget.props.active def set_value(self, value): self.widget.handler_block_by_func(self.parent_widget.sig_activate) try: self.widget.props.active = bool(value) finally: self.widget.handler_unblock_by_func( self.parent_widget.sig_activate) def set_readonly(self, readonly): self.widget.set_sensitive(not readonly) class DictSelectionEntry(DictEntry): expand = False fill = False def create_widget(self): widget = gtk.ComboBoxEntry() # customizing entry child = widget.get_child() child.props.activates_default = True child.connect('changed', self.parent_widget.send_modified) child.connect('focus-out-event', lambda w, e: self.parent_widget._focus_out()) child.connect('activate', lambda w: self.parent_widget._focus_out()) widget.connect('notify::active', lambda w, e: self.parent_widget._focus_out()) widget.connect( 'scroll-event', lambda c, e: c.emit_stop_by_name('scroll-event')) selection_shortcuts(widget) # setting completion and selection model = gtk.ListStore(gobject.TYPE_STRING) model.append(('',)) self._selection = {'': None} width = 10 selection = self.definition['selection'] if self.definition.get('sorted', True): selection.sort(key=operator.itemgetter(1)) for value, name in selection: name = str(name) self._selection[name] = value model.append((name,)) width = max(width, len(name)) widget.set_model(model) widget.set_text_column(0) child.set_width_chars(width) completion = gtk.EntryCompletion() completion.set_inline_selection(True) completion.set_model(model) child.set_completion(completion) completion.set_text_column(0) return widget def get_value(self): child = self.widget.get_child() if not child: # widget is destroyed return text = child.get_text() value = None if text: for txt, val in list(self._selection.items()): if not val: continue if txt[:len(text)].lower() == text.lower(): value = val if len(txt) == len(text): break return value def set_value(self, value): values = dict(self.definition['selection']) child = self.widget.get_child() child.set_text(values.get(value, '')) reset_position(child) def set_readonly(self, readonly): self.widget.set_sensitive(not readonly) class DictIntegerEntry(DictEntry): expand = False fill = False def create_widget(self): widget = super(DictIntegerEntry, self).create_widget() widget.set_width_chars(8) widget.set_max_length(0) widget.set_alignment(1.0) widget.connect('insert-text', self.sig_insert_text) return widget def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] if new_value == '-': return try: locale.atoi(new_value) except ValueError: entry.stop_emission('insert-text') def get_value(self): txt_value = self.widget.get_text() if txt_value: try: return locale.atoi(txt_value) except ValueError: pass return None def set_value(self, value): if value is not None: txt_val = locale.format('%d', value, True) else: txt_val = '' self.widget.set_text(txt_val) reset_position(self.widget) class DictFloatEntry(DictIntegerEntry): def digits(self): default = (16, 2) record = self.parent_widget.record if not record: return default return tuple(y if x is None else x for x, y in zip( record.expr_eval(self.definition.get('digits', default)), default)) def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] decimal_point = locale.localeconv()['decimal_point'] if new_value in ('-', decimal_point): return digits = self.digits() try: locale.atof(new_value) except ValueError: entry.stop_emission('insert-text') return new_int = new_value new_decimal = '' if decimal_point in new_value: new_int, new_decimal = new_value.rsplit(decimal_point, 1) if (len(new_int) > digits[0] or len(new_decimal) > digits[1]): entry.stop_emission('insert-text') def get_value(self): txt_value = self.widget.get_text() if txt_value: try: return locale.atof(txt_value) except ValueError: pass return None def set_value(self, value): digits = self.digits() if value is not None: txt_val = locale.format('%.' + str(digits[1]) + 'f', value, True) else: txt_val = '' self.widget.set_width_chars(sum(digits)) self.widget.set_text(txt_val) reset_position(self.widget) class DictNumericEntry(DictFloatEntry): def get_value(self): txt_value = self.widget.get_text() if txt_value: try: return locale.atof(txt_value, Decimal) except decimal.InvalidOperation: pass return None class DictDateTimeEntry(DictEntry): expand = False fill = False def create_widget(self): widget = DateTime() record = self.parent_widget.record field = self.parent_widget.field if record and field: format_ = field.time_format(record) widget.props.format = format_ widget.connect('key_press_event', self.parent_widget.send_modified) widget.connect('focus-out-event', lambda w, e: self.parent_widget._focus_out()) return widget def get_value(self): return untimezoned_date(self.widget.props.value) def set_value(self, value): self.widget.props.value = timezoned_date(value) class DictDateEntry(DictEntry): expand = False fill = False def create_widget(self): widget = Date() record = self.parent_widget.record field = self.parent_widget.field if record and field: format_ = field.date_format(record) widget.props.format = format_ widget.connect('key_press_event', self.parent_widget.send_modified) widget.connect('focus-out-event', lambda w, e: self.parent_widget._focus_out()) return widget def get_value(self): return self.widget.props.value def set_value(self, value): self.widget.props.value = value DICT_ENTRIES = { 'char': DictEntry, 'boolean': DictBooleanEntry, 'selection': DictSelectionEntry, 'datetime': DictDateTimeEntry, 'date': DictDateEntry, 'integer': DictIntegerEntry, 'float': DictFloatEntry, 'numeric': DictNumericEntry, } class DictWidget(Widget): def __init__(self, view, attrs): super(DictWidget, self).__init__(view, attrs) self.schema_model = attrs['schema_model'] self.fields = {} self.buttons = {} self.rows = {} self.widget = gtk.Frame() label = gtk.Label(set_underline(attrs.get('string', ''))) label.set_use_underline(True) self.widget.set_label_widget(label) self.widget.set_shadow_type(gtk.SHADOW_OUT) vbox = gtk.VBox() self.widget.add(vbox) self.table = gtk.Table(1, 3, homogeneous=False) self.table.set_col_spacings(0) self.table.set_row_spacings(0) self.table.set_border_width(0) vbox.pack_start(self.table, expand=True, fill=True) hbox = gtk.HBox() hbox.set_border_width(2) self.wid_text = gtk.Entry() self.wid_text.set_placeholder_text(_('Search')) self.wid_text.props.width_chars = 13 self.wid_text.connect('activate', self._sig_activate) hbox.pack_start(self.wid_text, expand=True, fill=True) label.set_mnemonic_widget(self.wid_text) if int(self.attrs.get('completion', 1)): self.wid_completion = get_completion(search=False, create=False) self.wid_completion.connect('match-selected', self._completion_match_selected) self.wid_text.set_completion(self.wid_completion) self.wid_text.connect('changed', self._update_completion) else: self.wid_completion = None self.but_add = gtk.Button() self.but_add.connect('clicked', self._sig_add) self.but_add.add(IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_add.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_add, expand=False, fill=False) hbox.set_focus_chain([self.wid_text]) vbox.pack_start(hbox, expand=True, fill=True) self.tooltips = Tooltips() self.tooltips.set_tip(self.but_add, _('Add value')) self.tooltips.enable() self._readonly = False self._record_id = None @property def _invalid_widget(self): return self.wid_text def _new_remove_btn(self): but_remove = gtk.Button() but_remove.add(IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_remove.set_relief(gtk.RELIEF_NONE) return but_remove def _sig_activate(self, *args): if self.wid_text.get_editable(): self._sig_add() def _sig_add(self, *args): context = self.field.get_context(self.record) value = self.wid_text.get_text() domain = self.field.domain_get(self.record) def callback(result): if result: self.add_new_keys([r[0] for r in result]) self.wid_text.set_text('') win = WinSearch(self.schema_model, callback, sel_multi=True, context=context, domain=domain, new=False) win.screen.search_filter(quote(value)) win.show() def add_new_keys(self, ids): new_keys = self.field.add_new_keys(ids, self.record) self.send_modified() focus = False for key_name in new_keys: if key_name not in self.fields: self.add_line(key_name) if not focus: # Use idle add because it can be called from the callback # of WinSearch while the popup is still there gobject.idle_add(self.fields[key_name].widget.grab_focus) focus = True def _sig_remove(self, button, key, modified=True): del self.fields[key] del self.buttons[key] for widget in self.rows[key]: self.table.remove(widget) widget.destroy() del self.rows[key] if modified: self.send_modified() self.set_value(self.record, self.field) def set_value(self, record, field): field.set_client(record, self.get_value()) def get_value(self): return dict((key, widget.get_value()) for key, widget in list(self.fields.items())) @property def modified(self): if self.record and self.field: value = self.field.get_client(self.record) return any(widget.modified(value) for widget in self.fields.values()) return False def _readonly_set(self, readonly): self._readonly = readonly self._set_button_sensitive() for widget in list(self.fields.values()): widget.set_readonly(readonly) self.wid_text.set_sensitive(not readonly) self.wid_text.set_editable(not readonly) def _set_button_sensitive(self): self.but_add.set_sensitive(bool( not self._readonly and self.attrs.get('create', True))) for button in self.buttons.values(): button.set_sensitive(bool( not self._readonly and self.attrs.get('delete', True))) def add_line(self, key): key_schema = self.field.keys[key] self.fields[key] = DICT_ENTRIES[key_schema['type_']](key, self) field = self.fields[key] alignment = gtk.Alignment( float(self.attrs.get('xalign', 0.0)), float(self.attrs.get('yalign', 0.5)), float(self.attrs.get('xexpand', 1.0)), float(self.attrs.get('yexpand', 1.0))) hbox = gtk.HBox() hbox.pack_start(field.widget, expand=field.expand, fill=field.fill) alignment.add(hbox) n_rows = self.table.props.n_rows self.table.resize(n_rows + 1, 3) text = key_schema['string'] + _(':') label = gtk.Label(set_underline(text)) label.set_use_underline(True) label.set_alignment(1., .5) self.table.attach(label, 0, 1, n_rows - 1, n_rows, xoptions=gtk.FILL, yoptions=False, xpadding=2) label.set_mnemonic_widget(field.widget) label.show() self.table.attach(alignment, 1, 2, n_rows - 1, n_rows, xoptions=gtk.FILL | gtk.EXPAND, yoptions=False, xpadding=2) alignment.show_all() remove_but = self._new_remove_btn() self.tooltips.set_tip(remove_but, _('Remove "%s"') % key_schema['string']) self.table.attach(remove_but, 2, 3, n_rows - 1, n_rows, xoptions=gtk.FILL, yoptions=False, xpadding=2) remove_but.connect('clicked', self._sig_remove, key) remove_but.show_all() self.rows[key] = [label, alignment, remove_but] self.buttons[key] = remove_but def display(self, record, field): super(DictWidget, self).display(record, field) if field is None: return record_id = record.id if record else None if record_id != self._record_id: for key in list(self.fields.keys()): self._sig_remove(None, key, modified=False) self._record_id = record_id value = field.get_client(record) if field else {} new_key_names = set(value.keys()) - set(field.keys) if new_key_names: field.add_keys(list(new_key_names), self.record) decoder = PYSONDecoder() for key, val in sorted(value.items()): if key not in field.keys: continue if key not in self.fields: self.add_line(key) widget = self.fields[key] widget.set_value(val) widget.set_readonly(self._readonly) key_domain = decoder.decode( self.field.keys[key].get('domain') or '[]') widget_class( widget.widget, 'invalid', not eval_domain(key_domain, value)) for key in set(self.fields.keys()) - set(value.keys()): self._sig_remove(None, key, modified=False) self._set_button_sensitive() def _completion_match_selected(self, completion, model, iter_): record_id, = model.get(iter_, 1) self.add_new_keys([record_id]) self.wid_text.set_text('') completion_model = self.wid_completion.get_model() completion_model.clear() completion_model.search_text = self.wid_text.get_text() return True def _update_completion(self, widget): if not self.wid_text.get_editable(): return if not self.record: return update_completion(self.wid_text, self.record, self.field, self.schema_model) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/multiselection.py0000644000175000017500000000721413463252532026307 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of this # repository contains the full copyright notices and license terms. import gtk import gobject from .widget import Widget from tryton.common.selection import SelectionMixin from tryton.common.treeviewcontrol import TreeViewControl class MultiSelection(Widget, SelectionMixin): expand = True def __init__(self, view, attrs): super(MultiSelection, self).__init__(view, attrs) if int(attrs.get('yexpand', self.expand)): self.widget = gtk.ScrolledWindow() self.widget.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.widget.set_shadow_type(gtk.SHADOW_ETCHED_IN) else: self.widget = gtk.VBox() self.widget.get_accessible().set_name(attrs.get('string', '')) self.model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING) self.tree = self.mnemonic_widget = TreeViewControl() self.tree.set_model(self.model) self.tree.set_search_column(1) self.tree.connect('focus-out-event', lambda *a: self._focus_out()) self.tree.set_headers_visible(False) selection = self.tree.get_selection() selection.set_mode(gtk.SELECTION_MULTIPLE) selection.connect('changed', self.changed) self.widget.add(self.tree) name_column = gtk.TreeViewColumn() name_cell = gtk.CellRendererText() name_column.pack_start(name_cell) name_column.add_attribute(name_cell, 'text', 1) self.tree.append_column(name_column) self.nullable_widget = False self.init_selection() self.id2path = {} def _readonly_set(self, readonly): super(MultiSelection, self)._readonly_set(readonly) selection = self.tree.get_selection() selection.set_select_function(lambda *a: not readonly) @property def modified(self): if self.record and self.field: group = set(r.id for r in self.field.get_client(self.record)) value = set(self.get_value()) return value != group return False def changed(self, selection): def focus_out(): if self.widget.props.window: self._focus_out() # Must be deferred because it triggers a display of the form gobject.idle_add(focus_out) def get_value(self): model, paths = self.tree.get_selection().get_selected_rows() return [model[path][0] for path in paths] def set_value(self, record, field): field.set_client(record, self.get_value()) def display(self, record, field): selection = self.tree.get_selection() selection.handler_block_by_func(self.changed) try: # Remove select_function to allow update, # it will be set back in the super call selection.set_select_function(lambda *a: True) self.update_selection(record, field) self.model.clear() if field is None: return id2path = {} for idx, (value, name) in enumerate(self.selection): self.model.append((value, name)) id2path[value] = idx selection.unselect_all() group = field.get_client(record) for element in group: if (element not in group.record_removed and element not in group.record_deleted and element.id in id2path): selection.select_path(id2path[element.id]) super(MultiSelection, self).display(record, field) finally: selection.handler_unblock_by_func(self.changed) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/integer.py0000644000175000017500000000263713367164774024725 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .char import Char import locale class Integer(Char): "Integer" def __init__(self, view, attrs): super(Integer, self).__init__(view, attrs) self.entry.set_width_chars(8) _, _, padding, pack_type = self.widget.query_child_packing( self.entry) self.widget.set_child_packing(self.entry, False, False, padding, pack_type) self.entry.set_max_length(0) self.entry.set_alignment(1.0) self.entry.connect('insert_text', self.sig_insert_text) self.factor = float(attrs.get('factor', 1)) def set_value(self, record, field): return field.set_client(record, self.entry.get_text(), factor=self.factor) def get_client_value(self, record, field): if not field: value = '' else: value = field.get_client(record, factor=self.factor) return value def sig_insert_text(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] if new_value == '-': return try: locale.atoi(new_value) except ValueError: entry.stop_emission('insert-text') tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/many2one.py0000644000175000017500000003327513463252532025005 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gobject import gettext from .widget import Widget import tryton.common as common from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_search import WinSearch from tryton.gui.window.win_form import WinForm from tryton.common.popup_menu import populate from tryton.common.completion import get_completion, update_completion from tryton.common.entry_position import reset_position from tryton.common.domain_parser import quote from tryton.config import CONFIG _ = gettext.gettext class Many2One(Widget): def __init__(self, view, attrs): super(Many2One, self).__init__(view, attrs) self.widget = gtk.HBox(spacing=0) self.widget.set_property('sensitive', True) self.wid_text = self.mnemonic_widget = gtk.Entry() self.wid_text.set_property('width-chars', 13) self.wid_text.set_property('activates_default', True) self.wid_text.connect('key-press-event', self.send_modified) self.wid_text.connect('key_press_event', self.sig_key_press) self.wid_text.connect('populate-popup', self._populate_popup) self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out()) self.wid_text.connect('changed', self.sig_changed) self.changed = True self.focus_out = True if int(self.attrs.get('completion', 1)): self.wid_text.connect('changed', self._update_completion) self.wid_completion = None self.wid_text.connect('icon-press', self.sig_edit) self.widget.pack_end(self.wid_text, expand=True, fill=True) self._readonly = False def get_model(self): return self.attrs['relation'] def _readonly_set(self, value): self._readonly = value self._set_button_sensitive() if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() def _set_button_sensitive(self): self.wid_text.set_editable(not self._readonly) self.wid_text.set_icon_sensitive( gtk.ENTRY_ICON_PRIMARY, self.read_access) self.wid_text.set_icon_sensitive( gtk.ENTRY_ICON_SECONDARY, not self._readonly) def get_access(self, type_): model = self.get_model() if model: return common.MODELACCESS[model][type_] else: return True @property def read_access(self): return self.get_access('read') @property def create_access(self): return self.attrs.get('create', True) and self.get_access('create') @property def modified(self): if self.record and self.field: value = self.wid_text.get_text() return self.field.get_client(self.record) != value return False @staticmethod def has_target(value): return value is not None @staticmethod def value_from_id(id_, str_=None): if str_ is None: str_ = '' return id_, str_ @staticmethod def id_from_value(value): return value def sig_activate(self): model = self.get_model() if not model or not common.MODELACCESS[model]['read']: return if not self.focus_out or not self.field: return self.changed = False value = self.field.get(self.record) model = self.get_model() self.focus_out = False if model and not self.has_target(value): if (not self._readonly and (self.wid_text.get_text() or self.field.get_state_attrs( self.record)['required'])): domain = self.field.domain_get(self.record) context = self.field.get_search_context(self.record) order = self.field.get_search_order(self.record) text = self.wid_text.get_text() def callback(result): if result: self.field.set_client(self.record, self.value_from_id(*result[0]), force_change=True) else: self.wid_text.set_text('') self.focus_out = True self.changed = True win = WinSearch(model, callback, sel_multi=False, context=context, domain=domain, order=order, view_ids=self.attrs.get('view_ids', '').split(','), views_preload=self.attrs.get('views', {}), new=self.create_access, title=self.attrs.get('string')) win.screen.search_filter(quote(text)) if len(win.screen.group) == 1: win.response(None, gtk.RESPONSE_OK) else: win.show() return self.focus_out = True self.changed = True return def get_screen(self): domain = self.field.domain_get(self.record) context = self.field.get_context(self.record) # Remove first tree view as mode is form only view_ids = self.attrs.get('view_ids', '').split(',')[1:] return Screen(self.get_model(), domain=domain, context=context, mode=['form'], view_ids=view_ids, views_preload=self.attrs.get('views', {}), readonly=self._readonly, exclude_field=self.attrs.get('relation_field')) def sig_new(self, *args): model = self.get_model() if not model or not common.MODELACCESS[model]['create']: return self.focus_out = False screen = self.get_screen() def callback(result): if result: self.field.set_client(self.record, self.value_from_id(screen.current_record.id, screen.current_record.rec_name())) self.focus_out = True WinForm(screen, callback, new=True, save_current=True, title=self.attrs.get('string'), rec_name=self.wid_text.get_text()) def sig_edit(self, entry=None, icon_pos=None, *args): model = self.get_model() if not model or not common.MODELACCESS[model]['read']: return if not self.focus_out or not self.field: return self.changed = False self.focus_out = False value = self.field.get(self.record) if (icon_pos == gtk.ENTRY_ICON_SECONDARY and not self._readonly and self.has_target(value)): self.field.set_client(self.record, self.value_from_id(None, '')) self.wid_text.set_text('') self.changed = True self.focus_out = True return if self.has_target(value): screen = self.get_screen() screen.load([self.id_from_value(self.field.get(self.record))]) def callback(result): if result: self.field.set_client(self.record, self.value_from_id(screen.current_record.id, screen.current_record.rec_name()), force_change=True) self.focus_out = True self.changed = True WinForm(screen, callback, save_current=True, title=self.attrs.get('string')) return if not self._readonly: domain = self.field.domain_get(self.record) context = self.field.get_search_context(self.record) order = self.field.get_search_order(self.record) text = self.wid_text.get_text() def callback(result): if result: self.field.set_client(self.record, self.value_from_id(*result[0]), force_change=True) self.focus_out = True self.changed = True win = WinSearch(model, callback, sel_multi=False, context=context, domain=domain, order=order, view_ids=self.attrs.get('view_ids', '').split(','), views_preload=self.attrs.get('views', {}), new=self.create_access, title=self.attrs.get('string')) win.screen.search_filter(quote(text)) win.show() return self.focus_out = True self.changed = True def sig_key_press(self, widget, event, *args): editable = self.wid_text.get_editable() activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab] if not self.wid_completion: activate_keys.append(gtk.keysyms.Return) if (event.keyval == gtk.keysyms.F3 and editable and self.create_access): self.sig_new(widget, event) return True elif event.keyval == gtk.keysyms.F2 and self.read_access: self.sig_edit(widget) return True elif (event.keyval in activate_keys and editable): self.sig_activate() elif (self.has_target(self.field.get(self.record)) and editable and event.keyval in (gtk.keysyms.Delete, gtk.keysyms.BackSpace)): self.wid_text.set_text('') return False def sig_changed(self, *args): if not self.changed: return False value = self.field.get(self.record) if self.has_target(value) and self.modified: def clean(): if not self.wid_text.props.window: return text = self.wid_text.get_text() position = self.wid_text.get_position() self.field.set_client(self.record, self.value_from_id(None, '')) # The value of the field could be different of None # in such case, the original text should not be restored if not self.wid_text.get_text(): # Restore text and position after display self.wid_text.set_text(text) self.wid_text.set_position(position) gobject.idle_add(clean) return False def get_value(self): return self.wid_text.get_text() def set_value(self, record, field): if field.get_client(record) != self.wid_text.get_text(): field.set_client(record, self.value_from_id(None, '')) self.wid_text.set_text('') def set_text(self, value): if not value: value = '' self.wid_text.set_text(value) reset_position(self.wid_text) def display(self, record, field): self.changed = False super(Many2One, self).display(record, field) self._set_button_sensitive() self._set_completion() if not field: self.set_text(None) self.changed = True return False self.set_text(field.get_client(record)) if self.has_target(field.get(record)): icon1, tooltip1 = 'tryton-open', _('Open the record ') icon2, tooltip2 = 'tryton-clear', _('Clear the field ') else: icon1, tooltip1 = None, '' icon2, tooltip2 = 'tryton-search', _('Search a record ') if not self.wid_text.get_editable(): icon2, tooltip2 = None, '' for pos, icon, tooltip in [ (gtk.ENTRY_ICON_PRIMARY, icon1, tooltip1), (gtk.ENTRY_ICON_SECONDARY, icon2, tooltip2)]: if icon: pixbuf = common.IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_MENU) else: pixbuf = None self.wid_text.set_icon_from_pixbuf(pos, pixbuf) self.wid_text.set_icon_tooltip_text(pos, tooltip) self.changed = True def _populate_popup(self, widget, menu): value = self.field.get(self.record) if self.has_target(value): # Delay filling of popup as it can take time gobject.idle_add(populate, menu, self.get_model(), self.id_from_value(value), '', self.field) return True def _set_completion(self): if not int(self.attrs.get('completion', 1)): return self.wid_completion = get_completion( search=self.read_access, create=self.create_access) self.wid_completion.connect('match-selected', self._completion_match_selected) self.wid_completion.connect('action-activated', self._completion_action_activated) self.wid_text.set_completion(self.wid_completion) def _completion_match_selected(self, completion, model, iter_): rec_name, record_id = model.get(iter_, 0, 1) # GTK on win32 doesn't like synchronous call to set_client # because it triggers a display which reset the completion gobject.idle_add(self.field.set_client, self.record, self.value_from_id(record_id, rec_name), True) completion_model = self.wid_completion.get_model() completion_model.clear() completion_model.search_text = rec_name return True def _update_completion(self, widget): if self._readonly: return if not self.record: return value = self.field.get(self.record) if self.has_target(value): id_ = self.id_from_value(value) if id_ is not None and id_ >= 0: return model = self.get_model() update_completion(self.wid_text, self.record, self.field, model) def _completion_action_activated(self, completion, index): if index == 0: self.sig_edit() elif index == 1: self.sig_new() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/progressbar.py0000644000175000017500000000240413354423127025573 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from .widget import Widget _ = gettext.gettext class ProgressBar(Widget): 'Progress Bar' orientations = { 'left_to_right': gtk.PROGRESS_LEFT_TO_RIGHT, 'right_to_left': gtk.PROGRESS_RIGHT_TO_LEFT, 'bottom_to_top': gtk.PROGRESS_BOTTOM_TO_TOP, 'top_to_bottom': gtk.PROGRESS_TOP_TO_BOTTOM, } def __init__(self, view, attrs): super(ProgressBar, self).__init__(view, attrs) self.widget = self.mnemonic_widget = gtk.ProgressBar() orientation = self.orientations.get(attrs.get('orientation', 'left_to_right'), gtk.PROGRESS_LEFT_TO_RIGHT) self.widget.set_orientation(orientation) def display(self, record, field): super(ProgressBar, self).display(record, field) if not field: self.widget.set_text('') self.widget.set_fraction(0.0) return False text = field.get_client(record, factor=100) if text: text = _('%s%%') % text self.widget.set_text(text) value = field.get(record) or 0.0 self.widget.set_fraction(value) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/pyson.py0000644000175000017500000000336513463252532024422 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from gi.repository import Gtk from .char import Char from tryton.common import IconFactory from tryton.pyson import CONTEXT, PYSONEncoder, PYSONDecoder class PYSON(Char): def __init__(self, view, attrs): super(PYSON, self).__init__(view, attrs) self.encoder = PYSONEncoder() self.decoder = PYSONDecoder(noeval=True) self.entry.connect('key-release-event', self.validate_pyson) def get_encoded_value(self): value = self.get_value() if not value: return value try: return self.encoder.encode(eval(value, CONTEXT)) except Exception: return None def set_value(self, record, field): # avoid modification because different encoding value = self.get_encoded_value() previous = field.get_client(record) if (previous and value == self.encoder.encode( self.decoder.decode(previous))): value = previous field.set_client(record, value) def get_client_value(self, record, field): value = super(PYSON, self).get_client_value(record, field) if value: value = repr(self.decoder.decode(value)) return value def validate_pyson(self, *args): icon = 'tryton-ok' if self.get_encoded_value() is None: icon = 'tryton-error' pixbuf = IconFactory.get_pixbuf(icon, Gtk.IconSize.MENU) self.entry.set_icon_from_pixbuf( Gtk.EntryIconPosition.SECONDARY, pixbuf) def _focus_out(self): self.validate_pyson() super(PYSON, self)._focus_out() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/url.py0000644000175000017500000000672613463252532024060 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk from .char import Char import webbrowser import tryton.common as common from tryton.config import CONFIG class URL(Char): "url" def __init__(self, view, attrs): super(URL, self).__init__(view, attrs) self.tooltips = common.Tooltips() self.button = gtk.Button() self.button.set_image(common.IconFactory.get_image( 'tryton-public', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.button.set_relief(gtk.RELIEF_NONE) self.button.connect('clicked', self.button_clicked) self.button.set_alignment(0.5, 0.5) self.widget.pack_start(self.button, expand=False, fill=False) self.widget.set_focus_chain([self.entry]) def display(self, record, field): super(URL, self).display(record, field) self.set_tooltips() if record and 'icon' in self.attrs: icon = self.attrs['icon'] if icon in record.group.fields: value = record[icon].get_client(record) or 'tryton-public' else: value = icon self.button.set_image(common.IconFactory.get_image( value, gtk.ICON_SIZE_SMALL_TOOLBAR)) def set_tooltips(self): value = self.entry.get_text() if value: self.tooltips.enable() self.tooltips.set_tip(self.button, value) else: self.tooltips.set_tip(self.button, '') self.tooltips.disable() def _readonly_set(self, value): super(URL, self)._readonly_set(value) if value: self.entry.hide() else: self.entry.show() if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([self.button]) else: self.widget.set_focus_chain([self.entry]) self.button.set_sensitive(True) def button_clicked(self, widget): value = self.entry.get_text() if value: webbrowser.open(value, new=2) class Email(URL): "email" def button_clicked(self, widget): value = self.entry.get_text() if value: webbrowser.open('mailto:%s' % value, new=2) def set_tooltips(self): value = self.entry.get_text() if value: self.tooltips.enable() self.tooltips.set_tip(self.button, 'mailto:%s' % value) else: self.tooltips.set_tip(self.button, '') self.tooltips.disable() class CallTo(URL): "call to" def button_clicked(self, widget): value = self.entry.get_text() if value: webbrowser.open('callto:%s' % value, new=2) def set_tooltips(self): value = self.entry.get_text() if value: self.tooltips.enable() self.tooltips.set_tip(self.button, 'callto:%s' % value) else: self.tooltips.set_tip(self.button, '') self.tooltips.disable() class SIP(URL): "sip" def button_clicked(self, widget): value = self.entry.get_text() if value: webbrowser.open('sip:%s' % value, new=2) def set_tooltips(self): value = self.entry.get_text() if value: self.tooltips.enable() self.tooltips.set_tip(self.button, 'sip:%s' % value) else: self.tooltips.set_tip(self.button, '') self.tooltips.disable() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/__init__.py0000644000175000017500000000022013354423127024773 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/char.py0000644000175000017500000001511513463252532024163 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext import gobject import gtk from .widget import Widget, TranslateMixin from tryton.common import Tooltips, IconFactory from tryton.common.entry_position import reset_position from tryton.common.selection import PopdownMixin, selection_shortcuts from tryton.config import CONFIG _ = gettext.gettext class Char(Widget, TranslateMixin, PopdownMixin): "Char" def __init__(self, view, attrs): super(Char, self).__init__(view, attrs) self.widget = gtk.HBox() self.autocomplete = bool(attrs.get('autocomplete')) if self.autocomplete: self.entry = gtk.ComboBoxEntry() selection_shortcuts(self.entry) focus_entry = self.entry.get_child() self.set_popdown([], self.entry) self.entry.connect('changed', self.changed) self.entry.connect('move-active', self._move_active) self.entry.connect( 'scroll-event', lambda c, e: c.emit_stop_by_name('scroll-event')) else: self.entry = gtk.Entry() focus_entry = self.entry self.mnemonic_widget = focus_entry focus_entry.set_property('activates_default', True) focus_entry.connect('activate', self.sig_activate) focus_entry.connect('focus-out-event', lambda x, y: self._focus_out()) focus_entry.connect('key-press-event', self.send_modified) expand, fill = True, True if attrs.get('size'): expand, fill = False, False self.widget.pack_start(self.entry, expand=expand, fill=fill) if attrs.get('translate'): self.entry.set_icon_from_pixbuf( gtk.ENTRY_ICON_SECONDARY, IconFactory.get_pixbuf('tryton-translate', gtk.ICON_SIZE_MENU)) self.entry.connect('icon-press', self.translate) def translate_widget(self): entry = gtk.Entry() entry.set_property('activates_default', True) if self.record: field_size = self.record.expr_eval(self.attrs.get('size')) entry.set_width_chars(field_size or -1) entry.set_max_length(field_size or 0) return entry def translate_widget_set(self, widget, value): widget.set_text(value) reset_position(widget) def translate_widget_get(self, widget): return widget.get_text() def translate_widget_set_readonly(self, widget, value): widget.set_editable(not value) widget.props.sensitive = not value def changed(self, combobox): def focus_out(): if combobox.props.window: self._focus_out() # Only when changed from pop list if not combobox.get_child().has_focus(): # Must be deferred because it triggers a display of the form gobject.idle_add(focus_out) @property def modified(self): if self.record and self.field: value = self.get_client_value(self.record, self.field) return value != self.get_value() return False def set_value(self, record, field): entry = self.entry.get_child() if self.autocomplete else self.entry value = entry.get_text() or '' return field.set_client(record, value) def get_value(self): entry = self.entry.get_child() if self.autocomplete else self.entry return entry.get_text() def get_client_value(self, record, field): if not field: value = '' else: value = field.get_client(record) return value def display(self, record, field): super(Char, self).display(record, field) if self.autocomplete: if record: if self.field_name not in record.autocompletion: record.do_autocomplete(self.field_name) selection = record.autocompletion.get(self.field_name, []) else: selection = [] self.set_popdown([(x, x) for x in selection], self.entry) # Set size if self.autocomplete: size_entry = self.entry.get_child() else: size_entry = self.entry if record: field_size = record.expr_eval(self.attrs.get('size')) size_entry.set_width_chars(field_size or -1) size_entry.set_max_length(field_size or 0) else: size_entry.set_width_chars(-1) size_entry.set_max_length(0) value = self.get_client_value(record, field) if not self.autocomplete: self.entry.set_text(value) reset_position(self.entry) else: self.entry.handler_block_by_func(self.changed) if not self.set_popdown_value(self.entry, value) or not value: child = self.entry.get_child() child.set_text(value) reset_position(child) self.entry.handler_unblock_by_func(self.changed) def _move_active(self, combobox, scroll_type): if not combobox.get_child().get_editable(): combobox.emit_stop_by_name('move-active') def _readonly_set(self, value): sensitivity = {True: gtk.SENSITIVITY_OFF, False: gtk.SENSITIVITY_AUTO} super(Char, self)._readonly_set(value) if self.autocomplete: entry_editable = self.entry.get_child() self.entry.set_button_sensitivity(sensitivity[value]) else: entry_editable = self.entry entry_editable.set_editable(not value) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() class Password(Char): def __init__(self, view, attrs): super(Password, self).__init__(view, attrs) self.entry.props.visibility = False self.visibility_checkbox = gtk.CheckButton() self.visibility_checkbox.connect('toggled', self.toggle_visibility) Tooltips().set_tip(self.visibility_checkbox, _('Show plain text')) self.widget.pack_start(self.visibility_checkbox, expand=False) def _readonly_set(self, value): super(Char, self)._readonly_set(value) self.entry.set_editable(not value) self.visibility_checkbox.props.visible = not value if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() def toggle_visibility(self, button): self.entry.props.visibility = not self.entry.props.visibility tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/textbox.py0000644000175000017500000001243013463252532024740 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import logging import gtk from .widget import Widget, TranslateMixin from tryton.config import CONFIG try: from gi.repository import GtkSpell except ImportError: GtkSpell = None logger = logging.getLogger(__name__) class TextBox(Widget, TranslateMixin): expand = True def __init__(self, view, attrs): super(TextBox, self).__init__(view, attrs) self.widget = gtk.VBox() self.scrolledwindow = gtk.ScrolledWindow() self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.scrolledwindow.set_size_request(-1, 80) self.textview = self.mnemonic_widget = self._get_textview() self.textview.connect('focus-out-event', lambda x, y: self._focus_out()) self.textview.connect('key-press-event', self.send_modified) self.scrolledwindow.add(self.textview) self.scrolledwindow.show_all() self.button = None if attrs.get('translate'): self.button = self.translate_button() self.widget.pack_end(self.button, False, False) self.widget.pack_end(self.scrolledwindow) def _get_textview(self): if self.attrs.get('size'): textbuffer = TextBufferLimitSize(int(self.attrs['size'])) textview = gtk.TextView() textview.set_buffer(textbuffer) else: textview = gtk.TextView() textview.set_wrap_mode(gtk.WRAP_WORD) # TODO better tab solution textview.set_accepts_tab(False) return textview def translate_widget(self): box = gtk.VBox() scrolledwindow = gtk.ScrolledWindow() scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.set_shadow_type(gtk.SHADOW_ETCHED_IN) scrolledwindow.set_size_request(-1, 80) textview = self._get_textview() scrolledwindow.add(textview) box.pack_end(scrolledwindow) return box def translate_widget_set(self, widget, value): textview = widget.get_children()[-1].get_child() self.set_buffer(value, textview) def translate_widget_get(self, widget): textview = widget.get_children()[-1].get_child() return self.get_buffer(textview) def translate_widget_set_readonly(self, widget, value): textview = widget.get_children()[-1].get_child() textview.set_editable(not value) textview.props.sensitive = not value def _readonly_set(self, value): super(TextBox, self)._readonly_set(value) self.textview.set_editable(not value) if self.button: self.button.set_sensitive(not value) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() @property def modified(self): if self.record and self.field: return self.field.get_client(self.record) != self.get_value() return False def get_value(self): return self.get_buffer(self.textview) def set_value(self, record, field): field.set_client(record, self.get_value()) def set_buffer(self, value, textview): buf = textview.get_buffer() buf.delete(buf.get_start_iter(), buf.get_end_iter()) iter_start = buf.get_start_iter() buf.insert(iter_start, value) def get_buffer(self, textview): buf = textview.get_buffer() iter_start = buf.get_start_iter() iter_end = buf.get_end_iter() return buf.get_text(iter_start, iter_end, False) def display(self, record, field): super(TextBox, self).display(record, field) value = field and field.get(record) if not value: value = '' self.set_buffer(value, self.textview) if (GtkSpell and self.textview.get_editable() and self.attrs.get('spell') and CONFIG['client.spellcheck']): checker = GtkSpell.Checker.get_from_text_view(self.textview) if self.record: language = self.record.expr_eval(self.attrs['spell']) if not checker: checker = GtkSpell.Checker() checker.attach(self.textview) if checker.get_language() != language: try: checker.set_language(language) except Exception: logger.debug( 'Could not set spell checker to "%s"', language) checker.detach() elif checker: checker.detach() class TextBufferLimitSize(gtk.TextBuffer): __gsignals__ = { 'insert-text': 'override', } def __init__(self, max_length): super(TextBufferLimitSize, self).__init__() self.max_length = max_length def do_insert_text(self, iter, text, length): free_chars = self.max_length - self.get_char_count() text = text[0:free_chars] length = len(text) return gtk.TextBuffer.do_insert_text(self, iter, text, length) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/richtextbox.py0000644000175000017500000003251313463252532025612 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from gettext import gettext as _ from weakref import WeakKeyDictionary import gtk from .textbox import TextBox from tryton.common import get_toplevel_window, IconFactory from tryton.common.htmltextbuffer import (serialize, deserialize, setup_tags, normalize_markup, remove_tags, register_foreground, FAMILIES, SIZE2SCALE, MIME, use_serialize_func) from tryton.config import CONFIG SIZES = sorted(SIZE2SCALE.keys()) class RichTextBox(TextBox): def __init__(self, view, attrs): super(RichTextBox, self).__init__(view, attrs) self.toolbar = None self.tag_widgets = WeakKeyDictionary() self.tags = {} self.colors = {} if int(self.attrs.get('toolbar', 1)): self.toolbar = self.get_toolbar(self.textview) self.widget.pack_start(self.toolbar, expand=False, fill=True) def get_toolbar(self, textview): toolbar = gtk.Toolbar() toolbar.set_style({ 'default': False, 'both': gtk.TOOLBAR_BOTH, 'text': gtk.TOOLBAR_TEXT, 'icons': gtk.TOOLBAR_ICONS}[CONFIG['client.toolbar']]) tag_widgets = self.tag_widgets[textview] = {} for icon in ['bold', 'italic', 'underline']: button = gtk.ToggleToolButton() button.set_icon_widget(IconFactory.get_image( 'tryton-format-%s' % icon, gtk.ICON_SIZE_SMALL_TOOLBAR)) button.connect('toggled', self.toggle_props, icon, textview) toolbar.insert(button, -1) tag_widgets[icon] = button toolbar.insert(gtk.SeparatorToolItem(), -1) for name, options, active in [ ('family', FAMILIES, FAMILIES.index('normal')), ('size', SIZES, SIZES.index('4')), ]: try: combobox = gtk.ComboBoxText() except AttributeError: combobox = gtk.combo_box_new_text() for option in options: combobox.append_text(option) combobox.set_active(active) combobox.set_focus_on_click(False) combobox.connect('changed', self.change_props, name, textview) tool = gtk.ToolItem() tool.add(combobox) toolbar.insert(tool, -1) tag_widgets[name] = combobox toolbar.insert(gtk.SeparatorToolItem(), -1) button = None for name in ['left', 'center', 'right', 'justify']: icon = 'tryton-format-align-%s' % name button = gtk.RadioToolButton.new_from_widget(button) button.set_icon_widget(IconFactory.get_image( icon, gtk.ICON_SIZE_SMALL_TOOLBAR)) button.set_active(icon == 'left') button.connect( 'toggled', self.toggle_justification, name, textview) toolbar.insert(button, -1) tag_widgets[name] = button toolbar.insert(gtk.SeparatorToolItem(), -1) for icon, label in [ ('foreground', _('Foreground')), # TODO ('background', _('Background')), ]: button = gtk.ToolButton() if icon == 'foreground': button.set_icon_widget(IconFactory.get_image( 'tryton-format-color-text', gtk.ICON_SIZE_SMALL_TOOLBAR)) button.set_label(label) button.connect('clicked', self.toggle_color, icon, textview) toolbar.insert(button, -1) tag_widgets[icon] = button return toolbar def _get_textview(self): textview = super(RichTextBox, self)._get_textview() text_buffer = textview.get_buffer() setup_tags(text_buffer) text_buffer.register_serialize_format(str(MIME), serialize, None) text_buffer.register_deserialize_format(str(MIME), deserialize, None) text_buffer.connect_after( 'insert-text', self.insert_text_style, textview) textview.connect_after('move-cursor', self.detect_style) textview.connect('button-release-event', self.detect_style) return textview def translate_widget(self): widget = super(RichTextBox, self).translate_widget() textview = widget.get_children()[-1].get_child() if self.toolbar: widget.pack_start( self.get_toolbar(textview), expand=False, fill=True) return widget def translate_widget_set_readonly(self, widget, value): super(RichTextBox, self).translate_widget_set_readonly(widget, value) if self.toolbar: toolbar = widget.get_children()[0] for n in range(toolbar.get_n_items()): tool = toolbar.get_nth_item(n) tool.set_sensitive(not value) def set_value(self, record, field): # avoid modification of not normalized value value = self.get_value() prev_value = field.get_client(record) or '' if value == normalize_markup(prev_value): value = prev_value field.set_client(record, value) @property def modified(self): if self.record and self.field: value = normalize_markup(self.field.get_client(self.record) or '') return value != self.get_value() return False def set_buffer(self, value, textview): text_buffer = textview.get_buffer() text_buffer.handler_block_by_func(self.insert_text_style) start = text_buffer.get_start_iter() end = text_buffer.get_end_iter() text_buffer.delete(start, end) if use_serialize_func: text_buffer.deserialize(text_buffer, MIME, start, value) else: deserialize( text_buffer, text_buffer, start, value, text_buffer.deserialize_get_can_create_tags(MIME), None) text_buffer.handler_unblock_by_func(self.insert_text_style) def get_buffer(self, textview): text_buffer = textview.get_buffer() start = text_buffer.get_start_iter() end = text_buffer.get_end_iter() if use_serialize_func: return text_buffer.serialize(text_buffer, MIME, start, end) else: return serialize(text_buffer, text_buffer, start, end, None) def _readonly_set(self, value): super(RichTextBox, self)._readonly_set(value) if self.toolbar: self.toolbar.set_sensitive(not value) def detect_style(self, textview, *args): tag_widgets = self.tag_widgets[textview] text_buffer = textview.get_buffer() try: start, end = text_buffer.get_selection_bounds() except ValueError: start = end = text_buffer.get_iter_at_mark( text_buffer.get_insert()) def toggle_button(name, values): try: value, = values except ValueError: value = False button = tag_widgets[name] button.handler_block_by_func(self.toggle_props) button.set_active(value) button.handler_unblock_by_func(self.toggle_props) def set_combobox(name, indexes): try: index, = indexes except ValueError: index = -1 combobox = tag_widgets[name] combobox.handler_block_by_func(self.change_props) combobox.set_active(index) combobox.handler_unblock_by_func(self.change_props) def toggle_justification(names, value): if len(names) != 1: value = False for name in names: button = tag_widgets[name] button.handler_block_by_func(self.toggle_justification) button.set_active(value) button.handler_unblock_by_func(self.toggle_justification) bolds, italics, underlines = set(), set(), set() families, sizes, justifications = set(), set(), set() iter_ = start.copy() while True: bold, italic, underline = False, False, False family = FAMILIES.index('normal') size = SIZES.index('4') justification = 'left' for tag in iter_.get_tags(): if not tag.props.name: continue elif tag.props.name == 'bold': bold = True elif tag.props.name == 'italic': italic = True elif tag.props.name == 'underline': underline = True elif tag.props.name.startswith('family'): _, family = tag.props.name.split() family = FAMILIES.index(family) elif tag.props.name.startswith('size'): _, size = tag.props.name.split() size = SIZES.index(size) elif tag.props.name.startswith('justification'): _, justification = tag.props.name.split() bolds.add(bold) italics.add(italic) underlines.add(underline) families.add(family) sizes.add(size) justifications.add(justification) iter_.forward_char() if iter_.compare(end) > 0: iter_ = end if iter_.compare(end) == 0: break for name, values in [ ('bold', bolds), ('italic', italics), ('underline', underlines)]: toggle_button(name, values) set_combobox('family', families) set_combobox('size', sizes) toggle_justification(justifications, True) def insert_text_style(self, text_buffer, iter_, text, length, textview): # Text is already inserted so iter_ point to the end start = iter_.copy() start.backward_chars(length) end = iter_.copy() # Apply tags activated from toolbar for name, widget in self.tag_widgets[textview].items(): self._apply_tool(text_buffer, name, widget, start, end) def _apply_tool(self, text_buffer, name, tool, start, end): # First test RadioToolButton as they inherit from ToggleToolButton if isinstance(tool, gtk.RadioToolButton): name = 'justification %s' % name if not tool.get_active(): remove_tags(text_buffer, start, end, name) else: remove_tags(text_buffer, start, end, 'justification') text_buffer.apply_tag_by_name(name, start, end) elif isinstance(tool, gtk.ToggleToolButton): if tool.get_active(): text_buffer.apply_tag_by_name(name, start, end) else: text_buffer.remove_tag_by_name(name, start, end) elif isinstance(tool, gtk.ComboBox): value = tool.get_active_text() remove_tags(text_buffer, start, end, name) name = '%s %s' % (name, value) text_buffer.apply_tag_by_name(name, start, end) def toggle_props(self, toggle, name, textview): text_buffer = textview.get_buffer() try: start, end = text_buffer.get_selection_bounds() except ValueError: return self._apply_tool(text_buffer, name, toggle, start, end) def change_props(self, combobox, name, textview): text_buffer = textview.get_buffer() try: start, end = text_buffer.get_selection_bounds() except ValueError: return self._apply_tool(text_buffer, name, combobox, start, end) def toggle_justification(self, button, name, textview): text_buffer = textview.get_buffer() try: start, end = text_buffer.get_selection_bounds() except ValueError: insert = text_buffer.get_insert() start = text_buffer.get_iter_at_mark(insert) end = start.copy() start.set_line_offset(0) if not end.ends_line(): end.forward_to_line_end() self._apply_tool(text_buffer, name, button, start, end) def toggle_color(self, button, name, textview): text_buffer = textview.get_buffer() insert = text_buffer.get_insert() try: start, end = text_buffer.get_selection_bounds() except ValueError: start = end = None else: # Use offset position to preserve across buffer modification start = start.get_offset() end = end.get_offset() dialog = gtk.ColorSelectionDialog(_('Select a color')) dialog.set_transient_for(get_toplevel_window()) colorsel = dialog.get_color_selection() colorsel.set_has_palette(True) color = self.colors.get(name) if color: colorsel.set_current_color(color) if dialog.run() == gtk.RESPONSE_OK: color = colorsel.get_current_color() self.colors[name] = color if start is not None and end is not None: start = text_buffer.get_iter_at_offset(start) end = text_buffer.get_iter_at_offset(end) tag = register_foreground(text_buffer, color) remove_tags(text_buffer, start, end, name) text_buffer.apply_tag(tag, start, end) dialog.destroy() text_buffer.place_cursor(text_buffer.get_iter_at_mark(insert)) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/one2many.py0000644000175000017500000005210113524765775025012 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import itertools from .widget import Widget from tryton.gui.window.view_form.screen import Screen from tryton.gui.window.win_search import WinSearch from tryton.gui.window.win_form import WinForm import tryton.common as common from tryton.common.completion import get_completion, update_completion from tryton.common.domain_parser import quote from tryton.common.underline import set_underline _ = gettext.gettext class One2Many(Widget): expand = True def __init__(self, view, attrs): super(One2Many, self).__init__(view, attrs) self.widget = gtk.Frame() self.widget.set_shadow_type(gtk.SHADOW_NONE) self.widget.get_accessible().set_name(attrs.get('string', '')) vbox = gtk.VBox(homogeneous=False, spacing=2) self.widget.add(vbox) self._readonly = True self._required = False self._position = 0 self._length = 0 self.title_box = hbox = gtk.HBox(homogeneous=False, spacing=0) hbox.set_border_width(2) self.title = gtk.Label(set_underline(attrs.get('string', ''))) self.title.set_use_underline(True) self.title.set_alignment(0.0, 0.5) hbox.pack_start(self.title, expand=True, fill=True) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) tooltips = common.Tooltips() but_switch = gtk.Button() tooltips.set_tip(but_switch, _('Switch')) but_switch.connect('clicked', self.switch_view) but_switch.add(common.IconFactory.get_image( 'tryton-switch', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_switch.set_relief(gtk.RELIEF_NONE) hbox.pack_start(but_switch, expand=False, fill=False) self.but_pre = gtk.Button() tooltips.set_tip(self.but_pre, _('Previous')) self.but_pre.connect('clicked', self._sig_previous) self.but_pre.add(common.IconFactory.get_image( 'tryton-back', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_pre.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_pre, expand=False, fill=False) self.label = gtk.Label('(0,0)') hbox.pack_start(self.label, expand=False, fill=False) self.but_next = gtk.Button() tooltips.set_tip(self.but_next, _('Next')) self.but_next.connect('clicked', self._sig_next) self.but_next.add(common.IconFactory.get_image( 'tryton-forward', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_next.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_next, expand=False, fill=False) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) self.focus_out = True self.wid_completion = None if attrs.get('add_remove'): self.wid_text = gtk.Entry() self.wid_text.set_placeholder_text(_('Search')) self.wid_text.set_property('width_chars', 13) self.wid_text.connect('focus-out-event', self._focus_out) hbox.pack_start(self.wid_text, expand=True, fill=True) if int(self.attrs.get('completion', 1)): access = common.MODELACCESS[attrs['relation']] self.wid_completion = get_completion( search=access['read'] and access['write'], create=attrs.get('create', True) and access['create']) self.wid_completion.connect('match-selected', self._completion_match_selected) self.wid_completion.connect('action-activated', self._completion_action_activated) self.wid_text.set_completion(self.wid_completion) self.wid_text.connect('changed', self._update_completion) self.but_add = gtk.Button() tooltips.set_tip(self.but_add, _('Add existing record')) self.but_add.connect('clicked', self._sig_add) self.but_add.add(common.IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_add.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_add, expand=False, fill=False) self.but_remove = gtk.Button() tooltips.set_tip(self.but_remove, _('Remove selected record')) self.but_remove.connect('clicked', self._sig_remove, True) self.but_remove.add(common.IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_remove.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_remove, expand=False, fill=False) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) self.but_new = gtk.Button() tooltips.set_tip(self.but_new, _('Create a new record ')) self.but_new.connect('clicked', self._sig_new) self.but_new.add(common.IconFactory.get_image( 'tryton-create', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_new.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_new, expand=False, fill=False) self.but_open = gtk.Button() tooltips.set_tip(self.but_open, _('Edit selected record ')) self.but_open.connect('clicked', self._sig_edit) self.but_open.add(common.IconFactory.get_image( 'tryton-open', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_open.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_open, expand=False, fill=False) self.but_del = gtk.Button() tooltips.set_tip(self.but_del, _('Delete selected record ')) self.but_del.connect('clicked', self._sig_remove, False) self.but_del.add(common.IconFactory.get_image( 'tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_del.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_del, expand=False, fill=False) self.but_undel = gtk.Button() tooltips.set_tip(self.but_undel, _('Undelete selected record ')) self.but_undel.connect('clicked', self._sig_undelete) self.but_undel.add(common.IconFactory.get_image( 'tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_undel.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_undel, expand=False, fill=False) if attrs.get('add_remove'): hbox.set_focus_chain([self.wid_text]) else: hbox.set_focus_chain([]) tooltips.enable() frame = gtk.Frame() frame.add(hbox) frame.set_shadow_type(gtk.SHADOW_OUT) vbox.pack_start(frame, expand=False, fill=True) self.screen = Screen(attrs['relation'], mode=attrs.get('mode', 'tree,form').split(','), view_ids=attrs.get('view_ids', '').split(','), views_preload=attrs.get('views', {}), row_activate=self._on_activate, exclude_field=attrs.get('relation_field', None), limit=None) self.screen.pre_validate = bool(int(attrs.get('pre_validate', 0))) self.screen.signal_connect(self, 'record-message', self._sig_label) vbox.pack_start(self.screen.widget, expand=True, fill=True) self.title.set_mnemonic_widget( self.screen.current_view.mnemonic_widget) self.screen.widget.connect('key_press_event', self.on_keypress) if self.attrs.get('add_remove'): self.wid_text.connect('key_press_event', self.on_keypress) but_switch.props.sensitive = self.screen.number_of_views > 1 def on_keypress(self, widget, event): if (event.keyval == gtk.keysyms.F3) \ and self.but_new.get_property('sensitive'): self._sig_new(widget) return True if event.keyval == gtk.keysyms.F2 \ and widget == self.screen.widget: self._sig_edit(widget) return True if (event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) and widget == self.screen.widget and self.but_del.get_property('sensitive')): self._sig_remove(widget) return True if event.keyval == gtk.keysyms.Insert and widget == self.screen.widget: self._sig_undelete(widget) return True if self.attrs.get('add_remove'): editable = self.wid_text.get_editable() activate_keys = [gtk.keysyms.Tab, gtk.keysyms.ISO_Left_Tab] if not self.wid_completion: activate_keys.append(gtk.keysyms.Return) if (widget == self.wid_text and event.keyval in activate_keys and editable and self.wid_text.get_text()): self._sig_add() self.wid_text.grab_focus() return False def destroy(self): if self.attrs.get('add_remove'): self.wid_text.disconnect_by_func(self._focus_out) self.screen.destroy() def _on_activate(self): self._sig_edit() def switch_view(self, widget): self.screen.switch_view() mnemonic_widget = self.screen.current_view.mnemonic_widget string = self.attrs.get('string', '') if mnemonic_widget: string = set_underline(string) self.title.set_mnemonic_widget(mnemonic_widget) self.title.set_label(string) @property def modified(self): return self.screen.current_view.modified def _readonly_set(self, value): self._readonly = value self._set_button_sensitive() self._set_label_state() def _required_set(self, value): self._required = value self._set_label_state() def _set_label_state(self): common.apply_label_attributes( self.title, self._readonly, self._required) def _set_button_sensitive(self): access = common.MODELACCESS[self.screen.model_name] if self.record and self.field: field_size = self.record.expr_eval(self.attrs.get('size')) o2m_size = len(self.field.get_eval(self.record)) size_limit = (field_size is not None and o2m_size >= field_size >= 0) else: o2m_size = None size_limit = False first = last = False if isinstance(self._position, int): first = self._position <= 1 last = self._position >= self._length self.but_new.set_sensitive(bool( not self._readonly and self.attrs.get('create', True) and not size_limit and access['create'])) self.but_del.set_sensitive(bool( not self._readonly and self.attrs.get('delete', True) and self._position and access['delete'])) self.but_undel.set_sensitive(bool( not self._readonly and not size_limit and self._position)) self.but_open.set_sensitive(bool( self._position and access['read'])) self.but_next.set_sensitive(bool( self._position and not last)) self.but_pre.set_sensitive(bool( self._position and not first)) if self.attrs.get('add_remove'): self.but_add.set_sensitive(bool( not self._readonly and not size_limit and access['write'] and access['read'])) self.but_remove.set_sensitive(bool( not self._readonly and self._position and access['write'] and access['read'])) self.wid_text.set_sensitive(self.but_add.get_sensitive()) self.wid_text.set_editable(self.but_add.get_sensitive()) # New button must be added to focus chain to allow keyboard only # creation when there is no existing record on form view. focus_chain = self.title_box.get_focus_chain() or [] if o2m_size == 0 and self.screen.current_view.view_type == 'form': if self.but_new not in focus_chain: focus_chain.append(self.but_new) else: if self.but_new in focus_chain: focus_chain.remove(self.but_new) self.title_box.set_focus_chain(focus_chain) def _validate(self): self.view.set_value() record = self.screen.current_record if record: fields = self.screen.current_view.get_fields() if not record.validate(fields): self.screen.display(set_cursor=True) return False if self.screen.pre_validate and not record.pre_validate(): return False return True def _sequence(self): for view in self.screen.views: if view.view_type == 'tree': sequence = view.attributes.get('sequence') if sequence: return sequence def _sig_new(self, *args): if not common.MODELACCESS[self.screen.model_name]['create']: return if not self._validate(): return if self.attrs.get('product'): self._new_product() else: self._new_single() def _new_single(self): ctx = {} ctx.update(self.field.get_context(self.record)) sequence = self._sequence() def update_sequence(): if sequence: self.screen.group.set_sequence(field=sequence) if self.screen.current_view.editable: self.screen.new() self.screen.current_view.widget.set_sensitive(True) update_sequence() else: field_size = self.record.expr_eval(self.attrs.get('size')) or -1 field_size -= len(self.field.get_eval(self.record)) + 1 WinForm(self.screen, lambda a: update_sequence(), new=True, many=field_size, context=ctx, title=self.attrs.get('string')) def _new_product(self): fields = self.attrs['product'].split(',') product = {} first = self.screen.new(default=False) default = first.default_get() first.set_default(default) def search_set(*args): if not fields: return make_product() field = self.screen.group.fields[fields.pop()] relation = field.attrs.get('relation') if not relation: search_set() domain = field.domain_get(first) context = field.get_search_context(first) order = field.get_search_order(first) def callback(result): if result: product[field.name] = result win_search = WinSearch(relation, callback, sel_multi=True, context=context, domain=domain, order=order, title=self.attrs.get('string')) win_search.win.connect('destroy', search_set) win_search.screen.search_filter() win_search.show() def make_product(): self.screen.group.remove(first, remove=True) if not product: return fields = list(product.keys()) for values in itertools.product(*list(product.values())): record = self.screen.new(default=False) default_value = default.copy() for field, value in zip(fields, values): id_, rec_name = value default_value[field] = id_ default_value[field + '.rec_name'] = rec_name record.set_default(default_value) sequence = self._sequence() if sequence: self.screen.group.set_sequence(field=sequence) search_set() def _sig_edit(self, widget=None): if not common.MODELACCESS[self.screen.model_name]['read']: return if not self._validate(): return record = self.screen.current_record if record: WinForm(self.screen, lambda a: None, title=self.attrs.get('string')) def _sig_next(self, widget): if not self._validate(): return self.screen.display_next() def _sig_previous(self, widget): if not self._validate(): return self.screen.display_prev() def _sig_remove(self, widget, remove=False): access = common.MODELACCESS[self.screen.model_name] if remove: if not access['write'] or not access['read']: return else: if not access['delete']: return self.screen.remove(remove=remove) def _sig_undelete(self, button): self.screen.unremove() def _sig_add(self, *args): if not self.focus_out: return access = common.MODELACCESS[self.screen.model_name] if not access['write'] or not access['read']: return self.view.set_value() domain = self.field.domain_get(self.record) context = self.field.get_search_context(self.record) domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))] removed_ids = self.field.get_removed_ids(self.record) domain = ['OR', domain, ('id', 'in', removed_ids)] text = self.wid_text.get_text() self.focus_out = False sequence = self._sequence() def callback(result): self.focus_out = True if result: ids = [x[0] for x in result] self.screen.load(ids, modified=True) self.screen.display(res_id=ids[0]) if sequence: self.screen.group.set_sequence(field=sequence) self.screen.set_cursor() self.wid_text.set_text('') order = self.field.get_search_order(self.record) win = WinSearch(self.attrs['relation'], callback, sel_multi=True, context=context, domain=domain, order=order, view_ids=self.attrs.get('view_ids', '').split(','), views_preload=self.attrs.get('views', {}), new=self.but_new.get_property('sensitive'), title=self.attrs.get('string')) win.screen.search_filter(quote(text)) win.show() def _sig_label(self, screen, signal_data): self._position = signal_data[0] self._length = signal_data[1] if self._position: name = str(self._position) else: name = '_' line = '(%s/%s)' % (name, self._length) self.label.set_text(line) self._set_button_sensitive() def display(self, record, field): super(One2Many, self).display(record, field) self._set_button_sensitive() if field is None: self.screen.new_group() self.screen.current_record = None self.screen.parent = None self.screen.display() return False new_group = field.get_client(record) if id(self.screen.group) != id(new_group): self.screen.group = new_group if (self.screen.current_view.view_type == 'tree') \ and self.screen.current_view.editable: self.screen.current_record = None domain = [] size_limit = None if record: domain = field.domain_get(record) size_limit = record.expr_eval(self.attrs.get('size')) if self._readonly: if size_limit is None: size_limit = len(self.screen.group) else: size_limit = min(size_limit, len(self.screen.group)) if self.screen.domain != domain: self.screen.domain = domain self.screen.size_limit = size_limit self.screen.display() return True def set_value(self, record, field): self.screen.current_view.set_value() if self.screen.modified(): # TODO check if required record.modified_fields.setdefault(field.name) record.signal('record-modified') return True def _completion_match_selected(self, completion, model, iter_): record_id, = model.get(iter_, 1) self.screen.load([record_id], modified=True) self.wid_text.set_text('') self.wid_text.grab_focus() completion_model = self.wid_completion.get_model() completion_model.clear() completion_model.search_text = self.wid_text.get_text() return True def _update_completion(self, widget): if self._readonly: return if not self.record: return model = self.attrs['relation'] domain = self.field.domain_get(self.record) domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))] removed_ids = self.field.get_removed_ids(self.record) domain = ['OR', domain, ('id', 'in', removed_ids)] update_completion(self.wid_text, self.record, self.field, model, domain=domain) def _completion_action_activated(self, completion, index): if index == 0: self._sig_add() self.wid_text.grab_focus() elif index == 1: self._sig_new() tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/checkbox.py0000644000175000017500000000231213430121327025016 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk from .widget import Widget import gettext _ = gettext.gettext class CheckBox(Widget): def __init__(self, view, attrs): super(CheckBox, self).__init__(view, attrs) self.widget = self.mnemonic_widget = gtk.CheckButton() self.widget.connect('focus-out-event', lambda x, y: self._focus_out()) self.widget.connect_after('toggled', self.sig_activate) def _readonly_set(self, value): super(CheckBox, self)._readonly_set(value) # TODO find a better solution to accept focus self.widget.set_sensitive(not value) def set_value(self, record, field): field.set_client(record, self.widget.get_active()) def display(self, record, field): super(CheckBox, self).display(record, field) if not field: self.widget.set_active(False) return False self.widget.handler_block_by_func(self.sig_activate) try: self.widget.set_active(bool(field.get(record))) finally: self.widget.handler_unblock_by_func(self.sig_activate) tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/binary.py0000644000175000017500000001677613463252532024550 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext import os from tryton.common import common from tryton.common import file_selection, Tooltips, file_open, file_write from tryton.common.entry_position import reset_position from tryton.config import CONFIG from .widget import Widget _ = gettext.gettext class BinaryMixin(Widget): def __init__(self, view, attrs): super(BinaryMixin, self).__init__(view, attrs) self.filename = attrs.get('filename') def toolbar(self): 'Return HBox with the toolbar' hbox = gtk.HBox(spacing=0) tooltips = Tooltips() self.but_save_as = gtk.Button() self.but_save_as.set_image(common.IconFactory.get_image( 'tryton-save', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_save_as.set_relief(gtk.RELIEF_NONE) self.but_save_as.connect('clicked', self.save_as) tooltips.set_tip(self.but_save_as, _('Save As...')) hbox.pack_start(self.but_save_as, expand=False, fill=False) self.but_select = gtk.Button() self.but_select.set_image(common.IconFactory.get_image( 'tryton-search', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_select.set_relief(gtk.RELIEF_NONE) self.but_select.connect('clicked', self.select) tooltips.set_tip(self.but_select, _('Select...')) hbox.pack_start(self.but_select, expand=False, fill=False) self.but_clear = gtk.Button() self.but_clear.set_image(common.IconFactory.get_image( 'tryton-clear', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_clear.set_relief(gtk.RELIEF_NONE) self.but_clear.connect('clicked', self.clear) tooltips.set_tip(self.but_clear, _('Clear')) hbox.pack_start(self.but_clear, expand=False, fill=False) tooltips.enable() return hbox @property def filename_field(self): return self.record.group.fields.get(self.filename) @property def filters(self): filter_all = gtk.FileFilter() filter_all.set_name(_('All files')) filter_all.add_pattern("*") return [filter_all] @property def preview(self): return False def update_buttons(self, value): if value: self.but_save_as.show() self.but_select.hide() self.but_clear.show() else: self.but_save_as.hide() self.but_select.show() self.but_clear.hide() def select(self, widget=None): if not self.field: return filters = self.filters filename = file_selection(_('Select'), preview=self.preview, filters=filters) if filename: self.field.set_client(self.record, open(filename, 'rb').read()) if self.filename_field: self.filename_field.set_client(self.record, os.path.basename(filename)) def get_data(self): if hasattr(self.field, 'get_data'): data = self.field.get_data(self.record) else: data = self.field.get(self.record) if isinstance(data, str): data = data.encode('utf-8') return data def open_(self, widget=None): if not self.filename_field: return filename = self.filename_field.get(self.record) if not filename: return file_path = file_write(filename, self.get_data()) root, type_ = os.path.splitext(filename) if type_: type_ = type_[1:] file_open(file_path, type_) def save_as(self, widget=None): filename = '' if self.filename_field: filename = self.filename_field.get(self.record) filename = file_selection(_('Save As...'), filename=filename, action=gtk.FILE_CHOOSER_ACTION_SAVE) if filename: with open(filename, 'wb') as fp: fp.write(self.get_data()) def clear(self, widget=None): if self.filename_field: self.filename_field.set_client(self.record, None) self.field.set_client(self.record, None) class Binary(BinaryMixin, Widget): "Binary" def __init__(self, view, attrs): super(Binary, self).__init__(view, attrs) self.widget = gtk.HBox(spacing=0) self.wid_size = gtk.Entry() self.wid_size.set_width_chars(10) self.wid_size.set_alignment(1.0) self.wid_size.props.sensitive = False if self.filename and attrs.get('filename_visible'): self.wid_text = gtk.Entry() self.wid_text.set_property('activates_default', True) self.wid_text.connect('focus-out-event', lambda x, y: self._focus_out()) self.wid_text.connect_after('key_press_event', self.sig_key_press) self.wid_text.connect('icon-press', self.sig_icon_press) self.widget.pack_start(self.wid_text, expand=True, fill=True) else: self.wid_text = None self.mnemonic_widget = self.wid_text self.widget.pack_start(self.wid_size, expand=not self.filename, fill=True) self.widget.pack_start(self.toolbar(), expand=False, fill=False) def _readonly_set(self, value): self.but_select.set_sensitive(not value) self.but_clear.set_sensitive(not value) if self.wid_text: self.wid_text.set_editable(not value) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() def sig_key_press(self, widget, event, *args): editable = self.wid_text and self.wid_text.get_editable() if event.keyval == gtk.keysyms.F3 and editable: self.sig_new(widget) return True elif event.keyval == gtk.keysyms.F2: if self.filename: self.sig_open(widget) else: self.sig_save_as(widget) return True return False def sig_icon_press(self, widget, icon_pos, event): if icon_pos == gtk.ENTRY_ICON_PRIMARY: self.open_() def display(self, record, field): super(Binary, self).display(record, field) if not field: if self.wid_text: self.wid_text.set_text('') self.wid_size.set_text('') self.but_save_as.hide() return False if hasattr(field, 'get_size'): size = field.get_size(record) else: size = len(field.get(record)) self.wid_size.set_text(common.humanize(size or 0)) reset_position(self.wid_size) if self.wid_text: self.wid_text.set_text(self.filename_field.get(record) or '') reset_position(self.wid_text) if size: icon, tooltip = 'tryton-open', _("Open...") else: icon, tooltip = None, '' pos = gtk.ENTRY_ICON_PRIMARY if icon: pixbuf = common.IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_MENU) else: pixbuf = None self.wid_text.set_icon_from_pixbuf(pos, pixbuf) self.wid_text.set_icon_tooltip_text(pos, tooltip) self.update_buttons(bool(size)) return True def set_value(self, record, field): if self.wid_text: self.filename_field.set_client(self.record, self.wid_text.get_text() or False) return tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/float.py0000644000175000017500000000334413354423127024353 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import locale from .integer import Integer class Float(Integer): "Float" def __init__(self, view, attrs): super(Float, self).__init__(view, attrs) self.entry.connect('key-press-event', self.key_press_event) def display(self, record, field): super(Float, self).display(record, field) if field: digits = field.digits(record, factor=self.factor) if digits: self.entry.set_width_chars(sum(digits)) else: self.entry.set_width_chars(18) def key_press_event(self, widget, event): for name in ('KP_Decimal', 'KP_Separator'): if event.keyval == gtk.gdk.keyval_from_name(name): event.keyval = int(gtk.gdk.unicode_to_keyval( ord(locale.localeconv()['decimal_point']))) def sig_insert_text(self, entry, new_text, new_text_length, position): if not self.record: entry.stop_emission('insert-text') return value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] decimal_point = locale.localeconv()['decimal_point'] if new_value in ('-', decimal_point): return digits = self.field.digits(self.record, factor=self.factor) try: value = locale.atof(new_value) except ValueError: entry.stop_emission('insert-text') return if digits and not (round(value, digits[1]) == float(value)): entry.stop_emission('insert-text') tryton-5.0.17/tryton/gui/window/view_form/view/form_gtk/calendar.py0000644000175000017500000001266013524765775025041 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime import gtk import gettext import gobject from .widget import Widget from tryton import common from tryton.common.datetime_ import (Date as DateEntry, Time as TimeEntry, DateTime as DateTimeEntry, add_operators) from tryton.config import CONFIG _ = gettext.gettext class Date(Widget): def __init__(self, view, attrs, _entry=DateEntry): super(Date, self).__init__(view, attrs) self.widget = gtk.HBox() self.entry = self.mnemonic_widget = add_operators(_entry()) self.real_entry.set_property('activates_default', True) self.real_entry.connect('key_press_event', self.sig_key_press) self.real_entry.connect('activate', self.sig_activate) self.real_entry.connect('changed', lambda _: self.send_modified()) self.real_entry.connect('focus-out-event', lambda x, y: self._focus_out()) self.widget.pack_start(self.entry, expand=False, fill=False) @property def real_entry(self): return self.entry def _set_editable(self, value): self.entry.set_editable(value) self.entry.set_icon_sensitive(gtk.ENTRY_ICON_PRIMARY, value) def _readonly_set(self, value): self._set_editable(not value) if value and CONFIG['client.fast_tabbing']: self.widget.set_focus_chain([]) else: self.widget.unset_focus_chain() @classmethod def cast(cls, value): if isinstance(value, datetime.datetime): value = value.date() return value @property def modified(self): if self.record and self.field: field_value = self.cast(self.field.get_client(self.record)) return field_value != self.get_value() return False def sig_key_press(self, widget, event): self.send_modified() def set_value(self, record, field): field.set_client(record, self.get_value()) def get_value(self): self.entry.parse() return self.entry.props.value def set_format(self, record, field): if field and record: format_ = field.date_format(record) else: format_ = common.date_format( self.view.screen.context.get('date_format')) self.entry.props.format = format_ def display(self, record, field): super(Date, self).display(record, field) if field and record: value = field.get_client(record) else: value = '' self.entry.props.value = value self.set_format(record, field) class Time(Date): def __init__(self, view, attrs): super(Time, self).__init__(view, attrs, _entry=TimeEntry) self.entry.set_focus_chain([self.entry.get_child()]) self.entry.connect('time-changed', self.changed) def _set_editable(self, value): self.entry.set_sensitive(value) @classmethod def cast(cls, value): if isinstance(value, datetime.datetime): value = value.time() return value @property def real_entry(self): return self.entry.get_child() def display(self, record, field): super(Time, self).display(record, field) def set_format(self, record, field): if field and record: format_ = field.time_format(record) else: format_ = '%X' self.entry.props.format = format_ def changed(self, combobox): def focus_out(): if combobox.props.window: self._focus_out() # Only when changed from pop list if not combobox.get_child().has_focus(): # Must be deferred because it triggers a display of the form gobject.idle_add(focus_out) class DateTime(Date): def __init__(self, view, attrs): Widget.__init__(self, view, attrs) self.widget = gtk.HBox() self.entry = self.mnemonic_widget = DateTimeEntry() for child in self.entry.get_children(): add_operators(child) if isinstance(child, gtk.ComboBoxEntry): child.set_focus_chain([child.get_child()]) child = child.get_child() child.set_property('activates_default', True) child.connect('key_press_event', self.sig_key_press) child.connect('activate', self.sig_activate) child.connect('changed', lambda _: self.send_modified()) child.connect('focus-out-event', lambda x, y: self._focus_out()) self.widget.pack_start(self.entry, expand=False, fill=False) @classmethod def cast(cls, value): return value def _set_editable(self, value): for child in self.entry.get_children(): if isinstance(child, gtk.Entry): child.set_editable(value) child.set_icon_sensitive(gtk.ENTRY_ICON_PRIMARY, value) elif isinstance(child, gtk.ComboBoxEntry): child.set_sensitive(value) def set_format(self, record, field): if field and record: date_format = field.date_format(record) time_format = field.time_format(record) else: date_format = common.date_format( self.view.screen.context.get('date_format')) time_format = '%X' self.entry.props.date_format = date_format self.entry.props.time_format = time_format tryton-5.0.17/tryton/gui/window/view_form/view/list.py0000644000175000017500000013060413563614150022411 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gobject import gtk import sys import json import locale import gettext from functools import wraps from collections import defaultdict from tryton.config import CONFIG from tryton.common.cellrendererbutton import CellRendererButton from tryton.gui.window import Window from tryton.common.popup_menu import populate from tryton.common import RPCExecute, RPCException, node_attributes, Tooltips from tryton.common import domain_inversion, simplify, unique_value from tryton.pyson import PYSONDecoder import tryton.common as common from . import View from .list_gtk.editabletree import EditableTreeView, TreeView from .list_gtk.widget import (Affix, Char, Text, Int, Boolean, URL, Date, Time, Float, TimeDelta, Binary, M2O, O2O, O2M, M2M, Selection, Reference, ProgressBar, Button, Image) _ = gettext.gettext def delay(func): """Decorator for ViewTree method to delay execution when idle and if display counter did not change""" @wraps(func) def wrapper(self, *args, **kwargs): def wait(): if not self.treeview.props.window: return if self.treeview.display_counter == display_counter: func(self, *args, **kwargs) display_counter = self.treeview.display_counter gobject.idle_add(wait) return wrapper def path_convert_id2pos(model, id_path): "This function will transform a path of id into a path of position" group = model.group id_path = id_path[:] indexes = [] while id_path: current_id = id_path.pop(0) try: record = group.get(current_id) indexes.append(group.index(record)) group = record.children_group(model.children_field) except (KeyError, AttributeError, ValueError): return None return tuple(indexes) class AdaptModelGroup(gtk.GenericTreeModel): def __init__(self, group, children_field=None): super(AdaptModelGroup, self).__init__() self.group = group self.set_property('leak_references', False) self.children_field = children_field self.__removed = None # XXX dirty hack to allow update of has_child def added(self, group, record): if (group is self.group and (record.group is self.group or record.group.child_name == self.children_field)): path = record.get_index_path(self.group) iter_ = self.get_iter(path) self.row_inserted(path, iter_) if record.children_group(self.children_field): self.row_has_child_toggled(path, iter_) if (record.parent and record.group is not self.group): path = record.parent.get_index_path(self.group) iter_ = self.get_iter(path) self.row_has_child_toggled(path, iter_) def removed(self, group, record): if (group is self.group and (record.group is self.group or record.group.child_name == self.children_field)): path = record.get_index_path(self.group) self.row_deleted(path) def append(self, model): self.group.add(model) def prepend(self, model): self.group.add(model, 0) def remove(self, iter_): record = self.get_value(iter_, 0) record.group.remove(record) self.invalidate_iters() def __move(self, record, path, offset=0): iter_ = self.get_iter(path) record_pos = self.get_value(iter_, 0) group = record_pos.group pos = group.index(record_pos) + offset if group is not record.group: prev_group = record.group record.group.remove(record, remove=True, force_remove=True) # Don't remove record from previous group # as the new parent will change the parent # This prevents concurrency conflict record.group.record_removed.remove(record) group.add(record) if not record.parent_name: record.modified_fields.setdefault(prev_group.parent_name) record.value[prev_group.parent_name] = None else: record.modified_fields.setdefault(record.parent_name) group.move(record, pos) def move_before(self, record, path): self.__move(record, path) def move_after(self, record, path): self.__move(record, path, 1) def move_into(self, record, path): iter_ = self.get_iter(path) parent = self.get_value(iter_, 0) group = parent.children_group(self.children_field) if group is not record.group: record.group.remove(record, remove=True, force_remove=True) # Don't remove record from previous group # as the new parent will change the parent # This prevents concurrency conflict if record in record.group.record_removed: record.group.record_removed.remove(record) group.add(record) record.modified_fields.setdefault(record.parent_name or 'id') group.move(record, 0) def sort(self, ids): old_idx = {record.id: i for i, record in enumerate(self.group)} new_idx = {id_: i for i, id_ in enumerate(ids)} size = len(self.group) self.group.sort(key=lambda r: new_idx.get(r.id, size)) new_order = [] prev = None for record in self.group: new_order.append(old_idx.get(record.id)) if prev: prev.next[id(self.group)] = record prev = record if prev: prev.next[id(self.group)] = None path = gtk.TreePath() # XXX pygobject does not allow to create empty TreePath, # it is always a path of 0 # see: https://bugzilla.gnome.org/show_bug.cgi?id=770665 if hasattr(path, 'get_depth'): while path.get_depth(): path.up() self.rows_reordered(path, None, new_order) def __len__(self): return len(self.group) def on_get_flags(self): if not self.children_field: return gtk.TREE_MODEL_LIST_ONLY return 0 def on_get_n_columns(self): # XXX return 1 def on_get_column_type(self, index): # XXX return gobject.TYPE_PYOBJECT def on_get_path(self, record): return record.get_index_path(self.group) def on_get_iter(self, path): group = self.group record = None for i in path: if group is None or i >= len(group): return None record = group[i] if not self.children_field: break group = record.children_group(self.children_field) return record def on_get_value(self, record, column): return record def on_iter_next(self, record): if record is None: return None return record.next.get(id(record.group)) def on_iter_has_child(self, record): if record is None or not self.children_field: return False children = record.children_group(self.children_field) if children is None: return False length = len(children) if self.__removed and self.__removed in children: length -= 1 return bool(length) def on_iter_children(self, record): if record is None: if self.group: return self.group[0] else: return None if self.children_field: children = record.children_group(self.children_field) if children: return children[0] return None def on_iter_n_children(self, record): if record is None: return len(self.group) if not self.children_field: return 0 return len(record.children_group(self.children_field)) def on_iter_nth_child(self, record, nth): if record is None: if nth < len(self.group): return self.group[nth] return None if not self.children_field: return None if nth < len(record.children_group(self.children_field)): return record.children_group(self.children_field)[nth] return None def on_iter_parent(self, record): if record is None: return None return record.parent class ViewTree(View): def __init__(self, screen, xml, children_field): super(ViewTree, self).__init__(screen, xml) self.view_type = 'tree' self.widgets = defaultdict(list) self.state_widgets = [] self.children_field = children_field self.sum_widgets = [] self.sum_box = gtk.HBox() if self.attributes.get('editable') and not screen.readonly: self.treeview = EditableTreeView(self.attributes['editable'], self) grid_lines = gtk.TREE_VIEW_GRID_LINES_BOTH else: self.treeview = TreeView(self) grid_lines = gtk.TREE_VIEW_GRID_LINES_VERTICAL self.mnemonic_widget = self.treeview self.parse(xml) self.treeview.set_property('rules-hint', True) self.treeview.set_property('enable-grid-lines', grid_lines) self.treeview.set_fixed_height_mode( all(c.get_sizing() == gtk.TREE_VIEW_COLUMN_FIXED for c in self.treeview.get_columns())) self.treeview.connect('button-press-event', self.__button_press) self.treeview.connect('key-press-event', self.on_keypress) self.treeview.connect_after('row-activated', self.__sig_switch) if self.children_field: self.treeview.connect('test-expand-row', self.test_expand_row) self.treeview.set_expander_column(self.treeview.get_column(0)) self.treeview.set_rubber_banding(True) selection = self.treeview.get_selection() selection.set_mode(gtk.SELECTION_MULTIPLE) selection.connect('changed', self.__select_changed) self.set_drag_and_drop() self.widget = gtk.VBox() self.scroll = scroll = gtk.ScrolledWindow() scroll.add(self.treeview) scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.set_placement(gtk.CORNER_TOP_LEFT) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN) viewport.add(scroll) self.widget.pack_start(viewport, expand=True, fill=True) self.sum_box.show() self.widget.pack_start(self.sum_box, expand=False, fill=False) self.display() def parse(self, xml): for node in xml.childNodes: if node.nodeType != node.ELEMENT_NODE: continue if node.tagName == 'field': self._parse_field(node) elif node.tagName == 'button': self._parse_button(node) self.add_last_column() def _parse_field(self, node): group = self.screen.group node_attrs = node_attributes(node) name = node_attrs['name'] field = group.fields[name] for b_field in ('readonly', 'expand'): if b_field in node_attrs: node_attrs[b_field] = bool(int(node_attrs[b_field])) for i_field in ('width', 'height'): if i_field in node_attrs: node_attrs[i_field] = int(node_attrs[i_field]) if 'widget' not in node_attrs: node_attrs['widget'] = field.attrs['type'] for attr in ('relation', 'domain', 'selection', 'relation_field', 'string', 'views', 'invisible', 'add_remove', 'sort', 'context', 'size', 'filename', 'autocomplete', 'translate', 'create', 'delete', 'selection_change_with', 'schema_model'): if (attr in field.attrs and attr not in node_attrs): node_attrs[attr] = field.attrs[attr] Widget = self.get_widget(node_attrs['widget']) widget = Widget(self, node_attrs) self.widgets[name].append(widget) column = gtk.TreeViewColumn(node_attrs['string']) column._type = 'field' column.name = name prefixes = [] suffixes = [] if node_attrs['widget'] in ('url', 'email', 'callto', 'sip'): prefixes.append(Affix(self, node_attrs, protocol=node_attrs['widget'])) if 'icon' in node_attrs: prefixes.append(Affix(self, node_attrs)) for affix in node.childNodes: affix_attrs = node_attributes(affix) if 'name' not in affix_attrs: affix_attrs['name'] = name if affix.tagName == 'prefix': list_ = prefixes else: list_ = suffixes list_.append(Affix(self, affix_attrs)) for prefix in prefixes: column.pack_start(prefix.renderer, expand=False) column.set_cell_data_func(prefix.renderer, prefix.setter) column.pack_start(widget.renderer, expand=True) column.set_cell_data_func(widget.renderer, widget.setter) for suffix in suffixes: column.pack_start(suffix.renderer, expand=False) column.set_cell_data_func(suffix.renderer, suffix.setter) self.set_column_widget(column, field, node_attrs, align=widget.align) self.set_column_width(column, field, node_attrs) if (not self.attributes.get('sequence') and not self.children_field and field.attrs.get('sortable', True)): column.connect('clicked', self.sort_model) self.treeview.append_column(column) self.add_sum(node_attrs) def _parse_button(self, node): node_attrs = node_attributes(node) widget = Button(self, node_attrs) self.state_widgets.append(widget) column = gtk.TreeViewColumn(node_attrs.get('string', ''), widget.renderer) column._type = 'button' column.name = None column.set_cell_data_func(widget.renderer, widget.setter) self.set_column_widget(column, None, node_attrs, arrow=False) self.set_column_width(column, None, node_attrs) decoder = PYSONDecoder(self.screen.context) column.set_visible( not decoder.decode(node_attrs.get('tree_invisible', '0'))) self.treeview.append_column(column) WIDGETS = { 'char': Char, 'many2one': M2O, 'date': Date, 'one2many': O2M, 'many2many': M2M, 'selection': Selection, 'float': Float, 'numeric': Float, 'timedelta': TimeDelta, 'integer': Int, 'biginteger': Int, 'time': Time, 'boolean': Boolean, 'text': Text, 'url': URL, 'email': URL, 'callto': URL, 'sip': URL, 'progressbar': ProgressBar, 'reference': Reference, 'one2one': O2O, 'binary': Binary, 'image': Image, } @classmethod def get_widget(cls, name): return cls.WIDGETS[name] def set_column_widget(self, column, field, attributes, arrow=True, align=0.5): hbox = gtk.HBox(False, 2) label = gtk.Label(attributes['string']) if field and self.editable: required = field.attrs.get('required') readonly = field.attrs.get('readonly') common.apply_label_attributes(label, readonly, required) label.show() help = None if field and field.attrs.get('help'): help = field.attrs['help'] elif attributes.get('help'): help = attributes['help'] if help: tooltips = Tooltips() tooltips.set_tip(label, help) tooltips.enable() if arrow: arrow_widget = gtk.Arrow(gtk.ARROW_NONE, gtk.SHADOW_NONE) arrow_widget.show() column.arrow = arrow_widget hbox.pack_start(label, True, True, 0) if arrow: hbox.pack_start(arrow_widget, False, False, 0) column.set_clickable(True) hbox.show() column.set_widget(hbox) column.set_alignment(align) def set_column_width(self, column, field, attributes): default_width = { 'integer': 60, 'biginteger': 60, 'float': 80, 'numeric': 80, 'timedelta': 100, 'date': 100, 'datetime': 100, 'time': 100, 'selection': 90, 'char': 100, 'one2many': 50, 'many2many': 50, 'boolean': 20, 'binary': 200, } width = self.screen.tree_column_width[self.screen.model_name].get( column.name) if not width: if 'width' in attributes: width = int(attributes['width']) elif field: width = default_width.get(field.attrs['type'], 100) else: width = 80 column.width = width if width > 0: column.set_fixed_width(width) column.set_min_width(1) expand = attributes.get('expand', False) column.set_expand(expand) column.set_resizable(True) if attributes.get('widget') != 'text': column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) def get_column_widget(self, column): 'Return the widget of the column' idx = [c for c in self.treeview.get_columns() if c.name == column.name].index(column) return self.widgets[column.name][idx] def add_sum(self, attributes): if 'sum' not in attributes: return text = attributes['sum'] + _(':') label, sum_ = gtk.Label(text), gtk.Label() hbox = gtk.HBox() hbox.pack_start(label, expand=True, fill=False, padding=2) hbox.pack_start(sum_, expand=True, fill=False, padding=2) hbox.show_all() self.sum_box.pack_start(hbox, expand=False, fill=False) self.sum_widgets.append((attributes['name'], sum_)) def sort_model(self, column): for col in self.treeview.get_columns(): if col != column and getattr(col, 'arrow', None): col.arrow.set(gtk.ARROW_NONE, gtk.SHADOW_NONE) self.screen.order = self.screen.default_order if column.arrow.props.arrow_type == gtk.ARROW_NONE: column.arrow.set(gtk.ARROW_DOWN, gtk.SHADOW_IN) self.screen.order = [(column.name, 'ASC')] else: if column.arrow.props.arrow_type == gtk.ARROW_DOWN: column.arrow.set(gtk.ARROW_UP, gtk.SHADOW_IN) self.screen.order = [(column.name, 'DESC')] else: column.arrow.set(gtk.ARROW_NONE, gtk.SHADOW_NONE) model = self.treeview.get_model() unsaved_records = [x for x in model.group if x.id < 0] search_string = self.screen.screen_container.get_text() or '' if (self.screen.search_count == len(model) or unsaved_records or self.screen.parent): ids = self.screen.search_filter( search_string=search_string, only_ids=True) model.sort(ids) else: self.screen.search_filter(search_string=search_string) def add_last_column(self): for column in self.treeview.get_columns(): if column.get_expand(): break else: column = gtk.TreeViewColumn() column._type = 'fill' column.name = None column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) self.treeview.append_column(column) def set_drag_and_drop(self): dnd = False if self.children_field: children = self.screen.group.fields.get(self.children_field) if children: parent_name = children.attrs.get('relation_field') dnd = parent_name in self.widgets elif self.attributes.get('sequence'): dnd = True # Disable DnD on mac until it is fully supported if sys.platform == 'darwin': dnd = False if self.screen.readonly: dnd = False if not dnd: return self.treeview.enable_model_drag_dest( [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0)], gtk.gdk.ACTION_MOVE) self.treeview.enable_model_drag_source( gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, [('MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0)], gtk.gdk.ACTION_MOVE) # XXX have to set manually because enable_model_drag_source # does not set the mask # https://bugzilla.gnome.org/show_bug.cgi?id=756177 self.treeview.drag_source_set( gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, [gtk.TargetEntry.new( 'MY_TREE_MODEL_ROW', gtk.TARGET_SAME_WIDGET, 0)], gtk.gdk.ACTION_MOVE) self.treeview.connect("drag-data-get", self.drag_data_get) self.treeview.connect('drag-data-received', self.drag_data_received) self.treeview.connect('drag-drop', self.drag_drop) self.treeview.connect('drag-data-delete', self.drag_data_delete) @property def modified(self): return False @property def editable(self): return (bool(getattr(self.treeview, 'editable', False)) and not self.screen.readonly) def get_fields(self): return [col.name for col in self.treeview.get_columns() if col.name] def get_buttons(self): return [b for b in self.state_widgets if isinstance(b.renderer, CellRendererButton)] def on_keypress(self, widget, event): control_mask = gtk.gdk.CONTROL_MASK if sys.platform == 'darwin': control_mask = gtk.gdk.MOD2_MASK if (event.keyval == gtk.keysyms.c and event.state & control_mask): self.on_copy() return False if (event.keyval == gtk.keysyms.v and event.state & control_mask): self.on_paste() return False def test_expand_row(self, widget, iter_, path): model = widget.get_model() if model.iter_n_children(iter_) > CONFIG['client.limit']: self.screen.current_record = model.get_value(iter_, 0) self.screen.switch_view('form') return True iter_ = model.iter_children(iter_) if not iter_: return False fields = [col.name for col in self.treeview.get_columns() if col.name] while iter_: record = model.get_value(iter_, 0) if not record.get_loaded(fields): for field in fields: record[field] if record.exception: return True iter_ = model.iter_next(iter_) return False def on_copy(self): for clipboard_type in (gtk.gdk.SELECTION_CLIPBOARD, gtk.gdk.SELECTION_PRIMARY): clipboard = self.treeview.get_clipboard(clipboard_type) selection = self.treeview.get_selection() data = [] selection.selected_foreach(self.copy_foreach, data) clipboard.set_text('\n'.join(data), -1) def copy_foreach(self, treemodel, path, iter, data): record = treemodel.get_value(iter, 0) values = [] for col in self.treeview.get_columns(): if not col.get_visible() or not col.name: continue widget = self.get_column_widget(col) values.append('"' + str(widget.get_textual_value(record)).replace('"', '""') + '"') data.append('\t'.join(values)) return def on_paste(self): if not self.editable: return def unquote(value): if value[:1] == '"' and value[-1:] == '"': return value[1:-1] return value data = [] for clipboard_type in (gtk.gdk.SELECTION_CLIPBOARD, gtk.gdk.SELECTION_PRIMARY): clipboard = self.treeview.get_clipboard(clipboard_type) text = clipboard.wait_for_text() if not text: continue data = [[unquote(v) for v in l.split('\t')] for l in text.splitlines()] break col = self.treeview.get_cursor()[1] columns = [c for c in self.treeview.get_columns() if c.get_visible() and c.name] if col in columns: idx = columns.index(col) columns = columns[idx:] if self.screen.current_record: record = self.screen.current_record group = record.group idx = group.index(record) else: group = self.screen.group idx = len(group) default = None for line in data: if idx >= len(group): record = group.new(default=False) if default is None: default = record.default_get() record.set_default(default) group.add(record) record = group[idx] for col, value in zip(columns, line): widget = self.get_column_widget(col) if widget.get_textual_value(record) != value: widget.value_from_text(record, value) if value and not widget.get_textual_value(record): # Stop setting value if a value is correctly set idx = len(group) break if not record.validate(): break idx += 1 self.screen.current_record = record self.screen.display(set_cursor=True) def drag_data_get(self, treeview, context, selection, target_id, etime): treeview.emit_stop_by_name('drag-data-get') def _func_sel_get(model, path, iter_, data): value = model.get_value(iter_, 0) data.append(json.dumps( value.get_path(model.group), separators=(',', ':'))) data = [] treeselection = treeview.get_selection() treeselection.selected_foreach(_func_sel_get, data) if not data: return selection.set(selection.get_target(), 8, data[0].encode('utf-8')) return True def drag_data_received(self, treeview, context, x, y, selection, info, etime): treeview.emit_stop_by_name('drag-data-received') if self.attributes.get('sequence'): field = self.screen.group.fields[self.attributes['sequence']] for record in self.screen.group: if field.get_state_attrs( record).get('readonly', False): return try: selection_data = selection.data except AttributeError: selection_data = selection.get_data() if not selection_data: return selection_data = selection_data.decode('utf-8') # Don't received if the treeview was editing because it breaks the # internal state of the cursor. cursor, column = treeview.get_cursor() if column: for renderer in column.get_cell_renderers(): if renderer.props.editing: return model = treeview.get_model() try: data = json.loads(selection_data) except ValueError: return record = model.group.get_by_path(data) record_path = record.get_index_path(model.group) drop_info = treeview.get_dest_row_at_pos(x, y) def check_recursion(from_, to): if not from_ or not to: return True if from_ == to: return False length = min(len(from_), len(to)) if len(from_) < len(to) and from_[:length] == to[:length]: return False return True if drop_info: path, position = drop_info check_path = tuple(path) if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_AFTER): check_path = path[:-1] if not check_recursion(record_path, check_path): return if position == gtk.TREE_VIEW_DROP_BEFORE: model.move_before(record, path) elif position == gtk.TREE_VIEW_DROP_AFTER: model.move_after(record, path) elif self.children_field: model.move_into(record, path) else: model.move_after(record, (len(model) - 1,)) if hasattr(gtk.gdk, 'drop_finish'): gtk.gdk.drop_finish(context, False, etime) else: context.drop_finish(False, etime) selection = self.treeview.get_selection() selection.unselect_all() selection.select_path(record.get_index_path(model.group)) if self.attributes.get('sequence'): record.group.set_sequence(field=self.attributes['sequence']) return True def drag_drop(self, treeview, context, x, y, time): treeview.emit_stop_by_name('drag-drop') targets = treeview.drag_dest_get_target_list() target = treeview.drag_dest_find_target(context, targets) treeview.drag_get_data(context, target, time) return True def drag_data_delete(self, treeview, context): treeview.emit_stop_by_name('drag-data-delete') def __button_press(self, treeview, event): if event.button == 3: try: path, col, x, y = treeview.get_path_at_pos( int(event.x), int(event.y)) except TypeError: # Outside row return False menu = gtk.Menu() copy_item = gtk.ImageMenuItem('gtk-copy') copy_item.set_use_stock(True) copy_item.connect('activate', lambda x: self.on_copy()) menu.append(copy_item) if self.editable: paste_item = gtk.ImageMenuItem('gtk-paste') paste_item.set_use_stock(True) paste_item.connect('activate', lambda x: self.on_paste()) menu.append(paste_item) menu.show_all() menu.popup(None, None, None, event.button, event.time) def pop(menu, group, record): # Don't activate actions if parent is modified parent = record.parent if record else None while parent: if parent.modified: break parent = parent.parent else: populate(menu, group.model_name, record) for col in self.treeview.get_columns(): if not col.get_visible() or not col.name: continue field = group.fields[col.name] model = None if field.attrs['type'] == 'many2one': model = field.attrs['relation'] record_id = field.get(record) elif field.attrs['type'] == 'reference': value = field.get(record) if value: model, record_id = value.split(',') record_id = int(record_id) if not model: continue label = field.attrs['string'] context = field.get_context(record) populate( menu, model, record_id, title=label, field=field, context=context) menu.show_all() selection = treeview.get_selection() if selection.count_selected_rows() == 1: group = self.screen.group if selection.get_mode() == gtk.SELECTION_SINGLE: model = selection.get_selected()[0] elif selection.get_mode() == gtk.SELECTION_MULTIPLE: model = selection.get_selected_rows()[0] record = model.get_value(model.get_iter(path), 0) # Delay filling of popup as it can take time gobject.idle_add(pop, menu, group, record) return True # Don't change the selection elif event.button == 2: with Window(allow_similar=True): self.screen.row_activate() return True return False def group_list_changed(self, group, signal): model = self.treeview.get_model() if model is not None: if signal[0] == 'record-added': model.added(group, signal[1]) elif signal[0] == 'record-removed': model.removed(group, signal[1]) self.display() def __str__(self): return 'ViewList (%d)' % id(self) def __getitem__(self, name): return None def save_width_height(self): if not CONFIG['client.save_width_height']: return fields = {} last_col = None for col in self.treeview.get_columns(): if col.get_visible(): last_col = col if not hasattr(col, 'name') or not hasattr(col, 'width'): continue if (col.get_width() != col.width and col.get_visible() and not col.get_expand()): fields[col.name] = col.get_width() # Don't set width for last visible columns # as it depends of the screen size if last_col and last_col.name in fields: del fields[last_col.name] if fields and any(fields.values()): model_name = self.screen.model_name try: RPCExecute('model', 'ir.ui.view_tree_width', 'set_width', model_name, fields) except RPCException: pass self.screen.tree_column_width[model_name].update(fields) def destroy(self): self.save_width_height() self.treeview.destroy() def __sig_switch(self, treeview, path, column): if column._type == 'button': return allow_similar = False event = gtk.get_current_event() if (event.state & gtk.gdk.MOD1_MASK or event.state & gtk.gdk.SHIFT_MASK): allow_similar = True with Window(allow_similar=allow_similar): if not self.screen.row_activate() and self.children_field: if treeview.row_expanded(path): treeview.collapse_row(path) else: treeview.expand_row(path, False) def __select_changed(self, tree_sel): previous_record = self.screen.current_record if previous_record and previous_record not in previous_record.group: previous_record = None if tree_sel.get_mode() == gtk.SELECTION_SINGLE: model, iter_ = tree_sel.get_selected() if model and iter_: record = model.get_value(iter_, 0) self.screen.current_record = record else: self.screen.current_record = None elif tree_sel.get_mode() == gtk.SELECTION_MULTIPLE: model, paths = tree_sel.get_selected_rows() if model and paths: iter_ = model.get_iter(paths[0]) record = model.get_value(iter_, 0) self.screen.current_record = record else: self.screen.current_record = None if self.editable and previous_record: def go_previous(): self.screen.current_record = previous_record self.set_cursor() if (not self.screen.parent and previous_record != self.screen.current_record): def save(): if not previous_record.destroyed: if not previous_record.save(): go_previous() if not previous_record.validate(self.get_fields()): go_previous() return True # Delay the save to let GTK process the current event gobject.idle_add(save) elif (previous_record != self.screen.current_record and self.screen.pre_validate): def pre_validate(): if not previous_record.destroyed: if not previous_record.pre_validate(): go_previous() # Delay the pre_validate to let GTK process the current event gobject.idle_add(pre_validate) self.update_sum() def set_value(self): if self.editable: self.treeview.set_value() def reset(self): pass def display(self, force=False): self.treeview.display_counter += 1 current_record = self.screen.current_record if (force or not self.treeview.get_model() or (self.screen.group != self.treeview.get_model().group)): model = AdaptModelGroup(self.screen.group, self.children_field) self.treeview.set_model(model) # __select_changed resets current_record to None self.screen.current_record = current_record if current_record: selection = self.treeview.get_selection() path = current_record.get_index_path(model.group) selection.select_path(path) if not current_record: selection = self.treeview.get_selection() selection.unselect_all() self.treeview.queue_draw() if self.editable: self.set_state() self.update_sum() # Set column visibility depending on attributes and domain domain = [] if self.screen.domain: domain.append(self.screen.domain) tab_domain = self.screen.screen_container.get_tab_domain() if tab_domain: domain.append(tab_domain) domain = simplify(domain) decoder = PYSONDecoder(self.screen.context) for column in self.treeview.get_columns(): name = column.name if not name: continue widget = self.get_column_widget(column) if decoder.decode(widget.attrs.get('tree_invisible', '0')): column.set_visible(False) elif name == self.screen.exclude_field: column.set_visible(False) else: inv_domain = domain_inversion(domain, name) if not isinstance(inv_domain, bool): inv_domain = simplify(inv_domain) unique, _, _ = unique_value(inv_domain) column.set_visible(not unique or bool(self.children_field)) def set_state(self): record = self.screen.current_record if record: for field in record.group.fields: field = record.group.fields.get(field, None) if field: field.state_set(record) @delay def update_sum(self): selected_records = self.selected_records for name, label in self.sum_widgets: sum_ = None selected_sum = None loaded = True digit = 0 field = self.screen.group.fields[name] for record in self.screen.group: if not record.get_loaded([name]) and record.id >= 0: loaded = False break value = field.get(record) if value is not None: if sum_ is None: sum_ = value else: sum_ += value if record in selected_records or not selected_records: if selected_sum is None: selected_sum = value else: selected_sum += value if hasattr(field, 'digits'): fdigits = field.digits(record) if fdigits and digit is not None: digit = max(fdigits[1], digit) else: digit = None if loaded: if field.attrs['type'] == 'timedelta': converter = field.converter(self.screen.group) selected_sum = common.timedelta.format( selected_sum, converter) sum_ = common.timedelta.format(sum_, converter) elif digit: selected_sum = locale.format( '%.*f', (digit, selected_sum or 0), True) sum_ = locale.format('%.*f', (digit, sum_ or 0), True) else: selected_sum = locale.format( '%s', selected_sum or 0, True) sum_ = locale.format('%s', sum_ or 0, True) text = '%s / %s' % (selected_sum, sum_) else: text = '-' label.set_text(text) def set_cursor(self, new=False, reset_view=True): self.treeview.grab_focus() model = self.treeview.get_model() if self.screen.current_record and model: path = self.screen.current_record.get_index_path(model.group) if model.get_flags() & gtk.TREE_MODEL_LIST_ONLY: path = (path[0],) focus_column = self.treeview.next_column(path, editable=new) if path[:-1]: self.treeview.expand_to_path(gtk.TreePath(path[:-1])) self.treeview.scroll_to_cell(path, focus_column, use_align=False) current_path = self.treeview.get_cursor()[0] selected_path = \ self.treeview.get_selection().get_selected_rows()[1] path = gtk.TreePath(path) if (current_path != path and path not in selected_path) or new: self.treeview.set_cursor(path, focus_column, new) @property def selected_records(self): def _func_sel_get(model, path, iter_, records): records.append(model.get_value(iter_, 0)) records = [] sel = self.treeview.get_selection() sel.selected_foreach(_func_sel_get, records) return records def get_selected_paths(self): selection = self.treeview.get_selection() model, rows = selection.get_selected_rows() id_paths = [] for row in rows: path = () id_path = [] for node in row: path += (node,) iter_ = model.get_iter(path) id_path.append(model.get_value(iter_, 0).id) id_paths.append(id_path) return id_paths def select_nodes(self, nodes): selection = self.treeview.get_selection() if not nodes: return selection.unselect_all() scroll = False model = self.treeview.get_model() for node in nodes: path = path_convert_id2pos(model, node) if path: selection.select_path(gtk.TreePath(path)) if not scroll: self.treeview.scroll_to_cell(path) scroll = True def get_expanded_paths(self, starting_path=None, starting_id_path=None): # Use id instead of position # because the position may change between load if not starting_path: starting_path = tuple() if not starting_id_path: starting_id_path = [] id_paths = [] model = self.treeview.get_model() if starting_path: iter_ = model.get_iter(gtk.TreePath(starting_path)) else: iter_ = None for path_idx in range(model.iter_n_children(iter_)): path = starting_path + (path_idx,) expanded = self.treeview.row_expanded(gtk.TreePath(path)) if expanded: iter_ = model.get_iter(path) expanded_record = model.get_value(iter_, 0) id_path = starting_id_path + [expanded_record.id] id_paths.append(id_path) child_id_paths = self.get_expanded_paths(path, id_path) id_paths += child_id_paths return id_paths def expand_nodes(self, nodes): model = self.treeview.get_model() for node in nodes: expand_path = path_convert_id2pos(model, node) if expand_path: self.treeview.expand_to_path(gtk.TreePath(expand_path)) tryton-5.0.17/tryton/gui/window/view_form/view/calendar_.py0000644000175000017500000001143613463252532023350 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from functools import wraps import gtk import datetime import gettext from tryton.common import node_attributes from . import View try: from .calendar_gtk.calendar_ import Calendar_ from .calendar_gtk.toolbar import Toolbar except ImportError as e: Calendar_ = None Toolbar = None _ = gettext.gettext def goocalendar_required(func): "Decorator for goocalendar required" @wraps(func) def wrapper(self, *args, **kwargs): if 'goocalendar' not in self.widgets: return return func(self, *args, **kwargs) return wrapper class ViewCalendar(View): def __init__(self, screen, xml): super(ViewCalendar, self).__init__(screen, xml) self.view_type = 'calendar' self.editable = False self.widgets = {} self.widget = self.parse(xml) def parse(self, node): vbox = gtk.VBox() if not Calendar_: return vbox fields = [] for node in node.childNodes: if node.nodeType != node.ELEMENT_NODE: continue if node.tagName == 'field': fields.append(node_attributes(node)) goocalendar = Calendar_(attrs=self.attributes, screen=self.screen, fields=fields) toolbar = Toolbar(goocalendar) self.widgets['toolbar'] = toolbar goocalendar.connect('view-changed', self.on_view_changed, toolbar) goocalendar.connect('page-changed', self.on_page_changed, toolbar) goocalendar.connect('event-pressed', self.on_event_pressed) goocalendar.connect('event-activated', self.on_event_activated) goocalendar.connect('event-released', self.on_event_released) goocalendar.connect('day-pressed', self.on_day_pressed) goocalendar.connect('day-activated', self.on_day_activated) self.widgets['goocalendar'] = goocalendar self.scroll = scrolledWindow = gtk.ScrolledWindow() scrolledWindow.add_with_viewport(goocalendar) vbox.pack_start(toolbar, False, False) vbox.pack_start(scrolledWindow, True, True) return vbox def on_page_changed(self, goocalendar, day, toolbar): toolbar.update_displayed_date() if goocalendar.update_domain(): self.screen.search_filter() def on_view_changed(self, goocalendar, view, toolbar): toolbar.update_displayed_date() if goocalendar.update_domain(): self.screen.search_filter() def on_event_pressed(self, goocalendar, event): self.screen.current_record = event.record def on_event_activated(self, goocalendar, event): self.screen.switch_view('form') def on_event_released(self, goocalendar, event): dtstart = self.attributes['dtstart'] dtend = self.attributes.get('dtend') record = event.record group = record.group previous_start = record[dtstart].get(record) new_start = event.start new_end = event.end if not isinstance(previous_start, datetime.datetime): new_start = event.start.date() new_end = event.end.date() if event.end else None if previous_start <= new_start: if dtend: group.fields[dtend].set_client(record, new_end) group.fields[dtstart].set_client(record, new_start) else: group.fields[dtstart].set_client(record, new_start) if dtend: group.fields[dtend].set_client(record, new_end) goocalendar.select(new_start) record.save() def on_day_pressed(self, goocalendar, day): self.screen.current_record = None def on_day_activated(self, goocalendar, day): self.screen.new() def __getitem__(self, name): return None @goocalendar_required def destroy(self): self.widget.destroy() self.widgets['goocalendar'].destroy() @goocalendar_required def get_selected_date(self): return self.widgets['goocalendar'].selected_date @goocalendar_required def set_default_date(self, record, selected_date): self.widgets['goocalendar'].set_default_date(record, selected_date) def current_domain(self): if 'goocalendar' in self.widgets: return self.widgets['goocalendar'].current_domain() else: # No need to load any record as nothing will be shown return [('id', '=', -1)] def set_value(self): pass def reset(self): pass @goocalendar_required def display(self): self.widgets['goocalendar'].display(self.screen.group) def set_cursor(self, new=False, reset_view=True): pass def get_fields(self): return [] tryton-5.0.17/tryton/gui/window/view_form/view/__init__.py0000644000175000017500000000261613463252532023177 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from tryton.common import node_attributes class View(object): view_type = None widget = None mnemonic_widget = None view_id = None modified = None editable = None children_field = None scroll = None def __init__(self, screen, xml): self.screen = screen self.fields = {} self.attributes = node_attributes(xml) screen.set_on_write(self.attributes.get('on_write')) def set_value(self): raise NotImplementedError def get_fields(self): raise NotImplementedError @property def selected_records(self): return [] def get_buttons(self): raise NotImplementedError @staticmethod def parse(screen, xml, children_field): from .list import ViewTree from .form import ViewForm from .graph import ViewGraph from .calendar_ import ViewCalendar root, = xml.childNodes tagname = root.tagName if tagname == 'tree': return ViewTree(screen, root, children_field) elif tagname == 'form': return ViewForm(screen, root) elif tagname == 'graph': return ViewGraph(screen, root) elif tagname == 'calendar': return ViewCalendar(screen, root) tryton-5.0.17/tryton/gui/window/view_form/view/screen_container.py0000644000175000017500000006277713463252532024777 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import datetime import gtk import gettext import gobject import tryton.common as common from tryton.gui import Main from tryton.common.domain_parser import quote from tryton.common.treeviewcontrol import TreeViewControl from tryton.common.datetime_ import Date, Time, DateTime, add_operators from tryton.pyson import PYSONDecoder _ = gettext.gettext class Dates(gtk.HBox): def __init__(self, format_=None, _entry=Date): super(Dates, self).__init__() self.from_ = add_operators(_entry()) self.pack_start(self.from_, expand=True, fill=True) self.pack_start(gtk.Label(_('..')), expand=False, fill=False) self.to = add_operators(_entry()) self.pack_start(self.to, expand=True, fill=True) if format_: self.from_.props.format = format_ self.to.props.format = format_ def _get_value(self, widget): value = widget.props.value if value: return common.datetime_strftime(value, widget.props.format) def get_value(self): from_ = self._get_value(self.from_) to = self._get_value(self.to) if from_ and to: if from_ != to: return '%s..%s' % (quote(from_), quote(to)) else: return quote(from_) elif from_: return '>=%s' % quote(from_) elif to: return '<=%s' % quote(to) @property def _widgets(self): return [self.from_, self.to] def connect_activate(self, callback): for widget in self._widgets: if isinstance(widget, Date): widget.connect('activate', callback) elif isinstance(widget, Time): widget.get_child().connect('activate', callback) def connect_combo(self, callback): for widget in self._widgets: if isinstance(widget, Time): widget.connect('notify::popup-shown', callback) def set_values(self, from_, to): self.from_.props.value = from_ self.to.props.value = to class Times(Dates): def __init__(self, format_, _entry=Time): super(Times, self).__init__(_entry=_entry) def _get_value(self, widget): value = widget.props.value if value: return datetime.time.strftime(value, widget.props.format) class DateTimes(Dates): def __init__(self, date_format, time_format, _entry=DateTime): super(DateTimes, self).__init__(_entry=_entry) self.from_.props.date_format = date_format self.to.props.date_format = date_format self.from_.props.time_format = time_format self.to.props.time_format = time_format def _get_value(self, widget): value = widget.props.value if value: return common.datetime_strftime(value, widget.props.date_format + ' ' + widget.props.time_format) @property def _widgets(self): return self.from_.get_children() + self.to.get_children() class Selection(gtk.ScrolledWindow): def __init__(self, selections): super(Selection, self).__init__() self.treeview = TreeViewControl() model = gtk.ListStore(gobject.TYPE_STRING) for selection in selections: model.append((selection,)) self.treeview.set_model(model) column = gtk.TreeViewColumn() cell = gtk.CellRendererText() column.pack_start(cell) column.add_attribute(cell, 'text', 0) self.treeview.append_column(column) self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.treeview.set_headers_visible(False) self.add(self.treeview) self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.set_shadow_type(gtk.SHADOW_ETCHED_IN) self.set_min_content_height(min(20 * len(selections), 200)) self.set_max_content_height(200) def get_value(self): values = [] model, paths = self.treeview.get_selection().get_selected_rows() if not paths: return for path in paths: iter_ = model.get_iter(path) values.append(model.get_value(iter_, 0)) return ';'.join(quote(v) for v in values) class ScreenContainer(object): def __init__(self, tab_domain): self.viewport = gtk.Viewport() self.viewport.set_shadow_type(gtk.SHADOW_NONE) self.vbox = gtk.VBox(spacing=3) self.alternate_viewport = gtk.Viewport() self.alternate_viewport.set_shadow_type(gtk.SHADOW_NONE) self.alternate_view = False self.search_window = None self.search_table = None self.last_search_text = '' self.tab_domain = tab_domain or [] self.tab_counter = [] tooltips = common.Tooltips() self.filter_vbox = gtk.VBox(spacing=0) self.filter_vbox.set_border_width(0) hbox = gtk.HBox(homogeneous=False, spacing=0) self.search_entry = gtk.Entry() self.search_entry.set_placeholder_text(_('Search')) self.search_entry.set_alignment(0.0) self.search_entry.set_icon_from_pixbuf( gtk.ENTRY_ICON_PRIMARY, common.IconFactory.get_pixbuf('tryton-filter', gtk.ICON_SIZE_MENU)) self.search_entry.set_icon_tooltip_text( gtk.ENTRY_ICON_PRIMARY, _('Open filters')) self.completion = gtk.EntryCompletion() self.completion.set_model(gtk.ListStore(str)) self.completion.set_text_column(0) self.completion.props.inline_selection = True self.completion.props.popup_set_width = False self.completion.set_match_func(lambda *a: True) self.completion.connect('match-selected', self.match_selected) self.search_entry.connect('activate', self.activate) self.search_entry.set_completion(self.completion) self.search_entry.connect('key-press-event', self.key_press) self.search_entry.connect('focus-in-event', self.focus_in) self.search_entry.connect('icon-press', self.icon_press) hbox.pack_start(self.search_entry, expand=True, fill=True) def popup(widget): menu = widget._menu for child in menu.get_children(): menu.remove(child) if not widget.props.active: menu.popdown() return def menu_position(menu, data=None): widget_allocation = widget.get_allocation() if hasattr(widget.window, 'get_root_coords'): x, y = widget.window.get_root_coords( widget_allocation.x, widget_allocation.y) else: x, y = widget.window.get_origin() x += widget_allocation.x y += widget_allocation.y return (x, y + widget_allocation.height, False) for id_, name, domain in self.bookmarks(): menuitem = gtk.MenuItem(name) menuitem.connect('activate', self.bookmark_activate, domain) menu.add(menuitem) menu.show_all() menu.popup(None, None, menu_position, 0, 0) def deactivate(menuitem, togglebutton): togglebutton.props.active = False but_active = gtk.ToggleButton() self.but_active = but_active self._set_active_tooltip() but_active.add(common.IconFactory.get_image( 'tryton-archive', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_active.set_relief(gtk.RELIEF_NONE) but_active.connect('toggled', self.search_active) hbox.pack_start(but_active, expand=False, fill=False) but_bookmark = gtk.ToggleButton() self.but_bookmark = but_bookmark tooltips.set_tip(but_bookmark, _('Show bookmarks of filters')) but_bookmark.add(common.IconFactory.get_image( 'tryton-bookmarks', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_bookmark.set_relief(gtk.RELIEF_NONE) menu = gtk.Menu() menu.set_property('reserve-toggle-size', False) menu.connect('deactivate', deactivate, but_bookmark) but_bookmark._menu = menu but_bookmark.connect('toggled', popup) hbox.pack_start(but_bookmark, expand=False, fill=False) but_prev = gtk.Button() self.but_prev = but_prev tooltips.set_tip(but_prev, _('Previous')) but_prev.connect('clicked', self.search_prev) but_prev.add(common.IconFactory.get_image( 'tryton-back', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_prev.set_relief(gtk.RELIEF_NONE) hbox.pack_start(but_prev, expand=False, fill=False) but_next = gtk.Button() self.but_next = but_next tooltips.set_tip(but_next, _('Next')) but_next.connect('clicked', self.search_next) but_next.add(common.IconFactory.get_image( 'tryton-forward', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_next.set_relief(gtk.RELIEF_NONE) hbox.pack_start(but_next, expand=False, fill=False) hbox.show_all() hbox.set_focus_chain([self.search_entry]) self.filter_vbox.pack_start(hbox, expand=False, fill=False) hseparator = gtk.HSeparator() hseparator.show() self.filter_vbox.pack_start(hseparator, expand=False, fill=False) if self.tab_domain: self.notebook = gtk.Notebook() try: self.notebook.props.homogeneous = True except AttributeError: # No more supported by GTK+3 pass self.notebook.set_scrollable(True) for name, domain, count in self.tab_domain: hbox = gtk.HBox(spacing=3) label = gtk.Label('_' + name) label.set_use_underline(True) hbox.pack_start(label, expand=True, fill=True) counter = gtk.Label() hbox.pack_start(counter, expand=False, fill=True) hbox.show_all() self.notebook.append_page(gtk.VBox(), hbox) self.tab_counter.append(counter) self.filter_vbox.pack_start(self.notebook, expand=True, fill=True) self.notebook.show_all() # Set the current page before connecting to switch-page to not # trigger the search a second times. self.notebook.set_current_page(0) self.notebook.get_nth_page(0).pack_end(self.viewport) self.notebook.connect('switch-page', self.switch_page) self.notebook.connect_after('switch-page', self.switch_page_after) filter_expand = True else: self.notebook = None self.vbox.pack_end(self.viewport) filter_expand = False self.vbox.pack_start(self.filter_vbox, expand=filter_expand, fill=True) self.but_next.set_sensitive(False) self.but_prev.set_sensitive(False) tooltips.enable() def destroy(self): if self.search_window: self.search_window.hide() def widget_get(self): return self.vbox def set_screen(self, screen): self.screen = screen self.but_bookmark.set_sensitive(bool(list(self.bookmarks()))) self.bookmark_match() def show_filter(self): if self.filter_vbox: self.filter_vbox.show() if self.notebook: self.notebook.set_show_tabs(True) if self.viewport in self.vbox.get_children(): self.vbox.remove(self.viewport) self.notebook.get_nth_page(self.notebook.get_current_page() ).pack_end(self.viewport) def hide_filter(self): if self.filter_vbox: self.filter_vbox.hide() if self.notebook: self.notebook.set_show_tabs(False) if self.viewport not in self.vbox.get_children(): self.notebook.get_nth_page(self.notebook.get_current_page() ).remove(self.viewport) self.vbox.pack_end(self.viewport) def set(self, widget): viewport1 = self.viewport viewport2 = self.alternate_viewport if self.alternate_view: viewport1, viewport2 = viewport2, viewport1 if viewport1.get_child(): viewport1.remove(viewport1.get_child()) if widget == viewport2.get_child(): viewport2.remove(widget) viewport1.add(widget) viewport1.show_all() def update(self): res = self.screen.search_complete(self.get_text()) model = self.completion.get_model() model.clear() for r in res: model.append([r.strip()]) def get_text(self): return self.search_entry.get_text() def set_text(self, value): self.search_entry.set_text(value) self.bookmark_match() def bookmarks(self): for id_, name, domain in common.VIEW_SEARCH[self.screen.model_name]: if self.screen.domain_parser.stringable(domain): yield id_, name, domain def bookmark_activate(self, menuitem, domain): self.set_text(self.screen.domain_parser.string(domain)) self.do_search() def bookmark_match(self): current_text = self.get_text() if current_text: current_domain = self.screen.domain_parser.parse(current_text) self.search_entry.set_icon_activatable(gtk.ENTRY_ICON_SECONDARY, bool(current_text)) self.search_entry.set_icon_sensitive(gtk.ENTRY_ICON_SECONDARY, bool(current_text)) for id_, name, domain in self.bookmarks(): text = self.screen.domain_parser.string(domain) domain = self.screen.domain_parser.parse(text) if (text == current_text or domain == current_domain): self.search_entry.set_icon_from_pixbuf( gtk.ENTRY_ICON_SECONDARY, common.IconFactory.get_pixbuf( 'tryton-bookmark', gtk.ICON_SIZE_MENU)) self.search_entry.set_icon_tooltip_text( gtk.ENTRY_ICON_SECONDARY, _('Remove this bookmark')) return id_ self.search_entry.set_icon_from_pixbuf( gtk.ENTRY_ICON_SECONDARY, common.IconFactory.get_pixbuf( 'tryton-bookmark-border', gtk.ICON_SIZE_MENU)) if current_text: self.search_entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY, _('Bookmark this filter')) elif self.search_entry.get_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY): self.search_entry.set_icon_tooltip_text(gtk.ENTRY_ICON_SECONDARY, None) def search_next(self, widget=None): self.screen.search_next(self.get_text()) def search_prev(self, widget=None): self.screen.search_prev(self.get_text()) def search_active(self, widget=None): self._set_active_tooltip() self.screen.search_filter(self.get_text()) def _set_active_tooltip(self): if self.but_active.get_active(): tooltip = _('Show active records') else: tooltip = _('Show inactive records') tooltips = common.Tooltips() tooltips.set_tip(self.but_active, tooltip) def switch_page(self, notebook, page, page_num): current_page = notebook.get_nth_page(notebook.get_current_page()) current_page.remove(self.viewport) new_page = notebook.get_nth_page(page_num) new_page.pack_end(self.viewport) def switch_page_after(self, notebook, page, page_num): self.do_search() notebook.grab_focus() self.screen.count_tab_domain() def get_tab_domain(self): if not self.notebook: return [] idx = self.notebook.get_current_page() if idx < 0: return [] return self.tab_domain[idx][1] def set_tab_counter(self, count, idx=None): if not self.tab_counter or not self.notebook: return if idx is None: idx = self.notebook.get_current_page() if idx < 0: return label = self.tab_counter[idx] tooltip = common.Tooltips() if count is None: label.set_label('') tooltip.set_tip(label, '') else: tooltip.set_tip(label, '%d' % count) fmt = '(%d)' if count > 99: fmt = '(%d+)' count = 99 label.set_label(fmt % count) def match_selected(self, completion, model, iter): def callback(): if not self.search_entry.props.window: return self.update() self.search_entry.emit('changed') gobject.idle_add(callback) def activate(self, widget): if not self.search_entry.get_selection_bounds(): self.do_search(widget) def do_search(self, widget=None): self.screen.search_filter(self.get_text()) def set_cursor(self, new=False, reset_view=True): if self.filter_vbox: self.search_entry.grab_focus() def key_press(self, widget, event): def keypress(): if not self.search_entry.props.window: return self.update() self.bookmark_match() gobject.idle_add(keypress) def icon_press(self, widget, icon_pos, event): if icon_pos == gtk.ENTRY_ICON_PRIMARY: self.search_box(widget) elif icon_pos == gtk.ENTRY_ICON_SECONDARY: model_name = self.screen.model_name id_ = self.bookmark_match() if not id_: text = self.get_text() if not text: return name = common.ask(_('Bookmark Name:')) if not name: return domain = self.screen.domain_parser.parse(text) common.VIEW_SEARCH.add(model_name, name, domain) self.set_text(self.screen.domain_parser.string(domain)) else: common.VIEW_SEARCH.remove(model_name, id_) # Refresh icon and bookmark button self.bookmark_match() self.but_bookmark.set_sensitive(bool(list(self.bookmarks()))) def focus_in(self, widget, event): self.update() self.search_entry.emit('changed') def search_box(self, widget): def window_hide(window, *args): window.hide() self.search_entry.grab_focus() def key_press(widget, event): if event.keyval == gtk.keysyms.Escape: window_hide(widget) return True return False def search(): self.search_window.hide() text = '' for label, entry in self.search_table.fields: if isinstance(entry, gtk.ComboBox): value = quote(entry.get_active_text()) or None elif isinstance(entry, (Dates, Selection)): value = entry.get_value() else: value = quote(entry.get_text()) or None if value is not None: text += quote(label) + ': ' + value + ' ' self.set_text(text) self.do_search() # Store text after doing the search # because domain parser could simplify the text self.last_search_text = self.get_text() if not self.search_window: self.search_window = gtk.Window() Main().add_window(self.search_window) self.search_window.set_transient_for(widget.get_toplevel()) self.search_window.set_type_hint( gtk.gdk.WINDOW_TYPE_HINT_POPUP_MENU) self.search_window.set_destroy_with_parent(True) self.search_window.set_decorated(False) self.search_window.set_deletable(False) self.search_window.connect('delete-event', window_hide) self.search_window.connect('key-press-event', key_press) self.search_window.connect('focus-out-event', window_hide) def toggle_window_hide(combobox, shown): if combobox.props.popup_shown: self.search_window.handler_block_by_func(window_hide) else: self.search_window.handler_unblock_by_func(window_hide) vbox = gtk.VBox() fields = [f for f in self.screen.domain_parser.fields.values() if f.get('searchable', True)] self.search_table = gtk.Table(rows=len(fields), columns=2) self.search_table.set_homogeneous(False) self.search_table.set_border_width(5) self.search_table.set_row_spacings(2) self.search_table.set_col_spacings(2) # Fill table with fields self.search_table.fields = [] for i, field in enumerate(fields): label = gtk.Label(field['string']) label.set_alignment(0.0, 0.0) self.search_table.attach(label, 0, 1, i, i + 1, yoptions=gtk.FILL) yoptions = False if field['type'] == 'boolean': if hasattr(gtk, 'ComboBoxText'): entry = gtk.ComboBoxText() else: entry = gtk.combo_box_new_text() entry.connect('notify::popup-shown', toggle_window_hide) entry.append_text('') selections = (_('True'), _('False')) for selection in selections: entry.append_text(selection) elif field['type'] == 'selection': selections = tuple(x[1] for x in field['selection']) entry = Selection(selections) yoptions = gtk.FILL | gtk.EXPAND elif field['type'] in ('date', 'datetime', 'time'): date_format = common.date_format( self.screen.context.get('date_format')) if field['type'] == 'date': entry = Dates(date_format) elif field['type'] in ('datetime', 'time'): time_format = PYSONDecoder({}).decode(field['format']) if field['type'] == 'time': entry = Times(time_format) elif field['type'] == 'datetime': entry = DateTimes(date_format, time_format) entry.connect_activate(lambda *a: search()) entry.connect_combo(toggle_window_hide) else: entry = gtk.Entry() entry.connect('activate', lambda *a: search()) label.set_mnemonic_widget(entry) self.search_table.attach(entry, 1, 2, i, i + 1, yoptions=yoptions) self.search_table.fields.append((field['string'], entry)) scrolled = gtk.ScrolledWindow() scrolled.add_with_viewport(self.search_table) scrolled.set_shadow_type(gtk.SHADOW_NONE) scrolled.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) vbox.pack_start(scrolled, expand=True, fill=True) find_button = gtk.Button(_('Find')) find_button.connect('clicked', lambda *a: search()) find_button.set_image(common.IconFactory.get_image( 'tryton-search', gtk.ICON_SIZE_SMALL_TOOLBAR)) hbuttonbox = gtk.HButtonBox() hbuttonbox.set_spacing(5) hbuttonbox.pack_start(find_button) hbuttonbox.set_layout(gtk.BUTTONBOX_END) vbox.pack_start(hbuttonbox, expand=False, fill=True) self.search_window.add(vbox) vbox.show_all() new_size = list(map(sum, list(zip(self.search_table.size_request(), scrolled.size_request())))) self.search_window.set_default_size(*new_size) parent = widget.get_toplevel() widget_x, widget_y = widget.translate_coordinates(parent, 0, 0) widget_allocation = widget.get_allocation() # Resize the window to not be out of the parent width, height = self.search_window.get_default_size() allocation = parent.get_allocation() delta_width = allocation.width - (widget_x + width) delta_height = allocation.height - (widget_y + widget_allocation.height + height) if delta_width < 0: width += delta_width if delta_height < 0: height += delta_height self.search_window.resize(width, height) # Move the window under the button if hasattr(widget.window, 'get_root_coords'): x, y = widget.window.get_root_coords( widget_allocation.x, widget_allocation.y) else: x, y = widget.window.get_origin() self.search_window.move( x, y + widget_allocation.height) self.search_window.show() self.search_window.grab_focus() if self.last_search_text.strip() != self.get_text().strip(): for label, entry in self.search_table.fields: if isinstance(entry, gtk.ComboBox): entry.set_active(-1) elif isinstance(entry, Dates): entry.set_values(None, None) elif isinstance(entry, Selection): entry.treeview.get_selection().unselect_all() else: entry.set_text('') if self.search_table.fields: self.search_table.fields[0][1].grab_focus() tryton-5.0.17/tryton/gui/window/view_form/view/form.py0000644000175000017500000005166513524765775022433 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import operator import gtk import gettext from collections import defaultdict from . import View from tryton.common.focus import (get_invisible_ancestor, find_focused_child, next_focus_widget, find_focusable_child, find_first_focus_widget) from tryton.common import Tooltips, node_attributes, IconFactory from tryton.common.underline import set_underline from tryton.common.button import Button from tryton.config import CONFIG from .form_gtk.calendar import Date, Time, DateTime from .form_gtk.float import Float from .form_gtk.integer import Integer from .form_gtk.selection import Selection from .form_gtk.char import Char, Password from .form_gtk.timedelta import TimeDelta from .form_gtk.checkbox import CheckBox from .form_gtk.reference import Reference from .form_gtk.binary import Binary from .form_gtk.textbox import TextBox from .form_gtk.one2many import One2Many from .form_gtk.many2many import Many2Many from .form_gtk.many2one import Many2One from .form_gtk.url import Email, URL, CallTo, SIP from .form_gtk.image import Image as Image2 from .form_gtk.progressbar import ProgressBar from .form_gtk.one2one import One2One from .form_gtk.richtextbox import RichTextBox from .form_gtk.dictionary import DictWidget from .form_gtk.multiselection import MultiSelection from .form_gtk.pyson import PYSON from .form_gtk.state_widget import (Label, VBox, Image, Frame, ScrolledWindow, Notebook, Alignment, Expander) _ = gettext.gettext class Container(object): @staticmethod def constructor(col=4, homogeneous=False): if CONFIG['client.modepda']: col = 1 if col <= 0: return HContainer(col, homogeneous) elif col == 1: return VContainer(col, homogeneous) else: return Container(col, homogeneous) def __init__(self, col=4, homogeneous=False): if col < 0: col = 0 self.col = col self.table = gtk.Table(1, col) self.table.set_homogeneous(homogeneous) self.table.set_col_spacings(0) self.table.set_row_spacings(0) self.table.set_border_width(0) self.last = (0, 0) self.tooltips = Tooltips() self.tooltips.enable() def add_row(self): height, width = self.last self.table.resize(height + 1, self.col or width) self.last = (height + 1, 0) def add_col(self): height, width = self.last self.table.resize(height or 1, width + 1) self.last = (height, width + 1) def add(self, widget, attributes): colspan = attributes.get('colspan', 1) if self.col > 0: height, width = self.last if colspan > self.col: colspan = self.col if width + colspan > self.col: self.add_row() else: self.add_col() height, width = self.last self.last = height, width + colspan if not widget: return yopt = 0 if attributes.get('yexpand'): yopt = gtk.EXPAND if attributes.get('yfill'): if yopt: yopt |= gtk.FILL else: yopt = gtk.FILL xopt = 0 if attributes.get('xexpand', True): xopt = gtk.EXPAND if attributes.get('xfill', True): if xopt: xopt |= gtk.FILL else: xopt = gtk.FILL if attributes.get('help'): self.tooltips.set_tip(widget, attributes['help']) widget.show_all() self.table.attach(widget, width, width + colspan, height, height + 1, yoptions=yopt, xoptions=xopt, ypadding=1, xpadding=2) class VContainer(Container): def __init__(self, col=1, homogeneous=False): self.col = 1 self.table = gtk.VBox() self.table.set_homogeneous(homogeneous) def add_row(self): pass def add_col(self): pass def add(self, widget, attributes): if not widget: return expand = bool(int(attributes.get('yexpand', False))) fill = bool(int(attributes.get('yfill', False))) self.table.pack_start(widget, expand=expand, fill=fill, padding=2) class HContainer(Container): def __init__(self, col=0, homogeneous=False): self.col = 0 self.table = gtk.HBox() self.table.set_homogeneous(homogeneous) def add_row(self): pass def add_col(self): pass def add(self, widget, attributes): if not widget: return expand = bool(int(attributes.get('xexpand', True))) fill = bool(int(attributes.get('xfill', True))) self.table.pack_start(widget, expand=expand, fill=fill, padding=1) class ViewForm(View): editable = True def __init__(self, screen, xml): super(ViewForm, self).__init__(screen, xml) self.view_type = 'form' self.widgets = defaultdict(list) self.state_widgets = [] self.notebooks = [] self.expandables = [] container = self.parse(xml) vbox = gtk.VBox() vp = gtk.Viewport() vp.set_shadow_type(gtk.SHADOW_NONE) vp.add(container.table) self.scroll = scroll = gtk.ScrolledWindow() scroll.add(vp) scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.set_placement(gtk.CORNER_TOP_LEFT) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_ETCHED_IN) viewport.add(scroll) vbox.pack_start(viewport, expand=True, fill=True) self.widget = vbox self._viewport = vp def parse(self, node, container=None): if not container: node_attrs = node_attributes(node) container = Container.constructor( int(node_attrs.get('col', 4)), node_attrs.get('homogeneous', False)) mnemonics = {} for node in node.childNodes: if node.nodeType != node.ELEMENT_NODE: continue node_attrs = node_attributes(node) for b_field in ('readonly', 'homogeneous'): if b_field in node_attrs: node_attrs[b_field] = bool(int(node_attrs[b_field])) for i_field in ('yexpand', 'yfill', 'xexpand', 'xfill', 'colspan', 'position'): if i_field in node_attrs: node_attrs[i_field] = int(node_attrs[i_field]) parser = getattr(self, '_parse_%s' % node.tagName) widget = parser(node, container, node_attrs) if not widget: continue name = node_attrs.get('name') if node.tagName == 'label' and name: mnemonics[name] = widget if node.tagName == 'field': if name in mnemonics and widget.mnemonic_widget: label = mnemonics.pop(name) label.set_label(set_underline(label.get_label())) label.set_use_underline(True) label.set_mnemonic_widget(widget.mnemonic_widget) return container def _parse_image(self, node, container, attributes): image = Image(attrs=attributes) self.state_widgets.append(image) container.add(image, attributes) def _parse_separator(self, node, container, attributes): if 'name' in attributes: field = self.screen.group.fields[attributes['name']] for attr in ('states', 'string'): if attr not in attributes and attr in field.attrs: attributes[attr] = field.attrs[attr] vbox = VBox(attrs=attributes) if attributes.get('string'): label = Label(attributes['string'], attrs=attributes) label.set_alignment(float(attributes.get('xalign', 0.0)), float(attributes.get('yalign', 0.5))) vbox.pack_start(label) self.state_widgets.append(label) vbox.pack_start(gtk.HSeparator()) self.state_widgets.append(vbox) container.add(vbox, attributes) def _parse_label(self, node, container, attributes): if 'name' in attributes: field = self.screen.group.fields[attributes['name']] if attributes['name'] == self.screen.exclude_field: container.add(None, attributes) return if 'states' not in attributes and 'states' in field.attrs: attributes['states'] = field.attrs['states'] if 'string' not in attributes: attributes['string'] = field.attrs['string'] + _(':') if CONFIG['client.modepda']: attributes['xalign'] = 0.0 label = Label(attributes.get('string', ''), attrs=attributes) label.set_alignment(float(attributes.get('xalign', 1.0)), float(attributes.get('yalign', 0.5))) label.set_angle(int(attributes.get('angle', 0))) attributes.setdefault('xexpand', 0) self.state_widgets.append(label) container.add(label, attributes) return label def _parse_newline(self, node, container, attributes): container.add_row() def _parse_button(self, node, container, attributes): button = Button(attributes) button.connect('clicked', self.button_clicked) self.state_widgets.append(button) container.add(button, attributes) def _parse_notebook(self, node, container, attributes): attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) attributes.setdefault('colspan', 4) notebook = Notebook(attrs=attributes) notebook.set_scrollable(True) notebook.set_border_width(3) if attributes.get('height') or attributes.get('width'): notebook.set_size_request( int(attributes.get('width', -1)), int(attributes.get('height', -1))) # Force to display the first time it switches on a page # This avoids glitch in position of widgets def switch(notebook, page, page_num): if not self.widget: # Not yet finish to parse return notebook.grab_focus() self.display() notebook.disconnect(handler_id) handler_id = notebook.connect('switch-page', switch) self.state_widgets.append(notebook) self.notebooks.append(notebook) container.add(notebook, attributes) self.parse(node, notebook) def _parse_page(self, node, notebook, attributes): tab_box = gtk.HBox(spacing=3) if 'name' in attributes: field = self.screen.group.fields[attributes['name']] if attributes['name'] == self.screen.exclude_field: return for attr in ('states', 'string'): if attr not in attributes and attr in field.attrs: attributes[attr] = field.attrs[attr] label = gtk.Label(set_underline(attributes['string'])) label.set_use_underline(True) if 'icon' in attributes: tab_box.pack_start(IconFactory.get_image( attributes['icon'], gtk.ICON_SIZE_SMALL_TOOLBAR)) tab_box.pack_start(label) tab_box.show_all() viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) scrolledwindow = ScrolledWindow(attrs=attributes) scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scrolledwindow.add(viewport) scrolledwindow.show_all() self.state_widgets.append(scrolledwindow) notebook.append_page(scrolledwindow, tab_box) container = self.parse(node) viewport.add(container.table) def _parse_field(self, node, container, attributes): name = attributes['name'] field = self.screen.group.fields[name] if (name not in self.screen.group.fields or name == self.screen.exclude_field): container.add(None, attributes) return if 'widget' not in attributes: attributes['widget'] = field.attrs['type'] for i_field in ('width', 'height'): if i_field in attributes: attributes[i_field] = int(attributes[i_field]) for attr in ('relation', 'domain', 'selection', 'relation_field', 'string', 'help', 'views', 'add_remove', 'sort', 'context', 'size', 'filename', 'autocomplete', 'translate', 'create', 'delete', 'selection_change_with', 'schema_model'): if attr in field.attrs and attr not in attributes: attributes[attr] = field.attrs[attr] Widget = self.get_widget(attributes['widget']) widget = Widget(self, attributes) self.widgets[name].append(widget) if Widget.expand: attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) if attributes.get('height') or attributes.get('width'): widget.widget.set_size_request( int(attributes.get('width', -1)), int(attributes.get('height', -1))) container.add(Alignment(widget.widget, attributes), attributes) return widget def _parse_group(self, node, container, attributes): group = self.parse(node) if 'name' in attributes: field = self.screen.group.fields[attributes['name']] if attributes['name'] == self.screen.exclude_field: container.add(None, attributes) return for attr in ('states', 'string'): if attr not in attributes and attr in field.attrs: attributes[attr] = field.attrs[attr] can_expand = attributes.get('expandable') if can_expand: widget = Expander(attributes.get('string'), attrs=attributes) widget.add(group.table) widget.set_expanded(can_expand == '1') self.expandables.append(widget) else: widget = Frame(attributes.get('string'), attrs=attributes) widget.add(group.table) self.state_widgets.append(widget) container.add(widget, attributes) def _parse_paned(self, node, container, attributes, Paned): attributes.setdefault('yexpand', True) attributes.setdefault('yfill', True) paned = Paned() if 'position' in attributes: paned.set_position(attributes['position']) container.add(paned, attributes) self.parse(node, paned) def _parse_hpaned(self, node, container, attributes): self._parse_paned(node, container, attributes, gtk.HPaned) def _parse_vpaned(self, node, container, attributes): self._parse_paned(node, container, attributes, gtk.VPaned) def _parse_child(self, node, paned, attributes): container = self.parse(node) if not paned.get_child1(): pack = paned.pack1 else: pack = paned.pack2 pack(container.table, resize=True, shrink=True) WIDGETS = { 'date': Date, 'datetime': DateTime, 'time': Time, 'timestamp': DateTime, 'float': Float, 'numeric': Float, 'integer': Integer, 'biginteger': Integer, 'selection': Selection, 'char': Char, 'password': Password, 'timedelta': TimeDelta, 'boolean': CheckBox, 'reference': Reference, 'binary': Binary, 'text': TextBox, 'one2many': One2Many, 'many2many': Many2Many, 'many2one': Many2One, 'email': Email, 'url': URL, 'callto': CallTo, 'sip': SIP, 'image': Image2, 'progressbar': ProgressBar, 'one2one': One2One, 'richtext': RichTextBox, 'dict': DictWidget, 'multiselection': MultiSelection, 'pyson': PYSON, } @classmethod def get_widget(cls, name): return cls.WIDGETS[name] def get_fields(self): return list(self.widgets.keys()) def __getitem__(self, name): return self.widgets[name][0] def destroy(self): for widget_name in list(self.widgets.keys()): for widget in self.widgets[widget_name]: widget.destroy() self.widget.destroy() def set_value(self, focused_widget=False): record = self.screen.current_record if record: for name, widgets in self.widgets.items(): if name in record.group.fields: field = record.group.fields[name] for widget in widgets: if (not focused_widget or widget.widget.is_focus() or (isinstance(widget.widget, gtk.Container) and widget.widget.get_focus_child())): widget.set_value(record, field) @property def selected_records(self): if self.screen.current_record: return [self.screen.current_record] return [] @property def modified(self): return any(w.modified for widgets in self.widgets.values() for w in widgets) def get_buttons(self): return [b for b in self.state_widgets if isinstance(b, gtk.Button)] def reset(self): record = self.screen.current_record if record: for name, widgets in self.widgets.items(): field = record.group.fields.get(name) if field and 'invalid' in field.get_state_attrs(record): for widget in widgets: field.get_state_attrs(record)['invalid'] = False widget.display(record, field) def display(self): record = self.screen.current_record if record: # Force to set fields in record # Get first the lazy one from the view to reduce number of requests fields = ((name, record.group.fields[name]) for name in self.widgets) fields = ( (name, field.attrs.get('loading', 'eager') == 'eager', len(field.views)) for name, field in fields) fields = sorted(fields, key=operator.itemgetter(1, 2)) for field, _, _ in fields: record[field].get(record) focused_widget = find_focused_child(self.widget) for name, widgets in self.widgets.items(): field = None if record: field = record.group.fields.get(name) if field: field.state_set(record) for widget in widgets: widget.display(record, field) for widget in self.state_widgets: widget.state_set(record) if focused_widget: invisible_ancestor = get_invisible_ancestor(focused_widget) if invisible_ancestor: new_focused_widget = next_focus_widget(invisible_ancestor) if new_focused_widget: new_focused_widget.grab_focus() return True def set_cursor(self, new=False, reset_view=True): focus_widget = None if reset_view or not self.widget.has_focus(): if reset_view: for notebook in self.notebooks: notebook.set_current_page(0) if self.attributes.get('cursor') in self.widgets: focus_widget = find_focusable_child(self.widgets[ self.attributes['cursor']][0].widget) else: child = find_focusable_child(self._viewport) if child: child.grab_focus() record = self.screen.current_record if record: invalid_widgets = [] for name in record.invalid_fields: widgets = self.widgets.get(name, []) for widget in widgets: invalid_widget = find_focusable_child(widget.widget) if invalid_widget: invalid_widgets.append(invalid_widget) if invalid_widgets: focus_widget = find_first_focus_widget( self._viewport, invalid_widgets) if focus_widget: for notebook in self.notebooks: for i in range(notebook.get_n_pages()): child = notebook.get_nth_page(i) if focus_widget.is_ancestor(child): notebook.set_current_page(i) for group in self.expandables: if focus_widget.is_ancestor(group): group.set_expanded(True) focus_widget.grab_focus() def button_clicked(self, widget): widget.handler_block_by_func(self.button_clicked) try: self.screen.button(widget.attrs) finally: widget.handler_unblock_by_func(self.button_clicked) tryton-5.0.17/tryton/gui/window/view_form/view/graph.py0000644000175000017500000001402013463252532022531 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import sys import gtk import gettext from . import View from .graph_gtk.bar import VerticalBar, HorizontalBar from .graph_gtk.line import Line from .graph_gtk.pie import Pie from tryton.common import file_selection, IconFactory from tryton.common import node_attributes, get_toplevel_window, message from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main _ = gettext.gettext class ViewGraph(View): def __init__(self, screen, xml): super(ViewGraph, self).__init__(screen, xml) self.view_type = 'graph' self.widgets = {} self.widget = self.parse(xml) def parse(self, node): xfield = None yfields = [] for node in node.childNodes: if node.nodeType != node.ELEMENT_NODE: continue if node.tagName == 'x': for child in node.childNodes: if not child.nodeType == child.ELEMENT_NODE: continue xfield = node_attributes(child) field = self.screen.group.fields[xfield['name']] if not xfield.get('string'): xfield['string'] = field.attrs['string'] elif node.tagName == 'y': for child in node.childNodes: if not child.nodeType == child.ELEMENT_NODE: continue yattrs = node_attributes(child) if not yattrs.get('string') and yattrs['name'] != '#': field = self.screen.group.fields[yattrs['name']] yattrs['string'] = field.attrs['string'] yfields.append(yattrs) Widget = self.get_widget(self.attributes.get('type', 'vbar')) widget = Widget(self, xfield, yfields) self.widgets['root'] = widget event = gtk.EventBox() event.add(widget) event.connect('button-press-event', self.button_press) return event WIDGETS = { 'vbar': VerticalBar, 'hbar': HorizontalBar, 'line': Line, 'pie': Pie, } @classmethod def get_widget(cls, name): return cls.WIDGETS[name] def __getitem__(self, name): return None def destroy(self): self.widget.destroy() self.widgets['root'].destroy() self.widgets.clear() def set_value(self): pass def reset(self): pass def display(self): self.widgets['root'].display(self.screen.group) return True def set_cursor(self, new=False, reset_view=True): pass def get_fields(self): return [] def get_buttons(self): return [] def save(self, widget): parent = get_toplevel_window() dia = gtk.Dialog(_('Image Size'), parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(dia) cancel_button = dia.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) cancel_button.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) cancel_button.set_always_show_image(True) ok_button = dia.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) dia.set_icon(TRYTON_ICON) dia.set_default_response(gtk.RESPONSE_OK) hbox = gtk.HBox(spacing=3) dia.vbox.pack_start(hbox, False, True) hbox.pack_start(gtk.Label(_('Width:')), False, True) spinwidth = gtk.SpinButton() spinwidth.configure(gtk.Adjustment(400.0, 0.0, sys.maxsize, 1.0, 10.0), climb_rate=1, digits=0) spinwidth.set_numeric(True) spinwidth.set_activates_default(True) hbox.pack_start(spinwidth, True, True) hbox.pack_start(gtk.Label(_('Height:')), False, True) spinheight = gtk.SpinButton() spinheight.configure(gtk.Adjustment( 200.0, 0.0, sys.maxsize, 1.0, 10.0), climb_rate=1, digits=0) spinheight.set_numeric(True) spinheight.set_activates_default(True) hbox.pack_start(spinheight, True, True) dia.show_all() filter = gtk.FileFilter() filter.set_name(_('PNG image (*.png)')) filter.add_mime_type('image/png') filter.add_pattern('*.png') while True: response = dia.run() width = spinwidth.get_value_as_int() height = spinheight.get_value_as_int() if response == gtk.RESPONSE_OK: filename = file_selection(_('Save As'), action=gtk.FILE_CHOOSER_ACTION_SAVE, preview=False, filters=[filter]) if width and height and filename: if not filename.endswith('.png'): filename = filename + '.png' try: self.widgets['root'].export_png( filename, width, height) break except MemoryError: message(_('Image size too large.'), dia, gtk.MESSAGE_ERROR) else: break parent.present() dia.destroy() def button_press(self, widget, event): if event.button == 3: menu = gtk.Menu() item = gtk.ImageMenuItem(_('Save As...')) item.set_image(IconFactory.get_image( 'tryton-save-as', gtk.ICON_SIZE_MENU)) item.connect('activate', self.save) item.show() menu.append(item) menu.popup(None, None, None, event.button, event.time) return True elif event.button == 1: self.widgets['root'].action() tryton-5.0.17/tryton/gui/window/view_form/__init__.py0000644000175000017500000000024513463252532022221 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from . import screen tryton-5.0.17/tryton/gui/window/infobar.py0000644000175000017500000000212613463252532020105 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from gi.repository import Gtk class InfoBar(object): def create_info_bar(self): self.info_label = Gtk.Label() self.info_bar = Gtk.InfoBar() self.info_bar.get_content_area().pack_start( self.info_label, False, False) self.info_bar.set_show_close_button(True) self.info_bar.connect('response', lambda i, r: i.hide()) def response(self, bar, response): if response == Gtk.ResponseType.CLOSE: bar.hide() def message_info(self, message=None, type_=Gtk.MessageType.ERROR): if message: # Work around https://bugzilla.gnome.org/show_bug.cgi?id=710888 parent = self.info_bar.get_parent() self.info_bar.unparent() self.info_bar.set_parent(parent) self.info_label.set_label(message) self.info_bar.set_message_type(type_) self.info_bar.show_all() else: self.info_bar.hide() tryton-5.0.17/tryton/gui/window/dblogin.py0000644000175000017500000006530313463252532020111 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import configparser import gtk import gobject import os import gettext import threading import logging from gi.repository import Gtk from tryton import __version__ import tryton.common as common from tryton.config import CONFIG, TRYTON_ICON, PIXMAPS_DIR, get_config_dir import tryton.rpc as rpc from tryton.common.underline import set_underline _ = gettext.gettext logger = logging.getLogger(__name__) class DBListEditor(object): def __init__(self, parent, profile_store, profiles, callback): self.profiles = profiles self.current_database = None self.old_profile, self.current_profile = None, None self.db_cache = None self.updating_db = False # GTK Stuffs self.parent = parent self.dialog = gtk.Dialog(title=_('Profile Editor'), parent=parent, flags=gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) self.ok_button = self.dialog.add_button( set_underline(_("Close")), gtk.RESPONSE_CLOSE) self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_icon(TRYTON_ICON) tooltips = common.Tooltips() hpaned = gtk.HPaned() vbox_profiles = gtk.VBox(homogeneous=False, spacing=6) self.cell = gtk.CellRendererText() self.cell.set_property('editable', True) self.cell.connect('editing-started', self.edit_started) self.profile_tree = gtk.TreeView() self.profile_tree.set_model(profile_store) self.profile_tree.insert_column_with_attributes(-1, _('Profile'), self.cell, text=0) self.profile_tree.connect('cursor-changed', self.profile_selected) scroll = gtk.ScrolledWindow() scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.add(self.profile_tree) self.add_button = gtk.Button() self.add_button.set_image(common.IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_BUTTON)) tooltips.set_tip(self.add_button, _("Add new profile")) self.add_button.connect('clicked', self.profile_create) self.remove_button = gtk.Button() self.remove_button.set_image(common.IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_BUTTON)) tooltips.set_tip(self.remove_button, _("Remove selected profile")) self.remove_button.get_style_context().add_class( Gtk.STYLE_CLASS_DESTRUCTIVE_ACTION) self.remove_button.connect('clicked', self.profile_delete) bbox = Gtk.ButtonBox() bbox.pack_start(self.remove_button) bbox.pack_start(self.add_button) vbox_profiles.pack_start(scroll, expand=True, fill=True) vbox_profiles.pack_start(bbox, expand=False, fill=True) hpaned.add1(vbox_profiles) table = gtk.Table(4, 2, homogeneous=False) table.set_row_spacings(3) table.set_col_spacings(3) host = gtk.Label(set_underline(_('Host:'))) host.set_use_underline(True) host.set_alignment(1, 0.5) host.set_padding(3, 3) self.host_entry = gtk.Entry() self.host_entry.connect('focus-out-event', self.display_dbwidget) self.host_entry.connect('changed', self.update_profiles, 'host') self.host_entry.set_activates_default(True) host.set_mnemonic_widget(self.host_entry) table.attach(host, 0, 1, 1, 2, yoptions=False, xoptions=gtk.FILL) table.attach(self.host_entry, 1, 2, 1, 2, yoptions=False) database = gtk.Label(set_underline(_('Database:'))) database.set_use_underline(True) database.set_alignment(1, 0.5) database.set_padding(3, 3) self.database_entry = gtk.Entry() self.database_entry.connect('changed', self.dbentry_changed) self.database_entry.connect('changed', self.update_profiles, 'database') self.database_entry.set_activates_default(True) self.database_label = gtk.Label() self.database_label.set_use_markup(True) self.database_label.set_alignment(0, 0.5) self.database_combo = gtk.ComboBox() dbstore = gtk.ListStore(gobject.TYPE_STRING) cell = gtk.CellRendererText() self.database_combo.pack_start(cell, True) self.database_combo.add_attribute(cell, 'text', 0) self.database_combo.set_model(dbstore) self.database_combo.connect('changed', self.dbcombo_changed) self.database_progressbar = gtk.ProgressBar() self.database_progressbar.set_text(_('Fetching databases list')) db_box = gtk.VBox(homogeneous=True) db_box.pack_start(self.database_entry) db_box.pack_start(self.database_combo) db_box.pack_start(self.database_label) db_box.pack_start(self.database_progressbar) # Compute size_request of box in order to prevent "form jumping" width, height = 0, 0 for child in db_box.get_children(): cwidth, cheight = child.size_request() width, height = max(width, cwidth), max(height, cheight) db_box.set_size_request(width, height) table.attach(database, 0, 1, 2, 3, yoptions=False, xoptions=gtk.FILL) table.attach(db_box, 1, 2, 2, 3, yoptions=False) username = gtk.Label(set_underline(_('Username:'))) username.set_use_underline(True) username.set_alignment(1, 0.5) username.set_padding(3, 3) self.username_entry = gtk.Entry() self.username_entry.connect('changed', self.update_profiles, 'username') username.set_mnemonic_widget(self.username_entry) self.username_entry.set_activates_default(True) table.attach(username, 0, 1, 3, 4, yoptions=False, xoptions=gtk.FILL) table.attach(self.username_entry, 1, 2, 3, 4, yoptions=False) hpaned.add2(table) hpaned.set_position(250) self.dialog.vbox.pack_start(hpaned) self.dialog.set_default_size(640, 350) self.dialog.set_default_response(gtk.RESPONSE_CLOSE) self.dialog.connect('close', lambda *a: False) self.dialog.connect('response', self.response) self.callback = callback def response(self, widget, response): if self.callback: self.callback(self.current_profile['name']) self.parent.present() self.dialog.destroy() def run(self, profile_name): self.clear_entries() # must be done before show_all for windows self.dialog.show_all() model = self.profile_tree.get_model() if model: for i, row in enumerate(model): if row[0] == profile_name: break else: i = 0 self.profile_tree.get_selection().select_path((i,)) self.profile_selected(self.profile_tree) def _current_profile(self): model, selection = self.profile_tree.get_selection().get_selected() if not selection: return {'name': None, 'iter': None} return {'name': model[selection][0], 'iter': selection} def clear_entries(self): for entryname in ('host', 'database', 'username'): entry = getattr(self, '%s_entry' % entryname) entry.handler_block_by_func(self.update_profiles) entry.set_text('') entry.handler_unblock_by_func(self.update_profiles) self.current_database = None self.database_combo.set_active(-1) self.database_combo.get_model().clear() self.hide_database_info() def hide_database_info(self): self.database_entry.hide() self.database_combo.hide() self.database_label.hide() self.database_progressbar.hide() def profile_create(self, button): self.clear_entries() model = self.profile_tree.get_model() model.append(['', False]) column = self.profile_tree.get_column(0) self.profile_tree.set_cursor(len(model) - 1, column, start_editing=True) self.db_cache = None def profile_delete(self, button): self.clear_entries() model, selection = self.profile_tree.get_selection().get_selected() if not selection: return profile_name = model[selection][0] self.profiles.remove_section(profile_name) del model[selection] def profile_selected(self, treeview): self.old_profile = self.current_profile self.current_profile = self._current_profile() if not self.current_profile['name']: return if self.updating_db: self.current_profile = self.old_profile selection = treeview.get_selection() selection.select_iter(self.old_profile['iter']) return fields = ('host', 'database', 'username') for field in fields: entry = getattr(self, '%s_entry' % field) try: entry_value = self.profiles.get(self.current_profile['name'], field) except configparser.NoOptionError: entry_value = '' entry.set_text(entry_value) if field == 'database': self.current_database = entry_value self.display_dbwidget(None, None) def edit_started(self, renderer, editable, path): if isinstance(editable, gtk.Entry): editable.connect('focus-out-event', self.edit_profilename, renderer, path) def edit_profilename(self, editable, event, renderer, path): newtext = editable.get_text() model = self.profile_tree.get_model() try: oldname = model[path][0] except IndexError: return if oldname == newtext == '': del model[path] return elif oldname == newtext or newtext == '': return elif newtext in self.profiles.sections(): if not oldname: del model[path] return elif oldname in self.profiles.sections(): self.profiles.add_section(newtext) for itemname, value in self.profiles.items(oldname): self.profiles.set(newtext, itemname, value) self.profiles.remove_section(oldname) model[path][0] = newtext else: model[path][0] = newtext self.profiles.add_section(newtext) self.current_profile = self._current_profile() self.host_entry.grab_focus() def update_profiles(self, editable, entryname): new_value = editable.get_text() if not new_value: return section = self._current_profile()['name'] self.profiles.set(section, entryname, new_value) self.validate_profile(section) def validate_profile(self, profile_name): model, selection = self.profile_tree.get_selection().get_selected() if not selection: return active = all(self.profiles.has_option(profile_name, option) for option in ('host', 'database')) model[selection][1] = active @classmethod def test_server_version(cls, host, port): ''' Tests if the server version is compatible with the client version It returns None if no information on server version is available. ''' version = rpc.server_version(host, port) if not version: return None return version.split('.')[:2] == __version__.split('.')[:2] def refresh_databases(self, host, port): self.dbs_updated = threading.Event() threading.Thread(target=self.refresh_databases_start, args=(host, port)).start() gobject.timeout_add(100, self.refresh_databases_end, host, port) def refresh_databases_start(self, host, port): dbs = None try: dbs = rpc.db_list(host, port) except Exception: pass finally: self.dbs = dbs self.dbs_updated.set() def refresh_databases_end(self, host, port): if not self.dbs_updated.isSet(): self.database_progressbar.show() self.database_progressbar.pulse() return True self.database_progressbar.hide() dbs = self.dbs label = None if self.test_server_version(host, port) is False: label = _('Incompatible version of the server') elif dbs is None: label = _('Could not connect to the server') if label: self.database_label.set_label('%s' % label) self.database_label.show() else: liststore = self.database_combo.get_model() liststore.clear() index = -1 for db_num, db_name in enumerate(dbs): liststore.append([db_name]) if self.current_database and db_name == self.current_database: index = db_num if index == -1: index = 0 self.database_combo.set_active(index) self.database_entry.set_text(self.current_database if self.current_database else '') if dbs: self.database_combo.show() else: self.database_entry.show() self.db_cache = (host, port, self.current_profile['name']) self.add_button.set_sensitive(True) self.remove_button.set_sensitive(True) self.ok_button.set_sensitive(True) self.cell.set_property('editable', True) self.host_entry.set_sensitive(True) self.updating_db = False return False def display_dbwidget(self, entry, event): netloc = self.host_entry.get_text() host = common.get_hostname(netloc) if not host: return port = common.get_port(netloc) if (host, port, self.current_profile['name']) == self.db_cache: return if self.updating_db: return self.hide_database_info() self.add_button.set_sensitive(False) self.remove_button.set_sensitive(False) self.ok_button.set_sensitive(False) self.cell.set_property('editable', False) self.host_entry.set_sensitive(False) self.updating_db = True self.refresh_databases(host, port) def dbcombo_changed(self, combobox): dbname = combobox.get_active_text() if dbname: self.current_database = dbname self.profiles.set(self.current_profile['name'], 'database', dbname) self.validate_profile(self.current_profile['name']) def dbentry_changed(self, entry): dbname = entry.get_text() if dbname: self.current_database = dbname self.profiles.set(self.current_profile['name'], 'database', dbname) self.validate_profile(self.current_profile['name']) def insert_text_port(self, entry, new_text, new_text_length, position): value = entry.get_text() position = entry.get_position() new_value = value[:position] + new_text + value[position:] try: int(new_value) except ValueError: entry.stop_emission('insert-text') class DBLogin(object): def __init__(self): # Fake windows to avoid warning about Dialog without transient self._window = gtk.Window() self.dialog = gtk.Dialog(title=_('Login'), flags=gtk.DIALOG_MODAL) self.dialog.set_transient_for(self._window) self.dialog.set_icon(TRYTON_ICON) self.dialog.set_position(gtk.WIN_POS_CENTER_ALWAYS) tooltips = common.Tooltips() button_cancel = gtk.Button(_('_Cancel'), use_underline=True) tooltips.set_tip(button_cancel, _('Cancel connection to the Tryton server')) self.dialog.add_action_widget(button_cancel, gtk.RESPONSE_CANCEL) self.button_connect = gtk.Button(_('C_onnect'), use_underline=True) self.button_connect.get_style_context().add_class( Gtk.STYLE_CLASS_SUGGESTED_ACTION) self.button_connect.set_can_default(True) tooltips.set_tip(self.button_connect, _('Connect the Tryton server')) self.dialog.add_action_widget(self.button_connect, gtk.RESPONSE_OK) self.dialog.set_default_response(gtk.RESPONSE_OK) alignment = gtk.Alignment(yalign=0, yscale=0, xscale=1) self.table_main = gtk.Table(3, 3, False) self.table_main.set_border_width(0) self.table_main.set_row_spacings(3) self.table_main.set_col_spacings(3) alignment.add(self.table_main) self.dialog.vbox.pack_start(alignment, True, True, 0) image = gtk.Image() image.set_from_file(os.path.join(PIXMAPS_DIR, 'tryton.png')) image.set_alignment(0.5, 1) ebox = gtk.EventBox() ebox.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#1b2019")) ebox.add(image) self.table_main.attach(ebox, 0, 3, 0, 1, ypadding=2) self.profile_store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN) self.combo_profile = gtk.ComboBox() cell = gtk.CellRendererText() self.combo_profile.pack_start(cell, True) self.combo_profile.add_attribute(cell, 'text', 0) self.combo_profile.add_attribute(cell, 'sensitive', 1) self.combo_profile.set_model(self.profile_store) self.combo_profile.connect('changed', self.profile_changed) self.profile_label = gtk.Label(set_underline(_('Profile:'))) self.profile_label.set_use_underline(True) self.profile_label.set_justify(gtk.JUSTIFY_RIGHT) self.profile_label.set_alignment(1, 0.5) self.profile_label.set_padding(3, 3) self.profile_label.set_mnemonic_widget(self.combo_profile) self.profile_button = gtk.Button(set_underline(_('Manage...')), use_underline=True) self.profile_button.connect('clicked', self.profile_manage) self.table_main.attach(self.profile_label, 0, 1, 1, 2, xoptions=gtk.FILL) self.table_main.attach(self.combo_profile, 1, 2, 1, 2) self.table_main.attach(self.profile_button, 2, 3, 1, 2, xoptions=gtk.FILL) self.expander = gtk.Expander() self.expander.set_label(_('Host / Database information')) self.expander.connect('notify::expanded', self.expand_hostspec) self.table_main.attach(self.expander, 0, 3, 3, 4) self.label_host = gtk.Label(set_underline(_('Host:'))) self.label_host.set_use_underline(True) self.label_host.set_justify(gtk.JUSTIFY_RIGHT) self.label_host.set_alignment(1, 0.5) self.label_host.set_padding(3, 3) self.entry_host = gtk.Entry() self.entry_host.connect_after('focus-out-event', self.clear_profile_combo) self.entry_host.set_activates_default(True) self.label_host.set_mnemonic_widget(self.entry_host) self.table_main.attach(self.label_host, 0, 1, 4, 5, xoptions=gtk.FILL) self.table_main.attach(self.entry_host, 1, 3, 4, 5) self.label_database = gtk.Label(set_underline(_('Database:'))) self.label_database.set_use_underline(True) self.label_database.set_justify(gtk.JUSTIFY_RIGHT) self.label_database.set_alignment(1, 0.5) self.label_database.set_padding(3, 3) self.entry_database = gtk.Entry() self.entry_database.connect_after('focus-out-event', self.clear_profile_combo) self.entry_database.set_activates_default(True) self.label_database.set_mnemonic_widget(self.entry_database) self.table_main.attach(self.label_database, 0, 1, 5, 6, xoptions=gtk.FILL) self.table_main.attach(self.entry_database, 1, 3, 5, 6) self.entry_login = gtk.Entry() self.entry_login.set_activates_default(True) self.table_main.attach(self.entry_login, 1, 3, 6, 7) label_username = gtk.Label(set_underline(_("User name:"))) label_username.set_use_underline(True) label_username.set_alignment(1, 0.5) label_username.set_padding(3, 3) label_username.set_mnemonic_widget(self.entry_login) self.table_main.attach(label_username, 0, 1, 6, 7, xoptions=gtk.FILL) # Profile informations self.profile_cfg = os.path.join(get_config_dir(), 'profiles.cfg') self.profiles = configparser.ConfigParser() if not os.path.exists(self.profile_cfg): short_version = '.'.join(__version__.split('.', 2)[:2]) name = 'demo%s.tryton.org' % short_version self.profiles.add_section(name) self.profiles.set(name, 'host', name) self.profiles.set(name, 'database', 'demo%s' % short_version) self.profiles.set(name, 'username', 'demo') else: try: self.profiles.read(self.profile_cfg) except configparser.ParsingError: logger.error("Fail to parse profiles.cfg", exc_info=True) for section in self.profiles.sections(): active = all(self.profiles.has_option(section, option) for option in ('host', 'database')) self.profile_store.append([section, active]) def profile_manage(self, widget): def callback(profile_name): with open(self.profile_cfg, 'w') as configfile: self.profiles.write(configfile) for idx, row in enumerate(self.profile_store): if row[0] == profile_name and row[1]: self.combo_profile.set_active(idx) self.profile_changed(self.combo_profile) break dia = DBListEditor(self.dialog, self.profile_store, self.profiles, callback) active_profile = self.combo_profile.get_active() profile_name = None if active_profile != -1: profile_name = self.profile_store[active_profile][0] dia.run(profile_name) def profile_changed(self, combobox): position = combobox.get_active() if position == -1: return profile = self.profile_store[position][0] try: username = self.profiles.get(profile, 'username') except configparser.NoOptionError: username = '' host = self.profiles.get(profile, 'host') self.entry_host.set_text('%s' % host) self.entry_database.set_text(self.profiles.get(profile, 'database')) if username: self.entry_login.set_text(username) else: self.entry_login.set_text('') def clear_profile_combo(self, *args): netloc = self.entry_host.get_text() host = common.get_hostname(netloc) port = common.get_port(netloc) database = self.entry_database.get_text().strip() login = self.entry_login.get_text() for idx, profile_info in enumerate(self.profile_store): if not profile_info[1]: continue profile = profile_info[0] try: profile_host = self.profiles.get(profile, 'host') profile_db = self.profiles.get(profile, 'database') profile_login = self.profiles.get(profile, 'username') except configparser.NoOptionError: continue if (host == common.get_hostname(profile_host) and port == common.get_port(profile_host) and database == profile_db and (not login or login == profile_login)): break else: idx = -1 self.combo_profile.set_active(idx) return False def expand_hostspec(self, expander, *args): visibility = expander.props.expanded self.entry_host.props.visible = visibility self.label_host.props.visible = visibility self.entry_database.props.visible = visibility self.label_database.props.visible = visibility def run(self): profile_name = CONFIG['login.profile'] can_use_profile = self.profiles.has_section(profile_name) if can_use_profile: for (configname, option) in [ ('login.host', 'host'), ('login.db', 'database'), ]: try: value = self.profiles.get(profile_name, option) except configparser.NoOptionError: value = None if value != CONFIG[configname]: can_use_profile = False break if can_use_profile: for idx, row in enumerate(self.profile_store): if row[0] == profile_name: self.combo_profile.set_active(idx) break else: self.combo_profile.set_active(-1) host = CONFIG['login.host'] if CONFIG['login.host'] else '' self.entry_host.set_text(host) db = CONFIG['login.db'] if CONFIG['login.db'] else '' self.entry_database.set_text(db) self.entry_login.set_text(CONFIG['login.login']) self.clear_profile_combo() self.dialog.show_all() self.entry_login.grab_focus() # Reshow dialog for gtk-quarks self.dialog.reshow_with_initial_size() self.expander.set_expanded(CONFIG['login.expanded']) # The previous action did not called expand_hostspec self.expand_hostspec(self.expander) response, result = None, ('', '', '', '') while not all(result): response = self.dialog.run() if response != gtk.RESPONSE_OK: break self.clear_profile_combo() active_profile = self.combo_profile.get_active() if active_profile != -1: profile = self.profile_store[active_profile][0] else: profile = '' host = self.entry_host.get_text() hostname = common.get_hostname(host) port = common.get_port(host) test = DBListEditor.test_server_version(hostname, port) if not test: if test is False: common.warning('', _('Incompatible version of the server'), parent=self.dialog) else: common.warning('', _('Could not connect to the server'), parent=self.dialog) continue database = self.entry_database.get_text() login = self.entry_login.get_text() CONFIG['login.profile'] = profile CONFIG['login.host'] = host CONFIG['login.db'] = database CONFIG['login.expanded'] = self.expander.props.expanded CONFIG['login.login'] = login result = ( hostname, port, database, self.entry_login.get_text()) self.dialog.destroy() self._window.destroy() return response == gtk.RESPONSE_OK tryton-5.0.17/tryton/gui/window/revision.py0000644000175000017500000001025113524765775020341 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from tryton.common import (get_toplevel_window, IconFactory, timezoned_date, untimezoned_date) from tryton.common.datetime_ import date_parse from tryton.common.datetime_strftime import datetime_strftime from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main _ = gettext.gettext class Revision(object): 'Ask revision' def __init__(self, revisions, revision=None, format_='%x %H:%M:%S.%f'): self.parent = get_toplevel_window() self.win = gtk.Dialog(_('Revision'), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) cancel_button = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) cancel_button.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) cancel_button.set_always_show_image(True) ok_button = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.vbox.set_spacing(3) self.win.vbox.pack_start(gtk.Label( _('Select a revision')), expand=False, fill=True) self.win.vbox.pack_start(gtk.HSeparator()) hbox = gtk.HBox(spacing=3) label = gtk.Label(_('Revision:')) hbox.pack_start(label, expand=True, fill=True) list_store = gtk.ListStore(str, str) # Set model on instantiation to get the default cellrenderer as text combobox = gtk.ComboBoxEntry(model=list_store) self.entry = combobox.get_child() self.entry.connect('focus-out-event', self.focus_out) self.entry.connect('activate', self.activate) label.set_mnemonic_widget(self.entry) combobox.connect('changed', self.changed) self.entry.set_property('activates_default', True) self._format = format_ if revision: self.entry.set_text(datetime_strftime(revision, self._format)) self._value = revision active = -1 else: self._value = None active = 0 list_store.append(('', '')) for i, (rev, id_, name) in enumerate(revisions, 1): list_store.append( (datetime_strftime(timezoned_date(rev), self._format), name)) if rev == revision: active = i combobox.set_active(active) cell = gtk.CellRendererText() combobox.pack_start(cell, True) combobox.add_attribute(cell, 'text', 1) hbox.pack_start(combobox, expand=True, fill=True) combobox.set_entry_text_column(0) self.win.vbox.pack_start(hbox, expand=True, fill=True) self.win.show_all() def focus_out(self, entry, event): self.parse() self.update() return False def activate(self, entry): self.parse() self.update() return False def changed(self, combobox): # "changed" signal is also triggered by text editing # so only parse when a row is active if combobox.get_active_iter(): self.parse() self.update() return False def parse(self): text = self.entry.get_text() value = None if text: try: value = untimezoned_date(date_parse(text, self._format)) except ValueError: pass self._value = value def update(self): if not self._value: self.entry.set_text('') else: self.entry.set_text(datetime_strftime(self._value, self._format)) def run(self): response = self.win.run() revision = None if response == gtk.RESPONSE_OK: revision = self._value self.parent.present() self.win.destroy() return revision tryton-5.0.17/tryton/gui/window/__init__.py0000644000175000017500000000024613463252532020225 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .window import * tryton-5.0.17/tryton/gui/window/win_export.py0000644000175000017500000003253613524765775020713 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import csv import os import tempfile import gtk import gobject import gettext import tryton.common as common from tryton.common import RPCExecute, RPCException from tryton.gui.window.win_csv import WinCSV _ = gettext.gettext class WinExport(WinCSV): "Window export" def __init__(self, name, model, ids, context=None): self.name = name self.ids = ids self.model = model self.context = context self.fields = {} super(WinExport, self).__init__() self.dialog.set_title(_('CSV Export: %s') % name) def add_buttons(self, box): button_save_export = gtk.Button( _('_Save Export'), stock=None, use_underline=True) button_save_export.set_image(common.IconFactory.get_image( 'tryton-save', gtk.ICON_SIZE_BUTTON)) button_save_export.set_always_show_image(True) button_save_export.connect_after('clicked', self.addreplace_predef) box.pack_start(button_save_export, False, False, 0) button_del_export = gtk.Button( _('_Delete Export'), stock=None, use_underline=True) button_del_export.set_image(common.IconFactory.get_image( 'tryton-delete', gtk.ICON_SIZE_BUTTON)) button_del_export.set_always_show_image(True) button_del_export.connect_after('clicked', self.remove_predef) box.pack_start(button_del_export, False, False, 0) frame_predef_exports = gtk.Frame() frame_predef_exports.set_border_width(2) frame_predef_exports.set_shadow_type(gtk.SHADOW_NONE) box.pack_start(frame_predef_exports, True, True, 0) viewport_exports = gtk.Viewport() scrolledwindow_exports = gtk.ScrolledWindow() scrolledwindow_exports.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) label_predef_exports = gtk.Label(_("Predefined exports")) label_predef_exports.set_use_markup(True) frame_predef_exports.set_label_widget(label_predef_exports) viewport_exports.add(scrolledwindow_exports) frame_predef_exports.add(viewport_exports) self.pref_export = gtk.TreeView() self.pref_export.append_column(gtk.TreeViewColumn(_('Name'), gtk.CellRendererText(), text=2)) scrolledwindow_exports.add(self.pref_export) self.pref_export.connect("button-press-event", self.export_click) self.pref_export.connect("key-press-event", self.export_keypress) self.predef_model = gtk.ListStore( gobject.TYPE_INT, gobject.TYPE_PYOBJECT, gobject.TYPE_STRING) self.fill_predefwin() def add_chooser(self, box): hbox_csv_export = gtk.HBox() box.pack_start(hbox_csv_export, False, True, 0) if hasattr(gtk, 'ComboBoxText'): self.saveas = gtk.ComboBoxText() else: self.saveas = gtk.combo_box_new_text() hbox_csv_export.pack_start(self.saveas, True, True, 0) self.saveas.append_text(_("Open")) self.saveas.append_text(_("Save")) self.saveas.set_active(0) def add_csv_header_param(self, table): self.add_field_names = gtk.CheckButton(_("Add _field names")) self.add_field_names.set_active(True) table.attach(self.add_field_names, 2, 4, 1, 2) def model_populate(self, fields, parent_node=None, prefix_field='', prefix_name=''): def key(n_f): return n_f[1].get('string') or n_f[0] for name, field in sorted(list(fields.items()), key=key, reverse=True): string_ = field['string'] or name items = [(name, field, string_)] if field['type'] == 'selection': items.insert(0, ('%s.translated' % name, field, _('%s (string)') % string_)) elif field['type'] == 'reference': items.insert(0, ('%s.translated' % name, field, _('%s (model name)') % string_)) items.insert(0, ('%s/rec_name' % name, field, _("%s (record name)") % string_)) for name, field, string_ in items: path = prefix_field + name long_string = string_ if prefix_field: long_string = prefix_name + string_ node = self.model1.insert(parent_node, 0, [string_, path]) self.fields[path] = (string_, long_string, field.get('relation')) # Insert relation only to real field if '.' not in name: if field.get('relation'): self.model1.insert(node, 0, [None, '']) def _get_fields(self, model): try: return RPCExecute('model', model, 'fields_get', None, context=self.context) except RPCException: return '' def on_row_expanded(self, treeview, iter, path): child = self.model1.iter_children(iter) if self.model1.get_value(child, 0) is None: prefix_field = self.model1.get_value(iter, 1) string_, long_string, relation = self.fields[prefix_field] self.model_populate(self._get_fields(relation), iter, prefix_field + '/', string_ + '/') self.model1.remove(child) def sig_sel(self, *args): sel = self.view1.get_selection() sel.selected_foreach(self._sig_sel_add) def _sig_sel_add(self, store, path, iter): name = store.get_value(iter, 1) string_, long_string, relation = self.fields[name] if relation: return num = self.model2.append() self.model2.set(num, 0, long_string, 1, name) def sig_unsel(self, *args): store, paths = self.view2.get_selection().get_selected_rows() # Convert first into TreeIter before removing from the store iters = [store.get_iter(p) for p in paths] for i in iters: store.remove(i) def sig_unsel_all(self, *args): self.model2.clear() def fill_predefwin(self): try: export_ids = RPCExecute('model', 'ir.export', 'search', [('resource', '=', self.model)], 0, None, None, context=self.context) except RPCException: return try: exports = RPCExecute('model', 'ir.export', 'read', export_ids, None, context=self.context) except RPCException: return try: lines = RPCExecute('model', 'ir.export.line', 'read', sum((list(x['export_fields']) for x in exports), []), None, context=self.context) except RPCException: return id2lines = {} for line in lines: id2lines.setdefault(line['export'], []).append(line) for export in exports: self.predef_model.append(( export['id'], [x['name'] for x in id2lines.get(export['id'], [])], export['name'])) self.pref_export.set_model(self.predef_model) def addreplace_predef(self, widget): iter = self.model2.get_iter_first() fields = [] while iter: field_name = self.model2.get_value(iter, 1) fields.append(field_name) iter = self.model2.iter_next(iter) if not fields: return selection = self.pref_export.get_selection().get_selected() if selection is None: return model, iter_ = selection if iter_ is None: pref_id = None name = common.ask(_('What is the name of this export?')) if not name: return else: pref_id = model.get_value(iter_, 0) name = model.get_value(iter_, 2) override = common.sur(_("Override '%s' definition?") % name) if not override: return try: new_id, = RPCExecute('model', 'ir.export', 'create', [{ 'name': name, 'resource': self.model, 'export_fields': [('create', [{ 'name': x, } for x in fields])], }], context=self.context) if pref_id: RPCExecute('model', 'ir.export', 'delete', [pref_id], context=self.context) except RPCException: return if iter_ is None: self.predef_model.append((new_id, fields, name)) else: model.set_value(iter_, 0, new_id) model.set_value(iter_, 1, fields) def remove_predef(self, widget): sel = self.pref_export.get_selection().get_selected() if sel is None: return None (model, i) = sel if not i: return None export_id = model.get_value(i, 0) try: RPCExecute('model', 'ir.export', 'delete', [export_id], context=self.context) except RPCException: return for i in range(len(self.predef_model)): if self.predef_model[i][0] == export_id: del self.predef_model[i] break self.pref_export.set_model(self.predef_model) def sel_predef(self, path): self.model2.clear() for name in self.predef_model[path[0]][1]: if name not in self.fields: iter = self.model1.get_iter_first() prefix = '' for parent in name.split('/')[:-1]: while iter: if self.model1.get_value(iter, 1) == \ (prefix + parent): self.on_row_expanded(self.view1, iter, self.model1.get_path(iter)) iter = self.model1.iter_children(iter) prefix += parent + '/' break else: iter = self.model1.iter_next(iter) if name not in self.fields: continue self.sel_field(name) def sel_field(self, name): _, long_string, relation = self.fields[name] if relation: return self.model2.append((long_string, name)) def response(self, dialog, response): if response == gtk.RESPONSE_OK: fields = [] fields2 = [] iter = self.model2.get_iter_first() while iter: fields.append(self.model2.get_value(iter, 1)) fields2.append(self.model2.get_value(iter, 0)) iter = self.model2.iter_next(iter) action = self.saveas.get_active() try: data = RPCExecute('model', self.model, 'export_data', self.ids, fields, context=self.context) except RPCException: data = [] if action == 0: fileno, fname = tempfile.mkstemp( '.csv', common.slugify(self.name) + '_') self.export_csv(fname, fields2, data, popup=False) os.close(fileno) common.file_open(fname, 'csv') else: fname = common.file_selection(_('Save As...'), action=gtk.FILE_CHOOSER_ACTION_SAVE) if fname: self.export_csv(fname, fields2, data) self.destroy() def export_csv(self, fname, fields, data, popup=True): encoding = self.csv_enc.get_active_text() or 'UTF-8' try: writer = csv.writer( open(fname, 'w', encoding=encoding, newline=''), quotechar=self.get_quotechar(), delimiter=self.get_delimiter()) if self.add_field_names.get_active(): writer.writerow(fields) for line in data: row = [] for val in line: row.append(val) writer.writerow(row) if popup: if len(data) == 1: common.message(_('%d record saved.') % len(data)) else: common.message(_('%d records saved.') % len(data)) return True except IOError as exception: common.warning(_("Operation failed.\nError message:\n%s") % exception, _('Error')) return False def export_click(self, treeview, event): path_at_pos = treeview.get_path_at_pos(int(event.x), int(event.y)) if not path_at_pos or event.button != 1: return path, col, x, y = path_at_pos selection = treeview.get_selection() if event.type == gtk.gdk._2BUTTON_PRESS: self.sel_predef(path) selection.select_path(path) return True elif selection.path_is_selected(path): selection.unselect_path(path) return True def export_keypress(self, treeview, event): if event.keyval not in (gtk.keysyms.Return, gtk.keysyms.space): return model, selected = treeview.get_selection().get_selected() if not selected: return self.sel_predef(model.get_path(selected)) tryton-5.0.17/tryton/gui/window/win_import.py0000644000175000017500000001725313524765775020703 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import csv import gettext import gtk import tryton.common as common from tryton.common import RPCExecute, RPCException from tryton.gui.window.win_csv import WinCSV _ = gettext.gettext class WinImport(WinCSV): "Window import" def __init__(self, name, model, context): self.name = name self.model = model self.context = context self.fields_data = {} self.fields = {} self.fields_invert = {} super(WinImport, self).__init__() self.dialog.set_title(_('CSV Import: %s') % name) def add_buttons(self, box): button_autodetect = gtk.Button( _('_Auto-Detect'), stock=None, use_underline=True) button_autodetect.set_alignment(0.0, 0.0) button_autodetect.set_image(common.IconFactory.get_image( 'tryton-search', gtk.ICON_SIZE_BUTTON)) button_autodetect.set_always_show_image(True) button_autodetect.connect_after('clicked', self.sig_autodetect) box.pack_start(button_autodetect, False, False, 0) def add_chooser(self, box): hbox_csv_import = gtk.HBox() box.pack_start(hbox_csv_import, False, True, 4) label_csv_import = gtk.Label(_("File to Import:")) hbox_csv_import.pack_start(label_csv_import, False, False, 0) self.import_csv_file = gtk.FileChooserButton(_("Open...")) label_csv_import.set_mnemonic_widget(self.import_csv_file) hbox_csv_import.pack_start(self.import_csv_file, True, True, 0) def add_csv_header_param(self, table): label_csv_skip = gtk.Label(_('Lines to Skip:')) label_csv_skip.set_alignment(1, 0.5) table.attach(label_csv_skip, 2, 3, 1, 2) self.csv_skip = gtk.SpinButton() self.csv_skip.configure(gtk.Adjustment(0, 0, 100, 1, 10), 1, 0) label_csv_skip.set_mnemonic_widget(self.csv_skip) table.attach(self.csv_skip, 3, 4, 1, 2) def model_populate(self, fields, parent_node=None, prefix_field='', prefix_name=''): fields_order = list(fields.keys()) fields_order.sort( key=lambda x: fields[x].get('string', ''), reverse=True) for field in fields_order: if not fields[field].get('readonly', False): self.fields_data[prefix_field + field] = fields[field] name = fields[field]['string'] or field node = self.model1.insert( parent_node, 0, [name, prefix_field + field]) name = prefix_name + name # Only One2Many can be nested for import if fields[field]['type'] == 'one2many': relation = fields[field].get('relation') else: relation = None self.fields[prefix_field + field] = (name, relation) self.fields_invert[name] = prefix_field + field if relation: self.model1.insert(node, 0, [None, '']) def _get_fields(self, model): try: return RPCExecute('model', model, 'fields_get', None, context=self.context) except RPCException: return '' def on_row_expanded(self, treeview, iter, path): child = self.model1.iter_children(iter) # autodetect could call for node without children if child is None: return if self.model1.get_value(child, 0) is None: prefix_field = self.model1.get_value(iter, 1) name, model = self.fields[prefix_field] self.model_populate(self._get_fields(model), iter, prefix_field + '/', name + '/') self.model1.remove(child) def sig_autodetect(self, widget=None): fname = self.import_csv_file.get_filename() if not fname: common.message(_('You must select an import file first.')) return True encoding = self.get_encoding() self.csv_skip.set_value(1) try: data = csv.reader( open(fname, 'r', encoding=encoding, newline=''), quotechar=self.get_quotechar(), delimiter=self.get_delimiter()) except IOError: common.warning(_('Error opening CSV file'), _('Error')) return True self.sig_unsel_all() word = '' for line in data: for word in line: if word not in self.fields_invert and word not in self.fields: iter = self.model1.get_iter_first() prefix = '' for parent in word.split('/')[:-1]: while iter: if self.model1.get_value(iter, 0) == parent or \ self.model1.get_value(iter, 1) == \ (prefix + parent): self.on_row_expanded(self.view1, iter, self.model1.get_path(iter)) break iter = self.model1.iter_next(iter) prefix = parent + '/' if word in self.fields_invert: name = word field = self.fields_invert[word] elif word in self.fields: name = self.fields[word][0] field = word else: common.warning(_('Error processing the file at field %s.') % word, _('Error')) return True num = self.model2.append() self.model2.set(num, 0, name, 1, field) break return True def sig_sel(self, *args): sel = self.view1.get_selection() sel.selected_foreach(self._sig_sel_add) def _sig_sel_add(self, store, path, iter): num = self.model2.append() name = self.fields[store.get_value(iter, 1)][0] self.model2.set(num, 0, name, 1, store.get_value(iter, 1)) def sig_unsel(self, *args): store, paths = self.view2.get_selection().get_selected_rows() # Convert first into TreeIter before removing from the store iters = [store.get_iter(p) for p in paths] for i in iters: store.remove(i) def sig_unsel_all(self, *args): self.model2.clear() def response(self, dialog, response): if response == gtk.RESPONSE_OK: fields = [] iter = self.model2.get_iter_first() while iter: fields.append(self.model2.get_value(iter, 1)) iter = self.model2.iter_next(iter) fname = self.import_csv_file.get_filename() if fname: self.import_csv(fname, fields) self.destroy() def import_csv(self, fname, fields): # TODO: make it works with references skip = self.csv_skip.get_value_as_int() encoding = self.get_encoding() reader = csv.reader( open(fname, 'r', encoding=encoding), quotechar=self.get_quotechar(), delimiter=self.get_delimiter()) data = [] for i, line in enumerate(reader): if i < skip or not line: continue data.append([x for x in line]) try: count = RPCExecute( 'model', self.model, 'import_data', fields, data, context=self.context) except RPCException: return if count == 1: common.message(_('%d record imported.') % count) else: common.message(_('%d records imported.') % count) tryton-5.0.17/tryton/gui/window/tabcontent.py0000644000175000017500000002570413463252532020635 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext import gtk import pango from gi.repository import Gtk import tryton.common as common from tryton.config import CONFIG from tryton.gui import Main from .infobar import InfoBar _ = gettext.gettext class ToolbarItem(object): def __init__(self, id, label, tooltip=None, icon_name=None, accel_path=None, toggle=False): self.id = id self.label = label self.tooltip = tooltip self.icon_name = icon_name self.accel_path = accel_path self.toggle = toggle @property def menu(self): return True @property def toolbar(self): return bool(self.tooltip) class TabContent(InfoBar): def __init__(self, **attributes): super(TabContent, self).__init__() self.attributes = attributes.copy() @property def menu_def(self): return [ ToolbarItem( id='switch', label=_("_Switch View"), tooltip=_("Switch View"), icon_name='tryton-switch', accel_path='/Form/Switch View'), ToolbarItem( id='previous', label=_("_Previous"), tooltip=_("Previous Record"), icon_name='tryton-back', accel_path='/Form/Previous'), ToolbarItem( id='next', label=_("_Next"), tooltip=_("Next Record"), icon_name='tryton-forward', accel_path='/Form/Next'), ToolbarItem( id='search', label=_("_Search"), icon_name='tryton-search', accel_path='/Form/Search'), None, ToolbarItem( id='new', label=_("_New"), tooltip=_("Create a new record"), icon_name='tryton-create', accel_path='/Form/New'), ToolbarItem( id='save', label=_("_Save"), tooltip=_("Save this record"), icon_name='tryton-save', accel_path='/Form/Save'), ToolbarItem( id='reload', label=_("_Reload/Undo"), tooltip=_("Reload/Undo"), icon_name='tryton-refresh', accel_path='/Form/Reload'), ToolbarItem( id='copy', label=_("_Duplicate"), icon_name='tryton-copy', accel_path='/Form/Duplicate'), ToolbarItem( id='remove', label=_("_Delete..."), icon_name='tryton-delete', accel_path='/Form/Delete'), None, ToolbarItem( id='logs', label=_("View _Logs..."), icon_name='tryton-log'), ToolbarItem( id='revision' if self.model in common.MODELHISTORY else None, label=_("Show revisions..."), icon_name='tryton-history'), None, ToolbarItem( id='attach', label=_("A_ttachments..."), tooltip=_("Add an attachment to the record"), icon_name='tryton-attach', accel_path='/Form/Attachments', toggle=True), ToolbarItem( id='note', label=_("_Notes..."), tooltip=_("Add a note to the record"), icon_name='tryton-note', accel_path='/Form/Notes'), ToolbarItem( id='action', label=_("_Actions..."), icon_name='tryton-launch', accel_path='/Form/Actions'), ToolbarItem( id='relate', label=_("_Relate..."), icon_name='tryton-link', accel_path='/Form/Relate'), None, ToolbarItem( id='print_open', label=_("_Report..."), icon_name='tryton-open', accel_path='/Form/Report'), ToolbarItem( id='print_email', label=_("_E-Mail..."), icon_name='tryton-email', accel_path='/Form/Email'), ToolbarItem( id='print', label=_("_Print..."), icon_name='tryton-print', accel_path='/Form/Print'), None, ToolbarItem( id='export', label=_("_Export Data..."), icon_name='tryton-export', accel_path='/Form/Export Data'), ToolbarItem( id='import', label=_("_Import Data..."), icon_name='tryton-import', accel_path='/Form/Import Data'), ToolbarItem( id='copy_url', label=_("Copy _URL..."), icon_name='tryton-public', accel_path='/Form/Copy URL'), None, ToolbarItem( id='win_close', label=_("_Close Tab"), icon_name='tryton-close', accel_path='/Form/Close'), ] def create_tabcontent(self): self.buttons = {} self.menu_buttons = {} self.tooltips = common.Tooltips() self.accel_group = Main().accel_group self.widget = gtk.VBox(spacing=3) self.widget.show() title_box = self.make_title_bar() self.widget.pack_start(title_box, expand=False, fill=True, padding=3) self.toolbar = self.create_toolbar(self.get_toolbars()) self.toolbar.show_all() self.widget.pack_start(self.toolbar, False, True) viewport = gtk.Viewport() viewport.set_shadow_type(gtk.SHADOW_NONE) viewport.add(self.widget_get()) viewport.show() self.scrolledwindow = gtk.ScrolledWindow() self.scrolledwindow.set_shadow_type(gtk.SHADOW_NONE) self.scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) self.scrolledwindow.add(viewport) self.scrolledwindow.show() self.widget.pack_start(self.scrolledwindow) self.create_info_bar() self.widget.pack_start(self.info_bar, False, True) def make_title_bar(self): self.title = title = gtk.Label() title.modify_font(pango.FontDescription("bold 14")) title.set_label(common.ellipsize(self.name, 80)) title.set_padding(10, 4) title.set_alignment(0.0, 0.5) title.set_size_request(0, -1) # Allow overflow title.set_max_width_chars(1) title.set_ellipsize(pango.ELLIPSIZE_END) title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) title.show() menu = Gtk.MenuButton.new() menu.set_relief(Gtk.ReliefStyle.NONE) menu.set_popup(self.set_menu_form()) menu.show() self.status_label = gtk.Label() self.status_label.set_padding(5, 4) self.status_label.set_alignment(0.0, 0.5) self.status_label.show() hbox = gtk.HBox() hbox.pack_start(title, expand=True, fill=True) hbox.pack_start(self.status_label, expand=False, fill=True) hbox.show() frame = gtk.Frame() frame.set_shadow_type(gtk.SHADOW_ETCHED_IN) frame.add(hbox) frame.show() eb = gtk.EventBox() eb.add(frame) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff")) eb.show() frame_menu = gtk.Frame() frame_menu.set_shadow_type(gtk.SHADOW_ETCHED_IN) frame_menu.add(menu) frame_menu.show() title_box = gtk.HBox() title_box.pack_start(frame_menu, expand=False, fill=True) title_box.pack_start(eb, expand=True, fill=True) title_box.show() return title_box def create_base_toolbar(self, toolbar): previous = None for item in self.menu_def: if item and item.toolbar: callback = getattr(self, 'sig_%s' % item.id, None) if not callback: continue if item.toggle: toolitem = gtk.ToggleToolButton() toolitem.connect('toggled', callback) else: toolitem = gtk.ToolButton() toolitem.connect('clicked', callback) toolitem.set_icon_widget( common.IconFactory.get_image( item.icon_name, gtk.ICON_SIZE_LARGE_TOOLBAR)) toolitem.set_label(item.label) toolitem.set_use_underline(True) self.tooltips.set_tip(toolitem, item.tooltip) self.buttons[item.id] = toolitem elif not item and previous: toolitem = gtk.SeparatorToolItem() else: continue previous = item toolbar.insert(toolitem, -1) def set_menu_form(self): menu_form = gtk.Menu() menu_form.set_accel_group(self.accel_group) menu_form.set_accel_path('/Form') previous = None for item in self.menu_def: if item and item.menu: callback = getattr(self, 'sig_%s' % item.id, None) if not callback: continue menuitem = gtk.ImageMenuItem(item.label, self.accel_group) menuitem.set_use_underline(True) menuitem.connect('activate', callback) if item.icon_name: menuitem.set_image( common.IconFactory.get_image( item.icon_name, gtk.ICON_SIZE_MENU)) if item.accel_path: menuitem.set_accel_path(item.accel_path) self.menu_buttons[item.id] = menuitem elif not item and previous: menuitem = gtk.SeparatorMenuItem() else: continue previous = item menu_form.add(menuitem) menu_form.show_all() return menu_form def create_toolbar(self, toolbars): gtktoolbar = gtk.Toolbar() option = CONFIG['client.toolbar'] if option == 'default': gtktoolbar.set_style(False) elif option == 'both': gtktoolbar.set_style(gtk.TOOLBAR_BOTH) elif option == 'text': gtktoolbar.set_style(gtk.TOOLBAR_TEXT) elif option == 'icons': gtktoolbar.set_style(gtk.TOOLBAR_ICONS) self.create_base_toolbar(gtktoolbar) return gtktoolbar def compare(self, model, attributes): return False tryton-5.0.17/tryton/gui/window/win_csv.py0000644000175000017500000003144213524765775020160 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import locale import os import sys import gtk import gobject import gettext from tryton.common import IconFactory from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main from tryton.gui.window.nomodal import NoModal _ = gettext.gettext encodings = ["ascii", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp720", "cp737", "cp775", "cp850", "cp852", "cp855", "cp856", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949", "cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", "euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2", "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5", "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "iso8859_16", "johab", "koi8_r", "koi8_u", "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004", "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8", "utf_8_sig"] class WinCSV(NoModal): def __init__(self, *args, **kwargs): super(WinCSV, self).__init__(*args, **kwargs) self.dialog = gtk.Dialog( parent=self.parent, flags=gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.dialog) self.dialog.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.dialog.set_icon(TRYTON_ICON) self.dialog.connect('response', self.response) dialog_vbox = gtk.VBox() hbox_mapping = gtk.HBox(True) dialog_vbox.pack_start(hbox_mapping, True, True, 0) frame_fields = gtk.Frame() frame_fields.set_shadow_type(gtk.SHADOW_NONE) viewport_fields = gtk.Viewport() scrolledwindow_fields = gtk.ScrolledWindow() scrolledwindow_fields.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) viewport_fields.add(scrolledwindow_fields) frame_fields.add(viewport_fields) label_all_fields = gtk.Label(_('All fields')) label_all_fields.set_use_markup(True) frame_fields.set_label_widget(label_all_fields) hbox_mapping.pack_start(frame_fields, True, True, 0) vbox_buttons = gtk.VBox(False, 10) vbox_buttons.set_border_width(5) hbox_mapping.pack_start(vbox_buttons, False, True, 0) button_add = gtk.Button(_('_Add'), stock=None, use_underline=True) button_add.set_image(IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_BUTTON)) button_add.set_always_show_image(True) button_add.connect_after('clicked', self.sig_sel) vbox_buttons.pack_start(button_add, False, False, 0) button_remove = gtk.Button( _('_Remove'), stock=None, use_underline=True) button_remove.set_image(IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_BUTTON)) button_remove.set_always_show_image(True) button_remove.connect_after('clicked', self.sig_unsel) vbox_buttons.pack_start(button_remove, False, False, 0) button_remove_all = gtk.Button( _('_Clear'), stock=None, use_underline=True) button_remove_all.set_image(IconFactory.get_image( 'tryton-clear', gtk.ICON_SIZE_BUTTON)) button_remove_all.set_always_show_image(True) button_remove_all.connect_after('clicked', self.sig_unsel_all) vbox_buttons.pack_start(button_remove_all, False, False, 0) hseparator_buttons = gtk.HSeparator() vbox_buttons.pack_start(hseparator_buttons, False, False, 3) self.add_buttons(vbox_buttons) frame_fields_selected = gtk.Frame() frame_fields_selected.set_shadow_type(gtk.SHADOW_NONE) viewport_fields_selected = gtk.Viewport() scrolledwindow_fields_selected = gtk.ScrolledWindow() scrolledwindow_fields_selected.set_policy( gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) viewport_fields_selected.add(scrolledwindow_fields_selected) frame_fields_selected.add(viewport_fields_selected) label_fields_selected = gtk.Label(_('Fields selected')) label_fields_selected .set_use_markup(True) frame_fields_selected.set_label_widget(label_fields_selected) hbox_mapping.pack_start(frame_fields_selected, True, True, 0) frame_csv_param = gtk.Frame() frame_csv_param.set_shadow_type(gtk.SHADOW_ETCHED_OUT) dialog_vbox.pack_start(frame_csv_param, False, True, 0) alignment_csv_param = gtk.Alignment(0.5, 0.5, 1, 1) alignment_csv_param.set_padding(7, 7, 7, 7) frame_csv_param.add(alignment_csv_param) vbox_csv_param = gtk.VBox() alignment_csv_param.add(vbox_csv_param) self.add_chooser(vbox_csv_param) expander_csv = gtk.Expander() vbox_csv_param.pack_start(expander_csv, False, True, 0) label_csv_param = gtk.Label(_('CSV Parameters')) expander_csv.set_label_widget(label_csv_param) table = gtk.Table(2, 4, False) table.set_border_width(8) table.set_row_spacings(9) table.set_col_spacings(8) expander_csv.add(table) label_csv_delimiter = gtk.Label(_('Delimiter:')) label_csv_delimiter.set_alignment(1, 0.5) table.attach(label_csv_delimiter, 0, 1, 0, 1) self.csv_delimiter = gtk.Entry() self.csv_delimiter.set_max_length(1) if os.name == 'nt' and ',' == locale.localeconv()['decimal_point']: delimiter = ';' else: delimiter = ',' self.csv_delimiter.set_text(delimiter) self.csv_delimiter.set_width_chars(1) label_csv_delimiter.set_mnemonic_widget(self.csv_delimiter) table.attach(self.csv_delimiter, 1, 2, 0, 1) label_csv_quotechar = gtk.Label(_("Quote char:")) label_csv_quotechar.set_alignment(1, 0.5) table.attach(label_csv_quotechar, 2, 3, 0, 1) self.csv_quotechar = gtk.Entry() self.csv_quotechar.set_text("\"") self.csv_quotechar.set_width_chars(1) label_csv_quotechar.set_mnemonic_widget(self.csv_quotechar) table.attach(self.csv_quotechar, 3, 4, 0, 1) label_csv_enc = gtk.Label(_("Encoding:")) label_csv_enc.set_alignment(1, 0.5) table.attach(label_csv_enc, 0, 1, 1, 2) if hasattr(gtk, 'ComboBoxText'): self.csv_enc = gtk.ComboBoxText() else: self.csv_enc = gtk.combo_box_new_text() for i, encoding in enumerate(encodings): self.csv_enc.append_text(encoding) if ((os.name == 'nt' and encoding == 'cp1252') or (os.name != 'nt' and encoding == 'utf_8')): self.csv_enc.set_active(i) label_csv_enc.set_mnemonic_widget(self.csv_enc) table.attach(self.csv_enc, 1, 2, 1, 2) self.add_csv_header_param(table) button_cancel = self.dialog.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) button_cancel.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) button_ok = self.dialog.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) button_ok.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) self.dialog.vbox.pack_start(dialog_vbox) self.view1 = gtk.TreeView() self.view1.get_selection().set_mode(gtk.SELECTION_MULTIPLE) self.view1.connect('row-expanded', self.on_row_expanded) scrolledwindow_fields.add(self.view1) self.view2 = gtk.TreeView() self.view2.get_selection().set_mode(gtk.SELECTION_MULTIPLE) scrolledwindow_fields_selected.add(self.view2) self.view1.set_headers_visible(False) self.view2.set_headers_visible(False) cell = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Field name'), cell, text=0) self.view1.append_column(column) cell = gtk.CellRendererText() column = gtk.TreeViewColumn(_('Field name'), cell, text=0) self.view2.append_column(column) self.model1 = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.model2 = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING) self.model_populate(self._get_fields(self.model)) self.view1.set_model(self.model1) self.view1.connect('row-activated', self.sig_sel) self.view2.set_model(self.model2) self.view2.connect('row-activated', self.sig_unsel) self.dialog.show_all() self.show() self.register() if sys.platform != 'darwin': self.view2.drag_source_set( gtk.gdk.BUTTON1_MASK | gtk.gdk.BUTTON3_MASK, [gtk.TargetEntry.new( 'EXPORT_TREE', gtk.TARGET_SAME_WIDGET, 0)], gtk.gdk.ACTION_MOVE) self.view2.drag_dest_set(gtk.DEST_DEFAULT_ALL, [gtk.TargetEntry.new( 'EXPORT_TREE', gtk.TARGET_SAME_WIDGET, 0)], gtk.gdk.ACTION_MOVE) self.view2.connect('drag-begin', self.drag_begin) self.view2.connect('drag-motion', self.drag_motion) self.view2.connect('drag-drop', self.drag_drop) self.view2.connect("drag-data-get", self.drag_data_get) self.view2.connect('drag-data-received', self.drag_data_received) self.view2.connect('drag-data-delete', self.drag_data_delete) def drag_begin(self, treeview, context): return True def drag_motion(self, treeview, context, x, y, time): try: treeview.set_drag_dest_row(*treeview.get_dest_row_at_pos(x, y)) except TypeError: treeview.set_drag_dest_row(len(treeview.get_model()) - 1, gtk.TREE_VIEW_DROP_AFTER) if hasattr(gtk.gdk, 'drag_status'): gtk.gdk.drag_status(context, gtk.gdk.ACTION_MOVE, time) else: context.drag_status(gtk.gdk.ACTION_MOVE, time) return True def drag_drop(self, treeview, context, x, y, time): treeview.emit_stop_by_name('drag-drop') return True def drag_data_get(self, treeview, context, selection, target_id, etime): treeview.emit_stop_by_name('drag-data-get') def _func_sel_get(store, path, iter_, data): data.append(path[0]) data = [] treeselection = treeview.get_selection() treeselection.selected_foreach(_func_sel_get, data) if not data: return data = ','.join(str(x) for x in data) selection.set(selection.get_target(), 8, data.encode('utf-8')) return True def drag_data_received(self, treeview, context, x, y, selection, info, etime): treeview.emit_stop_by_name('drag-data-received') try: selection_data = selection.data except AttributeError: selection_data = selection.get_data() if not selection_data: return selection_data = selection_data.decode('utf-8') store = treeview.get_model() data_iters = [store.get_iter((int(i),)) for i in selection_data.split(',')] drop_info = treeview.get_dest_row_at_pos(x, y) if drop_info: path, position = drop_info pos = store.get_iter(path) else: pos = store.get_iter((len(store) - 1,)) position = gtk.TREE_VIEW_DROP_AFTER if position == gtk.TREE_VIEW_DROP_AFTER: data_iters = reversed(data_iters) for item in data_iters: if position == gtk.TREE_VIEW_DROP_BEFORE: store.move_before(item, pos) else: store.move_after(item, pos) if hasattr(gtk.gdk, 'drop_finish'): gtk.gdk.drop_finish(context, False, etime) else: context.drop_finish(False, etime) return True def drag_data_delete(self, treeview, context): treeview.emit_stop_by_name('drag-data-delete') def get_delimiter(self): return self.csv_delimiter.get_text() or ',' def get_quotechar(self): return self.csv_quotechar.get_text() or '"' def get_encoding(self): return self.csv_enc.get_active_text() or 'utf_8' def destroy(self): super(WinCSV, self).destroy() self.dialog.destroy() def show(self): self.dialog.show() def hide(self): self.dialog.hide() tryton-5.0.17/tryton/gui/window/shortcuts.py0000644000175000017500000001132413463252532020523 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gtk import gettext from tryton.common import get_toplevel_window, IconFactory from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON from tryton.gui import Main _ = gettext.gettext class Shortcuts(object): 'Shortcuts window' def __init__(self): self.parent = get_toplevel_window() self.dialog = gtk.Dialog(_('Keyboard Shortcuts'), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT | gtk.WIN_POS_CENTER_ON_PARENT | gtk.gdk.WINDOW_TYPE_HINT_DIALOG) Main().add_window(self.dialog) ok_button = self.dialog.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) self.dialog.set_icon(TRYTON_ICON) self.dialog.set_default_response(gtk.RESPONSE_OK) notebook = gtk.Notebook() self.dialog.vbox.pack_start(notebook) shortcuts = [ (_('Text Entries Shortcuts'),), (' + X', _('Cut selected text')), (' + C', _('Copy selected text')), (' + V', _('Paste copied text')), ('', _('Next widget')), (' + ', _('Previous widget')), (_('Relation Entries Shortcuts'),), ('', _('Create new relation')), ('', _('Open/Search relation')), (_('List Entries Shortcuts'),), ('', _('Create new line')), ('', _('Open relation')), ('', _('Mark line for deletion')), ('', _('Unmark line for deletion')), ] notebook.append_page(self._fill_table(shortcuts), gtk.Label(_('Edition Widgets'))) shortcuts = [ (_('Move Cursor'),), ('', _('Move to right')), ('', _('Move to left')), ('', _('Move up')), ('', _('Move down')), ('', _('Move up of one page')), ('', _('Move down of one page')), ('', _('Move to top')), ('', _('Move to bottom')), ('', _('Move to parent')), (_('Selection'),), (' + a', _('Select all')), (' + /', _('Select all')), (' + + a', _('Unselect all')), (' + + /', _('Unselect all')), ('', _('Select parent')), ('', _('Select/Activate current row')), (' + ', _('Select/Activate current row')), ('', _('Select/Activate current row')), ('', _('Select/Activate current row')), (' + ', _('Toggle selection')), (_('Expand/Collapse'),), ('+', _('Expand row')), ('-', _('Collapse row')), ('', _('Toggle row')), (' + ', _('Collapse all rows')), (' + ', _('Expand all rows')), ] notebook.append_page(self._fill_table(shortcuts), gtk.Label(_('Tree view'))) self.dialog.show_all() def _fill_table(self, shortcuts): table = gtk.Table(len(shortcuts), 2) table.set_col_spacings(15) table.set_row_spacings(3) table.set_border_width(8) i = 0 for shortcut in shortcuts: if len(shortcut) == 1: label = gtk.Label() if '\n' not in shortcut[0]: label.set_markup('' + shortcut[0] + '') else: label.set_text(shortcut[0]) label.set_alignment(0, 0.5) label.set_padding(2, 0) table.attach(label, 0, 2, i, i + 1, yoptions=False, xoptions=gtk.FILL) elif len(shortcut) == 2: label = gtk.Label() label.set_text(shortcut[0]) label.set_alignment(0, 0.5) table.attach(label, 0, 1, i, i + 1, yoptions=False, xoptions=gtk.FILL) label = gtk.Label() label.set_text(shortcut[1]) label.set_alignment(0, 0.5) table.attach(label, 1, 2, i, i + 1, yoptions=False, xoptions=gtk.FILL) i += 1 return table def run(self): 'Run the window' self.dialog.run() self.parent.present() self.dialog.destroy() tryton-5.0.17/tryton/gui/window/form.py0000644000175000017500000006635413563614150017444 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Form" import gettext import gtk import gobject from gi.repository import Gtk from tryton.gui.window.view_form.screen import Screen from tryton.action import Action from tryton.gui import Main from tryton.gui.window import Window from tryton.gui.window.win_export import WinExport from tryton.gui.window.win_import import WinImport from tryton.gui.window.attachment import Attachment from tryton.gui.window.note import Note from tryton.gui.window.revision import Revision from tryton.signal_event import SignalEvent from tryton.common import message, sur, sur_3b, timezoned_date import tryton.common as common from tryton.common import RPCExecute, RPCException from tryton.common.datetime_strftime import datetime_strftime from tryton import plugins from .tabcontent import TabContent _ = gettext.gettext class Form(SignalEvent, TabContent): "Form" def __init__(self, model, res_id=None, name='', **attributes): super(Form, self).__init__(**attributes) self.model = model self.res_id = res_id self.mode = attributes.get('mode') self.view_ids = attributes.get('view_ids') self.dialogs = [] self.screen = Screen(self.model, **attributes) self.screen.widget.show() self.name = name self.create_tabcontent() self.set_buttons_sensitive() self.screen.signal_connect(self, 'record-message', self._record_message) self.screen.signal_connect(self, 'record-modified', lambda *a: gobject.idle_add(self._record_modified, *a)) self.screen.signal_connect(self, 'record-saved', self._record_saved) self.screen.signal_connect(self, 'attachment-count', self._attachment_count) self.screen.signal_connect(self, 'unread-note', self._unread_note) if res_id not in (None, False): if isinstance(res_id, int): res_id = [res_id] self.screen.load(res_id) else: if self.screen.current_view.view_type == 'form': self.sig_new(None, autosave=False) if self.screen.current_view.view_type \ in ('tree', 'graph', 'calendar'): self.screen.search_filter() self.update_revision() def get_toolbars(self): try: return RPCExecute('model', self.model, 'view_toolbar_get', context=self.screen.context) except RPCException: return {} def widget_get(self): return self.screen.widget def compare(self, model, attributes): if not attributes: return False return (self.model == model and self.res_id == attributes.get('res_id') and self.attributes.get('domain') == attributes.get('domain') and (self.attributes.get('mode') or []) == ( attributes.get('mode') or []) and self.attributes.get('view_ids') == attributes.get('view_ids') and self.attributes.get('context') == attributes.get('context') and self.attributes.get('limit') == attributes.get('limit') and self.attributes.get('search_value') == ( attributes.get('search_value'))) def __hash__(self): return id(self) def destroy(self): super(Form, self).destroy() self.screen.signal_unconnect(self) self.screen.destroy() def sig_attach(self, widget=None): def window(widget): return Attachment( record, lambda: self.update_attachment_count(reload=True)) def add_file(widget): filenames = common.file_selection(_("Select"), multi=True) if filenames: attachment = window(widget) for filename in filenames: attachment.add_file(filename) def activate(widget, callback): callback() button = self.buttons['attach'] if widget != button: if button.props.sensitive: button.props.active = True return record = self.screen.current_record menu = button._menu = Gtk.Menu() for name, callback in Attachment.get_attachments(record): item = Gtk.MenuItem() item.set_label(name) item.connect('activate', activate, callback) menu.add(item) menu.add(Gtk.SeparatorMenuItem()) add_item = Gtk.MenuItem() add_item.set_label(_("Add...")) add_item.connect('activate', add_file) menu.add(add_item) manage_item = Gtk.MenuItem() manage_item.set_label(_("Manage...")) manage_item.connect('activate', window) menu.add(manage_item) menu.show_all() menu.connect('deactivate', self._popup_menu_hide, button) self.action_popup(button) def update_attachment_count(self, reload=False): record = self.screen.current_record if record: attachment_count = record.get_attachment_count(reload=reload) else: attachment_count = 0 self._attachment_count(None, attachment_count) def _attachment_count(self, widget, signal_data): label = _('Attachment(%d)') % signal_data self.buttons['attach'].set_label(label) if signal_data: # FIXME icon = 'tryton-attach' else: icon = 'tryton-attach' image = common.IconFactory.get_image(icon, gtk.ICON_SIZE_LARGE_TOOLBAR) image.show() self.buttons['attach'].set_icon_widget(image) record = self.screen.current_record self.buttons['attach'].props.sensitive = bool( record.id >= 0 if record else False) def sig_note(self, widget=None): record = self.screen.current_record if not record or record.id < 0: return Note(record, lambda: self.update_unread_note(reload=True)) def update_unread_note(self, reload=False): record = self.screen.current_record if record: unread = record.get_unread_note(reload=reload) else: unread = 0 self._unread_note(None, unread) def _unread_note(self, widget, signal_data): label = _('Note(%d)') % signal_data self.buttons['note'].set_label(label) if signal_data: self.buttons['note'].set_stock_id('tryton-note-hi') else: self.buttons['note'].set_stock_id('tryton-note') record = self.screen.current_record if not record or record.id < 0: sensitive = False else: sensitive = True self.buttons['note'].props.sensitive = sensitive def sig_switch(self, widget=None): if not self.modified_save(): return self.screen.switch_view() def sig_logs(self, widget=None): current_record = self.screen.current_record if not current_record or current_record.id < 0: self.message_info( _('You have to select one record.'), gtk.MESSAGE_INFO) return False fields = [ ('id', _('ID:')), ('create_uid.rec_name', _('Creation User:')), ('create_date', _('Creation Date:')), ('write_uid.rec_name', _('Latest Modification by:')), ('write_date', _('Latest Modification Date:')), ] try: res = RPCExecute('model', self.model, 'read', [current_record.id], [x[0] for x in fields], context=self.screen.context) except RPCException: return date_format = self.screen.context.get('date_format', '%x') datetime_format = date_format + ' %H:%M:%S.%f' message_str = '' for line in res: for (key, val) in fields: value = str(line.get(key, False) or '/') if line.get(key, False) \ and key in ('create_date', 'write_date'): date = timezoned_date(line[key]) value = common.datetime_strftime(date, datetime_format) message_str += val + ' ' + value + '\n' message_str += _('Model:') + ' ' + self.model message(message_str) return True def sig_revision(self, widget=None): if not self.modified_save(): return current_id = (self.screen.current_record.id if self.screen.current_record else None) try: revisions = RPCExecute('model', self.model, 'history_revisions', [r.id for r in self.screen.selected_records]) except RPCException: return revision = self.screen.context.get('_datetime') format_ = self.screen.context.get('date_format', '%x') format_ += ' %H:%M:%S.%f' revision = Revision(revisions, revision, format_).run() # Prevent too old revision in form view if (self.screen.current_view.view_type == 'form' and revision and revision < revisions[-1][0]): revision = revisions[-1][0] if revision != self.screen.context.get('_datetime'): self.screen.clear() # Update root group context that will be propagated self.screen.group._context['_datetime'] = revision if self.screen.current_view.view_type != 'form': self.screen.search_filter( self.screen.screen_container.get_text()) else: # Test if record exist in revisions self.screen.load([current_id]) self.screen.display(set_cursor=True) self.update_revision() def update_revision(self): tooltips = common.Tooltips() revision = self.screen.context.get('_datetime') if revision: format_ = self.screen.context.get('date_format', '%x') format_ += ' %H:%M:%S.%f' revision_label = ' @ %s' % datetime_strftime(revision, format_) label = common.ellipsize( self.name, 80 - len(revision_label)) + revision_label tooltip = self.name + revision_label else: label = common.ellipsize(self.name, 80) tooltip = self.name self.title.set_label(label) tooltips.set_tip(self.title, tooltip) self.set_buttons_sensitive(revision) def set_buttons_sensitive(self, revision=None): if not revision: access = common.MODELACCESS[self.model] for name, sensitive in [ ('new', access['create']), ('save', access['create'] or access['write']), ('remove', access['delete']), ('copy', access['create']), ('import', access['create']), ]: if name in self.buttons: self.buttons[name].props.sensitive = sensitive if name in self.menu_buttons: self.menu_buttons[name].props.sensitive = sensitive else: for name in ['new', 'save', 'remove', 'copy', 'import']: if name in self.buttons: self.buttons[name].props.sensitive = False if name in self.menu_buttons: self.menu_buttons[name].props.sensitive = False def sig_remove(self, widget=None): if not common.MODELACCESS[self.model]['delete']: return if self.screen.current_view.view_type == 'form': msg = _('Are you sure to remove this record?') else: msg = _('Are you sure to remove those records?') if sur(msg): if not self.screen.remove(delete=True, force_remove=True): self.message_info(_('Records not removed.'), gtk.MESSAGE_ERROR) else: self.message_info(_('Records removed.'), gtk.MESSAGE_INFO) self.screen.count_tab_domain() def sig_import(self, widget=None): WinImport(self.title.get_text(), self.model, self.screen.context) def sig_export(self, widget=None): export = WinExport( self.title.get_text(), self.model, [r.id for r in self.screen.selected_records], context=self.screen.context) for name in self.screen.current_view.get_fields(): type = self.screen.group.fields[name].attrs['type'] if type == 'selection': export.sel_field(name + '.translated') elif type == 'reference': export.sel_field(name + '.translated') export.sel_field(name + '/rec_name') else: export.sel_field(name) def sig_new(self, widget=None, autosave=True): if not common.MODELACCESS[self.model]['create']: return if autosave: if not self.modified_save(): return self.screen.new() self.message_info() self.activate_save() def sig_copy(self, widget=None): if not common.MODELACCESS[self.model]['create']: return if not self.modified_save(): return if self.screen.copy(): self.message_info(_('Working now on the duplicated record(s).'), gtk.MESSAGE_INFO) self.screen.count_tab_domain() def sig_save(self, widget=None): if widget: # Called from button so we must save the tree state self.screen.save_tree_state() if not (common.MODELACCESS[self.model]['write'] or common.MODELACCESS[self.model]['create']): return if self.screen.save_current(): self.message_info(_('Record saved.'), gtk.MESSAGE_INFO) self.screen.count_tab_domain() return True else: self.message_info(self.screen.invalid_message(), gtk.MESSAGE_ERROR) return False def sig_previous(self, widget=None): if not self.modified_save(): return self.screen.display_prev() self.message_info() self.activate_save() def sig_next(self, widget=None): if not self.modified_save(): return self.screen.display_next() self.message_info() self.activate_save() def sig_reload(self, test_modified=True): if test_modified: if not self.modified_save(): return False else: self.screen.save_tree_state(store=False) self.screen.cancel_current() set_cursor = False record_id = (self.screen.current_record.id if self.screen.current_record else None) if self.screen.current_view.view_type != 'form': self.screen.search_filter(self.screen.screen_container.get_text()) for record in self.screen.group: if record.id == record_id: self.screen.current_record = record set_cursor = True break self.screen.display(set_cursor=set_cursor) self.message_info() self.activate_save() self.screen.count_tab_domain() return True def sig_action(self, widget): if self.buttons['action'].props.sensitive: self.buttons['action'].props.active = True def sig_print(self, widget): if self.buttons['print'].props.sensitive: self.buttons['print'].props.active = True def sig_print_open(self, widget): if self.buttons['open'].props.sensitive: self.buttons['open'].props.active = True def sig_print_email(self, widget): if self.buttons['email'].props.sensitive: self.buttons['email'].props.active = True def sig_relate(self, widget): if self.buttons['relate'].props.sensitive: self.buttons['relate'].props.active = True def sig_copy_url(self, widget): if self.buttons['copy_url'].props.sensitive: self.buttons['copy_url'].props.active = True def sig_search(self, widget): search_container = self.screen.screen_container if hasattr(search_container, 'search_entry'): search_container.search_entry.grab_focus() def action_popup(self, widget): button, = widget.get_children() button.grab_focus() menu = widget._menu if not widget.props.active: menu.popdown() return def menu_position(menu, data): widget_allocation = widget.get_allocation() if hasattr(widget.window, 'get_root_coords'): x, y = widget.window.get_root_coords( widget_allocation.x, widget_allocation.y) else: x, y = widget.window.get_origin() x += widget_allocation.x y += widget_allocation.y return (x, y + widget_allocation.height, False) menu.show_all() menu.popup(None, None, menu_position, 0, gtk.get_current_event_time(), None) def _record_message(self, screen, signal_data): name = '_' if signal_data[0]: name = str(signal_data[0]) for button_id in ('print', 'relate', 'email', 'open', 'save', 'attach'): button = self.buttons[button_id] can_be_sensitive = getattr(button, '_can_be_sensitive', True) if button_id in {'print', 'relate', 'email', 'open'}: action_type = button_id if button_id in {'email', 'open'}: action_type = 'print' can_be_sensitive |= any( b.attrs.get('keyword', 'action') == action_type for b in screen.get_buttons()) button.props.sensitive = (bool(signal_data[0]) and can_be_sensitive) button_switch = self.buttons['switch'] button_switch.props.sensitive = self.screen.number_of_views > 1 msg = name + ' / ' + str(signal_data[1]) if signal_data[1] < signal_data[2]: msg += _(' of ') + str(signal_data[2]) self.status_label.set_text(msg) self.message_info() self.activate_save() def _record_modified(self, screen, signal_data): # As it is called via idle_add, the form could have been destroyed in # the meantime. if self.widget_get().props.window: self.activate_save() def _record_saved(self, screen, signal_data): self.activate_save() self.update_attachment_count() def modified_save(self): self.screen.save_tree_state() self.screen.current_view.set_value() if self.screen.modified(): value = sur_3b( _('This record has been modified\n' 'do you want to save it?')) if value == 'ok': return self.sig_save(None) if value == 'ko': return self.sig_reload(test_modified=False) return False return True def sig_close(self, widget=None): for dialog in reversed(self.dialogs[:]): dialog.destroy() return self.modified_save() def _action(self, action, atype): action = action.copy() if self.screen.modified() and not self.sig_save(): return record_id = (self.screen.current_record.id if self.screen.current_record else None) record_ids = [r.id for r in self.screen.selected_records] action = Action.evaluate(action, atype, self.screen.current_record) data = { 'model': self.screen.model_name, 'id': record_id, 'ids': record_ids, } Action._exec_action(action, data, self.screen.local_context) def activate_save(self): self.buttons['save'].props.sensitive = self.screen.modified() def sig_win_close(self, widget): Main().sig_win_close(widget) def create_toolbar(self, toolbars): gtktoolbar = super(Form, self).create_toolbar(toolbars) attach_btn = self.buttons['attach'] target_entry = gtk.TargetEntry.new('text/uri-list', 0, 0) attach_btn.drag_dest_set(gtk.DEST_DEFAULT_ALL, [ target_entry, ], gtk.gdk.ACTION_MOVE | gtk.gdk.ACTION_COPY) attach_btn.connect('drag_data_received', self.attach_drag_data_received) iconstock = { 'print': 'tryton-print', 'action': 'tryton-launch', 'relate': 'tryton-link', 'email': 'tryton-email', 'open': 'tryton-open', } for action_type, special_action, action_name, tooltip in ( ('action', 'action', _('Action'), _('Launch action')), ('relate', 'relate', _('Relate'), _('Open related records')), (None,) * 4, ('print', 'open', _('Report'), _('Open report')), ('print', 'email', _('E-Mail'), _('E-Mail report')), ('print', 'print', _('Print'), _('Print report')), ): if action_type is not None: tbutton = gtk.ToggleToolButton() tbutton.set_icon_widget(common.IconFactory.get_image( iconstock.get(special_action), gtk.ICON_SIZE_LARGE_TOOLBAR)) tbutton.set_label(action_name) tbutton._menu = self._create_popup_menu(tbutton, action_type, toolbars[action_type], special_action) tbutton.connect('toggled', self.action_popup) self.tooltips.set_tip(tbutton, tooltip) self.buttons[special_action] = tbutton if action_type != 'action': tbutton._can_be_sensitive = bool( tbutton._menu.get_children()) else: tbutton = gtk.SeparatorToolItem() gtktoolbar.insert(tbutton, -1) gtktoolbar.insert(gtk.SeparatorToolItem(), -1) url_button = gtk.ToggleToolButton() url_button.set_icon_widget( common.IconFactory.get_image( 'tryton-public', gtk.ICON_SIZE_LARGE_TOOLBAR)) url_button.set_label(_('_Copy URL')) url_button.set_use_underline(True) self.tooltips.set_tip( url_button, _('Copy URL into clipboard')) url_button._menu = url_menu = gtk.Menu() url_menuitem = gtk.MenuItem() url_menuitem.connect('activate', self.url_copy) url_menu.add(url_menuitem) url_menu.show_all() url_menu.connect('deactivate', self._popup_menu_hide, url_button) url_button.connect('toggled', self.url_set, url_menuitem) url_button.connect('toggled', self.action_popup) self.buttons['copy_url'] = url_button gtktoolbar.insert(url_button, -1) return gtktoolbar def _create_popup_menu(self, widget, keyword, actions, special_action): menu = gtk.Menu() menu.connect('deactivate', self._popup_menu_hide, widget) widget.connect('toggled', self._update_popup_menu, menu, keyword) for action in actions: new_action = action.copy() if special_action == 'print': new_action['direct_print'] = True elif special_action == 'email': new_action['email_print'] = True action_name = action['name'] if '_' not in action_name: action_name = '_' + action_name menuitem = gtk.MenuItem(action_name) menuitem.set_use_underline(True) menuitem.connect('activate', self._popup_menu_selected, widget, new_action, keyword) menu.add(menuitem) return menu def _popup_menu_selected(self, menuitem, togglebutton, action, keyword): event = gtk.get_current_event() allow_similar = False if (event.state & gtk.gdk.CONTROL_MASK or event.state & gtk.gdk.MOD1_MASK): allow_similar = True with Window(hide_current=True, allow_similar=allow_similar): self._action(action, keyword) togglebutton.props.active = False def _popup_menu_hide(self, menuitem, togglebutton): togglebutton.props.active = False def _update_popup_menu(self, tbutton, menu, keyword): for item in menu.get_children(): if (getattr(item, '_update_action', False) or isinstance(item, gtk.SeparatorMenuItem)): menu.remove(item) buttons = [b for b in self.screen.get_buttons() if keyword == b.attrs.get('keyword', 'action')] if buttons and menu.get_children(): menu.add(gtk.SeparatorMenuItem()) for button in buttons: menuitem = gtk.ImageMenuItem() menuitem.set_label('_' + button.attrs.get('string', _('Unknown'))) menuitem.set_use_underline(True) if button.attrs.get('icon'): menuitem.set_image(common.IconFactory.get_image( button.attrs['icon'], gtk.ICON_SIZE_MENU)) menuitem.connect('activate', lambda m, attrs: self.screen.button(attrs), button.attrs) menuitem._update_action = True menu.add(menuitem) kw_plugins = [] for plugin in plugins.MODULES: for plugin_spec in plugin.get_plugins(self.model): name, func = plugin_spec[:2] try: plugin_keyword = plugin_spec[2] except IndexError: plugin_keyword = 'action' if keyword != plugin_keyword: continue kw_plugins.append((name, func)) if kw_plugins: menu.add(gtk.SeparatorMenuItem()) for name, func in kw_plugins: menuitem = gtk.MenuItem('_' + name) menuitem.set_use_underline(True) menuitem.connect('activate', lambda m, func: func({ 'model': self.model, 'ids': [r.id for r in self.screen.selected_records], 'id': (self.screen.current_record.id if self.screen.current_record else None), }), func) menuitem._update_action = True menu.add(menuitem) def url_copy(self, menuitem): url = self.screen.get_url(self.name) for selection in [gtk.CLIPBOARD_PRIMARY, gtk.CLIPBOARD_CLIPBOARD]: clipboard = gtk.clipboard_get(selection) clipboard.set_text(url, -1) def url_set(self, button, menuitem): url = self.screen.get_url(self.name) size = 80 if len(url) > size: url = url[:size // 2] + '...' + url[-size // 2:] menuitem.set_label(url) def set_cursor(self): if self.screen: self.screen.set_cursor(reset_view=False) def attach_drag_data_received(self, widget, context, x, y, selection, info, timestamp): record = self.screen.current_record if not record or record.id < 0: return win_attach = Attachment(record, lambda: self.update_attachment_count(reload=True)) if info == 0: for uri in selection.get_uris(): # Win32 cut&paste terminates the list with a NULL character if not uri or uri == '\0': continue win_attach.add_uri(uri) tryton-5.0.17/tryton/gui/window/win_form.py0000644000175000017500000004302213463252532020305 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from tryton.common import TRYTON_ICON import tryton.common as common import gtk import pango import gettext from .infobar import InfoBar from tryton.common.domain_parser import quote from tryton.common.underline import set_underline from tryton.gui import Main from tryton.gui.window.nomodal import NoModal _ = gettext.gettext class WinForm(NoModal, InfoBar): "Form window" def __init__(self, screen, callback, view_type='form', new=False, many=0, domain=None, context=None, save_current=False, title='', rec_name=None): tooltips = common.Tooltips() NoModal.__init__(self) self.screen = screen self.callback = callback self.many = many self.domain = domain self.context = context self.save_current = save_current self.title = title self.prev_view = self.screen.current_view self.screen.screen_container.alternate_view = True self.screen.switch_view(view_type=view_type) if self.screen.current_view.view_type != view_type: self.destroy() return if new: self.screen.new(rec_name=rec_name) self.win = gtk.Dialog(_('Link'), self.parent, gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) self.win.set_position(gtk.WIN_POS_CENTER_ON_PARENT) self.win.set_icon(TRYTON_ICON) self.win.set_deletable(False) self.win.connect('delete-event', lambda *a: True) self.win.connect('close', self.close) self.win.connect('response', self.response) allocation = self.parent.get_allocation() width, height, = allocation.width, allocation.height if self.parent != self.sensible_widget: width = max(width - 150, 0) height = max(height - 150, 0) self.win.set_default_size(width, height) self.accel_group = gtk.AccelGroup() self.win.add_accel_group(self.accel_group) readonly = self.screen.readonly or self.screen.group.readonly self.but_ok = None self.but_new = None self._initial_value = None if view_type == 'form': if new: label, icon = _("Delete"), 'tryton-delete' else: label, icon = _("Cancel"), 'tryton-cancel' self._initial_value = self.screen.current_record.get_eval() self.but_cancel = self.win.add_button( set_underline(label), gtk.RESPONSE_CANCEL) self.but_cancel.set_image(common.IconFactory.get_image( icon, gtk.ICON_SIZE_BUTTON)) self.but_cancel.set_always_show_image(True) if new and self.many: self.but_new = self.win.add_button( set_underline(_("New")), gtk.RESPONSE_ACCEPT) self.but_new.set_image(common.IconFactory.get_image( 'tryton-create', gtk.ICON_SIZE_BUTTON)) self.but_new.set_always_show_image(True) self.but_new.set_accel_path('/Form/New', self.accel_group) if self.save_current: self.but_ok = gtk.Button(_('_Save'), use_underline=True) self.but_ok.set_image(common.IconFactory.get_image( 'tryton-save', gtk.ICON_SIZE_BUTTON)) self.but_ok.set_always_show_image(True) self.but_ok.set_accel_path('/Form/Save', self.accel_group) self.but_ok.set_can_default(True) self.but_ok.show() self.win.add_action_widget(self.but_ok, gtk.RESPONSE_OK) if not new: self.but_ok.props.sensitive = False else: self.but_ok = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) self.but_ok.set_image(common.IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) self.but_ok.set_always_show_image(True) self.but_ok.add_accelerator('clicked', self.accel_group, gtk.keysyms.Return, gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_title(self.title) title = gtk.Label() title.modify_font(pango.FontDescription("bold 12")) title.set_label(common.ellipsize(self.title, 80)) tooltips.set_tip(title, self.title) title.set_padding(20, 3) title.set_alignment(0.0, 0.5) title.set_size_request(0, -1) # Allow overflow title.set_max_width_chars(1) title.set_ellipsize(pango.ELLIPSIZE_END) title.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#000000")) title.show() hbox = gtk.HBox() hbox.pack_start(title, expand=True, fill=True) hbox.show() frame = gtk.Frame() frame.set_shadow_type(gtk.SHADOW_ETCHED_IN) frame.add(hbox) frame.show() eb = gtk.EventBox() eb.add(frame) eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("#ffffff")) eb.show() self.win.vbox.pack_start(eb, expand=False, fill=True, padding=3) if view_type == 'tree': hbox = gtk.HBox(homogeneous=False, spacing=0) access = common.MODELACCESS[screen.model_name] but_switch = gtk.Button() tooltips.set_tip(but_switch, _('Switch')) but_switch.connect('clicked', self.switch_view) but_switch.add(common.IconFactory.get_image( 'tryton-switch', gtk.ICON_SIZE_SMALL_TOOLBAR)) but_switch.set_relief(gtk.RELIEF_NONE) hbox.pack_start(but_switch, expand=False, fill=False) self.but_pre = gtk.Button() tooltips.set_tip(self.but_pre, _('Previous')) self.but_pre.connect('clicked', self._sig_previous) self.but_pre.add(common.IconFactory.get_image( 'tryton-back', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_pre.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_pre, expand=False, fill=False) self.label = gtk.Label('(0,0)') hbox.pack_start(self.label, expand=False, fill=False) self.but_next = gtk.Button() tooltips.set_tip(self.but_next, _('Next')) self.but_next.connect('clicked', self._sig_next) self.but_next.add(common.IconFactory.get_image( 'tryton-forward', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_next.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_next, expand=False, fill=False) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) if domain is not None: self.wid_text = gtk.Entry() self.wid_text.set_property('width_chars', 13) self.wid_text.connect('activate', self._sig_activate) self.wid_text.connect('focus-out-event', self._focus_out) hbox.pack_start(self.wid_text, expand=True, fill=True) self.but_add = gtk.Button() tooltips.set_tip(self.but_add, _('Add')) self.but_add.connect('clicked', self._sig_add) self.but_add.add(common.IconFactory.get_image( 'tryton-add', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_add.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_add, expand=False, fill=False) if not access['read'] or readonly: self.but_add.set_sensitive(False) self.but_remove = gtk.Button() tooltips.set_tip(self.but_remove, _('Remove ')) self.but_remove.connect('clicked', self._sig_remove, True) self.but_remove.add(common.IconFactory.get_image( 'tryton-remove', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_remove.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_remove, expand=False, fill=False) if not access['read'] or readonly: self.but_remove.set_sensitive(False) hbox.pack_start(gtk.VSeparator(), expand=False, fill=True) self.but_new = gtk.Button() tooltips.set_tip(self.but_new, _('Create a new record ')) self.but_new.connect('clicked', self._sig_new) self.but_new.add(common.IconFactory.get_image( 'tryton-create', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_new.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_new, expand=False, fill=False) if not access['create'] or readonly: self.but_new.set_sensitive(False) self.but_del = gtk.Button() tooltips.set_tip(self.but_del, _('Delete selected record ')) self.but_del.connect('clicked', self._sig_remove, False) self.but_del.add(common.IconFactory.get_image( 'tryton-delete', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_del.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_del, expand=False, fill=False) if not access['delete'] or readonly: self.but_del.set_sensitive(False) self.but_undel = gtk.Button() tooltips.set_tip(self.but_undel, _('Undelete selected record ')) self.but_undel.connect('clicked', self._sig_undelete) self.but_undel.add(common.IconFactory.get_image( 'tryton-undo', gtk.ICON_SIZE_SMALL_TOOLBAR)) self.but_undel.set_relief(gtk.RELIEF_NONE) hbox.pack_start(self.but_undel, expand=False, fill=False) if not access['delete'] or readonly: self.but_undel.set_sensitive(False) but_switch.props.sensitive = screen.number_of_views > 1 tooltips.enable() alignment = gtk.Alignment(1.0) alignment.add(hbox) alignment.show_all() self.win.vbox.pack_start(alignment, expand=False, fill=True) scroll = gtk.ScrolledWindow() scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) scroll.set_placement(gtk.CORNER_TOP_LEFT) scroll.set_shadow_type(gtk.SHADOW_NONE) scroll.show() self.win.vbox.pack_start(scroll, expand=True, fill=True) scroll.add(self.screen.screen_container.alternate_viewport) self.create_info_bar() self.win.vbox.pack_start(self.info_bar, False, True) if view_type == 'tree': self.screen.signal_connect(self, 'record-message', self._sig_label) self.screen.screen_container.alternate_viewport.connect( 'key-press-event', self.on_keypress) if self.save_current and not new: self.screen.signal_connect(self, 'record-message', self.activate_save) self.screen.signal_connect(self, 'record-modified', self.activate_save) self.register() self.show() self.screen.display() self.screen.current_view.set_cursor() def on_keypress(self, widget, event): if (event.keyval == gtk.keysyms.F3) \ and self.but_new.get_property('sensitive'): self._sig_new(widget) return False if event.keyval in (gtk.keysyms.Delete, gtk.keysyms.KP_Delete) \ and widget == self.screen.screen_container.alternate_viewport: self._sig_remove(widget) return False def switch_view(self, widget): self.screen.switch_view() def _sig_new(self, widget): self.screen.new() self.screen.current_view.widget.set_sensitive(True) def _sig_next(self, widget): self.screen.display_next() def _sig_previous(self, widget): self.screen.display_prev() def _sig_remove(self, widget, remove=False): self.screen.remove(remove=remove) def _sig_undelete(self, button): self.screen.unremove() def _sig_activate(self, *args): self._sig_add() self.wid_text.grab_focus() def _focus_out(self, *args): if self.wid_text.get_text(): self._sig_add() def _sig_add(self, *args): from tryton.gui.window.win_search import WinSearch domain = self.domain[:] model_name = self.screen.model_name value = self.wid_text.get_text() def callback(result): if result: ids = [x[0] for x in result] self.screen.load(ids, modified=True) self.screen.display(res_id=ids[0]) self.screen.set_cursor() self.wid_text.set_text('') win = WinSearch(model_name, callback, sel_multi=True, context=self.context, domain=domain) win.screen.search_filter(quote(value)) win.show() def _sig_label(self, screen, signal_data): name = '_' access = common.MODELACCESS[screen.model_name] readonly = screen.group.readonly if signal_data[0] >= 1: name = str(signal_data[0]) if self.domain is not None: self.but_remove.set_sensitive(True) if signal_data[0] < signal_data[1]: self.but_next.set_sensitive(True) else: self.but_next.set_sensitive(False) if signal_data[0] > 1: self.but_pre.set_sensitive(True) else: self.but_pre.set_sensitive(False) if access['delete'] and not readonly: self.but_del.set_sensitive(True) self.but_undel.set_sensitive(True) else: self.but_del.set_sensitive(False) self.but_undel.set_sensitive(False) self.but_next.set_sensitive(False) self.but_pre.set_sensitive(False) if self.domain is not None: self.but_remove.set_sensitive(False) line = '(%s/%s)' % (name, signal_data[1]) self.label.set_text(line) def activate_save(self, *args): modified = self.screen.modified() # Keep sensible as change could have been trigger by a Many2One edition sensitive = modified or self.but_ok.props.sensitive self.but_ok.props.sensitive = sensitive self.win.set_default_response( gtk.RESPONSE_OK if sensitive else gtk.RESPONSE_CANCEL) def close(self, widget): widget.emit_stop_by_name('close') self.response(self.win, gtk.RESPONSE_CANCEL) return True def response(self, win, response_id): validate = False cancel_responses = (gtk.RESPONSE_CANCEL, gtk.RESPONSE_DELETE_EVENT) self.screen.current_view.set_value() readonly = self.screen.group.readonly if (response_id not in cancel_responses and not readonly and self.screen.current_record is not None): validate = self.screen.current_record.validate( self.screen.current_view.get_fields()) if validate and self.screen.pre_validate: validate = self.screen.current_record.pre_validate() if validate and self.save_current: if not self.screen.save_current(): validate = False elif validate and self.screen.current_view.view_type == 'form': view = self.screen.current_view for widgets in view.widgets.values(): for widget in widgets: if (hasattr(widget, 'screen') and widget.screen.pre_validate): record = widget.screen.current_record if record: validate = record.pre_validate() if not validate: self.message_info(self.screen.invalid_message(), gtk.MESSAGE_ERROR) self.screen.set_cursor() self.screen.display() return self.message_info() if response_id == gtk.RESPONSE_ACCEPT: self.new() return if (self.screen.current_record and not readonly and response_id in cancel_responses): if (self.screen.current_record.id < 0 or self.save_current): self.screen.cancel_current(self._initial_value) elif self.screen.current_record.modified: self.screen.current_record.cancel() self.screen.current_record.reload() self.screen.current_record.signal('record-changed') result = False else: result = response_id not in cancel_responses self.callback(result) self.destroy() def new(self): self.screen.new() self._initial_value = None self.screen.current_view.display() self.screen.set_cursor(new=True) self.many -= 1 if self.many == 0: self.but_new.set_sensitive(False) self.win.set_default_response(gtk.RESPONSE_OK) def destroy(self): self.screen.screen_container.alternate_view = False viewport = self.screen.screen_container.alternate_viewport if viewport and viewport.get_parent(): viewport.get_parent().remove(viewport) self.screen.switch_view(view_type=self.prev_view.view_type) self.screen.signal_unconnect(self) if getattr(self, 'win', None): self.win.destroy() NoModal.destroy(self) def show(self): self.win.show() def hide(self): self.win.hide() tryton-5.0.17/tryton/gui/window/limit.py0000644000175000017500000000456413463252532017613 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import sys import gtk import gettext from tryton.common import get_toplevel_window, IconFactory from tryton.common.underline import set_underline from tryton.config import TRYTON_ICON, CONFIG from tryton.gui import Main _ = gettext.gettext class Limit(object): 'Set Search Limit' def __init__(self): self.parent = get_toplevel_window() self.win = gtk.Dialog(_('Limit'), self.parent, gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT) Main().add_window(self.win) cancel_button = self.win.add_button( set_underline(_("Cancel")), gtk.RESPONSE_CANCEL) cancel_button.set_image(IconFactory.get_image( 'tryton-cancel', gtk.ICON_SIZE_BUTTON)) cancel_button.set_always_show_image(True) ok_button = self.win.add_button( set_underline(_("OK")), gtk.RESPONSE_OK) ok_button.set_image(IconFactory.get_image( 'tryton-ok', gtk.ICON_SIZE_BUTTON)) ok_button.set_always_show_image(True) self.win.set_default_response(gtk.RESPONSE_OK) self.win.set_icon(TRYTON_ICON) self.win.vbox.set_spacing(3) self.win.vbox.pack_start(gtk.Label( _('Search Limit Settings')), expand=False, fill=True) self.win.vbox.pack_start(gtk.HSeparator()) hbox = gtk.HBox(spacing=3) label = gtk.Label(_('Limit:')) hbox.pack_start(label, expand=True, fill=True) adjustment = gtk.Adjustment(value=CONFIG['client.limit'], lower=1, upper=sys.maxsize, step_incr=10, page_incr=100) self.spin_limit = gtk.SpinButton() self.spin_limit.configure(adjustment, climb_rate=1, digits=0) self.spin_limit.set_numeric(False) self.spin_limit.set_activates_default(True) label.set_mnemonic_widget(self.spin_limit) hbox.pack_start(self.spin_limit, expand=True, fill=True) self.win.vbox.pack_start(hbox, expand=True, fill=True) self.win.show_all() def run(self): 'Run the window' res = self.win.run() if res == gtk.RESPONSE_OK: CONFIG['client.limit'] = self.spin_limit.get_value_as_int() CONFIG.save() self.parent.present() self.win.destroy() return res tryton-5.0.17/tryton/gui/window/board.py0000644000175000017500000000357513463252532017565 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Board" import gettext from tryton.signal_event import SignalEvent from tryton.gui import Main from tryton.gui.window.view_board import ViewBoard from tryton.common import RPCExecute, RPCException from .tabcontent import TabContent _ = gettext.gettext class Board(SignalEvent, TabContent): 'Board' def __init__(self, model, name='', **attributes): super(Board, self).__init__(**attributes) context = attributes.get('context') self.view_ids = attributes.get('view_ids') try: view, = RPCExecute('model', 'ir.ui.view', 'read', self.view_ids, ['arch'], context=context) except RPCException: raise self.board = ViewBoard(view['arch'], context=context) self.model = model self.dialogs = [] if not name: self.name = self.board.name else: self.name = name self.create_tabcontent() def get_toolbars(self): return {} def widget_get(self): return self.board.widget_get() def sig_reload(self, test_modified=True): self.board.reload() return True def sig_close(self): return True def compare(self, model, attributes): if not attributes: return False return (self.model == model and self.attributes.get('view_ids') == attributes.get('view_ids') and self.attributes.get('context') == attributes.get('context')) def __hash__(self): return id(self) def sig_win_close(self, widget): Main().sig_win_close(widget) def set_cursor(self): if not self.board.actions: return first_action = self.board.actions[0] first_action.screen.set_cursor() tryton-5.0.17/tryton/gui/__init__.py0000644000175000017500000000024413463252532016714 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .main import * tryton-5.0.17/tryton/gui/main.py0000644000175000017500000011015413463252532016103 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext import json import logging import os import sys import threading import traceback import webbrowser from urllib.parse import urlparse, parse_qsl, unquote import gobject import gtk from gi.repository import Gtk, GLib, Gio import tryton.common as common import tryton.plugins import tryton.rpc as rpc import tryton.translate as translate from tryton.action import Action from tryton.common import RPCExecute, RPCException, RPCContextReload from tryton.common.cellrendererclickablepixbuf import \ CellRendererClickablePixbuf from tryton.config import CONFIG, TRYTON_ICON, get_config_dir from tryton.exceptions import TrytonError, TrytonServerUnavailable from tryton.gui.window import Window from tryton.jsonrpc import object_hook from tryton.pyson import PYSONDecoder _ = gettext.gettext logger = logging.getLogger(__name__) _PRIORITIES = [getattr(Gio.NotificationPriority, p) for p in ('LOW', 'NORMAL', 'HIGH', 'URGENT')] class Main(Gtk.Application): window = None _instance = None def __new__(cls, *args, **kwargs): if not cls._instance: cls._instance = super().__new__(cls, *args, **kwargs) return cls._instance def do_startup(self): Gtk.Application.do_startup(self) action = Gio.SimpleAction.new('preferences', None) action.connect('activate', lambda *a: self.preferences()) self.add_action(action) action = Gio.SimpleAction.new('menu-search', None) action.connect( 'activate', lambda *a: self.global_search_entry.grab_focus()) self.add_action(action) self.add_accelerator('k', 'app.menu-search') action = Gio.SimpleAction.new('menu-toggle', None) action.connect('activate', lambda *a: self.menu_toggle()) self.add_action(action) self.add_accelerator('m', 'app.menu-toggle') toolbar_variant = GLib.Variant.new_string( CONFIG['client.toolbar'] or 'both') action = Gio.SimpleAction.new_stateful( 'toolbar', toolbar_variant.get_type(), toolbar_variant) action.connect('change-state', self.on_change_toolbar) self.add_action(action) def on_change_action_boolean(action, value, key): action.set_state(value) CONFIG[key] = value.get_boolean() if key == 'client.check_version' and CONFIG[key]: common.check_version(self.info) for name, key in [ ('mode-pda', 'client.modepda'), ('save-width-height', 'client.save_width_height'), ('save-tree-state', 'client.save_tree_state'), ('fast-tabbing', 'client.fast_tabbing'), ('spell-checking', 'client.spellcheck'), ('check-version', 'client.check_version'), ]: variant = GLib.Variant.new_boolean(CONFIG[key]) action = Gio.SimpleAction.new_stateful(name, None, variant) action.connect('change-state', on_change_action_boolean, key) self.add_action(action) action = Gio.SimpleAction.new('tab-previous', None) action.connect('activate', lambda *a: self.win_prev()) self.add_action(action) self.add_accelerator('Left', 'app.tab-previous') action = Gio.SimpleAction.new('tab-next', None) action.connect('activate', lambda *a: self.win_next()) self.add_action(action) self.add_accelerator('Right', 'app.tab-next') action = Gio.SimpleAction.new('search-limit', None) action.connect('activate', lambda *a: self.edit_limit()) self.add_action(action) action = Gio.SimpleAction.new('email', None) action.connect('activate', lambda *a: self.edit_email()) self.add_action(action) action = Gio.SimpleAction.new('shortcuts', None) action.connect('activate', lambda *a: self.shortcuts()) self.add_action(action) action = Gio.SimpleAction.new('about', None) action.connect('activate', lambda *a: self.about()) self.add_action(action) action = Gio.SimpleAction.new('quit', None) action.connect('activate', self.on_quit) self.add_action(action) self.add_accelerator('q', 'app.quit') menu = Gio.Menu.new() menu.append(_("Preferences..."), 'app.preferences') section = Gio.Menu.new() toolbar = Gio.Menu.new() section.append_submenu(_("Toolbar"), toolbar) toolbar.append(_("Default"), 'app.toolbar::default') toolbar.append(_("Text and Icons"), 'app.toolbar::both') toolbar.append(_("Text"), 'app.toolbar::text') toolbar.append(_("Icons"), 'app.toolbar::icons') form = Gio.Menu.new() section.append_submenu(_("Form"), form) form.append(_("Save Width/Height"), 'app.save-width-height') form.append(_("Save Tree State"), 'app.save-tree-state') form.append(_("Fast Tabbing"), 'app.fast-tabbing') form.append(_("Spell Checking"), 'app.spell-checking') section.append(_("PDA Mode"), 'app.mode-pda') section.append(_("Search Limit..."), 'app.search-limit') section.append(_("Email..."), 'app.email') section.append(_("Check Version"), 'app.check-version') menu.append_section(_("Options"), section) section = Gio.Menu.new() section.append(_("Keyboard Shortcuts..."), 'app.shortcuts') section.append(_("About..."), 'app.about') menu.append_section(_("Help"), section) section = Gio.Menu.new() section.append(_("Quit"), 'app.quit') menu.append_section(None, section) self.set_app_menu(menu) def do_activate(self): if self.window: self.window.present() return self.window = Gtk.ApplicationWindow(application=self, title="Tryton") self.window.set_default_size(960, 720) self.window.maximize() self.window.set_position(Gtk.WIN_POS_CENTER) self.window.set_resizable(True) self.window.set_icon(TRYTON_ICON) self.window.connect("destroy", self.on_quit) self.window.connect("delete_event", self.on_quit) self.header = Gtk.HeaderBar.new() self.header.set_show_close_button(True) self.window.set_titlebar(self.header) self.set_title() menu = Gtk.Button.new() menu .set_relief(Gtk.ReliefStyle.NONE) menu.set_image( common.IconFactory.get_image('tryton-menu', Gtk.IconSize.BUTTON)) menu.connect('clicked', self.menu_toggle) self.header.pack_start(menu) favorite = Gtk.MenuButton.new() favorite.set_relief(Gtk.ReliefStyle.NONE) favorite.set_image(common.IconFactory.get_image( 'tryton-bookmarks', Gtk.IconSize.BUTTON)) self.menu_favorite = Gtk.Menu.new() favorite.set_popup(self.menu_favorite) favorite.connect('clicked', self.favorite_set) self.header.pack_start(favorite) self.set_global_search() self.header.pack_start(self.global_search_entry) self.accel_group = Gtk.AccelGroup() self.window.add_accel_group(self.accel_group) gtk.accel_map_add_entry('/Form/New', gtk.keysyms.N, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Save', gtk.keysyms.S, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Duplicate', gtk.keysyms.D, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK) gtk.accel_map_add_entry('/Form/Delete', gtk.keysyms.D, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Next', gtk.keysyms.Page_Down, 0) gtk.accel_map_add_entry('/Form/Previous', gtk.keysyms.Page_Up, 0) gtk.accel_map_add_entry('/Form/Switch View', gtk.keysyms.L, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Close', gtk.keysyms.W, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Reload', gtk.keysyms.R, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Attachments', gtk.keysyms.T, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK) gtk.accel_map_add_entry('/Form/Notes', gtk.keysyms.O, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK) gtk.accel_map_add_entry('/Form/Relate', gtk.keysyms.R, gtk.gdk.CONTROL_MASK | gtk.gdk.SHIFT_MASK) gtk.accel_map_add_entry('/Form/Actions', gtk.keysyms.E, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Report', gtk.keysyms.P, gtk.gdk.CONTROL_MASK) gtk.accel_map_add_entry('/Form/Search', gtk.keysyms.F, gtk.gdk.CONTROL_MASK) gtk.accel_map_load(os.path.join(get_config_dir(), 'accel.map')) self.tooltips = common.Tooltips() self.vbox = gtk.VBox() self.window.add(self.vbox) self.buttons = {} self.info = gtk.VBox() self.vbox.pack_start(self.info, expand=False) if CONFIG['client.check_version']: common.check_version(self.info) GLib.timeout_add_seconds( int(CONFIG['download.frequency']), common.check_version, self.info) self.pane = gtk.HPaned() self.vbox.pack_start(self.pane, True, True) self.pane.set_position(int(CONFIG['menu.pane'])) self.menu_screen = None self.menu = gtk.VBox() self.menu.set_vexpand(True) self.pane.add1(self.menu) self.notebook = gtk.Notebook() self.notebook.popup_enable() self.notebook.set_scrollable(True) self.notebook.connect_after('switch-page', self._sig_page_changt) self.pane.add2(self.notebook) self.window.show_all() self.pages = [] self.previous_pages = {} self.current_page = 0 self.last_page = 0 self.dialogs = [] # Register plugins tryton.plugins.register() self.set_title() # Adds username/profile while password is asked try: common.Login() except Exception as exception: if (not isinstance(exception, TrytonError) or exception.faultCode != 'QueryCanceled'): common.error(str(exception), traceback.format_exc()) return self.quit() self.get_preferences() def do_command_line(self, cmd): self.do_activate() arguments = cmd.get_arguments() if len(arguments) > 1: url = arguments[1] self.open_url(url) return True def do_shutdown(self): Gtk.Application.do_shutdown(self) common.Logout() CONFIG.save() Gtk.AccelMap.save(os.path.join(get_config_dir(), 'accel.map')) def on_quit(self, *args): try: if not self.close_pages(): return True except TrytonServerUnavailable: pass rpc.logout() self.quit() def set_global_search(self): self.global_search_entry = Gtk.Entry.new() self.global_search_entry.set_width_chars(20) global_search_completion = gtk.EntryCompletion() global_search_completion.set_match_func(lambda *a: True) global_search_completion.set_model(gtk.ListStore( gtk.gdk.Pixbuf, str, str, int, str)) pixbuf_cell = gtk.CellRendererPixbuf() global_search_completion.pack_start(pixbuf_cell, False) global_search_completion.add_attribute(pixbuf_cell, 'pixbuf', 0) text_cell = gtk.CellRendererText() global_search_completion.pack_start(text_cell) global_search_completion.add_attribute(text_cell, "markup", 1) global_search_completion.props.popup_set_width = True self.global_search_entry.set_completion(global_search_completion) def match_selected(completion, model, iter_): model, record_id, model_name = model.get(iter_, 2, 3, 4) if model == self.menu_screen.model_name: # ids is not defined to prevent to add suffix Action.exec_keyword('tree_open', { 'model': model, 'id': record_id, }) else: Window.create(model, res_id=record_id, mode=['form', 'tree'], name=model_name) self.global_search_entry.set_text('') return True global_search_completion.connect('match-selected', match_selected) def update(widget, search_text, callback=None): def end(): if callback: callback() return False if search_text != widget.get_text(): return end() gmodel = global_search_completion.get_model() if not search_text or not gmodel: gmodel.clear() gmodel.search_text = search_text return end() if getattr(gmodel, 'search_text', None) == search_text: return end() def set_result(result): try: result = result() except RPCException: result = [] if search_text != widget.get_text(): if callback: callback() return False gmodel.clear() for r in result: _, model, model_name, record_id, record_name, icon = r if icon: text = common.to_xml(record_name) pixbuf = common.IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_BUTTON) else: text = '%s:\n %s' % ( common.to_xml(model_name), common.to_xml(record_name)) pixbuf = None gmodel.append([pixbuf, text, model, record_id, model_name]) gmodel.search_text = search_text # Force display of popup widget.emit('changed') end() RPCExecute('model', 'ir.model', 'global_search', search_text, CONFIG['client.limit'], self.menu_screen.model_name, context=self.menu_screen.context, callback=set_result) return False def changed(widget): search_text = widget.get_text() gobject.timeout_add(300, update, widget, search_text) def activate(widget): def message(): gmodel = global_search_completion.get_model() if not len(gmodel): common.message(_('No result found.')) else: widget.emit('changed') search_text = widget.get_text() update(widget, search_text, message) self.global_search_entry.connect('changed', changed) self.global_search_entry.connect('activate', activate) def set_title(self, value=''): if CONFIG['login.profile']: login_info = CONFIG['login.profile'] else: login_info = '%s@%s/%s' % ( CONFIG['login.login'], CONFIG['login.host'], CONFIG['login.db']) titles = [CONFIG['client.title']] if value: titles.append(value) self.header.set_title(' - '.join(titles)) self.header.set_subtitle(login_info) try: style_context = self.header.get_style_context() except AttributeError: pass else: for name in style_context.list_classes(): if name.startswith('profile-'): style_context.remove_class(name) if CONFIG['login.profile']: style_context.add_class( 'profile-%s' % CONFIG['login.profile']) def favorite_set(self, *args): if self.menu_favorite.get_children(): return True def _action_favorite(widget, id_): event = gtk.get_current_event() allow_similar = (event.state & gtk.gdk.MOD1_MASK or event.state & gtk.gdk.SHIFT_MASK) with Window(allow_similar=allow_similar): # ids is not defined to prevent to add suffix Action.exec_keyword('tree_open', { 'model': self.menu_screen.model_name, 'id': id_, }) def _manage_favorites(widget): Window.create(self.menu_screen.model_name + '.favorite', mode=['tree', 'form'], name=_("Favorites")) try: favorites = RPCExecute('model', self.menu_screen.model_name + '.favorite', 'get', process_exception=False) except Exception: return False for id_, name, icon in favorites: if icon: menuitem = gtk.ImageMenuItem(name) menuitem.set_image( common.IconFactory.get_image(icon, gtk.ICON_SIZE_MENU)) else: menuitem = gtk.MenuItem(name) menuitem.connect('activate', _action_favorite, id_) self.menu_favorite.add(menuitem) self.menu_favorite.add(gtk.SeparatorMenuItem()) manage_favorites = gtk.MenuItem(_("Manage..."), use_underline=True) manage_favorites.connect('activate', _manage_favorites) self.menu_favorite.add(manage_favorites) self.menu_favorite.show_all() return True def favorite_unset(self): for child in self.menu_favorite.get_children(): self.menu_favorite.remove(child) def on_change_toolbar(self, action, value): action.set_state(value) option = value.get_string() CONFIG['client.toolbar'] = option if option == 'default': barstyle = False elif option == 'both': barstyle = gtk.TOOLBAR_BOTH elif option == 'text': barstyle = gtk.TOOLBAR_TEXT elif option == 'icons': barstyle = gtk.TOOLBAR_ICONS for page_idx in range(self.notebook.get_n_pages()): page = self.get_page(page_idx) page.toolbar.set_style(barstyle) def edit_limit(self): from tryton.gui.window.limit import Limit Limit().run() def edit_email(self): from tryton.gui.window.email import Email Email().run() def win_next(self): page = self.notebook.get_current_page() if page == len(self.pages) - 1: page = -1 self.notebook.set_current_page(page + 1) def win_prev(self): page = self.notebook.get_current_page() self.notebook.set_current_page(page - 1) def get_preferences(self): def _set_preferences(prefs): try: prefs = prefs() except RPCException: prefs = {} threads = [] for target in ( common.IconFactory.load_icons, common.MODELACCESS.load_models, common.MODELHISTORY.load_history, common.VIEW_SEARCH.load_searches, ): t = threading.Thread(target=target) threads.append(t) t.start() for t in threads: t.join() if prefs and 'language_direction' in prefs: translate.set_language_direction(prefs['language_direction']) CONFIG['client.language_direction'] = \ prefs['language_direction'] self.sig_win_menu(prefs=prefs) for action_id in prefs.get('actions', []): Action.execute(action_id, {}) self.set_title(prefs.get('status_bar', '')) if prefs and 'language' in prefs: translate.setlang(prefs['language'], prefs.get('locale')) if CONFIG['client.lang'] != prefs['language']: self.favorite_unset() CONFIG['client.lang'] = prefs['language'] # Set placeholder after language is set to get correct translation self.global_search_entry.set_placeholder_text(_("Action")) CONFIG.save() def _get_preferences(): RPCExecute('model', 'res.user', 'get_preferences', False, callback=_set_preferences) RPCContextReload(_get_preferences) def preferences(self): from tryton.gui.window.preference import Preference if not self.close_pages(): return False Preference(rpc._USER, self.get_preferences) def sig_win_close(self, widget=None): self._sig_remove_book(widget, self.notebook.get_nth_page(self.notebook.get_current_page())) def close_pages(self): if self.notebook.get_n_pages(): if not common.sur( _('The following action requires to close all tabs.\n' 'Do you want to continue?')): return False res = True while res: wid = self.get_page() if wid: if not wid.sig_close(): return False res = self._win_del() else: res = False if self.menu_screen: self.menu_screen.save_tree_state() if self.menu.get_visible(): CONFIG['menu.pane'] = self.pane.get_position() return True def about(self): from tryton.gui.window.about import About About() def shortcuts(self): from tryton.gui.window.shortcuts import Shortcuts Shortcuts().run() def menu_toggle(self, *args): if self.menu.get_visible(): CONFIG['menu.pane'] = self.pane.get_position() self.pane.set_position(0) self.notebook.grab_focus() self.menu.set_visible(False) else: self.pane.set_position(int(CONFIG['menu.pane'])) self.menu.set_visible(True) if self.menu_screen: self.menu_screen.set_cursor() def menu_row_activate(self): screen = self.menu_screen record_id = (screen.current_record.id if screen.current_record else None) # ids is not defined to prevent to add suffix return Action.exec_keyword('tree_open', { 'model': screen.model_name, 'id': record_id, }, warning=False) def sig_win_menu(self, prefs=None): from tryton.gui.window.view_form.screen import Screen if not prefs: try: prefs = RPCExecute('model', 'res.user', 'get_preferences', False) except RPCException: return False if self.menu_screen: self.menu_screen.save_tree_state() for child in self.menu.get_children(): self.menu.remove(child) action = PYSONDecoder().decode(prefs['pyson_menu']) view_ids = [] if action.get('views', []): view_ids = [x[0] for x in action['views']] elif action.get('view_id', False): view_ids = [action['view_id'][0]] ctx = rpc.CONTEXT.copy() decoder = PYSONDecoder(ctx) action_ctx = decoder.decode(action.get('pyson_context') or '{}') domain = decoder.decode(action['pyson_domain']) screen = Screen(action['res_model'], mode=['tree'], view_ids=view_ids, domain=domain, context=action_ctx, readonly=True, limit=None, row_activate=self.menu_row_activate) # Use alternate view to not show search box screen.screen_container.alternate_view = True screen.switch_view(view_type=screen.current_view.view_type) self.menu.pack_start( screen.screen_container.alternate_viewport, True, True) treeview = screen.current_view.treeview treeview.set_headers_visible(False) # Favorite column column = gtk.TreeViewColumn() column.name = None column._type = None favorite_renderer = CellRendererClickablePixbuf() column.pack_start(favorite_renderer, expand=False) def favorite_setter(column, cell, store, iter_): menu = store.get_value(iter_, 0) favorite = menu.value.get('favorite') if favorite: icon = 'tryton-star' elif favorite is False: icon = 'tryton-star-border' else: icon = None if icon: pixbuf = common.IconFactory.get_pixbuf( icon, gtk.ICON_SIZE_MENU) else: pixbuf = None cell.set_property('pixbuf', pixbuf) column.set_cell_data_func(favorite_renderer, favorite_setter) def toggle_favorite(renderer, path, treeview): if treeview.props.window: self.toggle_favorite(renderer, path, treeview) favorite_renderer.connect('clicked', lambda *a: gobject.idle_add(toggle_favorite, *a), treeview) # Unset fixed height mode to add column treeview.set_fixed_height_mode(False) treeview.set_property( 'enable-grid-lines', gtk.TREE_VIEW_GRID_LINES_NONE) treeview.append_column(column) screen.search_filter() screen.display(set_cursor=True) self.menu_screen = screen def toggle_favorite(self, renderer, path, treeview): store = treeview.get_model() iter_ = store.get_iter(path) menu = store.get_value(iter_, 0) favorite = menu.value.get('favorite') if favorite: value = False method = 'unset' elif favorite is False: value = True method = 'set' else: return try: RPCExecute('model', self.menu_screen.model_name + '.favorite', method, menu.id) except RPCException: return menu.value['favorite'] = value store.row_changed(path, iter_) self.favorite_unset() def win_set(self, page): current_page = self.notebook.get_current_page() page_num = self.notebook.page_num(page.widget) page.widget.props.visible = True self.notebook.set_current_page(page_num) # In order to focus the page if current_page == page_num: self._sig_page_changt(self.notebook, None, page_num) def win_add(self, page, hide_current=False): previous_page_id = self.notebook.get_current_page() previous_widget = self.notebook.get_nth_page(previous_page_id) if previous_widget and hide_current: page_id = previous_page_id + 1 else: page_id = -1 self.previous_pages[page] = previous_widget self.pages.append(page) hbox = gtk.HBox(spacing=3) if page.icon: hbox.pack_start( common.IconFactory.get_image( page.icon, gtk.ICON_SIZE_SMALL_TOOLBAR), expand=False, fill=False) name = page.name label = gtk.Label(common.ellipsize(name, 20)) self.tooltips.set_tip(label, page.name) self.tooltips.enable() label.set_alignment(0.0, 0.5) hbox.pack_start(label, expand=True, fill=True) button = gtk.Button() button.set_relief(gtk.RELIEF_NONE) button.set_can_focus(False) button.add(common.IconFactory.get_image( 'tryton-close', gtk.ICON_SIZE_MENU)) self.tooltips.set_tip(button, _('Close Tab')) button.connect('clicked', self._sig_remove_book, page.widget) hbox.pack_start(button, expand=False, fill=False) x, y = gtk.icon_size_lookup_for_settings(button.get_settings(), gtk.ICON_SIZE_MENU)[-2:] button.set_size_request(x, y) hbox.show_all() label_menu = gtk.Label(page.name) label_menu.set_alignment(0.0, 0.5) self.notebook.insert_page_menu(page.widget, hbox, label_menu, page_id) self.notebook.set_tab_reorderable(page.widget, True) self.notebook.set_current_page(page_id) def _sig_remove_book(self, widget, page_widget): for page in self.pages: if page.widget == page_widget: if not page.widget.props.sensitive: return page_num = self.notebook.page_num(page.widget) self.notebook.set_current_page(page_num) res = page.sig_close() if not res: return self._win_del(page_widget) def _win_del(self, page_widget=None): if page_widget: page_id = self.notebook.page_num(page_widget) else: page_id = int(self.notebook.get_current_page()) page_widget = self.notebook.get_nth_page(page_id) if page_id != -1: page = None for i in range(len(self.pages)): if self.pages[i].widget == page_widget: page = self.pages.pop(i) page.signal_unconnect(self) break self.notebook.remove_page(page_id) next_page_id = -1 to_pop = [] for i in self.previous_pages: if self.previous_pages[i] == page_widget: to_pop.append(i) if i.widget == page_widget: if self.previous_pages[i]: next_page_id = self.notebook.page_num( self.previous_pages[i]) to_pop.append(i) to_pop.reverse() for i in to_pop: self.previous_pages.pop(i) if hasattr(page, 'destroy'): page.destroy() del page current_widget = self.notebook.get_nth_page(next_page_id) if current_widget: current_widget.props.visible = True self.notebook.set_current_page(next_page_id) if not self.pages and self.menu_screen: self.menu_screen.set_cursor() return self.notebook.get_current_page() != -1 def get_page(self, page_id=None): if page_id is None: page_id = self.notebook.get_current_page() if page_id == -1: return None page_widget = self.notebook.get_nth_page(page_id) for page in self.pages: if page.widget == page_widget: return page return None def _sig_page_changt(self, notebook, page, page_num): self.last_page = self.current_page last_form = self.get_page(self.current_page) if last_form: for dialog in last_form.dialogs: dialog.hide() self.current_page = self.notebook.get_current_page() current_form = self.get_page(self.current_page) def set_cursor(): if self.current_page == self.notebook.get_current_page(): current_form.set_cursor() # Using idle_add because the gtk.TreeView grabs the focus at the # end of the event gobject.idle_add(set_cursor) for dialog in current_form.dialogs: dialog.show() def _open_url(self, url): urlp = urlparse(url) if not urlp.scheme == 'tryton': return urlp = urlparse('http' + url[6:]) database, path = list(map(unquote, (urlp.path[1:].split('/', 1) + [''])[:2])) if not path: return type_, path = (path.split('/', 1) + [''])[:2] params = {} if urlp.params: try: params.update(dict(parse_qsl(urlp.params, strict_parsing=True))) except ValueError: return def open_model(path): model, path = (path.split('/', 1) + [''])[:2] if not model: return res_id = None mode = None try: view_ids = json.loads(params.get('views', '[]')) limit = json.loads(params.get('limit', 'null')) name = json.loads(params.get('name', '""')) search_value = json.loads(params.get('search_value', '[]'), object_hook=object_hook) domain = json.loads(params.get('domain', '[]'), object_hook=object_hook) context = json.loads(params.get('context', '{}'), object_hook=object_hook) context_model = params.get('context_model') except ValueError: return if path: try: res_id = int(path) except ValueError: return mode = ['form', 'tree'] try: Window.create(model, view_ids=view_ids, res_id=res_id, domain=domain, context=context, context_model=context_model, mode=mode, name=name, limit=limit, search_value=search_value) except Exception: # Prevent crashing the client return def open_wizard(wizard): if not wizard: return try: data = json.loads(params.get('data', '{}'), object_hook=object_hook) direct_print = json.loads(params.get('direct_print', 'false')) email_print = json.loads(params.get('email_print', 'false')) email = json.loads(params.get('email', 'null')) name = json.loads(params.get('name', '""')) window = json.loads(params.get('window', 'false')) context = json.loads(params.get('context', '{}'), object_hook=object_hook) except ValueError: return try: Window.create_wizard(wizard, data, direct_print=direct_print, email_print=email_print, email=email, name=name, context=context, window=window) except Exception: # Prevent crashing the client return def open_report(report): if not report: return try: data = json.loads(params.get('data'), object_hook=object_hook) direct_print = json.loads(params.get('direct_print', 'false')) email_print = json.loads(params.get('email_print', 'false')) email = json.loads(params.get('email', 'null')) context = json.loads(params.get('context', '{}'), object_hook=object_hook) except ValueError: return try: Action.exec_report(report, data, direct_print=direct_print, email_print=email_print, email=email, context=context) except Exception: # Prevent crashing the client return def open_url(): try: url = json.loads(params.get('url', 'false')) except ValueError: return if url: webbrowser.open(url, new=2) if type_ == 'model': open_model(path) elif type_ == 'wizard': open_wizard(path) elif type_ == 'report': open_report(path) elif type_ == 'url': open_url() self.window.present() def open_url(self, url): def idle_open_url(): with gtk.gdk.lock: self._open_url(url) return False gobject.idle_add(idle_open_url) def show_notification(self, title, msg, priority=1): notification = Gio.Notification.new(title) notification.set_body(msg) notification.set_priority(_PRIORITIES[priority]) if sys.platform != 'win32' or GLib.glib_version >= (2, 57, 0): self.send_notification(None, notification) tryton-5.0.17/tryton/pyson.py0000644000175000017500000004665713463252532015563 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import json import datetime from decimal import Decimal from dateutil.relativedelta import relativedelta from functools import reduce class PYSON(object): def pyson(self): raise NotImplementedError def types(self): raise NotImplementedError @staticmethod def eval(dct, context): raise NotImplementedError def __invert__(self): if self.types() != {bool}: return Not(Bool(self)) else: return Not(self) def __and__(self, other): if (isinstance(other, PYSON) and other.types() != {bool}): other = Bool(other) if (isinstance(self, And) and not isinstance(self, Or)): self._statements.append(other) return self if self.types() != {bool}: return And(Bool(self), other) else: return And(self, other) __rand__ = __and__ def __or__(self, other): if (isinstance(other, PYSON) and other.types() != {bool}): other = Bool(other) if isinstance(self, Or): self._statements.append(other) return self if self.types() != {bool}: return Or(Bool(self), other) else: return Or(self, other) __ror__ = __or__ def __eq__(self, other): return Equal(self, other) def __ne__(self, other): return Not(Equal(self, other)) def __gt__(self, other): return Greater(self, other) def __ge__(self, other): return Greater(self, other, True) def __lt__(self, other): return Less(self, other) def __le__(self, other): return Less(self, other, True) def get(self, k, d=''): return Get(self, k, d) def in_(self, obj): return In(self, obj) def contains(self, k): return In(k, self) def __repr__(self): klass = self.__class__.__name__ return '%s(%s)' % (klass, ', '.join(map(repr, self.__repr_params__))) @property def __repr_params__(self): return NotImplementedError class PYSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, PYSON): return obj.pyson() elif isinstance(obj, datetime.date): if isinstance(obj, datetime.datetime): return DateTime(obj.year, obj.month, obj.day, obj.hour, obj.minute, obj.second, obj.microsecond ).pyson() else: return Date(obj.year, obj.month, obj.day).pyson() elif isinstance(obj, Decimal): return float(obj) return super(PYSONEncoder, self).default(obj) class PYSONDecoder(json.JSONDecoder): def __init__(self, context=None, noeval=False): self.__context = context or {} self.noeval = noeval super(PYSONDecoder, self).__init__(object_hook=self._object_hook) def _object_hook(self, dct): if '__class__' in dct: klass = CONTEXT.get(dct['__class__']) if klass: if not self.noeval: return klass.eval(dct, self.__context) else: dct = dct.copy() del dct['__class__'] return klass(**dct) return dct class Eval(PYSON): def __init__(self, v, d=''): super(Eval, self).__init__() self._value = v self._default = d @property def __repr_params__(self): return self._value, self._default def pyson(self): return { '__class__': 'Eval', 'v': self._value, 'd': self._default, } def types(self): if isinstance(self._default, PYSON): return self._default.types() else: return {type(self._default)} @staticmethod def eval(dct, context): return context.get(dct['v'], dct['d']) class Not(PYSON): def __init__(self, v): super(Not, self).__init__() if isinstance(v, PYSON): if v.types() != {bool}: v = Bool(v) elif not isinstance(v, bool): v = bool(v) self._value = v @property def __repr_params__(self): return (self._value,) def pyson(self): return { '__class__': 'Not', 'v': self._value, } def types(self): return {bool} @staticmethod def eval(dct, context): return not dct['v'] class Bool(PYSON): def __init__(self, v): super(Bool, self).__init__() self._value = v @property def __repr_params__(self): return (self._value,) def pyson(self): return { '__class__': 'Bool', 'v': self._value, } def types(self): return {bool} @staticmethod def eval(dct, context): return bool(dct['v']) class And(PYSON): def __init__(self, *statements, **kwargs): super(And, self).__init__() statements = list(statements) + kwargs.get('s', []) for i, statement in enumerate(list(statements)): if isinstance(statement, PYSON): if statement.types() != {bool}: statements[i] = Bool(statement) elif not isinstance(statement, bool): statements[i] = bool(statement) assert len(statements) >= 2, 'must have at least 2 statements' self._statements = statements @property def __repr_params__(self): return tuple(self._statements) def pyson(self): return { '__class__': 'And', 's': self._statements, } def types(self): return {bool} @staticmethod def eval(dct, context): return bool(reduce(lambda x, y: x and y, dct['s'])) class Or(And): def pyson(self): res = super(Or, self).pyson() res['__class__'] = 'Or' return res @staticmethod def eval(dct, context): return bool(reduce(lambda x, y: x or y, dct['s'])) class Equal(PYSON): def __init__(self, s1, s2): statement1, statement2 = s1, s2 super(Equal, self).__init__() if isinstance(statement1, PYSON): types1 = statement1.types() else: types1 = {type(s1)} if isinstance(statement2, PYSON): types2 = statement2.types() else: types2 = {type(s2)} assert types1 == types2, 'statements must have the same type' self._statement1 = statement1 self._statement2 = statement2 @property def __repr_params__(self): return (self._statement1, self._statement2) def pyson(self): return { '__class__': 'Equal', 's1': self._statement1, 's2': self._statement2, } def types(self): return {bool} @staticmethod def eval(dct, context): return dct['s1'] == dct['s2'] class Greater(PYSON): def __init__(self, s1, s2, e=False): statement1, statement2, equal = s1, s2, e super(Greater, self).__init__() for i in (statement1, statement2): if isinstance(i, PYSON): assert i.types().issubset({int, float, type(None)}), \ 'statement must be an integer or a float' else: assert isinstance(i, (int, float, type(None))), \ 'statement must be an integer or a float' if isinstance(equal, PYSON): if equal.types() != {bool}: equal = Bool(equal) elif not isinstance(equal, bool): equal = bool(equal) self._statement1 = statement1 self._statement2 = statement2 self._equal = equal @property def __repr_params__(self): return (self._statement1, self._statement2, self._equal) def pyson(self): return { '__class__': 'Greater', 's1': self._statement1, 's2': self._statement2, 'e': self._equal, } def types(self): return {bool} @staticmethod def _convert(dct): for i in ('s1', 's2'): if dct[i] is None: dct[i] = 0.0 if not isinstance(dct[i], (int, float)): dct = dct.copy() dct[i] = float(dct[i]) return dct @staticmethod def eval(dct, context): dct = Greater._convert(dct) if dct['e']: return dct['s1'] >= dct['s2'] else: return dct['s1'] > dct['s2'] class Less(Greater): def pyson(self): res = super(Less, self).pyson() res['__class__'] = 'Less' return res @staticmethod def eval(dct, context): dct = Less._convert(dct) if dct['e']: return dct['s1'] <= dct['s2'] else: return dct['s1'] < dct['s2'] class If(PYSON): def __init__(self, c, t, e=None): condition, then_statement, else_statement = c, t, e super(If, self).__init__() if isinstance(condition, PYSON): if condition.types() != {bool}: condition = Bool(condition) elif not isinstance(condition, bool): condition = bool(condition) if isinstance(then_statement, PYSON): then_types = then_statement.types() else: then_types = {type(then_statement)} if isinstance(else_statement, PYSON): else_types = else_statement.types() else: else_types = {type(else_statement)} assert then_types == else_types, \ 'then and else statements must be the same type' self._condition = condition self._then_statement = then_statement self._else_statement = else_statement @property def __repr_params__(self): return (self._condition, self._then_statement, self._else_statement) def pyson(self): return { '__class__': 'If', 'c': self._condition, 't': self._then_statement, 'e': self._else_statement, } def types(self): if isinstance(self._then_statement, PYSON): return self._then_statement.types() else: return {type(self._then_statement)} @staticmethod def eval(dct, context): if dct['c']: return dct['t'] else: return dct['e'] class Get(PYSON): def __init__(self, v, k, d=''): obj, key, default = v, k, d super(Get, self).__init__() if isinstance(obj, PYSON): assert obj.types() == {dict}, 'obj must be a dict' else: assert isinstance(obj, dict), 'obj must be a dict' self._obj = obj if isinstance(key, PYSON): assert key.types() == {str}, 'key must be a string' else: assert isinstance(key, str), 'key must be a string' self._key = key self._default = default @property def __repr_params__(self): return (self._obj, self._key, self._default) def pyson(self): return { '__class__': 'Get', 'v': self._obj, 'k': self._key, 'd': self._default, } def types(self): if isinstance(self._default, PYSON): return self._default.types() else: return {type(self._default)} @staticmethod def eval(dct, context): return dct['v'].get(dct['k'], dct['d']) class In(PYSON): def __init__(self, k, v): key, obj = k, v super(In, self).__init__() if isinstance(key, PYSON): assert key.types().issubset({str, int}), \ 'key must be a string or an integer or a long' else: assert isinstance(key, (str, int)), \ 'key must be a string or an integer or a long' if isinstance(obj, PYSON): assert obj.types().issubset({dict, list}), \ 'obj must be a dict or a list' if obj.types() == {dict}: assert isinstance(key, str), 'key must be a string' else: assert isinstance(obj, (dict, list)) if isinstance(obj, dict): assert isinstance(key, str), 'key must be a string' self._key = key self._obj = obj @property def __repr_params__(self): return (self._key, self._obj) def pyson(self): return { '__class__': 'In', 'k': self._key, 'v': self._obj, } def types(self): return {bool} @staticmethod def eval(dct, context): return dct['k'] in dct['v'] class Date(PYSON): def __init__(self, year=None, month=None, day=None, delta_years=0, delta_months=0, delta_days=0, **kwargs): year = kwargs.get('y', year) month = kwargs.get('M', month) day = kwargs.get('d', day) delta_years = kwargs.get('dy', delta_years) delta_months = kwargs.get('dM', delta_months) delta_days = kwargs.get('dd', delta_days) super(Date, self).__init__() for i in (year, month, day, delta_years, delta_months, delta_days): if isinstance(i, PYSON): assert i.types().issubset({int, type(None)}), \ '%s must be an integer or None' % (i,) else: assert isinstance(i, (int, type(None))), \ '%s must be an integer or None' % (i,) self._year = year self._month = month self._day = day self._delta_years = delta_years self._delta_months = delta_months self._delta_days = delta_days @property def __repr_params__(self): return (self._year, self._month, self._day, self._delta_years, self._delta_months, self._delta_days) def pyson(self): return { '__class__': 'Date', 'y': self._year, 'M': self._month, 'd': self._day, 'dy': self._delta_years, 'dM': self._delta_months, 'dd': self._delta_days, } def types(self): return {datetime.date} @staticmethod def eval(dct, context): return datetime.date.today() + relativedelta( year=dct['y'], month=dct['M'], day=dct['d'], years=dct['dy'], months=dct['dM'], days=dct['dd'], ) class DateTime(Date): def __init__(self, year=None, month=None, day=None, hour=None, minute=None, second=None, microsecond=None, delta_years=0, delta_months=0, delta_days=0, delta_hours=0, delta_minutes=0, delta_seconds=0, delta_microseconds=0, **kwargs): hour = kwargs.get('h', hour) minute = kwargs.get('m', minute) second = kwargs.get('s', second) microsecond = kwargs.get('ms', microsecond) delta_hours = kwargs.get('dh', delta_hours) delta_minutes = kwargs.get('dm', delta_minutes) delta_seconds = kwargs.get('ds', delta_seconds) delta_microseconds = kwargs.get('dms', delta_microseconds) super(DateTime, self).__init__(year=year, month=month, day=day, delta_years=delta_years, delta_months=delta_months, delta_days=delta_days, **kwargs) for i in (hour, minute, second, microsecond, delta_hours, delta_minutes, delta_seconds, delta_microseconds): if isinstance(i, PYSON): assert i.types() == {int, type(None)}, \ '%s must be an integer or None' % (i,) else: assert isinstance(i, (int, type(None))), \ '%s must be an integer or None' % (i,) self._hour = hour self._minute = minute self._second = second self._microsecond = microsecond self._delta_hours = delta_hours self._delta_minutes = delta_minutes self._delta_seconds = delta_seconds self._delta_microseconds = delta_microseconds @property def __repr_params__(self): date_params = super(DateTime, self).__repr_params__ return (date_params[:3] + (self._hour, self._minute, self._second, self._microsecond) + date_params[3:] + (self._delta_hours, self._delta_minutes, self._delta_seconds, self._delta_microseconds)) def pyson(self): res = super(DateTime, self).pyson() res['__class__'] = 'DateTime' res['h'] = self._hour res['m'] = self._minute res['s'] = self._second res['ms'] = self._microsecond res['dh'] = self._delta_hours res['dm'] = self._delta_minutes res['ds'] = self._delta_seconds res['dms'] = self._delta_microseconds return res def types(self): return {datetime.datetime} @staticmethod def eval(dct, context): return datetime.datetime.now() + relativedelta( year=dct['y'], month=dct['M'], day=dct['d'], hour=dct['h'], minute=dct['m'], second=dct['s'], microsecond=dct['ms'], years=dct['dy'], months=dct['dM'], days=dct['dd'], hours=dct['dh'], minutes=dct['dm'], seconds=dct['ds'], microseconds=dct['dms'], ) class TimeDelta(PYSON): def __init__(self, days=0, seconds=0, microseconds=0): for i in [days, seconds, microseconds]: if isinstance(i, PYSON): assert i.types().issubset({int, float}), \ '%s must be an integer' % (i,) else: assert isinstance(i, (int, float)), \ '%s must be an integer' % (i,) self._days = days self._seconds = seconds self._microseconds = microseconds @property def __repr_params__(self): return self._days, self._seconds, self._microseconds def pyson(self): return { '__class__': 'TimeDelta', 'd': self._days, 's': self._seconds, 'm': self._microseconds, } def types(self): return {datetime.timedelta} @staticmethod def eval(dct, context): return datetime.timedelta( days=dct['d'], seconds=dct['s'], microseconds=dct['m'], ) class Len(PYSON): def __init__(self, v): super(Len, self).__init__() if isinstance(v, PYSON): assert v.types().issubset({dict, list, str}), \ 'value must be a dict or a list or a string' else: assert isinstance(v, (dict, list, str)), \ 'value must be a dict or list or a string' self._value = v @property def __repr_params__(self): return (self._value,) def pyson(self): return { '__class__': 'Len', 'v': self._value, } def types(self): return {int} @staticmethod def eval(dct, context): return len(dct['v']) CONTEXT = { 'Eval': Eval, 'Not': Not, 'Bool': Bool, 'And': And, 'Or': Or, 'Equal': Equal, 'Greater': Greater, 'Less': Less, 'If': If, 'Get': Get, 'In': In, 'Date': Date, 'DateTime': DateTime, 'TimeDelta': TimeDelta, 'Len': Len, } tryton-5.0.17/tryton/bus.py0000644000175000017500000000515013463252531015162 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import base64 import json import logging import socket import threading import time import uuid from urllib.request import Request, urlopen from urllib.error import HTTPError from gi.repository import GObject from tryton.jsonrpc import object_hook from tryton.config import CONFIG logger = logging.getLogger(__name__) ID = str(uuid.uuid4()) CHANNELS = [ 'client:%s' % ID, ] def listen(connection): listener = threading.Thread( target=_listen, args=(connection,), daemon=True) listener.start() def _listen(connection): bus_timeout = CONFIG['client.bus_timeout'] session = connection.session authorization = base64.b64encode(session.encode('utf-8')) headers = { 'Content-Type': 'application/json', 'Authorization': b'Session ' + authorization, } wait = 1 last_message = None url = None while connection.session == session: if url is None: if connection.url is None: time.sleep(1) continue url = connection.url + '/bus' request = Request(url, data=json.dumps({ 'last_message': last_message, 'channels': CHANNELS, }).encode('utf-8'), headers=headers) logger.info('poll channels %s with last message %s', CHANNELS, last_message) try: response = urlopen(request, timeout=bus_timeout) wait = 1 except socket.timeout: wait = 1 continue except Exception as error: if isinstance(error, HTTPError) and error.code == 501: logger.info("Bus not supported") break logger.error( "An exception occured while connecting to the bus." "Sleeping for %s seconds", wait, exc_info=error) time.sleep(min(wait, bus_timeout)) wait *= 2 continue if connection.session != session: break data = json.loads(response.read(), object_hook=object_hook) if data['message']: last_message = data['message']['message_id'] GObject.idle_add(handle, data['message']) def handle(message): from tryton.gui.main import Main app = Main() if message['type'] == 'notification': app.show_notification( message.get('title', ''), message.get('body', ''), message.get('priority', 1)) tryton-5.0.17/tryton/jsonrpc.py0000644000175000017500000002657013524765775016101 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import xmlrpc.client import json import ssl import http.client from decimal import Decimal import datetime import socket import hashlib import base64 import threading import errno from functools import partial from contextlib import contextmanager from functools import reduce from urllib.parse import urljoin, quote __all__ = ["ResponseError", "Fault", "ProtocolError", "Transport", "ServerProxy", "ServerPool"] CONNECT_TIMEOUT = 5 DEFAULT_TIMEOUT = None class ResponseError(xmlrpc.client.ResponseError): pass class Fault(xmlrpc.client.Fault): def __init__(self, faultCode, faultString='', **extra): super(Fault, self).__init__(faultCode, faultString, **extra) self.args = faultString def __repr__(self): return ( "" % (repr(self.faultCode), repr(self.faultString)) ) class ProtocolError(xmlrpc.client.ProtocolError): pass def object_hook(dct): if '__class__' in dct: if dct['__class__'] == 'datetime': return datetime.datetime(dct['year'], dct['month'], dct['day'], dct['hour'], dct['minute'], dct['second'], dct['microsecond']) elif dct['__class__'] == 'date': return datetime.date(dct['year'], dct['month'], dct['day']) elif dct['__class__'] == 'time': return datetime.time(dct['hour'], dct['minute'], dct['second'], dct['microsecond']) elif dct['__class__'] == 'timedelta': return datetime.timedelta(seconds=dct['seconds']) elif dct['__class__'] == 'bytes': return base64.decodebytes(dct['base64'].encode('utf-8')) elif dct['__class__'] == 'Decimal': return Decimal(dct['decimal']) return dct class JSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, datetime.date): if isinstance(obj, datetime.datetime): return {'__class__': 'datetime', 'year': obj.year, 'month': obj.month, 'day': obj.day, 'hour': obj.hour, 'minute': obj.minute, 'second': obj.second, 'microsecond': obj.microsecond, } return {'__class__': 'date', 'year': obj.year, 'month': obj.month, 'day': obj.day, } elif isinstance(obj, datetime.time): return {'__class__': 'time', 'hour': obj.hour, 'minute': obj.minute, 'second': obj.second, 'microsecond': obj.microsecond, } elif isinstance(obj, datetime.timedelta): return {'__class__': 'timedelta', 'seconds': obj.total_seconds(), } elif isinstance(obj, bytes): return {'__class__': 'bytes', 'base64': base64.encodebytes(obj).decode('utf-8'), } elif isinstance(obj, Decimal): return {'__class__': 'Decimal', 'decimal': str(obj), } return super(JSONEncoder, self).default(obj) class JSONParser(object): def __init__(self, target): self.__targer = target def feed(self, data): self.__targer.feed(data) def close(self): pass class JSONUnmarshaller(object): def __init__(self): self.data = [] def feed(self, data): self.data.append(data.decode('utf-8')) def close(self): return json.loads(''.join(self.data), object_hook=object_hook) class Transport(xmlrpc.client.SafeTransport): accept_gzip_encoding = True encode_threshold = 1400 # common MTU def __init__(self, fingerprints=None, ca_certs=None, session=None): xmlrpc.client.Transport.__init__(self) self._connection = (None, None) self.__fingerprints = fingerprints self.__ca_certs = ca_certs self.session = session def getparser(self): target = JSONUnmarshaller() parser = JSONParser(target) return parser, target def get_host_info(self, host): host, extra_headers, x509 = xmlrpc.client.Transport.get_host_info( self, host) if extra_headers is None: extra_headers = [] if self.session: auth = base64.encodebytes( self.session.encode('utf-8')).decode('ascii') auth = ''.join(auth.split()) # get rid of whitespace extra_headers.append( ('Authorization', 'Session ' + auth), ) extra_headers.append(('Connection', 'keep-alive')) return host, extra_headers, x509 def send_headers(self, connection, headers): for key, val in headers: if key == 'Content-Type': val = 'application/json' connection.putheader(key, val) def make_connection(self, host): if self._connection and host == self._connection[0]: return self._connection[1] host, self._extra_headers, x509 = self.get_host_info(host) ssl_ctx = ssl.create_default_context(cafile=self.__ca_certs) class HTTPSConnection(http.client.HTTPSConnection): def connect(self): sock = socket.create_connection((self.host, self.port), self.timeout) if self._tunnel_host: self.sock = sock self._tunnel() self.sock = ssl_ctx.wrap_socket( sock, server_hostname=self.host) def http_connection(): self._connection = host, http.client.HTTPConnection(host, timeout=CONNECT_TIMEOUT) self._connection[1].connect() sock = self._connection[1].sock sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) def https_connection(allow_http=False): self._connection = host, HTTPSConnection(host, timeout=CONNECT_TIMEOUT) try: self._connection[1].connect() sock = self._connection[1].sock sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) try: peercert = sock.getpeercert(True) except socket.error: peercert = None def format_hash(value): return reduce(lambda x, y: x + y[1].upper() + ((y[0] % 2 and y[0] + 1 < len(value)) and ':' or ''), enumerate(value), '') return format_hash(hashlib.sha1(peercert).hexdigest()) except ssl.SSLError: if allow_http: http_connection() else: raise fingerprint = '' if self.__fingerprints is not None and host in self.__fingerprints: if self.__fingerprints[host]: fingerprint = https_connection() else: http_connection() else: fingerprint = https_connection(allow_http=True) if self.__fingerprints is not None: self.__fingerprints[host] = fingerprint self._connection[1].timeout = DEFAULT_TIMEOUT self._connection[1].sock.settimeout(DEFAULT_TIMEOUT) return self._connection[1] class ServerProxy(xmlrpc.client.ServerProxy): __id = 0 def __init__(self, host, port, database='', verbose=0, fingerprints=None, ca_certs=None, session=None): self.__host = '%s:%s' % (host, port) if database: database = quote(database) self.__handler = '/%s/' % database else: self.__handler = '/' self.__transport = Transport(fingerprints, ca_certs, session) self.__verbose = verbose def __request(self, methodname, params): self.__id += 1 id_ = self.__id request = json.dumps({ 'id': id_, 'method': methodname, 'params': params, }, cls=JSONEncoder, separators=(',', ':')).encode('utf-8') try: try: response = self.__transport.request( self.__host, self.__handler, request, verbose=self.__verbose ) except (socket.error, http.client.HTTPException) as v: if (isinstance(v, socket.error) and v.args[0] == errno.EPIPE): raise # try one more time self.__transport.close() response = self.__transport.request( self.__host, self.__handler, request, verbose=self.__verbose ) except xmlrpc.client.ProtocolError as e: raise Fault(str(e.errcode), e.errmsg) except Exception: self.__transport.close() raise if response['id'] != id_: raise ResponseError('Invalid response id (%s) excpected %s' % (response['id'], id_)) if response.get('error'): raise Fault(*response['error']) return response['result'] def close(self): self.__transport.close() @property def ssl(self): return isinstance(self.__transport.make_connection(self.__host), http.client.HTTPSConnection) class ServerPool(object): keep_max = 4 def __init__(self, host, port, database, *args, **kwargs): self.ServerProxy = partial( ServerProxy, host, port, database, *args, **kwargs) self._host = host self._port = port self._database = database self._lock = threading.Lock() self._pool = [] self._used = {} self.session = kwargs.get('session') def getconn(self): with self._lock: if self._pool: conn = self._pool.pop() else: conn = self.ServerProxy() self._used[id(conn)] = conn return conn def putconn(self, conn): with self._lock: self._pool.append(conn) del self._used[id(conn)] # Remove oldest connections while len(self._pool) > self.keep_max: conn = self._pool.pop() conn.close() def close(self): with self._lock: for conn in self._pool + list(self._used.values()): conn.close() self._pool = [] self._used.clear() @property def ssl(self): for conn in self._pool + list(self._used.values()): return conn.ssl return None @property def url(self): if self.ssl is None: return None scheme = 'https' if self.ssl else 'http' return urljoin( scheme + '://' + self._host + ':' + str(self._port), self._database) @contextmanager def __call__(self): conn = self.getconn() yield conn self.putconn(conn) tryton-5.0.17/tryton/signal_event.py0000644000175000017500000000247413463252532017056 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. "Signal event" class SignalEvent(object): "Signal event" def __init__(self, *args, **kwargs): super(SignalEvent, self).__init__(*args, **kwargs) self.__connects = {} def signal(self, signal, signal_data=None): for fnct, data, key in self.__connects.get(signal, []): fnct(self, signal_data, *data) return True def signal_connected(self, signal): return bool(self.__connects.get(signal)) def signal_connect(self, key, signal, fnct, *data): self.__connects.setdefault(signal, []) if (fnct, data, key) not in self.__connects[signal]: self.__connects[signal].append((fnct, data, key)) return True def signal_unconnect(self, key, signal=None): if signal is None: signal = list(self.__connects.keys()) else: signal = [signal] for sig in signal: i = 0 while i < len(self.__connects[sig]): if self.__connects[sig][i][2] is key: del self.__connects[sig][i] else: i += 1 return True def destroy(self): self.__connects = {} tryton-5.0.17/tryton/__init__.py0000644000175000017500000001434613563616132016141 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. __version__ = "5.0.17" import sys import gi import pygtkcompat pygtkcompat.enable() pygtkcompat.enable_gtk(version='3.0') try: pygtkcompat.enable_goocanvas() except ValueError: pass try: gi.require_version('GtkSpell', '3.0') except ValueError: pass from gi.repository import GdkPixbuf _unset = object() Gdk = sys.modules['gtk.gdk'] # XXX this prevents isinstance test Gdk.PixbufLoader = GdkPixbuf.PixbufLoader.new Gtk = sys.modules['gtk'] Gtk.widget_set_default_direction = Gtk.Widget.set_default_direction Gtk.accel_map_add_entry = Gtk.AccelMap.add_entry Gtk.accel_map_load = Gtk.AccelMap.load Gtk.accel_map_save = Gtk.AccelMap.save Gtk.PROGRESS_LEFT_TO_RIGHT = (Gtk.Orientation.HORIZONTAL, False) Gtk.PROGRESS_RIGHT_TO_LEFT = (Gtk.Orientation.HORIZONTAL, True) Gtk.PROGRESS_BOTTOM_TO_TOP = (Gtk.Orientation.VERTICAL, True) Gtk.PROGRESS_TOP_TO_BOTTOM = (Gtk.Orientation.VERTICAL, False) Gtk.CLIPBOARD_PRIMARY = Gdk.Atom.intern('PRIMARY', True) Gtk.CLIPBOARD_CLIPBOARD = Gdk.Atom.intern('CLIPBOARD', True) orig_tree_view_column_set_cell_data_func = ( Gtk.TreeViewColumn.set_cell_data_func) def set_cell_data_func(self, cell, func, user_data=_unset): def callback(*args): if args[-1] == _unset: args = args[:-1] return func(*args) orig_tree_view_column_set_cell_data_func( self, cell, callback, user_data) Gtk.TreeViewColumn.set_cell_data_func = set_cell_data_func Gtk.TreeViewColumn.get_cell_renderers = Gtk.TreeViewColumn.get_cells orig_set_orientation = Gtk.ProgressBar.set_orientation def set_orientation(self, orientation): orientation, inverted = orientation orig_set_orientation(self, orientation) self.set_inverted(inverted) Gtk.ProgressBar.set_orientation = set_orientation orig_set_orientation = Gtk.CellRendererProgress.set_orientation def set_orientation(self, orientation): orientation, inverted = orientation orig_set_orientation(self, orientation) self.set_property('inverted', inverted) Gtk.CellRendererProgress.set_orientation = set_orientation orig_popup = Gtk.Menu.popup def popup(self, parent_menu_shell, parent_menu_item, func, button, activate_time, data=None): if func: def position_func(menu, x, y, user_data=None): return func(menu, user_data) else: position_func = None orig_popup(self, parent_menu_shell, parent_menu_item, position_func, data, button, activate_time) Gtk.Menu.popup = popup def get_active_text(self): active = self.get_active() if active < 0: return None else: model = self.get_model() index = self.get_property('entry-text-column') return model[active][index] Gtk.ComboBox.get_active_text = get_active_text Gtk.GenericCellRenderer.__gobject_init__ = Gtk.GenericCellRenderer.__init__ from gi.repository import Pango def make_attr_constructor(method): def constructor(value, start_index, end_index): attr = getattr(Pango, method)(value) attr.start_index = start_index if end_index >= 0: attr.end_index = end_index return attr return constructor def make_attr_2_constructor(method): def constructor(one, two, start_index, end_index): attr = getattr(Pango, method)(one, two) attr.start_index = start_index if end_index >= 0: attr.end_index = end_index return attr return constructor def make_attr_3_constructor(method): def constructor(one, two, three, start_index, end_index): attr = getattr(Pango, method)(one, two, three) attr.start_index = start_index if end_index >= 0: attr.end_index = end_index return attr return constructor for method, name, constructor in [ ('attr_language_new', 'AttrLanguage', make_attr_constructor), ('attr_family_new', 'AttrFamily', make_attr_constructor), ('attr_foreground_new', 'AttrForeground', make_attr_3_constructor), ('attr_background_new', 'AttrBackground', make_attr_3_constructor), ('attr_size_new', 'AttrSize', make_attr_constructor), ('attr_size_new_absolute', 'AttrSizeAbsolute', make_attr_constructor), ('attr_style_new', 'AttrStyle', make_attr_constructor), ('attr_weight_new', 'AttrWeight', make_attr_constructor), ('attr_variant_new', 'AttrVariant', make_attr_constructor), ('attr_stretch_new', 'AttrStretch', make_attr_constructor), ('attr_font_desc_new', 'AttrFontDesc', make_attr_constructor), ('attr_underline_new', 'AttrUnderline', make_attr_constructor), ('attr_underline_color_new', 'AttrUnderlineColor', make_attr_3_constructor), ('attr_strikethrough_new', 'AttrStrikethrough', make_attr_constructor), ('attr_strikethrough_color_new', 'AttrStrikethroughColor', make_attr_3_constructor), ('attr_rise_new', 'AttrRise', make_attr_constructor), ('attr_scale_new', 'AttrScale', make_attr_constructor), ('attr_fallback_new', 'AttrFallback', make_attr_constructor), ('attr_letter_spacing_new', 'AttrLetterSpacing', make_attr_constructor), ('attr_shape_new', 'AttrShape', make_attr_2_constructor), ]: if hasattr(Pango, method): setattr(Pango, name, constructor(method)) import gtk if not hasattr(gtk, 'TreePath'): gtk.TreePath = tuple if not hasattr(gtk, 'TargetEntry'): gtk.TargetEntry = lambda *a: a gtk.TargetEntry.new = lambda *a: a if not hasattr(gtk, 'CLIPBOARD_PRIMARY'): gtk.CLIPBOARD_PRIMARY = 'PRIMARY' gtk.CLIPBOARD_CLIPBOARD = 'CLIPBOARD' import gobject try: # Import earlier otherwise there is a segmentation fault on MSYS2 import goocalendar except ImportError: pass gobject.threads_init() if not hasattr(gtk.gdk, 'lock'): class _Lock(object): __enter__ = gtk.gdk.threads_enter def __exit__(*ignored): gtk.gdk.threads_leave() gtk.gdk.lock = _Lock() if sys.platform == 'win32': class Dialog(gtk.Dialog): def run(self): with gtk.gdk.lock: return super(Dialog, self).run() gtk.Dialog = Dialog tryton-5.0.17/tryton/plugins/0000755000175000017500000000000013571264253015503 5ustar cedced00000000000000tryton-5.0.17/tryton/plugins/__init__.py0000644000175000017500000000176413463252532017621 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os import imp import gettext from tryton.config import get_config_dir, CURRENT_DIR __all__ = ['MODULES', 'register'] _ = gettext.gettext MODULES = [] def register(): global MODULES paths = [ os.path.join(get_config_dir(), 'plugins'), os.path.join(CURRENT_DIR, 'plugins'), ] paths = list(filter(os.path.isdir, paths)) imported = set() for path in paths: for plugin in os.listdir(path): module = os.path.splitext(plugin)[0] if module == '__init__' or module in imported: continue try: module = imp.load_module(module, *imp.find_module(module, [path])) MODULES.append(module) except ImportError: continue else: imported.add(module.__name__) tryton-5.0.17/tryton/plugins/translation/0000755000175000017500000000000013571264253020041 5ustar cedced00000000000000tryton-5.0.17/tryton/plugins/translation/__init__.py0000644000175000017500000000127113463252532022150 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext from tryton.gui.window import Window from tryton.common import MODELACCESS _ = gettext.gettext def translate_view(datas): model = datas['model'] Window.create('ir.translation', res_id=False, domain=[('model', '=', model)], mode=['tree', 'form'], name=_('Translate view')) def get_plugins(model): access = MODELACCESS['ir.translation'] if access['read'] and access['write']: return [ (_('Translate view'), translate_view), ] else: return [] tryton-5.0.17/tryton/rpc.py0000644000175000017500000001170513463252532015161 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import http.client import logging import socket import ssl import os try: from http import HTTPStatus except ImportError: from http import client as HTTPStatus from functools import partial from tryton import bus from tryton.jsonrpc import ServerProxy, ServerPool, Fault from tryton.fingerprints import Fingerprints from tryton.config import get_config_dir from tryton.exceptions import TrytonServerError, TrytonServerUnavailable from tryton.config import CONFIG CONNECTION = None _USER = None CONTEXT = {} _VIEW_CACHE = {} _TOOLBAR_CACHE = {} _KEYWORD_CACHE = {} _CA_CERTS = os.path.join(get_config_dir(), 'ca_certs') if not os.path.isfile(_CA_CERTS): _CA_CERTS = None _FINGERPRINTS = Fingerprints() ServerProxy = partial(ServerProxy, fingerprints=_FINGERPRINTS, ca_certs=_CA_CERTS) ServerPool = partial(ServerPool, fingerprints=_FINGERPRINTS, ca_certs=_CA_CERTS) def context_reset(): CONTEXT.clear() CONTEXT['client'] = bus.ID context_reset() def db_list(host, port): try: connection = ServerProxy(host, port) logging.getLogger(__name__).info('common.db.list()') result = connection.common.db.list() logging.getLogger(__name__).debug(repr(result)) return result except Fault as exception: logging.getLogger(__name__).debug(exception.faultCode) if exception.faultCode == str(HTTPStatus.FORBIDDEN.value): return [] else: return None def server_version(host, port): try: connection = ServerProxy(host, port) logging.getLogger(__name__).info( 'common.server.version(None, None)') result = connection.common.server.version() logging.getLogger(__name__).debug(repr(result)) return result except (Fault, socket.error, ssl.SSLError, ssl.CertificateError) as e: logging.getLogger(__name__).error(e) return None def login(parameters): from tryton import common global CONNECTION, _USER global _VIEW_CACHE, _TOOLBAR_CACHE, _KEYWORD_CACHE host = CONFIG['login.host'] hostname = common.get_hostname(host) port = common.get_port(host) database = CONFIG['login.db'] username = CONFIG['login.login'] language = CONFIG['client.lang'] connection = ServerProxy(hostname, port, database) logging.getLogger(__name__).info('common.db.login(%s, %s, %s)' % (username, 'x' * 10, language)) result = connection.common.db.login(username, parameters, language) logging.getLogger(__name__).debug(repr(result)) _USER = result[0] session = ':'.join(map(str, [username] + result)) if CONNECTION is not None: CONNECTION.close() CONNECTION = ServerPool(hostname, port, database, session=session) _VIEW_CACHE = {} _TOOLBAR_CACHE = {} _KEYWORD_CACHE = {} bus.listen(CONNECTION) def logout(): global CONNECTION, _USER global _VIEW_CACHE, _TOOLBAR_CACHE, _KEYWORD_CACHE if CONNECTION is not None: try: logging.getLogger(__name__).info('common.db.logout()') with CONNECTION() as conn: conn.common.db.logout() except (Fault, socket.error, http.client.CannotSendRequest): pass CONNECTION.close() CONNECTION = None _USER = None _VIEW_CACHE = {} _TOOLBAR_CACHE = {} _KEYWORD_CACHE = {} def _execute(blocking, *args): global CONNECTION, _USER if CONNECTION is None: raise TrytonServerError('403') key = False model = args[1] method = args[2] if not CONFIG['dev']: if method == 'fields_view_get': key = str(args) if key in _VIEW_CACHE: return _VIEW_CACHE[key] elif method == 'view_toolbar_get': key = str(args) if key in _TOOLBAR_CACHE: return _TOOLBAR_CACHE[key] elif model == 'ir.action.keyword' and method == 'get_keyword': key = str(args) if key in _KEYWORD_CACHE: return _KEYWORD_CACHE[key] try: name = '.'.join(args[:3]) args = args[3:] logging.getLogger(__name__).info('%s%s' % (name, args)) with CONNECTION() as conn: result = getattr(conn, name)(*args) except (http.client.CannotSendRequest, socket.error) as exception: raise TrytonServerUnavailable(*exception.args) if not CONFIG['dev']: if key and method == 'fields_view_get': _VIEW_CACHE[key] = result elif key and method == 'view_toolbar_get': _TOOLBAR_CACHE[key] = result elif key and model == 'ir.action.keyword' and method == 'get_keyword': _KEYWORD_CACHE[key] = result logging.getLogger(__name__).debug(repr(result)) return result def execute(*args): return _execute(True, *args) def execute_nonblocking(*args): return _execute(False, *args) tryton-5.0.17/tryton/fingerprints.py0000644000175000017500000000255213463252532017107 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import os from tryton.config import get_config_dir KNOWN_HOSTS_PATH = os.path.join(get_config_dir(), 'known_hosts') class Fingerprints(dict): def __init__(self): super(Fingerprints, self).__init__() self.load() def load(self): if not os.path.isfile(KNOWN_HOSTS_PATH): return with open(KNOWN_HOSTS_PATH) as known_hosts: for line in known_hosts: line = line.strip() try: host, sha1 = line.split(' ') except ValueError: host, sha1 = line, '' # Skip current implementation to avoid save dict.__setitem__(self, host, sha1) def save(self): with open(KNOWN_HOSTS_PATH, 'w') as known_hosts: known_hosts.writelines('%s %s' % (host, sha1) + os.linesep for host, sha1 in self.items()) def __setitem__(self, key, value): assert isinstance(key, str) if value: assert len(value) == 59 # len of formated sha1 else: value = '' changed = value != self.get(key) super(Fingerprints, self).__setitem__(key, value) if changed: self.save() tryton-5.0.17/tryton/action/0000755000175000017500000000000013571264253015277 5ustar cedced00000000000000tryton-5.0.17/tryton/action/__init__.py0000644000175000017500000000024413463252531017404 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. from .main import * tryton-5.0.17/tryton/action/main.py0000644000175000017500000001762413463252531016603 0ustar cedced00000000000000# This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. import gettext import webbrowser import tryton.rpc as rpc from tryton.common import RPCProgress, RPCExecute, RPCException from tryton.common import message, selection, file_write, file_open, mailto from tryton.config import CONFIG from tryton.pyson import PYSONDecoder _ = gettext.gettext class Action(object): @staticmethod def exec_report(name, data, direct_print=False, email_print=False, email=None, context=None): if context is None: context = {} if email is None: email = {} data = data.copy() ctx = rpc.CONTEXT.copy() ctx.update(context) ctx['direct_print'] = direct_print ctx['email_print'] = email_print ctx['email'] = email args = ('report', name, 'execute', data.get('ids', []), data, ctx) try: res = RPCProgress('execute', args).run() except RPCException: return False if not res: return False (type, data, print_p, name) = res if not print_p and direct_print: print_p = True fp_name = file_write((name, type), data) if email_print: mailto(to=email.get('to'), cc=email.get('cc'), subject=email.get('subject'), body=email.get('body'), attachment=fp_name) else: file_open(fp_name, type, print_p=print_p) return True @staticmethod def execute(act_id, data, action_type=None, context=None, keyword=False): # Must be executed synchronously to avoid double execution # on double click. if not action_type: action, = RPCExecute('model', 'ir.action', 'read', [act_id], ['type'], context=context) action_type = action['type'] action, = RPCExecute('model', action_type, 'search_read', [('action', '=', act_id)], 0, 1, None, None, context=context) if keyword: keywords = { 'ir.action.report': 'form_report', 'ir.action.wizard': 'form_action', 'ir.action.act_window': 'form_relate', } action.setdefault('keyword', keywords.get(action_type, '')) Action._exec_action(action, data, context=context) @staticmethod def _exec_action(action, data=None, context=None): from tryton.gui.window import Window if context is None: context = {} else: context = context.copy() if data is None: data = {} else: data = data.copy() if 'type' not in (action or {}): return context.pop('active_id', None) context.pop('active_ids', None) context.pop('active_model', None) def add_name_suffix(name, context=None): if not data.get('ids') or not data.get('model'): return name max_records = 5 rec_names = RPCExecute('model', data['model'], 'read', data['ids'][:max_records], ['rec_name'], context=context) name_suffix = _(', ').join([x['rec_name'] for x in rec_names]) if len(data['ids']) > max_records: name_suffix += _(',\u2026') return _('%s (%s)') % (name, name_suffix) data['action_id'] = action['id'] if action['type'] == 'ir.action.act_window': view_ids = [] view_mode = None if action.get('views', []): view_ids = [x[0] for x in action['views']] view_mode = [x[1] for x in action['views']] elif action.get('view_id', False): view_ids = [action['view_id'][0]] action.setdefault('pyson_domain', '[]') ctx = { 'active_model': data.get('model'), 'active_id': data.get('id'), 'active_ids': data.get('ids', []), } ctx.update(rpc.CONTEXT) ctx['_user'] = rpc._USER decoder = PYSONDecoder(ctx) action_ctx = context.copy() action_ctx.update( decoder.decode(action.get('pyson_context') or '{}')) ctx.update(action_ctx) ctx.update(context) ctx['context'] = ctx decoder = PYSONDecoder(ctx) domain = decoder.decode(action['pyson_domain']) order = decoder.decode(action['pyson_order']) search_value = decoder.decode(action['pyson_search_value'] or '[]') tab_domain = [(n, decoder.decode(d), c) for n, d, c in action['domains']] name = action.get('name', '') if action.get('keyword', ''): name = add_name_suffix(name, action_ctx) res_model = action.get('res_model', data.get('res_model')) res_id = action.get('res_id', data.get('res_id')) limit = action.get('limit') if limit is None: limit = CONFIG['client.limit'] Window.create(res_model, view_ids=view_ids, res_id=res_id, domain=domain, context=action_ctx, order=order, mode=view_mode, name=name, limit=limit, search_value=search_value, icon=(action.get('icon.rec_name') or ''), tab_domain=tab_domain, context_model=action['context_model'], context_domain=action['context_domain']) elif action['type'] == 'ir.action.wizard': name = action.get('name', '') if action.get('keyword', 'form_action') == 'form_action': name = add_name_suffix(name, context) Window.create_wizard(action['wiz_name'], data, direct_print=action.get('direct_print', False), email_print=action.get('email_print', False), email=action.get('email'), name=name, context=context, icon=(action.get('icon.rec_name') or ''), window=action.get('window', False)) elif action['type'] == 'ir.action.report': Action.exec_report(action['report_name'], data, direct_print=action.get('direct_print', False), email_print=action.get('email_print', False), email=action.get('email'), context=context) elif action['type'] == 'ir.action.url': if action['url']: webbrowser.open(action['url'], new=2) @staticmethod def exec_keyword(keyword, data=None, context=None, warning=True, alwaysask=False): actions = [] model_id = data.get('id', False) try: actions = RPCExecute('model', 'ir.action.keyword', 'get_keyword', keyword, (data['model'], model_id)) except RPCException: return False keyact = {} for action in actions: keyact[action['name'].replace('_', '')] = action res = selection(_('Select your action'), keyact, alwaysask=alwaysask) if res: (name, action) = res Action._exec_action(action, data, context=context) return (name, action) elif not len(keyact) and warning: message(_('No action defined.')) return False @staticmethod def evaluate(action, atype, record): ''' Evaluate the action with the record. ''' action = action.copy() email = {} if 'pyson_email' in action: email = record.expr_eval(action['pyson_email']) if not email: email = {} if 'subject' not in email: email['subject'] = action['name'].replace('_', '') action['email'] = email return action tryton-5.0.17/LICENSE0000644000175000017500000010451313354423127013470 0ustar cedced00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read .