changeset 6638:e1588ae185dc issue2550923_computed_property

merge from default branch. Fix travis.ci so CI builds don't error out
author John Rouillard <rouilj@ieee.org>
date Thu, 21 Apr 2022 16:54:17 -0400
parents 85db90cc1705 (current diff) e657826186c6 (diff)
children ca90f7270cd4
files CHANGES.txt doc/customizing.txt roundup/backends/rdbms_common.py roundup/cgi/templating.py roundup/hyperdb.py roundup/instance.py
diffstat 78 files changed, 9417 insertions(+), 4633 deletions(-) [+]
line wrap: on
line diff
--- a/.travis.yml	Fri Oct 08 00:37:16 2021 -0400
+++ b/.travis.yml	Thu Apr 21 16:54:17 2022 -0400
@@ -16,12 +16,13 @@
 #    - default
 #    - maint-1.6
 
-dist:
-  - bionic
+dist: focal
 
+#  - pypy3
 python:
   - 2.7
-  - 3.9-dev
+  - 3.10.0
+  - 3.9
   - 3.8
   - 3.6
   - nightly
@@ -33,11 +34,12 @@
 jobs:
     allow_failures:  # nightly not ready for prime time yet.
       - python: nightly
+      - python: pypy3
 
 addons:
   apt:
-    sources:
-      - sourceline: ppa:xapian-backports/ppa
+    #sources:
+    #  - sourceline: ppa:xapian-backports/ppa
 
     packages:
       # Required to build/install the xapian-binding
@@ -48,8 +50,12 @@
       - gpgsm
 
 before_install:
-  # Sphinx required to build the xapian python bindings
-  - pip install sphinx==1.8.5
+  - echo "$TRAVIS_PYTHON_VERSION"
+  # Sphinx required to build the xapian python bindings. Use 1.8.5 on
+  # older python and newest on newer.
+  - if [[ $TRAVIS_PYTHON_VERSION == "2."* ]]; then pip install sphinx==1.8.5; fi
+  - if [[ $TRAVIS_PYTHON_VERSION == '3.'* ]] ; then pip install sphinx; fi
+  - if [[ $TRAVIS_PYTHON_VERSION == "nightly" ]]; then pip install sphinx; fi
   - XAPIAN_VER=$(dpkg -l libxapian-dev | tail -n 1 | awk '{print $3}' | cut -d '-' -f 1)
   - cd /tmp
   - curl -s -O https://oligarchy.co.uk/xapian/$XAPIAN_VER/xapian-bindings-$XAPIAN_VER.tar.xz
@@ -59,12 +65,13 @@
   - if [[ $TRAVIS_PYTHON_VERSION == "2."* ]]; then ./configure --prefix=$VIRTUAL_ENV --with-python; fi
   - if [[ $TRAVIS_PYTHON_VERSION == "3."* ]]; then ./configure --prefix=$VIRTUAL_ENV --with-python3; fi
   - if [[ $TRAVIS_PYTHON_VERSION == "nightly" ]]; then ./configure --prefix=$VIRTUAL_ENV --with-python3; fi
+  - if [[ $TRAVIS_PYTHON_VERSION == "pypy3" ]]; then ./configure --prefix=$VIRTUAL_ENV --with-python3; fi
   - make && make install
 
   - PATH=$VIRTUAL_ENV/bin:$PATH
 
   # libgpg-error
-  - LIBGPG_ERROR_VERSION=1.32
+  - LIBGPG_ERROR_VERSION=1.43
   - cd /tmp
   - curl -s -O https://www.gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-$LIBGPG_ERROR_VERSION.tar.bz2
   - tar -jxvf libgpg-error-$LIBGPG_ERROR_VERSION.tar.bz2
@@ -73,7 +80,7 @@
   - make && make install
 
   # libassuan
-  - LIBASSUAN_VERSION=2.5.1
+  - LIBASSUAN_VERSION=2.5.5
   - cd /tmp
   - curl -s -O https://www.gnupg.org/ftp/gcrypt/libassuan/libassuan-$LIBASSUAN_VERSION.tar.bz2
   - tar -jxvf libassuan-$LIBASSUAN_VERSION.tar.bz2
@@ -82,7 +89,7 @@
   - make && make install
 
   # gpgme
-  - GPGME_VERSION=1.11.1
+  - GPGME_VERSION=1.16.0
   - cd /tmp
   - curl -s -O https://www.gnupg.org/ftp/gcrypt/gpgme/gpgme-$GPGME_VERSION.tar.bz2
   - tar -jxf gpgme-$GPGME_VERSION.tar.bz2
@@ -100,24 +107,31 @@
   - pip install gpg pytz whoosh pyjwt requests
   - pip install pytest-cov codecov
   - if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install docutils; fi
-  - if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install mistune; fi
+  - if [[ $TRAVIS_PYTHON_VERSION != "3.4"* ]]; then pip install mistune==0.8.4; fi
   - if [[ $TRAVIS_PYTHON_VERSION != "3.4"* && $TRAVIS_PYTHON_VERSION != "2."* ]]; then pip install Markdown; fi
   - pip install markdown2
-  - pip install brotli zstd
+  - pip install brotli
+  # zstd fails to build under python nightly aborting test.
+  # allow testing to still happen if the optional package doesn't install.
+  - pip install zstd || true
 
 before_script:
   # set up mysql database
   - sudo sed -i -e '/^\[mysqld\]/,/^\[mysql/s/^max_allowed_packet.*/max_allowed_packet = 500M/' /etc/mysql/my.cnf
   - cat /etc/mysql/my.cnf
   - sudo service mysql restart
-  - mysql -u root -e 'GRANT ALL ON rounduptest.* TO rounduptest@localhost IDENTIFIED BY "rounduptest";'
+  - mysql -u root -e 'CREATE USER "rounduptest"@"localhost" IDENTIFIED WITH mysql_native_password BY "rounduptest"; GRANT ALL on rounduptest.* TO "rounduptest"@"localhost";'
 
+  # Disable fsync for speed, don't care about data durability when testing
+  - sudo sed -i -e '$a\fsync = off' /etc/postgresql/*/*/postgresql.conf
   - sudo service postgresql restart; sleep 30
   # set up postgresql database
   - psql -c "CREATE ROLE rounduptest WITH CREATEDB LOGIN PASSWORD 'rounduptest';" -U postgres
 
   # HACK: workaround mysql bug: http://bugs.mysql.com/bug.php?id=74901
   #   needed for test_mysql.mysqlDBTest.testFilteringSpecialChars
+  # plus others. Otherwise we get:
+  # COLLATION 'utf8_bin' is not valid for CHARACTER SET 'utf8mb4'
   - sed -i 's/CREATE DATABASE \%s/CREATE DATABASE \%s COLLATE utf8_general_ci/' roundup/backends/back_mysql.py
 
   # build the .mo translation files and install them into a tree
@@ -141,6 +155,7 @@
   - if [[ "$TRAVIS_PYTHON_VERSION" == "2."* ]]; then
       py.test -v --maxfail=20 test/ --cov=roundup;
     fi
+  - ./setup.py build_doc
 
 after_success:
   - codecov
--- a/CHANGES.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/CHANGES.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -22,9 +22,62 @@
   Previously it used to accept only TLS v1.1. 1.1 is deprecated by
   chrome. I don't expect this to be a major problem since a front
   end server (apache, Nginx...) is usually customer facing and
-  terminates SSL.
+  terminates SSL.  (John Rouillard)
 - Fix hang when valid user without authorization for REST tries to use
-  the rest interface.
+  the rest interface.  (John Rouillard)
+- Remove Content-Type and make sure no content is returned by OPTIONS
+  request in REST interface. (John Rouillard)
+- In write_html set the Content-Length when response is not
+  encoded/compressed. (John Rouillard)
+- In REST interface do not raise UsageError for invalid api version.
+  Return json error with proper message. Fixes crash. (John Rouillard)
+- In REST interface, allow extensions on URI less than 6 characters in
+  length. All other paths with a . in then will be passed through
+  without change. This allows items like a JWT to be passed as a path
+  element. (John Rouillard)
+- issue2551167 - pip install in containerized environments puts
+  template and locale files under site-packages where roundup can't find
+  them. Change code to find them under site-packages.
+- REST replace hard coded list of child endpoints for /rest/ with list
+  pulled from registered endpoints. So newly added endpoints are
+  shown. (John Rouillard)
+- issue2551107 - Handle representation of long int in history params
+  for python3. Causes SyntaxError crash when showing history due to
+  long int e.g. 2345L. This is not a problem for roundup trackers
+  created using 1.2.0 or newer. The fix may have predated the 1.2.0
+  release but where the fix actually landed (representing id as a
+  string and not as an int) is unknown.
+- issue2551175 - Make ETag content-encoding aware. HTTP ETag headers
+  now include a suffix indicating the content-encoding used to send
+  the data per rfc7232. Properly validate any form of ETag suffixed or
+  non-suffixed for If-Match.
+- issue2551178 - fix Traceback in Apache WSGI - during file upload
+- issue2551179 - make roundup-demo initialize templates using
+  config_ini.ini overrides. Needed for jinja to set template lang etc.
+  Recognize minimal template when presented with a full
+  path. (John Kristensen (jerrykan) and John Rouillard)
+- handle configparser.InterpolationSyntaxError raised if value
+  has a single %. Seems to afect python 3 only. Reported by
+  nomicon on IRC. (John Rouillard)
+- add random delay to session database retry code between 0 and .125
+  seconds. This seems to help reduce stalled connections when a
+  number of connections are made at the same time. Log remaining
+  retries once 5 of them have been used. (John Rouillard)
+- issue2551169 - setup.py enters endless loop on gentoo linux python2
+  installation. Fixed.
+- issue2551185 - must set PYTHONPATH=... python2 setup.py install
+  --prefix=/tmp/r2. Force insert --old-and-unmangable to get it
+  to use a classic installer and not an easy install. This only
+  affects python2.
+- issue2551186 - Python versions >= 3.3 no longer use socket.sslerror.
+  Andrew (kragacles) patched uses of socket.sslerror in mailgy.py.
+  Patch adapted to allow trapping sslerror under both python2 and 3.
+  (John Rouillard)
+- issue2551142 - postgresql reworked to use savepoint/"rollback to"
+  rather than commit()/rollback(). Using savepoint should be faster.
+- issue2551196 - Unset labelprop of a Multilink can lead to Python
+  error when using context/history. (reported and initial patch: Nagy
+  Gabor, John Rouillard)
 
 Features:
 
@@ -42,6 +95,50 @@
   responsive templates already have this feature.
 - issue2550917 - Add a: "Welcome user, you have logged in" ok_message
   on login. (Ashley Burke)
+- enable HTTP/1.1 for roundup-server. This enables keep-alive for
+  faster response/loading. Also eliminates stalls when the front end web
+  server uses http 1.1 but the roundup-server uses 1.0. New option
+  "-V HTTP/1.0" can turn it off. (John Rouillard)
+- issue2551163 - add scripts/Docker/Dockerfile to provide basic support for
+  containerization. See installation.txt for details. (John Rouillard)
+- issue2551163 - add scripts/Docker/docker-compose.yml to get a
+  mysql/roundup deployment. (Norbert Schlemmer, modified by John
+  Rouilard)
+- REST add openapi_doc decorator to add openapi_doc to
+  endpoints. Decorate a couple of examples. (John Rouillard)
+- REST when incorrect method is used, report allowed methods in error
+  message as well as in an Allow header. (John Rouillard)
+- REST change response to invalid attribute specified in path.  Return
+  400 code not 405 code for this case and improve error. (John
+  Rouillard)
+- REST correct values for some Access-Control-Allow-Methods and
+  Access-Control-Allow-Headers headers. (John Rouillard)
+- issue2550991 - define default cache control settings for javascript
+  and css assets. (John Rouillard)
+- issue2551181 - fragments can be appended to designators. So
+  issue23#msg24 could jump to the element with id msg24 in issue 23.
+  Before this patch you would have two links issue23 and msg24
+  separated by # (John Rouillard).
+- added small utility script to dump dbm based tracker databases
+  (e.g. db/sessions). (John Rouillard)
+- issue2551182 - Enhance configuration module to allow loading values
+  from an external file. Secrets (passwords, secrets) can specify
+  file using file:// or file:///. The first line of the file is used
+  as the secret. This allows committing config.ini to a VCS. (John
+  Rouillard)
+- Added xapian indexer to Docker container. (John Rouillard)
+- Add support for indexer type native-fts to use FTS5 for sqlite
+  databases. (John Rouillard)
+- Add support for indexer type native-fts to use PostreSQL's full text
+  search. (John Rouillard)
+- Add better error display to the user. Needed to expose errors in fts5
+  search syntax to the user while also displaying the template page
+  structure. (John Rouillard)
+- issue2551189 - increase size of words in full text index.
+  Many terms (like exception names or symbolic constants) are larger
+  than 25. Also German words are long. Since there is little chance of
+  fixing German to shorten their words, change indexer maxlength to 50.
+  (Thomas Arendsen Hein provided patch; patch reworked John Rouillard)
 
 2021-07-13 2.1.0
 
--- a/doc/admin_guide.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/admin_guide.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,11 @@
+.. meta::
+    :description language=en:
+        How to administer, backup, upgrade a Roundup installation.
+        System and user security, configuring web compression,
+        documentation on using roundup-server and running
+        roundup-admin.
+
+
 ====================
 Administration Guide
 ====================
@@ -268,6 +276,175 @@
 mechanism allows the admin to allow use of brotli and zstd for
 dynamic content, but not for static content.
 
+Configuring native-fts Full Text Search
+=======================================
+
+Roundup release 2.2.0 supports database-native full text search.
+SQLite (minimum version 3.9.0) with FTS5 and PostgreSQL (minimum
+version 11.0) with websearch_to_tsvector are supported.
+
+To enable this method, change the ``indexer`` setting in the tracker's
+config.ini to ``native-fts``. Then reindex using ``roundup-admin -i
+tracker_home reindex``.  The amount of time it takes to reindex
+depends on the amount of data in your tracker, the speed of your
+disks, etc. It can take hours.
+
+SQLite details
+--------------
+
+The SQLite native-fts changes the full text search query a little bit.
+For the other search methods, the search terms are split on white
+space and each item in the index: a field (e.g. title), message
+content and file content is searched for all the terms. If any term is
+missing that item is ignored. Once the items are found they are mapped
+to an issue and the normal issue index is displayed.
+
+When using FTS5, the search terms can use the full text search query
+language described at:
+https://www.sqlite.org/fts5.html#full_text_query_syntax. This
+supports:
+
+  * plain word search (joined with and similar to other search methods)
+  * phrase search with terms enclosed in quotes (``"``)
+  * proximity search with varying distances using ``NEAR()``
+  * boolean operations by grouping with parentheses and using ``AND``
+    and ``OR``
+  * exclusion using ``NOT``
+  * prefix searching by prefixing the term with``^``
+
+All of the data that is indexed is in a single column, so when column
+specifiers are used they usually result in an error which is detected
+and an enhanced error message is produced.
+
+Unlike the native, xapian and whoosh indexers, there are no stopwords,
+and there is no limit to the length of terms that are indexed. Keeping
+these would break proximity and phrase searching. This may be helpful
+or problematic for your particular tracker.
+
+To support the most languages available, the unicode61 tokenizer is
+used without porter stemming. Using the ``indexer_language`` setting
+to enable stemming for ``english`` is not available in this
+implementation.  Also ranking information is not used in this
+implementation. These are areas for improvement.
+
+PostgreSQL info
+---------------
+
+The PostgreSQL native-fts changes the full text search query a little
+bit. When using PostgreSQL full text search, two different query
+languages are supported.
+
+1. websearch - described at the end of
+   `Parsing Queries`_ under websearch_to_tsquery. This is the default.
+
+2. tsquery - described at the beginning of `Parsing Queries`_ with
+   to_tsquery. It is enabled by starting the search phrase with ``ts:``.
+
+.. _Parsing Queries: \
+   https://www.postgresql.org/docs/14/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
+
+Websearch provides a more natural style of search and supports:
+
+* plain word search (stemmed in most cases)
+* phrase search with terms enclosed in quotes (``"``)
+* exclusion by prefixing a term/phrase with ``-``
+* alternative/or searching with ``or`` between terms
+* ignores non-word characters including punctuation
+
+Tsquery supports:
+
+* a strict query syntax
+* plain word search
+* phrase search with the ``<->`` operator or enclosing the phrase in
+  ``'`` single quotes (note this will use a stemmer on the terms
+  in the phrase).
+* proximity search with varying distances using ``<N>``
+* boolean operations by grouping with parentheses and using ``&``
+  and ``|``
+* exclusion using ``!``
+* prefix searching using ``:*`` at the end of the prefix
+
+All of the data that is indexed is in a single column and input
+weighing is not used.
+
+Depending on the FTS configuration (determined by the
+``indexer_language`` setting), stopwords are supported.  PostgreSQL
+takes the stopwords into account when calculating the data needed for
+proximity/near searches. Like SQLite FTS, there is no limit to the
+length of terms that are indexed. Again this may be helpful or
+problematic for your particular tracker.
+
+The config.ini ``indexer_language`` setting is used to define the
+configuration used for indexing. For example with the default
+``english`` setting a snowball stemmer (english_stem) is used. So
+words like 'drive' and 'driving' and 'drive-in' will all match a
+search for 'drive' but will not match 'driver'.
+
+The indexer_language is used as the configuration name for every call
+to the text search functions (to_tsvector, to_tsquery). Changing this
+requires reindexing.
+
+The `configuration list can be obtained using using psql's`_
+``\dF`` command.
+
+.. _configuration list can be obtained using using psql's: \
+    https://www.postgresql.org/docs/current/textsearch-psql.html
+
+Roundup includes a hardcoded list for all languages supported by
+PostgreSQL 14.1. The list includes 5 custom "languages"
+``custom1`` ... ``custom5`` to allow you to set up your `own textsearch
+configuration`_ using one of the custom names. Depending on your
+PostgreSQL version, we may allow an invalid language to be configured.
+You will see an error about ``text search configuration ... does not
+exist``.
+
+.. _own textsearch configuration: \
+  https://www.postgresql.org/docs/14/textsearch-configuration.html
+
+It may be possible to append to this list using the tracker's
+interfaces.py. For details, see ``test/test_indexer.py`` in the
+roundup distribution and search for ``valid_langs``. If you succeed
+please email roundup-users AT lists.sourceforge.net with a description
+of your success.
+
+After changing the configuration language, you must reindex the
+tracker since the index must match the configuration language used for
+querying.
+
+Also there are various `dictionaries`_ that allow you to:
+
+  * add stopwords
+  * override stemming for a term
+  * add synonyms (e.g. a search for "pg" can also match 'psql'
+    "postgresql")
+  * add terms that expand/contract the search space (Thesaurus
+    dictionary)
+  * additional transforms
+  
+.. _dictionaries: https://www.postgresql.org/docs/14/textsearch-dictionaries.html
+
+Use of these is beyond this documentation. Please visit the
+appropriate PostgreSQL documents. The following my also be helpful:
+
+* http://rachbelaid.com/postgres-full-text-search-is-good-enough/
+
+Ranking information is not used in this implementation. Also stop
+words set in config.ini are ignored. These are areas for improvement.
+
+Cleaning up old native indexes
+------------------------------
+
+If you are happy with the database fts indexing, you can save some space by
+removing the data from the native text indexing tables. This requires
+using the ``sqlite3`` or ``psql`` commands to execute SQL to delete the
+rows in the ``__textids`` and ``__words`` tables. You can do this with
+the following SQL commands::
+
+   delete from __words;
+   delete from __textids;
+
+Note this deletes data from the tables and does *not* delete the
+table.
 
 Users and Security
 ==================
--- a/doc/customizing.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/customizing.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,11 @@
+.. meta::
+    :description language=en:
+        How to customize and extend the Roundup Issue
+        Tracker. Includes many cookbook and how-to
+        examples. Reference for the design and internals
+        needed to understand and extend the examples to meet
+        new needs.
+
 :tocdepth: 2
 
 ===================
@@ -576,6 +584,71 @@
 
 then the above ``db.config.detectors['QA_RECIPIENTS']`` will still work.
 
+Unlike values in the tracker's main ``config.ini``, the values defined
+in these config files are not validated. For example: a setting that
+is supposed to be an integer value (e.g. 4) could be the word
+"foo". If you are writing Python code that uses these settings, you
+should expect to handle invalid values.
+
+Also, incorrect values aren't discovered until the config setting is
+used. This can be long after the tracker is started and the error may
+not be seen in the logs.
+
+It is possible to validate these settings. Validation involves calling
+the ``update_options`` method on the configuration option. This can be
+done from the ``init()`` function in the Python files implementing
+extensions_ or detectors_.
+
+As an example, adding the following to an extension::
+
+   from roundup.configuration import SecretMandatoryOption
+
+   def init(instance):
+       instance.config.ext.update_option('RECAPTCHA_SECRET',
+           SecretMandatoryOption,description="Secret securing reCaptcha.")
+
+similarly for a detector::
+
+   from roundup.configuration import MailAddressOption
+
+   def init(db):
+       try:
+           db.config.detectors.update_option('QA_RECIPIENTS',
+               MailAddressOption,
+	       description="Email used for QA comment followup.")
+       except KeyError:
+           # COMMENT_EMAIL setting is not found, but it's optional
+	   # so continue
+           pass
+
+will allow reading the secret from a file or append the tracker domain
+to an email address if it does not have a domain.
+
+Running ``roundup-admin -i tracker_home display user1`` will validate
+the settings for both config.ini`s. Otherwise detector options are not
+validated until the first request to the web interface (or email
+gateway).
+
+There are 4 arguments for ``update_option``:
+
+1. config setting name - string (positional, mandatory)
+2. option type - Option derived class from configuration.py
+   (positional, mandatory)
+3. default value - string (optional, named default) 
+4. description - string (optional, named description) 
+
+The first argument is the config setting name as described at the
+beginning of this section.
+
+The second argument is a class in the roundup.configuration module.
+There are a number of these classes: BooleanOption,
+IntegerNumberOption, RegExpOption.... Please see the configuration
+module for all Option validators and their descriptions. You can also
+define your own custom validator in `interfaces.py`_.
+
+The third and fourth arguments are strings and are optional. They are
+printed if there is an error and may help the user correct the problem.
+
 .. index:: ! schema
 
 Tracker Schema
@@ -2149,16 +2222,29 @@
 
 4. ``/@@file/``
 
+Two additional url's are used for the API's.
+The `REST api`_ is accessed via:
+ 
+5. ``/rest/``
+
+.. _`REST api`: rest.html
+
+and the `XMLRPC api`_ is available at:
+
+6. ``/rest/``
+
+.. _`XMLRPC api`: xmlrpc.html
+
 All other URLs depend on the classes configured in Roundup database.
 Each class receives two URLs - one for the class itself and another
 for specific items of that class. Example for class URL:
 
-5. ``/issue``
+7. ``/issue``
 
 This is usually used to show listings of class items. The URL for
 for specific object of issue class with id 1 will look like:
 
-6. ``/issue1``
+8. ``/issue1``
 
 
 Determining web context
@@ -5866,12 +5952,19 @@
         return check
     for cl in 'issue', 'file', 'msg':
         p = db.security.addPermission(name='View', klass=cl,
-            check=checker(cl))
+            check=checker(cl),
+            description='User can view only if creator.')
         db.security.addPermissionToRole('User', p)
         p = db.security.addPermission(name='Edit', klass=cl,
-            check=checker(cl))
+            check=checker(cl),
+            description='User can edit only if creator.')
         db.security.addPermissionToRole('User', p)
         db.security.addPermissionToRole('User', 'Create', cl)
+    # This allows the interface to get the names of the properties
+    # in the issue. Used for selecting sorting and grouping
+    # on the index page.
+    p = db.security.addPermission(name='Search', klass='issue')
+    db.security.addPermissionToRole ('User', p)
 
 
 Moderating user registration
@@ -6228,3 +6321,4 @@
 .. _`directions in the rest interface documentation`: rest.html#enabling-the-rest-api
 .. _`xmlrpc interface documentation`: xmlrpc.html#through-roundup
 .. _`zxcvbn`: https://github.com/dwolfhub/zxcvbn-python
+ 
--- a/doc/features.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/features.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,9 @@
+.. meta::
+    :description language=en:
+        Features of using the Roundup Issue Tracker. Describes
+        all access methods, configuration and workflow capabilities.
+	Links to detailed documentation.
+
 ================
 Roundup Features
 ================
--- a/doc/glossary.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/glossary.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,8 @@
+.. meta::
+    :description language=en:
+        Definitions of terms used in the Roundup Issue Tracker
+	documentation.
+
 ================
 Roundup Glossary
 ================
--- a/doc/index.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/index.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,7 @@
+.. meta::
+    :description language=en:
+        Table of contents for documentation on the Roundup Issue Tracker.
+
 =======================================================
 Roundup: an Issue-Tracking System for Knowledge Workers
 =======================================================
--- a/doc/installation.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/installation.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,10 @@
+.. meta::
+    :description language=en:
+        Everything about installing the Roundup issue tracker web and
+	mail interfaces and configuring a tracker. How to download and
+	demonstrate Roundup using using command line or
+	Docker. Optional software that adds functionality to Roundup.
+
 .. index:: Installation
 
 ==================
@@ -5,7 +12,7 @@
 ==================
 
 .. contents::
-   :depth: 2
+   :depth: 3
    :local:
 
 
@@ -42,15 +49,6 @@
 installed for Roundup installation to work. Debian and derivatives, are
 known to require this.
 
-If you are using the Roundup Windows installer on a 64 bit system and
-you get the error message::
-
-  "No Python installation found in the registry"
-
-you need to install a 32 bit version of python. The 64 bit versions
-use a different registry key that the installer doesn't detect. See:
-https://issues.roundup-tracker.org/issue2550718 for details.
-
 Optional Components
 ===================
 
@@ -89,6 +87,8 @@
   The Whoosh_ full-text indexer is also supported and will be used by
   default if it is available (and Xapian is not installed). This is
   recommended if you are anticipating a large number of issues (> 5000).
+  It is also the only search backend that implements fuzzy search. It
+  matches any word that has a 1 character difference from the search term.
 
   You may install Whoosh at any time, even after a tracker has been
   installed and used. You will need to run the "roundup-admin reindex"
@@ -145,10 +145,12 @@
 ===============
 
 .. note::
-    Some systems, such as Debian and NetBSD, already have Roundup
+    Some systems, such as Gentoo and NetBSD, already have Roundup
     installed. Try running the command "roundup-admin" with no arguments,
     and if it runs you may skip the `Basic Installation Steps`_
     below and go straight to `configuring your first tracker`_.
+    However they may install an old version, so you are probably
+    beter off installing it from the roundup web site or pypi.
 
 Download the latest version from https://www.roundup-tracker.org/.
 
@@ -216,6 +218,152 @@
 choose to do this, you may have to change Python's search path (sys.path)
 yourself.
 
+Docker Support
+~~~~~~~~~~~~~~
+
+If you don't want to install it natively, you can create a Docker
+container. This installs roundup using the `stand-alone web server`_
+method. This is an http only install so we suggest putting an https
+terminating proxy in front of it.
+
+This is a work in progress and patches to improve it are welcome. You
+can find the docker config files under the `scripts/Docker` directory
+of the source tree.
+
+The dockerized Roundup includes database drivers for anydbm, sqlite,
+MySQL and Postgresql (Postgresl is untested). It also includes
+additional libraries that are listed in
+`scripts/Docker/requirements.txt`.
+
+Email support is a work in progress. Outgoing email should work given
+an external SMTP server. Reciving email should work by using a
+scheduled (cron) job to access email:
+
+* `As a regular job using a mailbox source`_
+* `As a regular job using a POP source`_
+* `As a regular job using an IMAP source`_
+
+Patches for better email support are welcome.
+
+If you want to use a MySQL backend, the `docker-compose.yml` file will
+deploy a Roundup container and a MySQL container backend for use with
+Roundup.
+
+Building a Docker Container
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+To build a docker container using the code in the current directory,
+run this build command from the top of the source tree::
+
+     docker build -t roundup-app -f scripts/Docker/Dockerfile .
+
+You can also build a container using the newest Roundup release on
+PyPI, by running::
+
+     docker build -t roundup-app --build-arg="source=pypi" \
+          -f scripts/Docker/Dockerfile .
+
+The docker declares a single volume mounted at
+``/usr/src/app/tracker`` inside the container. You will mount your
+tracker home directory at this location.
+
+
+Configuring Roundup in the Container
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Once the docker is created using one of the build commands above, run
+an interactive session it with::
+
+    docker run -it --rm -p 9017:8080 \
+       -v $PWD/tracker:/usr/src/app/tracker roundup-app:latest
+
+The ``-v`` option maps a directory from the host into the docker
+container. Note that uid 1000 is used by roundup. So the uid of the
+directory (and all files under it) must be uid 1000.  This example
+assumes your tracker configs are in the tracker subdirectory. Replace
+``$PWD/tracker`` with the full path name to the directory where the
+tracker home(s) are to be stored.
+
+The ``-p`` option maps an external port (9017) to proxy the roundup
+server running at port 8080 to the outside.
+
+If the tracker directory is empty, the docker container will prompt
+you to install a tracker template and prompt you for the database
+type.
+
+Then you need to configure the tracker by editing
+``template/config.ini``.  Make sure that the tracker web setting ends
+in ``/issues/`` See `Configuring your first tracker` and the top of
+``config.ini`` for other settings.
+
+Once you have configured the tracker, run another interactive session
+with::
+
+    docker run --rm -it -p 9017:8080 \
+         -v $PWD/tracker:/usr/src/app/tracker roundup-app:latest
+
+this will initialize the database and attempt to start the server.  If
+that is successful, use control-c to exit the server.
+
+Now start the server non-interactively (note no `-it` option) with::
+
+    docker run -p 9017:8080 \
+       -v $PWD/tracker:/usr/src/app/tracker roundup-app:latest
+
+Your tracker will be available at: ``http://yourhost:9017/issues/``.
+
+If you need to access your container while the server is running you
+can use::
+
+   docker exec -it c0d5 sh
+
+where ``c0d5`` is the id prefix for the running container obtained
+from ``docker container ls``.
+
+If you add ``-e SHELL_DEBUG=1`` to the docker command, it sets the
+``SHELL_DEBUG`` environment variable which will enable debugging
+output from the startup script.
+
+Non-Guided Installation
+'''''''''''''''''''''''
+
+If you got a tracker installed using the automatic setup above, you
+can skip this section. To manually install and initialize the
+trackers, you can get a shell without starting the roundup-server
+using::
+
+    docker run -it \
+        -v $PWD/tracker:/usr/src/app/tracker \
+        --entrypoint sh roundup-app:latest
+
+Now you can configure your tracker using ``roundup-admin -i tracker``
+using the directions for `Configuring your first tracker`.
+
+Defining Multiple Trackers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you want to run multiple trackers, create a subdirectory for each
+tracker home under the volume mount point (``$PWD/tracker``). Then
+invoke ``docker run`` passing the roundup-server tracker
+specifications like::
+
+    docker run --rm -p 9017:8080 \
+        -v /.../issue.tracker:/usr/src/app/tracker \
+        roundup-app:latest tracker1=tracker/tracker1_home \
+          tracker2=tracker/tracker2_home
+
+This will set up two trackers that can be reached at
+``http://yourhost:9017/tracker1/`` and ``http://yourhost:9017/tracker2/``.
+The arguments after roundup-app:latest are tracker paths that are
+passed to roundup-server.
+
+Docker-compose Deployment
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If you want to run using the mysql backend, you can use docker-compose
+with ``scripts/Docker/docker-compose.yml``. This will run Roundup and
+MySQL in containers. Directions for building using docker-compose are
+at the top of the yml file.
 
 Configuring your first tracker
 ------------------------------
@@ -362,6 +510,10 @@
 
   Installed SQLite should be the latest version available (3.3.8 is known
   to work, 3.1.3 is known to have problems).
+
+  Roundup supports using sqlite's full text search capability. This
+  can improve searching if you are not installing another indexer like
+  xapian or whoosh. It works best with English text.
 **postgresql**
   Backend for popular RDBMS PostgreSQL. You must read doc/postgresql.txt for
   additional installation steps and requirements. You must also configure
@@ -388,14 +540,9 @@
 
 There are multiple web interfaces to choose from:
 
-1. `web server cgi-bin`_
-2. `cgi-bin for limited-access hosting`_
-3. `stand-alone web server`_
-4. `Zope product - ZRoundup`_
-5. `Apache HTTP Server with mod_wsgi`_
-6. `Apache HTTP Server with mod_python`_  (deprecated)
-7. `Nginx HTTP Server`_
-8. `WSGI Variations`_
+.. contents::
+   :depth: 1
+   :local:
 
 You may need to give the web server user permission to access the tracker home
 - see the `UNIX environment steps`_ for information. You may also need to
@@ -941,6 +1088,23 @@
     }
 
 
+FastCGI (Cherokee, Hiawatha, lighttpd)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The Hiawatha and lighttpd web servers can run Roundup using FastCGI.
+Cherokee can run FastCGI but it also supports wsgi directly using a
+uWSGI, Gnuicorn etc.
+
+To run Roundup suing FastCGI, the flup_ package can be used under
+Python 2 and Python 3. We don't have a detailed config for this, but
+the basic idea can be found at:
+https://flask.palletsprojects.com/en/2.0.x/deploying/fastcgi/
+
+If you have deployed Roundup using FastCGI and flup we welcome example
+configuration files and instructions.
+
+.. _flup: https://pypi.org/project/flup/
+
 WSGI Variations
 ~~~~~~~~~~~~~~~
 
@@ -1539,7 +1703,7 @@
    ``-d`` option to allow database creation.
 
 Once you've unpacked roundup's source, if you have pytest installed,
-run ``python -m pytest /test`` in the source directory and make sure
+run ``python -m pytest test`` in the source directory and make sure
 there are no errors. If there are errors, please let us know!
 
 .. _`table of contents`: index.html
--- a/doc/overview.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/overview.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,9 @@
+.. meta::
+    :description language=en:
+        Original proposal for the Roundup Issue Tracker. The problem
+        it solves, and guiding principles. Presents the
+        components of Roundup and how they interact.
+
 =======================================================
 Roundup: an Issue-Tracking System for Knowledge Workers
 =======================================================
--- a/doc/rest.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/rest.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,9 @@
+.. meta::
+    :description language=en:
+        Documentation on the RESTful interface to the Roundup Issue
+	Tracker.
+
+
 .. index:: pair: api; Representational state transfer
    pair: api; rest
 
@@ -227,7 +233,12 @@
 ETag header or an @etag property. This needs to be submitted with
 ``DELETE``, ``PUT`` and ``PATCH`` operations on the item using an
 ``If-Match`` header or an ``"@etag`` property in the data payload if
-the method supports a payload.
+the method supports a payload. The ETag header value will include a
+suffix (starting with '-') indicating the Content-Encoding used to
+respond to the request. If the response was uncompressed, there will
+be no suffix. The ``@etag`` property never includes the suffix. Any
+ETag value suffixed or not can be sent in an ``If-Match`` header as
+the suffix is ignored during comparison.
 
 The exact details of returned data is determined by the value of the
 ``@verbose`` query parameter.  The various supported values and their
@@ -708,8 +719,7 @@
 /, you get a web page that includes metadata about the message. With
 the slash you get a text/plain (in most cases) data stream.
 
-Also you can use the url:
-
+Also you can use the url: ``https://.../demo/rest/data/msg/11?@verbose=3``
 and the content property (if the data is utf-8 compatible) now looks
 like::
 
@@ -1857,6 +1867,8 @@
         @Routing.route("/jwt/issue", 'POST')
         @_data_decorator
         def generate_jwt(self, input):
+        """Create a JSON Web Token (jwt)
+        """
             import jwt
             import datetime
             from roundup.anypy.strings import b2s
@@ -1879,6 +1891,11 @@
             else:
                 raise Unauthorised(denialmsg)
 
+            # verify we have input data.
+            if not input:
+                raise UsageError("Missing data payload. "
+                             "Verify Content-Type is sent")
+
             # If we reach this point we have validated that the user has
             # logged in with a password using basic auth.
             all_roles = list(self.db.security.role.items())
@@ -1910,7 +1927,7 @@
 
             newroles = []
             if 'roles' in input:
-                for role in input['roles'].value:
+                for role in [ r.lower() for r in input['roles'].value ]:
                     if role not in rolenames:
                         raise UsageError("Role %s is not valid."%role)
                     if role in user_roles:
--- a/doc/upgrading.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/upgrading.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,9 @@
+.. meta::
+    :description language=en:
+        Critical documentation on how to upgrade the Roundup Issue
+	Tracker. Actions that must or can be taken when upgrading from
+	one version to another are documented here.
+
 .. index:: Upgrading
 
 ======================================
@@ -29,10 +35,44 @@
 Migrating from 2.1.0 to 2.x.y
 =============================
 
-Check Compression Settings
---------------------------
-
-Read the `administration guide`_ section on 'Configuring Compression'.
+Rdbms version change from 6 to 7 (required)
+-------------------------------------------
+
+This release includes two changes that require updates to the database
+schema:
+
+  1. The size of words included in the Roundup FTS indexers have been
+     increased from 25 to 50. This requires changes to the database
+     columns used by the native indexer.  This also affect the whoosh
+     and xapian indexers.
+  2. Some databases that include native full-text search (native-fts
+     indexer) searching are now supported.
+
+You should run the ``roundup-admin migrate`` command for your
+tracker once you've installed the latest codebase.
+
+Do this before you use the web, command-line or mail interface
+and before any users access the tracker.
+
+If successful, this command will respond with either "Tracker
+updated" (if you've not previously run it on an RDBMS backend) or
+"No migration action required" (if you have run it, or have used
+another interface to the tracker, or are using anydbm).
+
+See `below for directions on enabling native-fts`_.
+
+.. _below for directions on enabling native-fts: \
+    #enhanced-full-text-search-optional
+
+The increase in indexed word length also affects whoosh and xapian
+backends. You may want to run ``roundup-admin -i tracker_home
+reindex`` if you want to index or search for longer words in your full
+text searches. Re-indexing make take some time.
+
+Check compression settings (optional)
+-------------------------------------
+
+Read the `administration guide`_ section on `Configuring Compression`_.
 
 Upgrade tracker's config.ini file. Use::
 
@@ -44,13 +84,102 @@
 compression settings as you want. Then replace ``config.ini`` with the
 ``newconfig.ini`` file.
 
-Search Added to User Index Page
--------------------------------
+Search added to user index page (optional)
+------------------------------------------
 
 A search form and count of number of hits has been added to the
 ``user.index.html`` template page in the classic template. You may
 want to merge the search form and footer into your template.
 
+Enhanced full-text search (optional)
+------------------------------------
+
+SQLite's `FTS5 full-text search engine`_ is available as is
+`PostgreSQL's full text search`_. Both require a schema upgrade so you
+should run::
+
+  roundup-admin -i tracker_home migrate
+
+to create FTS specific tables before restarting the roundup-web or
+email interfaces.
+
+SQLite 3.9.0+ or PostgreSQL 11.0+ are required to use this feature.
+When using SQLite, all full text search fields will allow searching
+using the MATCH query format described at:
+https://www.sqlite.org/fts5.html#full_text_query_syntax. When using
+PostgreSQL either the websearch_to_tsquery or to_tsquery formats
+described on
+https://www.postgresql.org/docs/14/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
+can be used. The default is websearch. Prefixing the search with
+``ts:`` enables tsquery mode.
+
+A list of words behaves almost the same as the default text search
+(`native`). So the search string `fts search` will find all issues
+that have both of those words (an AND search) in a text-field (like
+title) or in a message (or file) attached to the issue.
+
+One thing to note is that native-fts searches do not ignore words
+longer than 50 characters or less than 2 characters. Also SQLite does
+not filter out common words (i.e. there is no stopword list). So words
+like "and", "or", "then", "with" ...  are included in the FTS5 search.
+
+You must explicitly enable this search mechanism by changing the
+``indexer`` setting in ``config.ini`` to ``native-fts``. Native-fts
+must be explicitly chosen. This is different from Xapian or Whoosh
+indexers, which are chosen if they are installed in the Python
+environment. This prevents the existing native indexing from being
+discarded if ``indexer`` is not set.
+
+Next re-index your data with ``roundup-admin -i tracker_home
+reindex``. This can take a while depending on the size of the tracker.
+
+You may want to update your ``config.ini`` by following the directions
+above to get the latest documentation.
+
+See the `administration guide notes on native-fts`_ for further details.
+
+Adding error reporting templates (optional)
+-------------------------------------------
+
+Currently some internal errors result in a bare html page with an
+error message. The usual chrome supplied by page.html is not shown.
+For example query language syntax errors for full text search methods
+will display a bare HTML error page.
+
+If you add an ``_generic.400.html`` template to the html directory, you
+can display the error inside of the layout provided by the ``page.html``
+template. This can make fixing the error and navigation easier. You
+can use the ``_generic.404.html`` template to create a
+``_generic.400.html`` by modifying the title and body text. You can test
+the 400 template by appending ``@template=400`` to the url for the
+tracker.
+
+Change passwords using crypt module (optional)
+----------------------------------------------
+
+The crypt module is being removed from the standard library.  Any
+stored password using crypt encoding will fail to verify once the
+crypt module is removed (expected in Python 3.13 see
+pep-0594). Automatic migration of passwords (if enabled in config.ini)
+re-encrypts old passwords using something other than crypt if a user
+logs in using the web interface.
+
+You can find users with passwords still encrypted using crypt by
+running::
+
+    roundup-admin -i <tracker_home> table password,id,username
+
+Look for lines starting with ``{CRYPT}``. You can reset the user's
+password using::
+
+    roundup-admin -i <tracker_home>
+    roundup> set user16 password=somenewpassword
+
+changing ``16`` to the id in the second column of the table output.
+The example uses interactive mode (indicated by the ``roundup>``
+prompt). This prevents the new password from showing up in the output
+of ps or shell history. The new password will be encrypted using the
+default encryption method (usually pbkdf2).
 
 Migrating from 2.0.0 to 2.1.0
 =============================
@@ -3264,3 +3393,7 @@
 .. _`security documentation`: security.html
 .. _`administration guide`: admin_guide.html
 .. _`xmlrpc guide`: xmlrpc.html
+.. _FTS5 full-text search engine: https://www.sqlite.org/fts5.html
+.. _PostgreSQL's full text search: https://www.postgresql.org/docs/current/textsearch.html
+.. _`administration guide notes on native-fts`: admin_guide.html#configuring-native-fts-full-text-search
+.. _Configuring Compression: admin_guide.html#configuring-compression
--- a/doc/user_guide.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/user_guide.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,8 @@
+.. meta::
+    :description language=en:
+        Describes how to interact with and use a tracker with the
+        Roundup Issue Tracker.
+
 ==========
 User Guide
 ==========
@@ -370,6 +375,24 @@
         @filters=status,keyword&
         @columns=title,status,fixer
 
+Full text search using the xapian, whoosh and native indexers treats
+the search query as a series of space separated words. Any word less
+than 2 characters or more than 50 characters is discarded. Also a
+stoplist is used to remove common words like "with", "and"
+etc. Additional stoplist words can be added in the tracker's
+config.ini file. Once filtering of the word list is done, each indexed
+item (e.g. title, file or message content ...) is searched and if all
+the terms are found in the item the item is returned. Then the items
+are mapped to an issue and the list of matching issues is generated.
+
+Other searching backends such as native-fts can be used in which case
+the filtering above is not used. The search query can support
+structure such as quoted phrases, matching one term or another rather
+than both (or search), prefixes etc. In this case you should look at
+the `documentation for configuring the native-fts`_ backend to find
+the supported format and features.
+
+.. _`documentation for configuring the native-fts`: admin_guide.html#configuring-native-fts-full-text-search
 
 Access Controls
 ---------------
--- a/doc/xmlrpc.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/doc/xmlrpc.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,3 +1,8 @@
+.. meta::
+    :description language=en:
+        Documentation on the XMLRPC interface to the Roundup Issue
+	Tracker. Includes sample clients.
+
 .. index:: triple: api; xml; remote procedure call
    pair: api; xmlrpc
 
--- a/locale/GNUmakefile	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/GNUmakefile	Thu Apr 21 16:54:17 2022 -0400
@@ -6,7 +6,7 @@
 MSGFMT ?= msgfmt
 MSGMERGE ?= msgmerge
 XGETTEXT ?= xgettext
-PYTHON ?= python
+PYTHON ?= python3
 
 TEMPLATE=roundup.pot
 
@@ -22,10 +22,13 @@
 
 help:
 	@echo "$(MAKE)           - build MO files.  Run this before sdist"
+	@echo "$(MAKE) dist      - same as above"
 	@echo "$(MAKE) template  - update message template from sources"
+	@echo "$(MAKE) diff      - see template differences in vi"
+	@echo "$(MAKE) pytest    - create locale files to run pytest"
 	@echo "$(MAKE) locale.po - update message file from template"
 	@echo "$(MAKE) locale.mo - compile individual message file"
-	@echo "$(MAKE) help      - this text"\
+	@echo "$(MAKE) help      - this text"
 
 # This will rebuild all MO files without updating their corresponding PO
 # files first.  Run before creating Roundup distribution (hence the name).
@@ -37,7 +40,7 @@
 	done
 
 template:
-	test -d $(PYTHON_BUILD) || (echo "Missing build directory. ln -s lib to build library"; exit 1)
+	test -d $(PYTHON_BUILD) || (echo "Missing build directory $(PYTHON_BUILD). ln -s lib to build library"; exit 1)
 	${XPOT} -n -o $(TEMPLATE) $(SOURCES)
 
 	${RUN_PYTHON} ../roundup/cgi/TAL/talgettext.py -u $(TEMPLATE) \
@@ -50,7 +53,7 @@
 	  --copyright-holder="See Roundup README.txt" \
 	  -o $(TEMPLATE) $(SOURCES)
 
-local_install: dist
+pytest local_install: dist
 	for file in $(MO_FILES); do \
 	   lang=`basename $$file .mo`; \
 	   mkdir -p locale/$$lang/LC_MESSAGES; \
@@ -59,7 +62,7 @@
 
 # helps to check template file before check in
 diff:
-	svn diff roundup.pot|grep -v '^[-+]#'|vim -Rv -
+	hg diff roundup.pot|grep -v '^[-+]#'| vi -Rv -
 
 %.po: $(TEMPLATE)
 	${MSGMERGE} -U --suffix=.bak $@ $<
--- a/locale/de.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/de.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.5.0\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2016-04-11 09:13+0200\n"
 "Last-Translator: Tobias Herp <tobias.herp@gmx.de>\n"
 "Language-Team: German Translators <roundup-devel@lists.sourceforge.net>\n"
@@ -30,19 +30,19 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr "Sie können den Administrator oder den Gast-Benutzer nicht löschen"
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "Die Klasse \"%(classname)s\" existiert nicht"
 
 # ../roundup/admin.py:93 :97
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "Der Parameter \"%(arg)s\" entspricht nicht dem Format Eigenschaft=Wert"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -51,7 +51,7 @@
 "Problem: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -100,12 +100,12 @@
 " roundup-admin help <Befehl>              -- Hilfe zu einem Befehl anzeigen\n"
 " roundup-admin help all                   -- sämtliche Hilfen anzeigen\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Befehle:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -113,7 +113,7 @@
 "Befehle können abgekürzt werden, solange sie eindeutig bleiben, \n"
 "z.B. l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -239,12 +239,12 @@
 "\n"
 "Befehlshilfe:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -264,22 +264,22 @@
 "        all       -- sämtlichen Hilfetext anzeigen\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Zum Thema \"%(topic)s\" existiert leider kein Hilfetext"
 
 # ../roundup/admin.py:336 :382
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Vorlagen:"
 
 # ../roundup/admin.py:339 :393
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Datenbanken:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -334,23 +334,23 @@
 
 # ../roundup/admin.py:358 :483 :562 :612 :682 :703 :731 :802 :869 :940 :988
 # :1010 :1037 :1098 :1156
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "Zu wenig Parameter übergeben"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "Das angegebene Tracker-Verzeichnis \"%(parent)s\" existiert nicht"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -361,22 +361,22 @@
 "installiert zu sein! Eine erneute Installation löscht sämtliche Daten!\n"
 "Wirklich löschen? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Vorlagensatz auswählen [classic]:"
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Datenbank auswählen [anydbm]"
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Fehler in der Konfiguration: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -388,11 +388,11 @@
 " Sie sollten nun die Konfigurationsdatei des Trackers bearbeiten:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... passen sie zumindest folgende Optionen an:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -418,7 +418,7 @@
 " Anschließend MÜSSEN Sie \"roundup-admin initialise\" ausführen.\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -431,7 +431,7 @@
 "        Standardwerten in die Datei <filename>.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -446,7 +446,7 @@
 "        "
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -464,23 +464,23 @@
 "        Die Funktion dbinit.init() wird aufgerufen\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Administratorpasswort: "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "  Wiederholen: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "Tracker-Verzeichnis existiert nicht"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "Tracker-Instanz wurde nicht installiert"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -490,7 +490,7 @@
 "Eine erneute Initialisierung löscht sämtliche Daten!\n"
 "Wirklich löschen? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -511,7 +511,7 @@
 "        "
 
 # ../roundup/admin.py:516 :531
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
@@ -519,21 +519,21 @@
 "hier nicht ausgewertet."
 
 # ../roundup/admin.py:539 :951 :1000 :1022
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr ""
 "Es existiert kein Eintrag der Klasse %(classname)s mit der ID \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 "Die Eigenschaft \"%(propname)s\" ist für die Klasse \"%(classname)s\" nicht "
 "definiert"
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -570,7 +570,7 @@
 "(\"1,2,3\").\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -592,20 +592,20 @@
 "        "
 
 # ../roundup/admin.py:631 :669 :822 :834 :888
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "Die Klasse \"%(classname)s\" hat keine Eigenschaft \"%(propname)s\""
 
 # ../roundup/admin.py:631 :669 :822 :834 :888
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "Die Klasse \"%(classname)s\" hat keine Eigenschaft \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -623,7 +623,7 @@
 "        als ID oder als Bezeichner (\"msg23\") spezifiziert werden.\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -637,17 +637,17 @@
 "        Zeigt sämtliche Eigenschaften der Klasse auf.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (Schlüsseleigenschaft)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -668,12 +668,12 @@
 "        gewählten Eintrags an.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -691,31 +691,31 @@
 "        werden mit den Werten initialisiert\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (Passwort):"
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Wiederholen):"
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Bitte erneut versuchen..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "Sie müssen einen Wert für \"%(propname)s\" angeben."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -746,16 +746,16 @@
 "aufgelistet.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "Sie haben zuviele Argumente übergeben"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -818,17 +818,17 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" entspricht nicht dem Format Eigenschaft:Breite"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -843,7 +843,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -868,7 +868,7 @@
 "        geschrieben.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -887,7 +887,7 @@
 "        verworfen.\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -908,7 +908,7 @@
 "        kann zudem wiederverwendet werden.\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -928,14 +928,14 @@
 "        "
 
 # ../roundup/admin.py:539 :951 :1000 :1022
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr ""
 "Es existiert kein Eintrag der Klasse %(classname)s mit der ID \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -964,7 +964,7 @@
 "        Exportverzeichnis geschrieben.\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -995,7 +995,7 @@
 "        Exportverzeichnis geschrieben.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1039,7 +1039,7 @@
 "        verbergen).\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1047,7 +1047,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1086,11 +1086,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Ungültiges Format"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1106,12 +1106,12 @@
 "        normalerweise automatisch.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "Der Eintrag \"%(designator)s\" existiert nicht"
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1123,48 +1123,48 @@
 "        Zeigt die Berechtigungen einer oder aller Rollen an.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "Die Rolle \"%(role)s\" existiert nicht "
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Neue Web-Benutzer erhalten die Rollen \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Neue Web-Benutzer erhalten die Rolle \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "Neue E-Mail-Benutzer erhalten die Rollen \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Neue E-Mail-Benutzer erhalten die Rolle \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "Rolle \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr "%(description)s (%(name)s einzig für \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 " %(description)s (%(name)s für \"%(klass)s\": ausschließlich %(properties)s)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1172,17 +1172,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr "%(description)s (%(name)s einzig für \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 #, fuzzy
 msgid ""
 "Usage: migrate\n"
@@ -1226,42 +1226,42 @@
 "        es nicht nötig ist; also gewöhnen Sie es sich einfach an.\n"
 "        "
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr "Tracker aktualisiert"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr "Keine Migration notwendig"
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr "Der Befehl \"%(command)s\" existiert nicht (siehe \"help commands\")"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "Zur Abkürzung \"%(command)s\" passen mehrere Befehle: %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Tracker-Verzeichnis: "
 
 # ../roundup/admin.py:1263 :1269 :1289
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Fehler: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Fehler: Die Tracker-Instanz konnte nicht geöffnet werden: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1270,34 +1270,34 @@
 "Roundup %s ist bereit.\n"
 "Schreiben Sie \"help\", um zur Hilfe zu gelangen."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Bemerkung: Befehlsverlauf/-bearbeitung möglicherweise nicht verfügbar"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "beenden..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Es gibt noch ungespeicherte Änderungen. Änderungen speichern (y/N)?"
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr "Konnte den Datenbanktyp nicht ermitteln"
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, fuzzy, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
@@ -1306,7 +1306,7 @@
 "Konnte die Datenbank nicht öffnen - das erforderliche Modul '%s' ist nicht "
 "verfügbar"
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1322,53 +1322,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr "Datenbank nur zum Lesen geöffnet"
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "erstellt"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "Link gelöscht"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "verlinkt"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "geändert"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "verborgen"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "wiederhergestellt"
 
@@ -1614,22 +1636,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Ungültiger Benutzername"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Sie sind nicht berechtigt, sich anzumelden"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Sie sind nicht berechtigt, Einträge der Klasse \"%(class)s\" zu lesen"
@@ -1735,154 +1762,154 @@
 "Admistratoren wurden benachrichtigt.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Formular-Fehler: "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Zeichensatz nicht erkannt: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "Gast-Benutzer sind nicht berechtigt, das Web-Interface zu benutzen."
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "Ungültiger Benutzername"
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
+#, python-format
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
-msgid "Invalid HOST %s"
-msgstr "Ungültige Anforderung"
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "Invalid Origin %s"
+msgstr "Ungültiger Benutzername"
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, fuzzy, python-format
+msgid "Invalid HOST %s"
+msgstr "Ungültige Anforderung"
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Sie sind nicht berechtigt, diese Seite anzuzeigen."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sBenötigte Zeit: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1891,6 +1918,13 @@
 "%(starttag)sCache benutzt: %(cache_hits)d, verfehlt: %(cache_misses)d. "
 "Einträge laden: %(get_items)fs; filtern: %(filtering)fs.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1966,18 +2000,18 @@
 msgstr "Eintrag speichern"
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[verborgen]"
 
@@ -2003,18 +2037,24 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "Die verlinkte Klasse \"%(classname)s\" existiert nicht mehr"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:905 :926
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>Der verknüpfte Eintrag existiert nicht mehr</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (kein Wert)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -2023,46 +2063,46 @@
 "<strong><em>Dieses Ereignis kann nicht im Verlauf angezeigt werden!</em></"
 "strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=\"4\"><strong>Bitte beachten:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Verlauf"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Datum</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Verlauf"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Datum</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Benutzer</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Aktion</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Argumente</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "Kopie von %(class)s %(id)s"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "Nein"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Ja"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2070,19 +2110,19 @@
 "Der voreingestellte Wert einer DateHTML-Eigenschaft muss entweder ein\n"
 "DateHTML-Objekt sein oder ein Datum repräsentieren."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr ""
 "Versuch, das Attribut %(attr)s eines nicht vorhandenen Werts abzufragen"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr ""
 "Versuch, das Attribut %(attr)s eines nicht vorhandenen Werts abzufragen"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- nichts ausgewählt -</option>"
@@ -2100,11 +2140,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Ungültige Anforderung"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Ungültige Anforderung"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2270,23 +2322,23 @@
 msgid "\"%s\" not a node designator"
 msgstr "\"%s\" ist kein gültiger Bezeichner"
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr "Keine Eigenschaft: %s"
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr "Eigenschaft %s: %r ist kein %s."
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr "Sie können für die Eigenschaft %s  nur IDs eingeben"
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr "%r ist keine Eigenschaft von %s"
@@ -2300,44 +2352,44 @@
 "WARNUNG: Das Verzeichnis '%s'\n"
 "\tenthält Vorlagen im alten Format, die ignoriert werden."
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr "Nachricht signiert mit unbekanntem Schlüssel: %s"
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr "Nachricht signiert mit abgelaufenem Schlüssel: %s"
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr "Nachricht signiert mit zurückgezogenem Schlüssel: %s"
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr "Ungültige PGP-Signatur festgestellt."
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Neuer Kommentar"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr "Unbekannte Version von multipart/encrypted."
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr "Kann Ihre Nachricht nicht entschlüsseln"
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr "Keine PGP-Signatur in Nachricht gefunden"
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2345,7 +2397,7 @@
 "\n"
 "Mails an Roundup müssen eine Subject-Zeile haben (Betreff)!\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2374,7 +2426,7 @@
 "\n"
 "Der Betreff war: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2390,7 +2442,7 @@
 "Gültige Klassen sind: %(validname)s\n"
 "Die Betreffzeile war: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2420,7 +2472,7 @@
 "Die Betreffzeile (Subject) war:\n"
 "   '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2439,7 +2491,7 @@
 "Die Betreffzeile (Subject) war:\n"
 "   '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2455,7 +2507,7 @@
 "Die Betreffzeile (Subject) war:\n"
 "   '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2468,21 +2520,21 @@
 "\n"
 "Unbekannte Adresse: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Sie haben keinen Zugriff auf diesen Tracker."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Sie sind nicht berechtigt, die Klasse \"%(classname)s\" zu bearbeiten"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Sie sind nicht berechtigt, ein \"%(classname)s\" zu erzeugen"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2497,7 +2549,7 @@
 "\n"
 "Die Betreffzeile war: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 #, fuzzy
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
@@ -2505,7 +2557,7 @@
 "Dieser Tracker wurde konfiguriert, E-Mail-Nachrichten nur PGP-signiert oder\n"
 "verschlüsselt entgegenzunehmen."
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
@@ -2515,16 +2567,16 @@
 "Dieser Tracker wurde konfiguriert, E-Mail-Nachrichten nur PGP-signiert oder\n"
 "verschlüsselt entgegenzunehmen."
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Sie sind nicht berechtigt, Dateien zu erzeugen."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "Sie sind nicht berechtigt, Dateien zu %(classname)s hinzuzufügen."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2535,11 +2587,11 @@
 "konnte\n"
 "keinen entsprechenden Teil (\"text/plain\") finden.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Sie sind nicht berechtigt, Nachrichten zu erzeugen"
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2550,12 +2602,12 @@
 "Die Mail-Nachricht wurde von einem Detektor zurückgewiesen.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Sie sind nicht berechtigt, Kommentare zu %(classname)s hinzuzufügen."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
@@ -2563,7 +2615,7 @@
 "%(classname)s\n"
 "zu bearbeiten."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
@@ -2571,7 +2623,7 @@
 "%(classname)s\n"
 "zu bearbeiten."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2582,7 +2634,7 @@
 "Es gab ein Problem mit Ihrer Nachricht:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2595,7 +2647,7 @@
 "Sie sich an %(mailadmin)s und bitten Sie um Korrektur der\n"
 "fehlerhaften Klasse:  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2608,22 +2660,39 @@
 "Sie sich an %(mailadmin)s und bitten Sie um Korrektur der\n"
 "fehlerhaften Eigenschaften:  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "entspricht nicht der Form [arg=wert,wert,...;arg=wert,wert,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Ungültiger Benutzername"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2921,7 +2990,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr "WARNUNG: erzeuge temporäres SSL-Zertifikat"
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2929,56 +2998,56 @@
 "<html><head><title>Roundup Tracker-Liste</title></head>\n"
 "<body><h1>Roundup Tracker-Liste</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 "WARNUNG: die Option \"-g\" wird ignoriert, da Sie nicht Administrator sind"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Die Gruppe kann nicht gewechselt werden - das Modul grp fehlt"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "Die Gruppe %(group)s existiert nicht"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr ""
 "Dieser Prozess kann nicht unter dem Administrator-Konto (\"root\") laufen!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 "WARNUNG: die Option \"-u\" wird ignoriert, da Sie nicht Administrator sind"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "Der Benutzer kann nicht gewechselt werden - das Modul pwd fehlt"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "Der Benutzer %(user)s existiert nicht"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 "Der Multiprozessmodus \"%s\" ist nicht verfügbar, Einprozessmodus aktiviert"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Start des Servers auf Port %s schlug fehl. Port bereits verwendet."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2994,7 +3063,7 @@
 "               Zudem müssen Sie die Logfile-Option aktivieren.\n"
 "               \"roundup-server -c help\" zeigt eine weitere Hilfe zum Thema."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -3008,9 +3077,10 @@
 "               die Prozess-ID in die Datei PIDDatei.\n"
 "               Die Option -l muss dann auch angegeben werden."
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -3033,6 +3103,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3124,21 +3197,21 @@
 "   URLs Probleme bereiten könnten. Am besten verwenden Sie nur Buchstaben, \n"
 "   Zahlen und \"-_\".\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "Instanzen müssen als Tracker-Name=Tracker-Verzeichnis angegeben werden"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Konfiguration in der Datei %s gespeichert"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Auf diesem Betriebssystem kann der Server nicht als Hintergrundprozess laufen"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Der Roundup-Server wurde unter %(HOST)s:%(PORT)s gestartet"
@@ -3277,6 +3350,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3293,6 +3367,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3309,6 +3384,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4141,6 +4217,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4687,7 +4764,7 @@
 msgid "User listing"
 msgstr "Benutzerliste"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4695,13 +4772,13 @@
 msgid "Username"
 msgstr "Benutzername"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Name"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4710,26 +4787,26 @@
 msgid "Organisation"
 msgstr "Organisation"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "E-Mail-Adresse"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Telefonnummer"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Entfernen"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4885,67 +4962,67 @@
 
 # priority translations:
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "Fehler (KRITISCH)"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "Fehler (dringend)"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "Fehler"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "Anforderung"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "Wunsch"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "ungelesen"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "zurückgestellt"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "in Diskussion"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "Beispiel erbeten"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "in Arbeit"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "im Test"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "erledigt (provisorisch)"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "erledigt"
 
--- a/locale/en.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/en.po	Thu Apr 21 16:54:17 2022 -0400
@@ -11,7 +11,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 0.7.0\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2004-11-20 13:47+0200\n"
 "Language-Team: English\n"
 "Language: \n"
@@ -28,25 +28,25 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr ""
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr ""
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -74,17 +74,17 @@
 " roundup-admin help all                   -- all available help\n"
 msgstr ""
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 msgid "Commands: "
 msgstr ""
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
 msgstr ""
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -151,12 +151,12 @@
 "Command help:\n"
 msgstr ""
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr ""
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -168,20 +168,20 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr ""
 
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr ""
 
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr ""
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -207,23 +207,23 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -231,20 +231,20 @@
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 msgid "Select template"
 msgstr ""
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 msgid "Select backend"
 msgstr ""
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr ""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -253,11 +253,11 @@
 "   %(config_file)s"
 msgstr ""
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr ""
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -274,7 +274,7 @@
 "---------------------------------------------------------------------------\n"
 msgstr ""
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -282,7 +282,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -292,7 +292,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -303,30 +303,30 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr ""
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr ""
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr ""
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 msgid ""
 "Usage: get property designator[,designator]*\n"
 "        Get the given property of one or more designator(s).\n"
@@ -339,23 +339,23 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr ""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 msgid ""
 "Usage: set items property=value property=value ...\n"
 "        Set the given properties of one or more items(s).\n"
@@ -376,7 +376,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 msgid ""
 "Usage: filter classname propname=value ...\n"
 "        Find the nodes of the given class with a given property value.\n"
@@ -389,19 +389,19 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr ""
 
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -412,7 +412,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -421,17 +421,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr ""
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr ""
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 msgid ""
 "Usage: display designator[,designator]*\n"
 "\n"
@@ -445,12 +445,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -462,31 +462,31 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr ""
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr ""
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr ""
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr ""
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -502,16 +502,16 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -543,17 +543,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr ""
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -568,7 +568,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -582,7 +582,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -594,7 +594,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 msgid ""
 "Usage: retire designator[,designator]*\n"
 "        Retire the node specified by designator.\n"
@@ -607,7 +607,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 msgid ""
 "Usage: restore designator[,designator]*\n"
 "        Restore the retired node specified by designator.\n"
@@ -619,12 +619,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr ""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -640,7 +640,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -657,7 +657,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -680,7 +680,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -688,7 +688,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -710,11 +710,11 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr ""
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -724,12 +724,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 msgid ""
 "Usage: security [Role name]\n"
 "\n"
@@ -737,46 +737,46 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -784,17 +784,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -818,82 +818,82 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr ""
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr ""
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr ""
 
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
 "Type \"help\" for help."
 msgstr ""
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr ""
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr ""
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -907,53 +907,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr ""
 
@@ -1182,22 +1204,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr ""
@@ -1281,160 +1308,167 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr ""
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, python-format
-msgid "Invalid Origin %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
+#, python-format
+msgid "Invalid Origin %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1500,18 +1534,18 @@
 msgstr ""
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr ""
 
@@ -1537,79 +1571,85 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr ""
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr ""
-
 #: ../roundup/cgi/templating.py:1379
-msgid "<th>User</th>"
-msgstr ""
-
-#: ../roundup/cgi/templating.py:1380
-msgid "<th>Action</th>"
+msgid "History"
 msgstr ""
 
 #: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1382
+msgid "<th>User</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1383
+msgid "<th>Action</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr ""
@@ -1627,10 +1667,21 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 msgid "Valid languages: "
 msgstr ""
 
+#: ../roundup/configuration.py:504
+msgid "Expected languages: "
+msgstr ""
+
 #: ../roundup/date.py:395
 #, python-format
 msgid ""
@@ -1789,23 +1840,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -1817,49 +1868,49 @@
 "\tcontains old-style template - ignored"
 msgstr ""
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 msgid "Unsigned Message"
 msgstr ""
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -1876,7 +1927,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -1887,7 +1938,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -1904,7 +1955,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -1915,7 +1966,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -1925,7 +1976,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -1934,21 +1985,21 @@
 "Unknown address: %(from_address)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr ""
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -1958,38 +2009,38 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr ""
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
 "not find a text/plain part to use.\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr ""
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -1997,22 +2048,22 @@
 "%(error)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2020,7 +2071,7 @@
 "   %(message)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, python-format
 msgid ""
 "\n"
@@ -2029,7 +2080,7 @@
 "  %(clsname)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2038,22 +2089,39 @@
 "  %(errors)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, python-format
+msgid "Invalid attribute %s"
+msgstr ""
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2273,58 +2341,58 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2334,7 +2402,7 @@
 "               specifics."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2343,9 +2411,10 @@
 "               specified if -d is used."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2368,6 +2437,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2406,20 +2478,20 @@
 "   any url-unsafe characters like spaces, as these confuse IE.\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr ""
@@ -2551,6 +2623,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -2567,6 +2640,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -2583,6 +2657,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3398,6 +3473,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -3931,7 +4007,7 @@
 msgid "User listing"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -3939,13 +4015,13 @@
 msgid "Username"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -3954,26 +4030,26 @@
 msgid "Organisation"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4122,67 +4198,67 @@
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr ""
 
--- a/locale/es.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/es.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.3.3\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 10:45+0100\n"
 "Last-Translator: Ramiro Morales <rm0@gmx.net>\n"
 "Language-Team: Spanish Translators <roundup-devel@lists.sourceforge.net>\n"
@@ -29,19 +29,19 @@
 msgstr "Ni el usuario admin ni el usuario anónimo pueden ser retirados"
 
 # ../roundup/admin.py:85 :955 :1004 :1026
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "la clase \"%(classname)s\" no existe"
 
 # ../roundup/admin.py:95 :99
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "el argumento \"%(arg)s\" no es de la forma nombrepropiedad=valor"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -50,7 +50,7 @@
 "Problema: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -106,12 +106,12 @@
 " roundup-admin help <comando>             -- ayuda específica a un comando\n"
 " roundup-admin help all                   -- toda la ayuda disponible\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Comandos:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -119,7 +119,7 @@
 "Los comandos pueden ser abreviados siempre y cuando la abreviación\n"
 "coincida con sólo un comando, ej. l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -264,12 +264,12 @@
 "\n"
 "Ayuda sobre comandos:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -289,22 +289,22 @@
 "        all       -- toda la ayuda disponible\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Lo siento, no hay ayuda para \"%(topic)s\""
 
 # ../roundup/admin.py:338 :387
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Plantillas:"
 
 # ../roundup/admin.py:341 :398
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Motor de almacenamiento"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -362,25 +362,25 @@
 
 # ../roundup/admin.py:360 :442 :503 :582 :632 :688 :709 :737 :808 :875 :946
 # :994 :1016 :1043 :1106 :1173
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "No se proveyó una cantidad suficiente de argumentos"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr ""
 "El directorio padre \"%(parent)s\" del directorio base de la instancia no "
 "existe"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -391,22 +391,22 @@
 "Si Ud. lo reinstala, perderá toda la información relacionada al mismo!\n"
 "Elimino la misma? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Seleccione la plantilla [classic]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Selecccione el motor de almacenamiento [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Error en opciones de configuración: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -419,11 +419,11 @@
 " Ud. debe ahora editar el fichero de configuración del tracker:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... como mínimo, debe configurar las siguientes opciones:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -451,7 +451,7 @@
 " completado los pasos arriba descriptos.\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -465,7 +465,7 @@
 "        con valores por defecto en el fichero <fichero>.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -481,7 +481,7 @@
 "        "
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -500,23 +500,23 @@
 "        Ejecuta la función de inicialización dbinit.init() del tracker\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Contraseña de administración: "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Confirmar: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "El directorio base de la instancia no existe"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "La instancia no ha sido instalada"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -526,7 +526,7 @@
 "Si la reinicializa, perderá toda la información!\n"
 "Eliminar la misma? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -547,7 +547,7 @@
 "        "
 
 # ../roundup/admin.py:536 :551
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
@@ -555,18 +555,18 @@
 "no puede usarse."
 
 # ../roundup/admin.py:559 :957 :1006 :1028
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "no existe nodo de clase %(classname)s llamado  \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "no existe propiedad de clase %(classname)s llamado  \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -601,7 +601,7 @@
 "        asociados como números separados por comas (\"1,2,3\").\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -626,20 +626,20 @@
 "        "
 
 # ../roundup/admin.py:675 :828 :840 :894
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s no posee la propiedad \"%(propname)s\""
 
 # ../roundup/admin.py:675 :828 :840 :894
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s no posee la propiedad \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -660,7 +660,7 @@
 "        enlazado o su valor clave.\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -674,17 +674,17 @@
 "        Visualiza las propiedades para una cierta clase.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (propiedad de clave)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -705,12 +705,12 @@
 "especificado.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -729,31 +729,31 @@
 "        nombre=valor provistos en la línea de comandos luego del comando\n"
 "        \"create\" para establecer valores de propiedad(es).        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (Contraseña): "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Nuevamente): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Lo lamento, intente nuevamente..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "debe proveer la propiedad \"%(propname)s\"."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -783,16 +783,16 @@
 "clase.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "Demasiados argumentos"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -856,17 +856,17 @@
 "        caracteres.\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" no es de la forma nombre:longitud"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -881,7 +881,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -906,7 +906,7 @@
 "        son automáticamente escritos si resultan exitosos.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -928,7 +928,7 @@
 "        no introduciría cambios en la base de datos.\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -949,7 +949,7 @@
 "        reusado.\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -969,13 +969,13 @@
 "        "
 
 # ../roundup/admin.py:559 :957 :1006 :1028
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "no existe nodo de clase %(classname)s llamado  \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -1003,7 +1003,7 @@
 "        directorio de destino especificado (dir_exportación).\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -1032,7 +1032,7 @@
 "        directorio de destino especificado.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1077,7 +1077,7 @@
 "        tediosamente, retirar toda los datos viejos.)\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1085,7 +1085,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1124,11 +1124,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Formato inválido"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1144,12 +1144,12 @@
 "        Es un comando que por lo general se ejecuta automáticamente.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "no existe un ítem llamado \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1161,49 +1161,49 @@
 "        Muestra los permisos disponibles para uno o todos los Roles.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "No existe un Rol llamado \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Los nuevos usuarios creados vía Web obtiene los Roles \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Los nuevos usuarios creados vía Web obtienen el Rol \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr ""
 "Los nuevos usuarios creados vía e-mail obtienen los Roles  \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Los nuevos usuarios creados vía e-mail obtienen el Rol \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "Rol \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s para \"%(klass)s\" solamente)"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 " %(description)s (%(name)s para \"%(klass)s\": %(properties)s solamente)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1211,17 +1211,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s para \"%(klass)s\" solamente)"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1245,45 +1245,45 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "Directorio base del tracker"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 "Comando desconocido \"%(command)s\" (tipee \"help commands\" para obtener "
 "una lista)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "Coinciden mas de un comando \"%(command)s\": %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Ingrese directorio base del tracker: "
 
 # ../roundup/admin.py:1296 :1302 :1322
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Error: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Error: No se pudo abrir el tracker: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1292,41 +1292,41 @@
 "Roundup %s listo para comandos.\n"
 "Tipee \"help\" para ayuda."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Nota: historia y edición de comandos no disponible"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "salir..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Hay cambios sin guardar. Debo guardar los mismos (y/N)? "
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1340,53 +1340,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "crea"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "desenlaza"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "enlaza"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "asigna"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "retira"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "restaura"
 
@@ -1629,23 +1651,28 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
 # ../roundup/cgi/actions.py:891 :895
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "nombre de usuario ó contraseña inválidos"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Ud. no tiene permiso para ingresar al sistema"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Ud. no posee los permisos necesarios para editar %(class)s"
@@ -1750,155 +1777,155 @@
 "p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Error de formulario"
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Conjunto de caracteres desconocido: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "Los usuarios anonimos no tienen permitido usar esta interfaz Web"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
+#: ../roundup/cgi/client.py:1289
 #, python-format
 msgid "Missing header: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
 #, python-format
 msgid "csrf Referer header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1258
+#: ../roundup/cgi/client.py:1300
 #, python-format
 msgid "Invalid Referer %s, %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
 msgid "csrf Origin header check failed for user%s. Value=%s"
 msgstr ""
 
 # ../roundup/cgi/actions.py:891 :895
-#: ../roundup/cgi/client.py:1274
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
 msgid "Invalid Origin %s"
 msgstr "nombre de usuario ó contraseña inválidos"
 
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
 #, python-format
 msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1289
-#, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
-#, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
-#, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Ud. no tiene permitido ver este fichero"
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sTiempo transcurrido: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1907,6 +1934,13 @@
 "%(starttag)sAciertos Cache: %(cache_hits)d, no aciertos %(cache_misses)d. "
 "Cargando items: %(get_items)f secs. Filtrado: %(filtering)f secs.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1986,18 +2020,18 @@
 # ../roundup/cgi/templating.py:673 :792 :1166 :1187 :1231 :1253 :1287 :1326
 # :1377 :1394 :1470 :1490 :1503 :1520 :1530 :1580 :1755
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[oculto]"
 
@@ -2023,18 +2057,24 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "La clase relacionada %(classname)s ya no existe"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:903 :924
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>El nodo relacionado ya no existe</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (sin valor)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -2043,46 +2083,46 @@
 "<strong><em>Este evento no es soportado por la visualización de historia!</"
 "em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Nota:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Historia"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Fecha</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Historia"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Fecha</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Usuario</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Acción</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Args</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "Copia de %(class)s %(id)s"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "No"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Si"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2090,17 +2130,17 @@
 "el valor por defecto para DateHTMLProperty debe ser un DateHTMLProperty o "
 "una cadena que represente una fecha."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "Se intentó buscar %(attr)s en un valor faltante"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "Se intentó buscar %(attr)s en un valor faltante"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- sin selección -</option>"
@@ -2118,11 +2158,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Formato inválido"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Formato inválido"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2289,23 +2341,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2319,44 +2371,44 @@
 "ATENCIÓN: El directorio '%s'\n"
 "\tcontiene una plantilla con el viejo formato - se ignorará"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Nuevo mensaje"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2364,7 +2416,7 @@
 "\n"
 "Todos los e-mails enviados a trackers Roundup deben incluir un Asunto:!\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2394,7 +2446,7 @@
 "\n"
 "El asunto que Ud. envió es: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2411,7 +2463,7 @@
 "Nombres válidos de clases son: %(validname)s\n"
 "El asunto que Ud. envió es: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2441,7 +2493,7 @@
 "\n"
 "El asunto que Ud. envió es: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2459,7 +2511,7 @@
 "\n"
 "El asunto que Ud. envió es: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2474,7 +2526,7 @@
 "\n"
 "El asunto que Ud. envió es: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2487,21 +2539,21 @@
 "\n"
 "Dirección desconocida: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Ud. no posee los permisos necesarios para acceder a este tracker."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Ud. no tiene permitido editar %(classname)s."
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Ud. no tiene permitido crear %(classname)s."
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2517,27 +2569,27 @@
 "\n"
 "El Asunto que Ud. envió es: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Ud. no tiene permitida la creación de ficheros."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "Ud. no tiene permitido agregar ficheros a %(classname)s."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2549,11 +2601,11 @@
 "podido localizar una parte MIME text/plain en su mensaje que pueda ser "
 "usada.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Ud. no tiene permitido crear mensajes."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2564,26 +2616,26 @@
 "El mensaje de e-mail ha sido rechazado por un detector.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Ud. no tiene permitido agregar mensajes a %(classname)s."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 "Ud. no tiene permitido editar la propiedad %(prop)s de la clase "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 "Ud. no tiene permitido editar la propiedad %(prop)s de la clase "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2594,7 +2646,7 @@
 "Ha habido un problema con el mensaje que envíó:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2608,7 +2660,7 @@
 "incorrecta:\n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2622,22 +2674,40 @@
 "incorrectas:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "no es de la forma [arg=valor,valor,...;arg=valor,valor,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+# ../roundup/cgi/actions.py:891 :895
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "nombre de usuario ó contraseña inválidos"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2935,7 +3005,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr "ATENCION: generando certificado SLL temporario"
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2943,53 +3013,53 @@
 "<html><head><title>Índice de trackers Roundup</title></head>\n"
 "<body><h1>Índice de trackers Roundup</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "ATENCIÓN: ignorando argumento \"-g\" , Ud. no es root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "No puede cambiar grupos - el módulo grp no está presente"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "El grupo %(group)s no existe"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "No puede ejecutarse como root!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "ATENCIÓN: ignorando argumento \"-u\", Ud. no es root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "No puedo cambiar usuarios - no existe el módulo pwd"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "El usuario %(user)s no existe"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 "El modo multiproceso \"%s\" no está disponible, conmutado a proceso simple"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Imposible asociarse al puerto %s, el mismo ya está en uso."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -3011,7 +3081,7 @@
 "para\n"
 "               Servicios Web."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -3026,9 +3096,10 @@
 "               PID del servidor en el fichero especificado por PIDfile.\n"
 "               La opción -l *debe* ser especificada si se usa la opción -d."
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -3051,6 +3122,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3155,22 +3229,22 @@
 "   caracteres tales como espacios, dado que los mismos confunden a Internet "
 "Explorer.\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "Las Instancias debe ser de la forma nombre=directorio base"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Configuración guardada en %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Lo siento, no puede ejecutar el servidor como un demonio en este Sistema "
 "Operativo"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "servidor Roundup iniciado en %(HOST)s:%(PORT)s"
@@ -3308,6 +3382,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3324,6 +3399,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3340,6 +3416,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4170,6 +4247,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4720,7 +4798,7 @@
 msgid "User listing"
 msgstr "Listado de usuarios"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4728,13 +4806,13 @@
 msgid "Username"
 msgstr "Nombre de usuario"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Nombre real"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4743,26 +4821,26 @@
 msgid "Organisation"
 msgstr "Organización"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "Dirección de e-mail"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Nro. telefónico"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Retirar"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4916,67 +4994,67 @@
 
 # priority translations:
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "critical"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "urgent"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "bug"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "feature"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "wish"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "unread"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "deferred"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "chatting"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "need-eg"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "in-progress"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "testing"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "done-cbb"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "resuelto"
 
--- a/locale/fr.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/fr.po	Thu Apr 21 16:54:17 2022 -0400
@@ -10,7 +10,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.4.6\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:19+0100\n"
 "Last-Translator: Stephane Raimbault <stephane.raimbault@gmail.com>\n"
 "Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
@@ -33,20 +33,20 @@
 
 # ../roundup/admin.py:85 :979 :1028 :1050
 # ../roundup/admin.py:1052 ../roundup/admin.py:85:981 :1030:1052
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "aucune classe nommée « %(classname)s »"
 
 # ../roundup/admin.py:95 :99
 # ../roundup/admin.py:95 ../roundup/admin.py:99 ../roundup/admin.py:95:99
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "l'argument « %(arg)s » n'est pas au format nom-de-propriété=valeur"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -55,7 +55,7 @@
 "Problème : %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -111,12 +111,12 @@
 " roundup-admin help <commande>            -- l'aide sur une commande\n"
 " roundup-admin help all                   -- toute l'aide disponible\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Commandes :"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -125,7 +125,7 @@
 "où l'abréviation ne correspond qu'à une seule commande,\n"
 "par ex. : l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -263,12 +263,12 @@
 "\n"
 "Aide sur les commandes :\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s :"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -288,24 +288,24 @@
 "        all        -- toute l'aide disponible\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Désolé, aucune aide n'est disponible au sujet de « %(topic)s »"
 
 # ../roundup/admin.py:338 :394
 # ../roundup/admin.py:340 ../roundup/admin.py:396 ../roundup/admin.py:340:396
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Modèles :"
 
 # ../roundup/admin.py:341 :405
 # ../roundup/admin.py:343 ../roundup/admin.py:407 ../roundup/admin.py:343:407
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Moteurs de stockage :"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 #, fuzzy
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
@@ -364,23 +364,23 @@
 # :1018 :1040 :1067 :1134 :1204
 # ../roundup/admin.py:1207 ../roundup/admin.py:369:466 :1020:1042 :1069:1136
 # :1207 :527:606 :656:714 :735:763 :834:901:972
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "Pas suffisamment d'arguments fournis"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "Le répertoire parent « %(parent)s » de l'instance de base n'existe pas"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -392,22 +392,22 @@
 "Si vous le réinstallez, vous perdrez toutes les données !\n"
 "Supprimer le pisteur (Y/N) ? "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Sélection du modèle [classic] : "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Sélection du moteur de stockage [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Erreur dans les paramètres de la configuration : « %s »"
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -420,11 +420,11 @@
 " Vous devez maintenant modifier le fichier de configuration du pisteur :\n"
 "    %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ou au minimum, vous devez définir les options suivantes :"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -456,7 +456,7 @@
 " que vous avez réalisé les étapes précédentes.\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -469,7 +469,7 @@
 "              (au format ini) avec des valeurs par défaut dans\n"
 "              <nomfichier>"
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -484,7 +484,7 @@
 "              <nomfichier>"
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -503,23 +503,23 @@
 "        Exécute la fonction d'initialisation dbinit.init() du pisteur.\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Mot de passe administrateur : "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Confirmez : "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "Le répertoire racine de l'instance n'existe pas"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "L'instance n'a pas été installée"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -529,7 +529,7 @@
 "Si vous la réinitialisez, vous perdrez toutes les données !\n"
 "Supprimez la base de données (Y/N) ? "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -551,7 +551,7 @@
 
 # ../roundup/admin.py:558 :573
 # ../roundup/admin.py:560 ../roundup/admin.py:575 ../roundup/admin.py:560:575
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
@@ -560,19 +560,19 @@
 
 # ../roundup/admin.py:581 :981 :1030 :1052
 # ../roundup/admin.py:1054 ../roundup/admin.py:583:983 :1032:1054
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "le noeud « %(nodeid)s » de classe « %(classname)s » n'existe pas"
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 "la propriété « %(propname)s » n'existe pas pour la classe « %(classname)s »"
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -607,7 +607,7 @@
 "        ce lien sont indiqués comme des nombres séparés par des\n"
 "        virgules (par ex. « 1,2,3 »)."
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -631,21 +631,21 @@
 
 # ../roundup/admin.py:699 :852 :864 :918
 # ../roundup/admin.py:920 ../roundup/admin.py:701:854 :866:920
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s n'a pas de propriété « %(propname)s »"
 
 # ../roundup/admin.py:699 :852 :864 :918
 # ../roundup/admin.py:920 ../roundup/admin.py:701:854 :866:920
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s n'a pas de propriété « %(propname)s »"
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -664,7 +664,7 @@
 "        noeud lié, ou sa valeur de clé.\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -678,17 +678,17 @@
 "        Cette commande énumère les propriétés de la classe nommée.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s : %(value)s (propriété clé)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s : %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -709,12 +709,12 @@
 "        des noeuds indiqués.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s : %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -734,31 +734,31 @@
 "        « create ».\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (mot de passe) : "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (à nouveau) : "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Désolé, essayez à nouveau..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s) : "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "vous devez renseigner la propriété « %(propname)s »."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -788,16 +788,16 @@
 "        propriété pour chaque instance de cette classe.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "Trop d'arguments fournis"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s : %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -859,17 +859,17 @@
 "        donnera une colonne « Name » large de 4 caractères.\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "« %(spec)s » ne correspond pas au format « nom:largeur »"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -884,7 +884,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -909,7 +909,7 @@
 "        automatiquement validées si elles réussissent.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -932,7 +932,7 @@
 "        base de données.\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -953,7 +953,7 @@
 "        valeur de clé peut être ré-utilisée.\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -975,13 +975,13 @@
 
 # ../roundup/admin.py:581 :981 :1030 :1052
 # ../roundup/admin.py:1054 ../roundup/admin.py:583:983 :1032:1054
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "le noeud « %(nodeid)s » de classe « %(classname)s » n'existe pas"
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 #, fuzzy
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
@@ -1008,7 +1008,7 @@
 "        format aux valeurs séparées par des doubles-points.\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 #, fuzzy
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
@@ -1036,7 +1036,7 @@
 "        format aux valeurs séparées par des doubles-points.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1081,7 +1081,7 @@
 "        plus péniblement, « abandonnez » toutes les anciennes données).\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1089,7 +1089,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1131,11 +1131,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Format non valide"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1151,12 +1151,12 @@
 "        Cette opération est normalement effectuer automatiquement.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "pas d'élément « %(designator)s »"
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1168,48 +1168,48 @@
 "        Affiche les permissions disponible pour un ou plusieurs rôles.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "Ce rôle « %(role)s » n'existe pas"
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Les nouveaux utilisateurs Web ont les rôles « %(role)s »"
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Les nouveaux utilisateurs Web ont le rôle « %(role)s »"
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "Les nouveaux utilisateurs Courriel ont les rôles « %(role)s »"
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Les nouveaux utilisateurs Courriel ont le rôle « %(role)s »"
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "Rôle « %(name)s » :"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s pour « %(klass)s » uniquement)"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 " %(description)s (%(name)s pour « %(klass)s » : %(properties)s uniquement)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1217,17 +1217,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s pour « %(klass)s » uniquement)"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1251,44 +1251,44 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "Accueil de Tracker"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr "Commande inconnue « %(command)s » (« help commands » pour la liste)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "Plusieurs commandes correspondent à « %(command)s » : %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Saisissez le répertoire racine du pisteur : "
 
 # ../roundup/admin.py:1332 :1338 :1358
 # ../roundup/admin.py:1335:1341:1361
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Erreur : %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Erreur : impossible d'ouvrir le pisteur, %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1297,41 +1297,41 @@
 "Roundup %s est prêt pour la saisie.\n"
 "Saisissez « help » pour l'aide."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Note : l'historique et l'édition des commandes n'est pas disponible"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "sortie..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Des changements n'ont pas été enregistrés, les valider (y/N) ?"
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1345,53 +1345,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "créer"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "détacher"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "attacher"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "assigner"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "retiré"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "restauré"
 
@@ -1640,24 +1662,29 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
 # ../roundup/cgi/actions.py:930 :934
 # ../roundup/cgi/actions.py:930:934
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Tentative de connexion non valide"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Vous n'avez la permission de vous connecter"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Vous n'avez pas la permission de modifier %(class)s"
@@ -1763,157 +1790,157 @@
 "Les administrateurs du pisteur ont été notifiés du problème.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Erreur de formulaire : "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Jeu de caractères non reconnu : %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr ""
 "Les utilisateurs anonymes ne sont pas autorisés à utiliser l'interface Web"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
+#: ../roundup/cgi/client.py:1289
 #, python-format
 msgid "Missing header: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
 #, python-format
 msgid "csrf Referer header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1258
+#: ../roundup/cgi/client.py:1300
 #, python-format
 msgid "Invalid Referer %s, %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
 msgid "csrf Origin header check failed for user%s. Value=%s"
 msgstr ""
 
 # ../roundup/cgi/actions.py:930 :934
 # ../roundup/cgi/actions.py:930:934
-#: ../roundup/cgi/client.py:1274
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
 msgid "Invalid Origin %s"
 msgstr "Tentative de connexion non valide"
 
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
 #, python-format
 msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1289
-#, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
-#, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
-#, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Vous n'êtes pas autorisé à voir ce fichier"
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sTemps écoulé: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1923,6 +1950,13 @@
 "Chargement d'éléments : %(get_items)f secondes. Filtrage : %(filtering)f "
 "secondes.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, fuzzy, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -2004,18 +2038,18 @@
 # :1236:1257 :1304:1327 :1361:1400 :1453:1470 :1549:1569 :1587:1619
 # :1629:1683 :1875
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[masqué]"
 
@@ -2041,19 +2075,25 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "La classe liée %(classname)s n'existe plus"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:940 :964
 # ../roundup/cgi/templating.py:940:964
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>Le noeud lié n'existe plus</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s : (pas de valeur)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -2062,31 +2102,31 @@
 "<strong><em>Cet évènement n'est pas géré par l'affichage de l'historique.</"
 "em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Note :</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Historique"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Date</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Historique"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Date</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Utilisateur</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Action</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Arguments</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "Copie de %(class)s %(id)s"
@@ -2094,20 +2134,20 @@
 # ../roundup/cgi/templating.py:1006 :1404 :1425 :1431
 # ../roundup/cgi/templating.py:1431 ../roundup/cgi/templating.py:1006:1404
 # :1425:1431
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "Non"
 
 # ../roundup/cgi/templating.py:1006 :1404 :1423 :1428
 # ../roundup/cgi/templating.py:1428 ../roundup/cgi/templating.py:1006:1404
 # :1423:1428
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Oui"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2115,17 +2155,17 @@
 "la valeur par défaut pour DateHTMLProperty doit être soit DateHTMLProperty "
 "soit une représentation textuelle de la date."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "Tentative de recherche de %(attr)s sur une valeur manquante"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "Tentative de recherche de %(attr)s sur une valeur manquante"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- pas de sélection -</option>"
@@ -2143,11 +2183,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Format non valide"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Format non valide"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2314,23 +2366,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2344,44 +2396,44 @@
 "ATTENTION : le répertoire '%s'\n"
 "\tcontient des modèles obsolètes - ignoré"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Nouveau message"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2390,7 +2442,7 @@
 "Les courriels envoyés au gestionnaire de ticket doivent comporter un "
 "sujet !\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2420,7 +2472,7 @@
 "\n"
 "Sujet original : '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2437,7 +2489,7 @@
 "Les noms de classes valides sont : %(validname)s\n"
 "Sujet original : « %(subject)s »\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2467,7 +2519,7 @@
 "\n"
 "Sujet original : '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2485,7 +2537,7 @@
 "\n"
 "Sujet original : « %(subject)s »\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2500,7 +2552,7 @@
 "\n"
 "Sujet original : « %(subject)s »\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2513,21 +2565,21 @@
 "\n"
 "Addresse inconnue : %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Vous n'êtes pas autorisé à accéder à ce pisteur."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Vous n'avez pas la permission de modifier %(classname)s"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Vous n'avez pas la permission de créer  %(classname)s"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2542,29 +2594,29 @@
 "\n"
 "Le sujet était « %(subject)s »\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Vous n'êtes pas autorisé à créer des fichiers."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr ""
 "Vous n'avez pas la permission d'ajouter des fichiers à la classe "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2575,11 +2627,11 @@
 "trouvé\n"
 "de partie text/plain à utiliser.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Vous n'avez pas la permission de créer des messages."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2590,26 +2642,26 @@
 "Le message a été rejeté par un détecteur.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Vous n'avez pas la permission d'ajouter des messages à %(classname)s."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 "Vous n'avez pas la permission de modifier la propriété %(prop)s de la classe "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 "Vous n'avez pas la permission de modifier la propriété %(prop)s de la classe "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2620,7 +2672,7 @@
 "Un problème a eu lieu à l'envoi de votre message :\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2634,7 +2686,7 @@
 "indiquée comme : \n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2648,22 +2700,41 @@
 "corrigés :\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "pas de la forme [arg=value,value,...;arg=value,value,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+# ../roundup/cgi/actions.py:930 :934
+# ../roundup/cgi/actions.py:930:934
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Tentative de connexion non valide"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2960,7 +3031,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2968,58 +3039,58 @@
 "<html><head><title>Index des pisteurs Roundup</title></head>\n"
 "<body><h1>Index des pisteurs Roundup</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s : %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 "ATTENTION : le paramètre « -g » est ignoré, vous n'êtes pas superutilisateur "
 "(« root »)"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Impossible de changer les groupes - le module grp n'est pas présent"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "Le groupe %(group)s n'existe pas"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "Impossible d'exécuter en tant que superutilisateur (\"root\")"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 "ATTENTION: le paramètre \"-u\" est ignoré, vous n'êtes pas superutilisateur "
 "(\"root\")"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr ""
 "Impossible de changer les utilisateurs - le module pwd n'est pas présent"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "L'utilisateur %(user)s n'existe pas"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 "Le mode multiprocessus \"%s\" n'existe pas, passage en mode processus unique"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Impossible de s'attacher au port %s, le port est déjà utilisé"
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -3038,7 +3109,7 @@
 "               La commande « roundup-server -c help » donne les\n"
 "               spécificités du service Windows."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -3057,9 +3128,10 @@
 "PID\n"
 "               L'option -l option *doit* être spécifiée si -d est utilisé."
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -3082,6 +3154,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3174,22 +3249,22 @@
 "    souhaité. Assurez-vous que « name » ne contienne pas de caractères\n"
 "    inappropriés pour une URL, comme les espaces qui perturbe IE.\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "Les instances doivent être nom=base-du-pisteur"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Configuration sauvegardée dans %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Désolé, vous ne pouvez pas démarrer le serveur en tâche de fond avec ce "
 "système d'exploitation"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Le serveur Roundup est démarré sur %(HOST)s:%(PORT)s"
@@ -3326,6 +3401,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3342,6 +3418,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3358,6 +3435,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4193,6 +4271,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4745,7 +4824,7 @@
 msgid "User listing"
 msgstr "Liste des utilisateurs"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4753,13 +4832,13 @@
 msgid "Username"
 msgstr "Nom d'utilisateur"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Nom r&eacute;el"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4768,26 +4847,26 @@
 msgid "Organisation"
 msgstr "Organisation"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "Adresse électronique"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Num&eacute;ro de t&eacute;l&eacute;phone"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Retirer"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4941,68 +5020,68 @@
 "dans le courriel."
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 #, fuzzy
 msgid "testing"
 msgstr "Liste des utilisateurs"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 #, fuzzy
 msgid "resolved"
 msgstr "non r&eacute;solu"
--- a/locale/hu.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/hu.po	Thu Apr 21 16:54:17 2022 -0400
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.3.3\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:19+0100\n"
 "Last-Translator: kilo aka Gabor Kmetyko <kg_kilo@freemail.hu>\n"
 "Language-Team: Hungarian\n"
@@ -30,26 +30,26 @@
 msgstr "Az admin és anonymous felhasználókat nem lehet visszavonultatni"
 
 # ../roundup/admin.py:85 :981 :1030 :1052
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "nincs \"%(classname)s\" osztály"
 
 # ../roundup/admin.py:95 :99
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "A(z) \"%(arg)s\" argumentum nem név=érték alakú"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
 "\n"
 msgstr "Probléma: %(message)s\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -101,12 +101,12 @@
 " roundup-admin help <command>             -- parancs-specifikus segítség\n"
 " roundup-admin help all                   -- minden elérhető segítség\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Parancsok:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -114,7 +114,7 @@
 "A parancsok rövidíthetők mindaddig, amíg csak egy parancsra illenek, pl. l "
 "== li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -181,12 +181,12 @@
 "Command help:\n"
 msgstr ""
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -206,22 +206,22 @@
 "        all       -- minden elérhető segítség\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Elnézést, \"%(topic)s\" témához nincs súgó"
 
 # ../roundup/admin.py:340 :396
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Sablonok:"
 
 # ../roundup/admin.py:343 :407
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Adatbázis hátterek:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -249,23 +249,23 @@
 
 # ../roundup/admin.py:369 :466 :527 :606 :656 :714 :735 :763 :834 :901 :972
 # :1020 :1042 :1069 :1136 :1207
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "Nincs megadva elég argumentum"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "Példány könyvtár szülője (\"%(parent)s\") nem létezik"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -277,22 +277,22 @@
 "Ha újra installálod, minden adat elveszik!\n"
 "Töröljem? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Sablon választása [classic]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Adatbázis háttér választása [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Hiba a konfigurációs beállításokban: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -305,11 +305,11 @@
 " Most kell szerkesztened a konfigurációs fájlt:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... legalább a következő opciókat kell beállítani:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -326,7 +326,7 @@
 "---------------------------------------------------------------------------\n"
 msgstr ""
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -340,7 +340,7 @@
 "        a <fájlnév> fájlba.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -356,7 +356,7 @@
 "        "
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -374,23 +374,23 @@
 "        Végrehajtja az adatbázist inicializáló dbinit.init() rutint\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Adminisztrátori jelszó: "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Megerősítés "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "A példány könyvtára nem létezik"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "A példány nem lett installálva"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -400,7 +400,7 @@
 "Újrainicializálás esetén minden adat elvész!\n"
 "Törli? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -421,7 +421,7 @@
 "        "
 
 # ../roundup/admin.py:560 :575
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
@@ -429,18 +429,18 @@
 "alkalmazható."
 
 # ../roundup/admin.py:583 :983 :1032 :1054
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "nincs \"%(nodeid)s\" %(classname)s csomópont"
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "nincs \"%(propname)s\" %(classname)s tulajdonság"
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 msgid ""
 "Usage: set items property=value property=value ...\n"
 "        Set the given properties of one or more items(s).\n"
@@ -461,7 +461,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 msgid ""
 "Usage: filter classname propname=value ...\n"
 "        Find the nodes of the given class with a given property value.\n"
@@ -475,20 +475,20 @@
 msgstr ""
 
 # ../roundup/admin.py:701 :854 :866 :920
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s-nek nincs \"%(propname)s\" tulajdonsága"
 
 # ../roundup/admin.py:701 :854 :866 :920
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s-nek nincs \"%(propname)s\" tulajdonsága"
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -499,7 +499,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -513,17 +513,17 @@
 "        Listázza az adott osztály tulajdonságait.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (kulcs tulajdonság)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -544,12 +544,12 @@
 "        csomópont értékét.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -561,31 +561,31 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (Jelszó): "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Ismét): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Sajnálom, próbálja újra..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "meg kell adni a(z) \"%(propname)s\" tulajdonságot."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -601,16 +601,16 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "Túl sok argumentum került megadásra"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -642,17 +642,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" nem név:hossz formátumú"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -667,7 +667,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -681,7 +681,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -693,7 +693,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 msgid ""
 "Usage: retire designator[,designator]*\n"
 "        Retire the node specified by designator.\n"
@@ -706,7 +706,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 msgid ""
 "Usage: restore designator[,designator]*\n"
 "        Restore the retired node specified by designator.\n"
@@ -719,13 +719,13 @@
 msgstr ""
 
 # ../roundup/admin.py:583 :983 :1032 :1054
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "nincs \"%(nodeid)s\" %(classname)s csomópont"
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -741,7 +741,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -758,7 +758,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -781,7 +781,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -789,7 +789,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -811,11 +811,11 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Hibás formátum"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -825,12 +825,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "nincs ilyen elem: \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -842,47 +842,47 @@
 "        Megjeleníti a megadott vagy az összes szerepkör jogosultságait.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "Nincs ilyen szerepkör: \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Új web felhasználók ezeket a szerepköröket kapják: \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Új web felhasználók ezt a szerepkört kapják \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "Új e-mail felhasználók ezeket a szerepköröket kapják: \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Új e-mail felhasználók ezt a szerepkört kapják: \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "\"%(name)s\" szerepkör:"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -890,17 +890,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -924,46 +924,46 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "Hibakövető"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 "\"%(command)s\": ismeretlen parancs (\"help commands\" parancsok "
 "listázásához)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr ""
 "Több parancs is illeszkedik a megadott \"%(command)s\" parancsra: %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Adja meg a hibakövető könyvtárát: "
 
 # ../roundup/admin.py:1335 :1341 :1361
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Hiba: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Hiba: Hibakövető megnyitása sikertelen: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -972,41 +972,41 @@
 "A Roundup %s fogadókész.\n"
 "Segítségért gépeljen \"help\"-et."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Megjegyzés: a parancsok története és szerkesztése nem elérhető"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "kilépés..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Vannak nem mentett változtatások. Elmenti őket (y/N)? "
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1024,53 +1024,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "létrehozás"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "törlés"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "kapcsolás"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "beállítás"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "visszavonult"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "visszaállított"
 
@@ -1309,23 +1331,28 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
 # ../roundup/cgi/actions.py:930 :934
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Hibás bejelentkezés"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Nincs jogosultsága bejelentkezni"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Nincs jogosultsága szerkeszteni %(class)s-t"
@@ -1423,155 +1450,155 @@
 "A hibakövető karbantartói értesítést kaptak a problémáról.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Űrlap hiba: "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Ismeretlen karakterkészlet: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "Anonim felhasználók nem használhatják a webes felületet"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
+#: ../roundup/cgi/client.py:1289
 #, python-format
 msgid "Missing header: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
 #, python-format
 msgid "csrf Referer header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1258
+#: ../roundup/cgi/client.py:1300
 #, python-format
 msgid "Invalid Referer %s, %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
 msgid "csrf Origin header check failed for user%s. Value=%s"
 msgstr ""
 
 # ../roundup/cgi/actions.py:930 :934
-#: ../roundup/cgi/client.py:1274
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
 msgid "Invalid Origin %s"
 msgstr "Hibás bejelentkezés"
 
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
 #, python-format
 msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1289
-#, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
-#, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
-#, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Nem nézheti meg ezt a fájlt."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sEltelt idő: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1580,6 +1607,13 @@
 "%(starttag)sCache találatok: %(cache_hits)d, tévedés %(cache_misses)d. "
 "Elemek betöltése: %(get_items)f mp. Szűrés: %(filtering)f mp.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, fuzzy, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1656,18 +1690,18 @@
 # ../roundup/cgi/templating.py:710 :829 :1236 :1257 :1304 :1327 :1361 :1400
 # :1453 :1470 :1549 :1569 :1587 :1619 :1629 :1683 :1875
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[rejtett]"
 
@@ -1693,18 +1727,24 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "A csatolt %(classname)s osztály már nem létezik"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:940 :964
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>A csatolt bejegyzés már nem létezik</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (nincs érték)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -1712,48 +1752,48 @@
 msgstr ""
 "<strong><em>Az előzmények képernyő nem kezeli ezt az eseményt!</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Megjegyzés:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Előzmények"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Dátum</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Előzmények"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Dátum</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Szerző</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Művelet</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Tulajdonságok</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "A(z) %(class)s %(id)s másolata"
 
 # ../roundup/cgi/templating.py:1006 :1404 :1425 :1431
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "Nem"
 
 # ../roundup/cgi/templating.py:1006 :1404 :1423 :1428
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Igen"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -1761,17 +1801,17 @@
 "a DateHTMLProperty alapértéke DateHTMLProperty vagy szöveges dátumleírás "
 "típusú kell legyen."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "Kísérlet %(attr)s keresésére egy hiányzó értéken"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "Kísérlet %(attr)s keresésére egy hiányzó értéken"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- nincs kiválasztás -</option>"
@@ -1789,11 +1829,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Hibás formátum"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Hibás formátum"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -1959,23 +2011,23 @@
 msgstr ""
 
 # ../roundup/hyperdb.py:949:957
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -1990,44 +2042,44 @@
 "\trégi típusú sablont tartalmaz - ignorálva"
 
 # ../roundup/mailgw.py:199:211
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Új üzenet"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2036,7 +2088,7 @@
 "A Roundup hibakövetőkhöz küldött e-maileknek tartalmazniuk kell egy Subject: "
 "sort!\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2053,7 +2105,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2070,7 +2122,7 @@
 "Az érvényes osztálynevek: %(validname)s\n"
 "A tárgy ez volt: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2087,7 +2139,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2105,7 +2157,7 @@
 "\n"
 "A tárgy ez volt: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2120,7 +2172,7 @@
 "\n"
 "A tárgy ez volt: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2133,21 +2185,21 @@
 "\n"
 "Ismeretlen cím: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Ehhez a hibakövetőhöz hozzáférése nem engedélyezett."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Nincs jogosultsága %(classname)s szerkesztéséhez."
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Nincs jogosultsága %(classname)s létrehozásához."
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2162,27 +2214,27 @@
 "\n"
 "A tárgy ez volt: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Nincs jogosultsága fájlok létrehozására."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "Nincs jogosultsága fájlok hozzáadására %(classname)s-hez."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2192,11 +2244,11 @@
 "A Roundup egyszerű szövegként tudja fogadni a kérelmet. Az üzenet értelmező\n"
 "nem talált használható, egyszerű szöveg formátumú részt.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Nincs jogosultsága üzenetek létrehozására."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2207,24 +2259,24 @@
 "A mail üzenetet a felderítő visszutasította.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Nincs jogosultsága üzenet hozzáadására %(classname)s-hez."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 "Nincs jogosultsága %(classname)s osztály %(prop)s tulajdonságát szerkeszteni."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 "Nincs jogosultsága %(classname)s osztály %(prop)s tulajdonságát szerkeszteni."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2235,7 +2287,7 @@
 "Probléma volt az Ön által küldött üzenettel:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2248,7 +2300,7 @@
 "%(mailadmin)s-nal és javíttassa ki a hibásan megadott osztályt:\n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2261,22 +2313,40 @@
 "%(mailadmin)s-nal és javíttassa ki a hibás tulajdonságokat:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "nem [arg=érték,érték,...;arg=érték,érték,...] formátumú"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+# ../roundup/cgi/actions.py:930 :934
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Hibás bejelentkezés"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2500,7 +2570,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2508,52 +2578,52 @@
 "<html><head><title>Roundup hibakövetők listája</title></head>\n"
 "<body><h1>Roundup hibakövetők listája</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "FIGYELEM: \"-g\" opció figyelmen kívül hagyásra került, nem root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Nem lehet csoportot váltani - nincs meg a grp modul"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "%(group)s csoport nem létezik"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "Nem futhat root-ként!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "FIGYELEM: \"-u\" opció figyelmen kívül hagyásra került, nem root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "Felhasználóváltás nem sikerült - nincs pwd modul"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "A(z) %(user)s felhasználó nem létezik"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr "\"%s\" többszálú mód nem érhető el, áttérés egyszálú módra"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Nem sikerült a(z) %s portra csatlakozni, a port már használatban van."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2563,7 +2633,7 @@
 "               specifics."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2572,9 +2642,10 @@
 "               specified if -d is used."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2597,6 +2668,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2635,21 +2709,21 @@
 "   any url-unsafe characters like spaces, as these confuse IE.\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "A példányoknak név=home formában kell lenniük"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Beállítások elmentve ide: %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Elnézést, ezen az operációs rendszeren a szerver nem indítható démonként"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Roundup server elindítva a(z) %(HOST)s:%(PORT)s gépen"
@@ -2785,6 +2859,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -2801,6 +2876,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -2817,6 +2893,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3638,6 +3715,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4184,7 +4262,7 @@
 msgid "User listing"
 msgstr "Felhasználók listája"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4192,13 +4270,13 @@
 msgid "Username"
 msgstr "Felhasználónév"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Valódi név"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4207,26 +4285,26 @@
 msgid "Organisation"
 msgstr "Szervezet"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "E-mail cím"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Telefonszám"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Visszavonulás"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4379,68 +4457,68 @@
 
 # priority translations:
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "kritikus"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "sürgős"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "hiba"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "szolgáltatás"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "óhaj"
 
 # status translations:
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "nem olvasott"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "elutasítva"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "megbeszélés"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "megerősítésre vár"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "folyamatban"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "tesztelés"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "elkészült-lehetne jobb"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "megoldva"
 
--- a/locale/it.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/it.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: roundup cvs\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:20+0100\n"
 "Last-Translator: Marco Ghidinelli <marco.ghidinelli@ing.unibs.it>\n"
 "Language-Team: italian <it@li.org>\n"
@@ -29,19 +29,19 @@
 msgstr "Non è possibile ritirare l'utente amministratore o l'utente anonimo"
 
 # ../roundup/admin.py:1052 ../roundup/admin.py:85:981 :1030:1052
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "classe \"%(classname)s\" mancante"
 
 # ../roundup/admin.py:95 ../roundup/admin.py:99 ../roundup/admin.py:95:99
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "argomento \"%(arg)s\" non nel formato nome=valore"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -50,7 +50,7 @@
 "Problema: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -78,12 +78,12 @@
 " roundup-admin help all                   -- all available help\n"
 msgstr ""
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Comandi:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -91,7 +91,7 @@
 "I comandi possono essere abbreviati finchè l'abbreviazione rimane univoca\n"
 "es: l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -158,12 +158,12 @@
 "Command help:\n"
 msgstr ""
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -175,22 +175,22 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Nessun aiuto per \"%(topic)s\""
 
 # ../roundup/admin.py:340 ../roundup/admin.py:396 ../roundup/admin.py:340:396
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Modelli predefiniti:"
 
 # ../roundup/admin.py:343 ../roundup/admin.py:407 ../roundup/admin.py:343:407
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Back ends:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -218,23 +218,23 @@
 
 # ../roundup/admin.py:1243 ../roundup/admin.py:369:466 :1020:1042 :1072:1171
 # :1243 :527:606 :656:714 :735:763 :834:901 :972
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "Non sono stati forniti abbastanza argomenti"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "la directory radice dell'istanza \"%(parent)s\" non esiste"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -245,22 +245,22 @@
 "Se verrà reinstallata, tutti i dati precedentemente salvati andranno persi\n"
 "Cancellare la directory specificata? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Seleziona il modello predefinito [classic]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Seleziona il backend [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Erorre nei settaggi di configurazione: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -269,11 +269,11 @@
 "   %(config_file)s"
 msgstr ""
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... devono essere configurate almeno le seguenti opzioni:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -290,7 +290,7 @@
 "---------------------------------------------------------------------------\n"
 msgstr ""
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -298,7 +298,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -308,7 +308,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -319,30 +319,30 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Password dell'amministratore"
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Conferma: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "La home dell'istanza non esiste"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "L'istanza non è stata installata"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 msgid ""
 "Usage: get property designator[,designator]*\n"
 "        Get the given property of one or more designator(s).\n"
@@ -356,24 +356,24 @@
 msgstr ""
 
 # ../roundup/admin.py:560 ../roundup/admin.py:575 ../roundup/admin.py:560:575
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 
 # ../roundup/admin.py:1054 ../roundup/admin.py:583:983 :1032:1054
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr ""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 msgid ""
 "Usage: set items property=value property=value ...\n"
 "        Set the given properties of one or more items(s).\n"
@@ -394,7 +394,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 msgid ""
 "Usage: filter classname propname=value ...\n"
 "        Find the nodes of the given class with a given property value.\n"
@@ -408,20 +408,20 @@
 msgstr ""
 
 # ../roundup/admin.py:920 ../roundup/admin.py:701:854 :866:920
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "la classe %(classname)s non ha la proprietà \"%(propname)s\""
 
 # ../roundup/admin.py:920 ../roundup/admin.py:701:854 :866:920
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "la classe %(classname)s non ha la proprietà \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -432,7 +432,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -441,17 +441,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s %(value)s (chiave)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s:·%(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 msgid ""
 "Usage: display designator[,designator]*\n"
 "\n"
@@ -465,12 +465,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s:·%(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -482,31 +482,31 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s·(Password):·"
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Ripeti password): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Mi dispiace, riprova..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "deve essere fornita la proprietà \"%(propname)s\"."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -522,16 +522,16 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -563,17 +563,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr ""
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -588,7 +588,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -602,7 +602,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -614,7 +614,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 msgid ""
 "Usage: retire designator[,designator]*\n"
 "        Retire the node specified by designator.\n"
@@ -627,7 +627,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 msgid ""
 "Usage: restore designator[,designator]*\n"
 "        Restore the retired node specified by designator.\n"
@@ -640,13 +640,13 @@
 msgstr ""
 
 # ../roundup/admin.py:1052 ../roundup/admin.py:85:981 :1030:1052
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "classe \"%(classname)s\" mancante"
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -662,7 +662,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -679,7 +679,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -702,7 +702,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -710,7 +710,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -732,11 +732,11 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr ""
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -746,12 +746,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 msgid ""
 "Usage: security [Role name]\n"
 "\n"
@@ -759,46 +759,46 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "Non è presente il ruolo \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "I nuovi utenti Web otterranno i ruoli \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "I nuovi utenti Web otterranno il ruolo \"%(role)s)\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "I nuovi utenti Email otterranno i ruoli \"%(role)s)\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "I nuovi utenti Email otterranno il ruolo \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "Ruolo \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -806,17 +806,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -840,83 +840,83 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr ""
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr ""
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr ""
 
 # ../roundup/admin.py:1371:1377 :1397
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
 "Type \"help\" for help."
 msgstr ""
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr ""
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr ""
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -930,53 +930,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "crea"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "collega"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "scollega"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "assegna"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "ritira"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "ripristina"
 
@@ -1218,23 +1240,28 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
 # ../roundup/cgi/actions.py:931:935
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Login invalida"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Non hai il permesso per eseguire la login"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Non hai i permessi per modificare i %(class)s"
@@ -1338,162 +1365,169 @@
 "La notifica del problema è stata notificata al manutentore del tracker.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Errore nella Form: "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Codice di carattere sconosciuto: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr ""
 "Gli utenti anonimi non hanno il permesso di utilizzare l'interfaccia web"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
+#: ../roundup/cgi/client.py:1289
 #, python-format
 msgid "Missing header: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
 #, python-format
 msgid "csrf Referer header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1258
+#: ../roundup/cgi/client.py:1300
 #, python-format
 msgid "Invalid Referer %s, %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
 msgid "csrf Origin header check failed for user%s. Value=%s"
 msgstr ""
 
 # ../roundup/cgi/actions.py:931:935
-#: ../roundup/cgi/client.py:1274
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
 msgid "Invalid Origin %s"
 msgstr "Login invalida"
 
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
 #, python-format
 msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1289
-#, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
-#, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
-#, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Non si dispone dei permessi per visualizzare questo file."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sTempo trascorso: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1570,18 +1604,18 @@
 # ../roundup/cgi/templating.py:728:862 :1269:1298 :1318:1364 :1387:1423
 # :1460:1513 :1530:1614 :1634:1652 :1684:1694 :1746:1935
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[nascosto]"
 
@@ -1607,18 +1641,24 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "La classe collegata %(classname)s non esiste più"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:973:997
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>Il Nodo collegato non esiste più</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (nessun valore)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -1627,50 +1667,50 @@
 "<strong><em>Questo evento non è gestito dal visualizzatore dello storico!</"
 "em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Storico"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Data</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Storico"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Data</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Utente</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Azione</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Argomenti</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "Copia di %(class)s %(id)s"
 
 # ../roundup/cgi/templating.py:1491 ../roundup/cgi/templating.py:1039:1464
 # :1485:1491
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "No"
 
 # ../roundup/cgi/templating.py:1488 ../roundup/cgi/templating.py:1039:1464
 # :1483:1488
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Sì"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -1678,17 +1718,17 @@
 "Il valore predefinito per DateHTMLProperty deve essere  DateHTMLProperty "
 "oppure una stringa rappresentante una data."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "Tentativo di visualizzare %(attr)s con un valore mancante"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "Tentativo di visualizzare %(attr)s con un valore mancante"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- nessuna selezione -</option>"
@@ -1706,12 +1746,25 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
 # ../roundup/cgi/actions.py:931:935
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Login invalida"
 
+# ../roundup/cgi/actions.py:931:935
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Login invalida"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -1876,23 +1929,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -1906,44 +1959,44 @@
 "ATTENZIONE: La directory '%s'\n"
 "\tcontene un template old-style - ignorato"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Nuovo Messagggio"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -1951,7 +2004,7 @@
 "\n"
 "Le Email al tracker Roundup devono includere il campo Oggetto: \n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -1978,7 +2031,7 @@
 "\n"
 "Il campo \"Subject: \" (Oggetto) era: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -1995,7 +2048,7 @@
 "Classi valide sono: %(validname)s\n"
 "Il campo Subject: conteneva il valore \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2022,7 +2075,7 @@
 "\n"
 "Il campo \"Subject: \" (Oggetto) era: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2039,7 +2092,7 @@
 "Subject precedente intatto.\n"
 "Il campo Subject: conteneva il valore \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2054,7 +2107,7 @@
 "\n"
 "Il campo Subject: conteneva il valore \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2067,21 +2120,21 @@
 "\n"
 "Indirizzo sconosciuto: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Non si dispone di permessi sufficienti per accedere a questo tracker"
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Non si dispone dei permessi sufficienti per modificare %(classname)s"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Non si dispone dei permessi sufficienti per creare %(classname)s"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2096,28 +2149,28 @@
 "\n"
 "Il Subject era: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Non si dispone dei permessi necessari a creare file."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr ""
 "Non si dispone dei permessi necessari per aggiungere file a %(classname)s"
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2127,11 +2180,11 @@
 "Roundup richiede che i valori immessi siano in formato testo. Il parser dei "
 "messaggi non ha trovato alcuna parte text/plain da utilizzare.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Non si disponde dei permessi necessari per creare messaggi."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2142,26 +2195,26 @@
 "La Mail è stata rifiutata da un detector.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Non si dispone dei permessi per aggiungere messaggi a %(classname)s"
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 "Non si dispone dei permessi necessari per modificare la proprietà %(prop)s "
 "della classe %(classname)s"
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 "Non si dispone dei permessi necessari per modificare la proprietà %(prop)s "
 "della classe %(classname)s"
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2172,7 +2225,7 @@
 "Si è verificato un problema con il messaggio che hai inviato:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2185,7 +2238,7 @@
 "%(mailadmin)s e segnala che la classe specificata come:\n"
 "  %(current_class)s è scorretta.\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2198,22 +2251,40 @@
 "%(mailadmin)s e segnala che la proprietà scorretta:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "Non nel formato [arg=valore,valore,...;arg=valore,valore,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+# ../roundup/cgi/actions.py:931:935
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Login invalida"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2446,7 +2517,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2454,54 +2525,54 @@
 "<html><head><title>indice dei ticket Roundup</title></head>\n"
 "<body><h1>indice dei ticket Roundup</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s:·%(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "ATTENZIONE: ignoro il parametro \"-g\", non sei root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Non è possibile cambiare gruppo - nessun modulo grp"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "Il gruppo %(group)s non esiste"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "Non può essere eseguito come root!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "Non è possibile cambiare utente - nessun modulo pwd"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "L'utente %(user)s non esiste"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 "La modalità multiprocesso \"%s\" non è disponibile, viene utilizzata quella "
 "a singolo processo"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Impossibile bindare alla porta %s, la porta risulta già in uso."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2511,7 +2582,7 @@
 "               specifics."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2520,9 +2591,10 @@
 "               specified if -d is used."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2545,6 +2617,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2583,22 +2658,22 @@
 "   any url-unsafe characters like spaces, as these confuse IE.\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "L'istanza deve essere nel formato nome=home"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Configurazione salvata in %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Spiacente, non è possibile utilizzare il server come demone su questo "
 "sistema operativo."
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Il server Roundup è stato attivato su %(HOST)s:%(PORT)s"
@@ -2736,6 +2811,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -2752,6 +2828,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -2768,6 +2845,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3595,6 +3673,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4140,7 +4219,7 @@
 msgid "User listing"
 msgstr "Elenco Utenti"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4148,13 +4227,13 @@
 msgid "Username"
 msgstr "Nome Utente"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Nome Completo"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4163,26 +4242,26 @@
 msgid "Organisation"
 msgstr "Organizzazione"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "Indirizzo di Email"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Telefono"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Dismetti"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4335,67 +4414,67 @@
 "completare il processo di registrazione, visita il link indicato nella mail."
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "critico"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "urgente"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "bug"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr ""
 
--- a/locale/ja.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/ja.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.4.8\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:20+0100\n"
 "Last-Translator: Yasushi Iwata <iwata@know-net.co.jp>\n"
 "Language-Team: Yasushi Iwata <iwata@know-net.co.jp>\n"
@@ -27,25 +27,25 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr "ユーザー admin 㨠anonymous を無効ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“"
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr ""
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -73,17 +73,17 @@
 " roundup-admin help all                   -- all available help\n"
 msgstr ""
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 msgid "Commands: "
 msgstr ""
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
 msgstr ""
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -150,12 +150,12 @@
 "Command help:\n"
 msgstr ""
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr ""
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -167,20 +167,20 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr ""
 
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr ""
 
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr ""
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -206,23 +206,23 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -230,20 +230,20 @@
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 msgid "Select template"
 msgstr ""
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 msgid "Select backend"
 msgstr ""
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr ""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -252,11 +252,11 @@
 "   %(config_file)s"
 msgstr ""
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr ""
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -273,7 +273,7 @@
 "---------------------------------------------------------------------------\n"
 msgstr ""
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -281,7 +281,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -291,7 +291,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -302,30 +302,30 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr ""
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr ""
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr ""
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 msgid ""
 "Usage: get property designator[,designator]*\n"
 "        Get the given property of one or more designator(s).\n"
@@ -338,23 +338,23 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr ""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 msgid ""
 "Usage: set items property=value property=value ...\n"
 "        Set the given properties of one or more items(s).\n"
@@ -375,7 +375,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 msgid ""
 "Usage: filter classname propname=value ...\n"
 "        Find the nodes of the given class with a given property value.\n"
@@ -388,19 +388,19 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr ""
 
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -411,7 +411,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -420,17 +420,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr ""
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr ""
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 msgid ""
 "Usage: display designator[,designator]*\n"
 "\n"
@@ -444,12 +444,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -461,31 +461,31 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr ""
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr ""
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr ""
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr ""
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -501,16 +501,16 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -542,17 +542,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr ""
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -567,7 +567,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -581,7 +581,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -593,7 +593,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 msgid ""
 "Usage: retire designator[,designator]*\n"
 "        Retire the node specified by designator.\n"
@@ -606,7 +606,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 msgid ""
 "Usage: restore designator[,designator]*\n"
 "        Restore the retired node specified by designator.\n"
@@ -618,12 +618,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr ""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -639,7 +639,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -656,7 +656,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -679,7 +679,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -687,7 +687,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -709,11 +709,11 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr ""
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -723,12 +723,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 msgid ""
 "Usage: security [Role name]\n"
 "\n"
@@ -736,46 +736,46 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -783,17 +783,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -817,82 +817,82 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr ""
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr ""
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr ""
 
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
 "Type \"help\" for help."
 msgstr ""
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr ""
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr ""
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -906,53 +906,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr ""
 
@@ -1185,22 +1207,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "%(class)s を表示ã™ã‚‹æ¨©é™ãŒã‚りã¾ã›ã‚“"
@@ -1286,160 +1313,167 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr ""
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
+#, python-format
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
-msgid "Invalid HOST %s"
+msgid "Invalid Origin %s"
 msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
 
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, fuzzy, python-format
+msgid "Invalid HOST %s"
+msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1509,18 +1543,18 @@
 msgstr "æ–°è¦ç™»éŒ²"
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr ""
 
@@ -1546,63 +1580,69 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "リンク先ã®ã‚¯ãƒ©ã‚¹ %(classname)s ã¯å­˜åœ¨ã—ã¾ã›ã‚“"
 
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>リンク先ã®ãƒŽãƒ¼ãƒ‰ã¯å­˜åœ¨ã—ã¾ã›ã‚“</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr "<strong><em>ã“ã®ã‚¤ãƒ™ãƒ³ãƒˆã¯å±¥æ­´ã®ä¸­ã«è¡¨ç¤ºã•れã¾ã›ã‚“!</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>備考:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "履歴"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>日時</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "履歴"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>日時</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>ユーザー</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>アクション</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>引数</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "%(class)s %(id)s ã®ã‚³ãƒ”ー"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -1610,17 +1650,17 @@
 "DateHTMLProperty ã®ãƒ‡ãƒ•ォルト値㯠DateHTMLProperty ã‚‚ã—ãã¯æ—¥ä»˜ã®æ–‡å­—列表ç¾ã§"
 "ãªãã¦ã¯ãªã‚Šã¾ã›ã‚“。"
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "存在ã—ãªã„値㮠%(attr)s 検索ãŒå®Ÿè¡Œã•れã¾ã—ãŸ"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "存在ã—ãªã„値㮠%(attr)s 検索ãŒå®Ÿè¡Œã•れã¾ã—ãŸ"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- æœªé¸æŠž -</option>"
@@ -1638,11 +1678,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
+
 #: ../roundup/date.py:395
 #, python-format
 msgid ""
@@ -1801,23 +1853,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -1829,50 +1881,50 @@
 "\tcontains old-style template - ignored"
 msgstr ""
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "æ–°è¦ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -1889,7 +1941,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -1900,7 +1952,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -1917,7 +1969,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -1928,7 +1980,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -1938,7 +1990,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -1947,21 +1999,21 @@
 "Unknown address: %(from_address)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr ""
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -1971,38 +2023,38 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr ""
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
 "not find a text/plain part to use.\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr ""
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2010,22 +2062,22 @@
 "%(error)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr "クラス %(class)s ã®ã‚¢ã‚¤ãƒ†ãƒ ã‚’ %(action)s ã™ã‚‹æ¨©é™ãŒã‚りã¾ã›ã‚“"
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2033,7 +2085,7 @@
 "   %(message)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, python-format
 msgid ""
 "\n"
@@ -2042,7 +2094,7 @@
 "  %(clsname)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2051,22 +2103,39 @@
 "  %(errors)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "䏿­£ãªãƒªã‚¯ã‚¨ã‚¹ãƒˆ"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2286,58 +2355,58 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2347,7 +2416,7 @@
 "               specifics."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2356,9 +2425,10 @@
 "               specified if -d is used."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2381,6 +2451,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2419,20 +2492,20 @@
 "   any url-unsafe characters like spaces, as these confuse IE.\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr ""
@@ -2570,6 +2643,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -2586,6 +2660,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -2602,6 +2677,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3429,6 +3505,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -3976,7 +4053,7 @@
 msgid "User listing"
 msgstr "ユーザー一覧"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -3984,13 +4061,13 @@
 msgid "Username"
 msgstr "ユーザーå"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "åå‰"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -3999,26 +4076,26 @@
 msgid "Organisation"
 msgstr "所属"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "メールアドレス"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "電話番å·"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "無効化"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4169,67 +4246,67 @@
 "ã¨ã§ç™»éŒ²å‡¦ç†ãŒå®Œäº†ã—ã¾ã™ã€‚"
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "致命的ä¸å…·åˆ"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "è¦æ—©æœŸå¯¾å¿œ"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "ãƒã‚°"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "機能拡張案"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "è¦æœ›"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "未読"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "ä¿ç•™"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "対応議論中"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "è¦è©³ç´°æƒ…å ±"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "対応作業中"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "テスト中"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "暫定対応済ã¿"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "解決"
 
--- a/locale/lt.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/lt.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: roundup-1.1.2\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:21+0100\n"
 "Last-Translator: Nerijus Baliunas <nerijus@users.sourceforge.net>\n"
 "Language-Team: \n"
@@ -29,19 +29,19 @@
 msgstr "Negalite deaktyvuoti administratoriaus ar anoniminio vartotojo"
 
 # ../roundup/admin.py:85 :962 :1011 :1033
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "nÄ—ra klasÄ—s \"%(classname)s\""
 
 # ../roundup/admin.py:95 :99
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "argumentas \"%(arg)s\" nėra parinktis=reikšmė formato"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -50,7 +50,7 @@
 "Problema: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -100,12 +100,12 @@
 " roundup-admin help <komanda>             -- specifinÄ— pagalba komandoms\n"
 " roundup-admin help all                   -- visa įmanoma pagalba\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Komandos:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -113,7 +113,7 @@
 "Komandos gali bÅ«ti sutrumpintos, taÄiau sutrumpinimas turi atitikti tik\n"
 "vienÄ… komandÄ…, pvz. l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -246,12 +246,12 @@
 "\n"
 "Komandų pagalba:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -271,22 +271,22 @@
 "        all       -- visa įmanoma pagalba\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Atsiprašome, pagalbos temai \"%(topic)s\" nėra"
 
 # ../roundup/admin.py:338 :387
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Å ablonai:"
 
 # ../roundup/admin.py:341 :398
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Duomenų saugyklos:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -336,23 +336,23 @@
 
 # ../roundup/admin.py:360 :447 :508 :587 :637 :695 :716 :744 :815 :882 :953
 # :1001 :1023 :1050 :1117 :1184
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "Paduota nepakankamai argumentų"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "Namų direktorijos tėvinė direktorija \"%(parent)s\" neegzistuoja"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -363,22 +363,22 @@
 "Jei jūs jį perdiegsite, prarasite visus duomenis!\n"
 "Ištrinti jį? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Pasirinkite šabloną [klasikinis]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Pasirinkite duomenų saugyklą [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Klaida konfigūracijos nustatymuose: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -391,11 +391,11 @@
 " Dabar jūs turėtumėte pakeisti tracker'io konfigūracijos failą:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... mažiausiai turėtumėte nustalyti šias parinktis:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -424,7 +424,7 @@
 " aukÅ¡Äiau minÄ—tus žingsnius.\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -437,7 +437,7 @@
 "            įprastomis reikšmėmis faile <failovardas>.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -452,7 +452,7 @@
 "        "
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -470,23 +470,23 @@
 "            Vykdyti tracker'io inicializacijos funkcijÄ… dbinit.init()\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Administratoriaus slaptažodis: "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Patvirtinkite: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "Namų direktorija neegzistuoja"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "Egzempliorius nebuvo įdiegtas"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -496,7 +496,7 @@
 "Jei jūs ją inicializuosite dar kartą, prarasite visus duomenis!\n"
 "Ištrinti duomenų bazę? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -516,7 +516,7 @@
 "            "
 
 # ../roundup/admin.py:541 :556
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
@@ -524,18 +524,18 @@
 "-d netinkamas."
 
 # ../roundup/admin.py:564 :964 :1013 :1035
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "nÄ—ra tokio %(classname)s elemento \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "nÄ—ra tokio %(classname)s parinkties \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -570,7 +570,7 @@
 "            reikšmės (t.y. \"1,2,3\").\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -593,20 +593,20 @@
 "        "
 
 # ../roundup/admin.py:682 :835 :847 :901
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s neturi parinkties \"%(propname)s\""
 
 # ../roundup/admin.py:682 :835 :847 :901
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s neturi parinkties \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -625,7 +625,7 @@
 "            arba jo raktinė reikšmė.\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -639,17 +639,17 @@
 "            Ši komanda išvardina duotos klasės parinktis.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (key property)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -669,12 +669,12 @@
 "            Ši komanda išvardina parinktis ir jų reikšmes duotam elementui.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -693,31 +693,31 @@
 "            eilutÄ—je po \"create\" komandos.\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (Slaptažodis): "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Pakartoti): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Bandykite dar kartÄ…..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "turite pateikti parinktį \"%(propname)s\"."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -745,16 +745,16 @@
 "            parinkties sąrašas kiekvienam klasės egzemplioriui.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "Pateikta per daug argumentų"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -816,17 +816,17 @@
 "            pateiks 4 simbolių ilgio \"Name\" stulpelį.\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" ne vardas:plotis"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -841,7 +841,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -866,7 +866,7 @@
 "            išsaugomos, jei jos įvykdomos sėkmingai.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -888,7 +888,7 @@
 "             nepadarys jokių pakeitimų duomenų bazėje.\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -909,7 +909,7 @@
 "            kartÄ….\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -928,13 +928,13 @@
 "        "
 
 # ../roundup/admin.py:564 :964 :1013 :1035
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "nÄ—ra tokio %(classname)s elemento \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -962,7 +962,7 @@
 "        direktorijoje.\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -992,7 +992,7 @@
 "        direktorijoje.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1037,7 +1037,7 @@
 "            veiksmas).\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1045,7 +1045,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1084,11 +1084,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Netinkamas formatas"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1104,12 +1104,12 @@
 "            Paprastai tai įvyksta automatiškai.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "nÄ—ra elemento \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1121,47 +1121,47 @@
 "            Parodo vienos ar kelių rolių permisijas.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "NÄ—ra tokios rolÄ—s \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Naujiems web vartotojams suteikiamos rolÄ—s \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Naujiems web vartotojams suteikiama rolÄ— \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "Naujiems vartotojams per el. paštą suteikiamos rolės \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Naujiems vartotojams per el. paštą suteikiama rolė \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "RolÄ— \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s skirta tik \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr " %(description)s (%(name)s skirta tik \"%(klass)s\": %(properties)s)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1169,17 +1169,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s skirta tik \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1203,45 +1203,45 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "Tracker'io namų direktorija"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 "Nežinoma komanda \"%(command)s\" (įveskite \"help commands\" komandų\n"
 "sąrašui gauti)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "Kelios komandos atitinka \"%(command)s\": %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Įveskite tracker'io namų direktoriją: "
 
 # ../roundup/admin.py:1312 :1318 :1338
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Klaida: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Klaida: Negaliu atidaryti tracker'io: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1250,41 +1250,41 @@
 "Roundup %s pasiruošęs priimti duomenis.\n"
 "Norėdami iškviesti pagalbą įveskite \"help\"."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Pastaba: komandų archyvas ir redagavimas neprieinami"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "išeiti..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Yra neišsaugotų pakeitimų. Išsaugoti juos (y/N)? "
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1298,53 +1298,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "sukurti"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "atsieti"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "susieti"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "nustatyti"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "deaktyvuotas"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "aktyvuotas"
 
@@ -1586,23 +1608,28 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
 # ../roundup/cgi/actions.py:897 :901
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Neteisingas vartotojo vardas ar slaptažodis"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Neturite prisijungimo teisių"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Neturite leidimo redaguoti %(class)s"
@@ -1706,155 +1733,155 @@
 "Apie klaidą pranešėme tracker'io administratoriui.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Formos klaida: "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Neatpažinta koduotė: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "Anoniminiai vartotojai neturi teisių naudoti web interfeisą"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
+#: ../roundup/cgi/client.py:1289
 #, python-format
 msgid "Missing header: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
 #, python-format
 msgid "csrf Referer header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1258
+#: ../roundup/cgi/client.py:1300
 #, python-format
 msgid "Invalid Referer %s, %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
 msgid "csrf Origin header check failed for user%s. Value=%s"
 msgstr ""
 
 # ../roundup/cgi/actions.py:897 :901
-#: ../roundup/cgi/client.py:1274
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
 msgid "Invalid Origin %s"
 msgstr "Neteisingas vartotojo vardas ar slaptažodis"
 
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
 #, python-format
 msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1289
-#, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
-#, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
-#, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Jūs neturite teisių žiūrėti šį failą."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sPraėjęs laikas: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1864,6 +1891,13 @@
 "%(cache_misses)d. Įkeliami elementai: %(get_items)f sek. Filtruojama: "
 "%(filtering)f sek.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1938,18 +1972,18 @@
 # ../roundup/cgi/templating.py:700 :819 :1193 :1214 :1258 :1280 :1314 :1353
 # :1404 :1421 :1497 :1517 :1530 :1547 :1557 :1607 :1794
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[paslÄ—pta]"
 
@@ -1975,66 +2009,72 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "Susietos klasÄ—s %(classname)s nebÄ—ra"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:930 :951
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>Susieto elemento nebÄ—ra</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (no value)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr "<strong><em>Šis įvykis nėra rodomas archyve!</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Pastaba:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Archyvas"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Data</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Archyvas"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Data</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Vartotojas</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Veiksmas</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Argumentai</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "%(class)s %(id)s kopija"
 
 # ../roundup/cgi/templating.py:993 :1357 :1378 :1384
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "Ne"
 
 # ../roundup/cgi/templating.py:993 :1357 :1376 :1381
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Taip"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2042,17 +2082,17 @@
 "standartinė DateHTMLProperty reikšmė turi būti arba DateHTMLProperty arba "
 "datos reprezentacija kaip simbolių eilutės."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "BandÄ—te pažiÅ«rÄ—ti %(attr)s neegzistuojanÄiai reikÅ¡mei"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "BandÄ—te pažiÅ«rÄ—ti %(attr)s neegzistuojanÄiai reikÅ¡mei"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- nepasirinkta -</option>"
@@ -2070,11 +2110,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Netinkamas formatas"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Netinkamas formatas"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2247,23 +2299,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2277,44 +2329,44 @@
 "PERSPÄ–JIMAS: direktorijoje '%s'\n"
 "\tseno tipo šablonas, praleistas"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Naujas pranešimas"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2322,7 +2374,7 @@
 "\n"
 "Laiškai Roundup'o tracker'iams privalo turėti temos (Subject:) eilutę!\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2349,7 +2401,7 @@
 "\n"
 "Tema buvo: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2366,7 +2418,7 @@
 "Teisingi klasių vardai yra: %(validname)s\n"
 "Tema buvo: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2393,7 +2445,7 @@
 "\n"
 "Tema buvo: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2410,7 +2462,7 @@
 "\n"
 "Tema buvo: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2425,7 +2477,7 @@
 "\n"
 "Tema buvo: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2438,21 +2490,21 @@
 "\n"
 "Nežinomas adresas: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Neturite teisių naudotis šiuo tracker'iu."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Neturite leidimo redaguoti %(classname)s."
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Neturite leidimo sukurti %(classname)s."
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2467,27 +2519,27 @@
 "\n"
 "Tema buvo: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Neturite teisių sukurti failą."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "Neturite leidimo pridėti failų prie %(classname)s."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2497,11 +2549,11 @@
 "Roundup'ui reikia, kad laiškas būtų tekstinis. Laiškų analizatorius nerado\n"
 "text/plain dalies.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Neturite leidimo sukurti pranešimų."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2512,22 +2564,22 @@
 "Detektorius atmetė jūsų laišką.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Neturite leidimo pridėti pranešimų prie %(classname)s."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr "Neturite leidimo redaguoti %(classname)s parinkties %(prop)s."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr "Neturite leidimo redaguoti %(classname)s parinkties %(prop)s."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2537,7 +2589,7 @@
 "\n"
 "Jūsų laiške %(message)s yra klaidų.\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2550,7 +2602,7 @@
 "%(mailadmin)s, kad pataisytų neteisingą klasės pavadinimą:\n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2563,22 +2615,40 @@
 "%(mailadmin)s, kad pataisytų neteisingus atributus:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "ne tokios formos: [arg=reikšmė,reikšmė,...;arg=reikšmė,reikšmė,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+# ../roundup/cgi/actions.py:897 :901
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Neteisingas vartotojo vardas ar slaptažodis"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2869,7 +2939,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2877,52 +2947,52 @@
 "<html><head><title>Roundup tracker'io indeksas</title></head>\n"
 "<body><h1>Roundup tracker'io indeksas</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "PERSPĖJIMAS: \"-g\" argumentas ignoruojamas, nėra root teisių"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Negaliu pakeisti grupių -- nėra grp modulio"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "GrupÄ—s %(group)s nÄ—ra"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "Negaliu paleisti root teisÄ—mis!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "PERSPĖJIMAS: \"-u\" argumentas ignoruojamas, nėra root teisių"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "Negaliu pakesiti vartotojų - nėra pwd modulio"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "Vartotojo %(user)s nÄ—ra"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr "Multiprocesinė aplinka \"%s\" neprieinama, perjungiu į vienprocesinę"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Negaliu prijungti prie jungties %s, jungtis jau naudojama."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2939,7 +3009,7 @@
 "               Įvedę \"roundup-server -c help\" pamatysite Windows Services\n"
 "               specifikÄ…."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2953,9 +3023,10 @@
 "               nurodytą PIDfaile. Parinktis -l *privalo* būti nurodyta\n"
 "               jei naudojama -d."
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2978,6 +3049,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3069,21 +3143,21 @@
 "   nesupras.\n"
 "\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "Egzempliorius turi būti nurodomas taip: vardas=namų_direktorija"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Konfigūracija išsaugota %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Jūs negalite paleisti serverio kaip daemon'o šioje operacinėje sistemoje"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Roundup serveris paleistas ant %(HOST)s:%(PORT)s"
@@ -3220,6 +3294,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3236,6 +3311,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3252,6 +3328,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4083,6 +4160,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4631,7 +4709,7 @@
 msgid "User listing"
 msgstr "Vartotojų sąrašas"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4639,13 +4717,13 @@
 msgid "Username"
 msgstr "Vartotojo vardas"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Tikras vardas"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4654,26 +4732,26 @@
 msgid "Organisation"
 msgstr "Organizacija"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "El. pašto adresas"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Telefono numeris"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Deaktyvuoti"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4826,67 +4904,67 @@
 "pabaigtumėte registracijoc procesą, sekite nuorodą atsiųstame laiške."
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "kritinis"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "skubus"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "klaida"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "nauja savybÄ—"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "pageidavimas"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "neskaityta"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "atidÄ—ta"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "vyksta pokalbis"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "reikia pvz."
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "eigoje"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "testuojama"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "atlikta - galėtų būti geriau"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "išspręsta"
 
--- a/locale/nb.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/nb.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:21+0100\n"
 "Last-Translator: Christian Aastorp <christian.aastorp@gmail.com>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -30,18 +30,18 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr "Du kan ikke slette admin eller anonymous brukerne"
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "ingen slik klasse \"%(classname)s\""
 
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "argumentet \"%(arg)s\" ikke propname=value"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -50,7 +50,7 @@
 "Problem: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -100,12 +100,12 @@
 " roundup-admin help <command>             -- kommandospesifikk hjelp\n"
 " roundup-admin help all                   -- all tilgjengelig hjelp\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "Kommandoer:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -113,7 +113,7 @@
 "Kommandoer kan forkortes så lenge som forkortelsen bare passer med en "
 "kommando, feks e.g. l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -249,12 +249,12 @@
 "\n"
 "Kommandohjelp:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -274,20 +274,20 @@
 "        all       -- all tilgjengeli hjelp\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "Beklager, ingen hjelp for \"%(topic)s\""
 
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "Maler:"
 
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "Back ends:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -334,23 +334,23 @@
 "\t\tSe også hjelp for initops.\n"
 "        "
 
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "For få parametre"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "Overordnet katalog \"%(parent)s\" finnes ikke"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -361,22 +361,22 @@
 "Du vil miste alle data hvis du reinstallerer!\n"
 "Slette den? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "Velg mal [classic]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "Velg database backend [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "Feil i konfigurasjon \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -389,11 +389,11 @@
 " Du bør redigere konfigurasjonsfilen for sporeren nå:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr "... du må spesifisere følgende opsjoner som et minimum:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -421,7 +421,7 @@
 " disse endringene.\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -434,7 +434,7 @@
 "        i <filename>.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -449,7 +449,7 @@
 "        "
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -467,23 +467,23 @@
 "        Kjør sporerens oppstartsfunksjon dbinit.init()\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "Admin passord:"
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       Bekreft: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "Hjemmekatalogen finnes ikke"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "Sporeren er ikke installert"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -493,7 +493,7 @@
 "Hvis du reinitialiserer den vil alle data bli slettet.\n"
 "Slette den? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -514,24 +514,24 @@
 "\t\tved angivelsene.\n"
 "        "
 
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 "egneskapen %s er ikke multilenke eller lenke so -d lfagget kan ikke anvendes."
 
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "finnes ikke %(classname)s node \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "finnes ikke %(classname)s property \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -566,7 +566,7 @@
 "som\n"
 "        en kommaseparert liste (feks \"1,2,3\")."
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -586,19 +586,19 @@
 "        Verdien kan enten være nodeid-en til den lenkede noden, eller dens "
 "nøkkelverdi.n        "
 
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s har ingen verdi \"%(propname)s\""
 
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s har ingen verdi \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -615,7 +615,7 @@
 "        Verdien kan enten være nodeid-en til den lenkede noden, eller dens "
 "nøkkelverdi.n        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -629,17 +629,17 @@
 "        Lister egenskapene til gitt klasse.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (key property)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -659,12 +659,12 @@
 "        Lister egenskapene og deres verdier for oppgitt node.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -682,31 +682,31 @@
 "        på kommandolinjen ette \"create\"kommandoen.\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (Password): "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (Again): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "Beklager, prøv en gang til..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr "%(propname)s (%(proptype)s): "
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "du må oppgi \"%(propname)s\" egenskapen."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -735,16 +735,16 @@
 "        for alle klasseinstanser.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "For mange argumenter"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -804,17 +804,17 @@
 "        resulterer i en fire bokstavaer bred \"Name\" kolonne.\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" ikke navn:bredde"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -829,7 +829,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -852,7 +852,7 @@
 "         permanent, hvis de lykkes.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -871,7 +871,7 @@
 "          commited. \n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -891,7 +891,7 @@
 "       av list eller find-kommandoene, og at dens nøkkel kan gjenbrukes.\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -909,13 +909,13 @@
 "\t   Oppgitte noder blir tilgjengelige for brukerne igjen.\n"
 "        "
 
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "finnes ikke %(classname)s node \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -942,7 +942,7 @@
 "\t  kolonseparerte filer som plasseres i angitt katalog.\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -971,7 +971,7 @@
 "      kolonseparerte filer som plasseres i angitt katalog.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1013,7 +1013,7 @@
 "    (eller, mer omstendelig glem alle gamle data).\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1021,7 +1021,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1060,11 +1060,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "Ugyldig format"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1080,12 +1080,12 @@
 "    automatisk.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "ingen slik enhet  \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1097,47 +1097,47 @@
 "    Viser tillatelsene som er tilgjengelige for en eller alle roller.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "Ingen slik rolle \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "Nye web-brukere for rollene \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "Nye web-brukere for rollen \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "Nye epostbrukere for rollene \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "Nye epostbrukere for rollen \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "Rolle \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s bare for \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr " %(description)s (%(name)s bare for \"%(klass)s\": %(properties)s )"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1145,17 +1145,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s bare for \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 #, fuzzy
 msgid ""
 "Usage: migrate\n"
@@ -1203,41 +1203,41 @@
 "    la det bli en vane.\n"
 "        "
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr "Sporer oppdatert"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr "Ingen migrasjon krevet"
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr "Ukjent kommando \"%(command)s\" (\"help commands\" for liste)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "Multiple kommandoer  matcher \"%(command)s\": %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "Oppgi sporers plassering:"
 
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "Feil: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "Feil: Kan ikke åpne sporer: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1246,34 +1246,34 @@
 "Roundup %s er klar til bruk.\n"
 "Skriv  \"help\" for hjelp."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "Merk: kommandohistorikk og redigering utilgjengelig"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup> "
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "exit..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "Det er ikkelagrede endringer. Lagre dem (y/N)? "
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr "Kunne ikke identifisere databsetypen"
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, fuzzy, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
@@ -1281,7 +1281,7 @@
 msgstr ""
 "Kunne ikke åpne databasen - den påkrevde modulen '%s' er ikke tilgjengelig"
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1296,53 +1296,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr "Databsen åpnet bare for lesing"
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "lag"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "fjern lenke"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "lenke"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "oppdater"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "glemt"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "brakt tilbake"
 
@@ -1579,22 +1601,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "Ugylig login"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "Du har ikke tillatelse til å logge inn"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "Du har ikke tillatelse til  å se på %(class)s"
@@ -1692,154 +1719,154 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "Skjema feil:"
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "Ukjent tegnsett: %r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "Anonyme brukere får ikke benytte web-grensesnittet"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "Ugylig login"
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
+#, python-format
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
-msgid "Invalid HOST %s"
-msgstr "Ugyldig forespørsel"
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "Invalid Origin %s"
+msgstr "Ugylig login"
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, fuzzy, python-format
+msgid "Invalid HOST %s"
+msgstr "Ugyldig forespørsel"
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "Du har ikke lov å se denne filen."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)sMedgått tid: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1848,6 +1875,13 @@
 "%(starttag)sCache treff: %(cache_hits)d, ikke-treff %(cache_misses)d. Laster "
 "saker: %(get_items)f secs. Filtrerer: %(filtering)f secs.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1916,18 +1950,18 @@
 msgstr "Legg til ny oppføring"
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[skjult]"
 
@@ -1953,17 +1987,23 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "Den lenkede klassen %(classname)s finnes ikke lenger"
 
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>Den lenkede noden finnes ikke lenger</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (ingen verdi)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
@@ -1972,46 +2012,46 @@
 "<strong><em>Denne hendelsen håndteres ikke av historievisningen!</em></"
 "strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>Noter:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "Historie"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>Dato</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "Historie"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>Dato</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>Bruker</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>Aksjon</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>Argumenter</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "Kopi av %(class)s %(id)s"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "Nei"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "Ja"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2019,17 +2059,17 @@
 "standard verdi for DateHTMLProperty må være enten DateHTMLProperty eller en "
 "streng represantasjon av tidspunkt."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "Forsøk på å slå opp  %(attr)s på manglende verdi"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "Forsøk på å slå opp  %(attr)s på manglende verdi"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- intet valg -</option>"
@@ -2047,11 +2087,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "Ugyldig forespørsel"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "Ugyldig forespørsel"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2215,23 +2267,23 @@
 msgid "\"%s\" not a node designator"
 msgstr "\"%s\" ikke en node-benevnelse"
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr "Ikke et navn på egenskap: %s"
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr "egenskap %s: %r er ikke en %s."
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr "du kan bare oppgi ID-verdier for egenskap %s"
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr "%r er ikke en egenskap ved %s"
@@ -2245,44 +2297,44 @@
 "ADVARSEL: katalog '%s'\n"
 "\tinneholder foreldet mal - ignorert"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr "Melding signert med ukjent verdi: %s"
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr "Melding signert med utgått verdi: %s"
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr "Melding signert med tilbakekalt verdi: %s"
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr "Ugyldig PGP-signatur oppdaget."
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "Ny melding"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr "Ukjent flerdeler(multipart)/koded versjon."
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr "Ikke i stand til å dekryptere meldingne din."
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr "Ingen PGP signatur funnet i melding."
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2290,7 +2342,7 @@
 "\n"
 "Epost til Roundup sporer må inneholde en verdi for Subjekt: linjen\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2320,7 +2372,7 @@
 "\n"
 "Subjekt var: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2337,7 +2389,7 @@
 "Gyldige klassenavn er: %(validname)s\n"
 "Subjekt var: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2364,7 +2416,7 @@
 "\n"
 "Subjekt var: '%(subject)s'\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2383,7 +2435,7 @@
 "\n"
 "Subjekt var: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2398,7 +2450,7 @@
 "\n"
 "Subjekt var: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2411,21 +2463,21 @@
 "\n"
 "Ukjent adresse: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "Du har ikke adgang til denne sporeren."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "Du har ikke tillatelse til å endre %(classname)s."
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "Du har ikke tillatelse til å opprette %(classname)s."
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2441,7 +2493,7 @@
 "\n"
 "Subjekt var: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 #, fuzzy
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
@@ -2449,7 +2501,7 @@
 "Denne sporeren er satt til å kreve at all epost entern er signert med PGP, \n"
 "eller kryptert."
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
@@ -2459,16 +2511,16 @@
 "Denne sporeren er satt til å kreve at all epost entern er signert med PGP, \n"
 "eller kryptert."
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "Du har ikke lov å lage en filer."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "Du har ikke tillatelse til å legge filer til %(classname)s."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2479,11 +2531,11 @@
 "finne ren tekst\n"
 "Ã¥ behandle.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "Du har ikke lov å lage en meldinger."
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2494,26 +2546,26 @@
 "Epost ble returnert av en detektor.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "Du har ikke tillatelse til å legge meldinger til  %(classname)s."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 "Du har ikke tillatelse til å redigere egenskapen %(prop)s til klassen "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 "Du har ikke tillatelse til å redigere egenskapen %(prop)s til klassen "
 "%(classname)s."
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2524,7 +2576,7 @@
 "Det var et problem med meldingen du sendte:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2537,7 +2589,7 @@
 "og få problemet løst. Referansen er til feil klasse: \n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2550,22 +2602,39 @@
 "og få problemet løst. Referansen er til feil egenskaper:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr "ikke på formen [arg=value,value,...;arg=value,value,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "Ugylig login"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2865,7 +2934,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr "ADVARSEL: genererer midlertidig SSL sertifikat"
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2873,53 +2942,53 @@
 "<html><head><title>Roundup saksliste</title></head>\n"
 "<body><h1>Roundup saksliste</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "ADVARSEL: ignorerer \"-g\" argument, ikke root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "Kan ikke skifte gruppe, ingen grp modul"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "Gruppe %(group)s finnes ikke"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "Kan ikke kjøre som root"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "ADVARSEL: ignorerer \"-u\" argument, ikke root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "Kan ikke skifte bruker , ingen pwd modul"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "Bruker %(user)s finnes ikke"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 "Multiprosess modus  \"%s\" ikke tilgjengelig, fortsetter som enkeltprosess"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "Ikke mulig å binde til port %s, porten er allerede i bruk."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2936,7 +3005,7 @@
 "               Skriv \"roundup-server -c help\" for å vise Windows Services\n"
 "               informasjon."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2950,9 +3019,10 @@
 "               serverens PID til filen indikert av PIDfile.\n"
 "               -l optsjonen *må* brukes hvis -d brukes."
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2975,6 +3045,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3068,21 +3141,21 @@
 "   Pass på at de ikke inneholder url-utrygge tegn som mellomrom, for de kan "
 "forvirre IE.\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "Instanser må være navn=home"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "Konfigurasjon lagret til %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "Beklager, du kan ikke kjøre servern som daemon under dette operativsystemet"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Roundup server startet på %(HOST)s:%(PORT)s"
@@ -3220,6 +3293,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3236,6 +3310,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3252,6 +3327,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4078,6 +4154,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4625,7 +4702,7 @@
 msgid "User listing"
 msgstr "Brukerliste"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4633,13 +4710,13 @@
 msgid "Username"
 msgstr "Brukernavn"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "Fullt navn"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4648,26 +4725,26 @@
 msgid "Organisation"
 msgstr "Organisasjon"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "E-postadresse"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "Telefonnummer"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "Glem"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4818,67 +4895,67 @@
 "registreringen, besøk linken i eposten."
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "kritisk"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "krise"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "feil"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "finesse"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "ønske"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "ulest"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "på vent"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "diskuteres"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "trenger eksempel"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "pågår"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "tester"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "utført slurvete"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "utført"
 
--- a/locale/roundup.pot	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/roundup.pot	Thu Apr 21 16:54:17 2022 -0400
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -27,25 +27,25 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr ""
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr ""
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -73,17 +73,17 @@
 " roundup-admin help all                   -- all available help\n"
 msgstr ""
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 msgid "Commands: "
 msgstr ""
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
 msgstr ""
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -148,12 +148,12 @@
 "Command help:\n"
 msgstr ""
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr ""
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -165,20 +165,20 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr ""
 
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr ""
 
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr ""
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -204,22 +204,22 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499 ../roundup/admin.py:378:510
-#: :1071 :1157:1218 :1245:1281 :1412:1499 :583:674 :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522 ../roundup/admin.py:404:536
+#: :1097 :1183:1244 :1271:1307 :1435:1522 :609:700 :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -227,20 +227,20 @@
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 msgid "Select template"
 msgstr ""
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 msgid "Select backend"
 msgstr ""
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr ""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -249,11 +249,11 @@
 "   %(config_file)s"
 msgstr ""
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr ""
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -269,7 +269,7 @@
 "---------------------------------------------------------------------------\n"
 msgstr ""
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -277,7 +277,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -287,7 +287,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -298,30 +298,30 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr ""
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr ""
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr ""
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr ""
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
 "Erase it? Y/N: "
 msgstr ""
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 msgid ""
 "Usage: get property designator[,designator]*\n"
 "        Get the given property of one or more designator(s).\n"
@@ -334,23 +334,23 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175 :1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201 :1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr ""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 msgid ""
 "Usage: set items property=value property=value ...\n"
 "        Set the given properties of one or more items(s).\n"
@@ -371,7 +371,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 msgid ""
 "Usage: filter classname propname=value ...\n"
 "        Find the nodes of the given class with a given property value.\n"
@@ -384,19 +384,19 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr ""
 
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091 ../roundup/admin.py:801:862
-#: :1024:1036 :1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117 ../roundup/admin.py:827:888
+#: :1050:1062 :1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr ""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -407,7 +407,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -416,17 +416,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr ""
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr ""
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 msgid ""
 "Usage: display designator[,designator]*\n"
 "\n"
@@ -440,12 +440,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -457,31 +457,31 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr ""
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr ""
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr ""
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr ""
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -497,16 +497,16 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr ""
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -538,17 +538,17 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr ""
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -563,7 +563,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -577,7 +577,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -589,7 +589,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 msgid ""
 "Usage: retire designator[,designator]*\n"
 "        Retire the node specified by designator.\n"
@@ -602,7 +602,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 msgid ""
 "Usage: restore designator[,designator]*\n"
 "        Restore the retired node specified by designator.\n"
@@ -614,12 +614,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr ""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -635,7 +635,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -652,7 +652,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -675,7 +675,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -683,7 +683,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -705,11 +705,11 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr ""
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -719,12 +719,12 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 msgid ""
 "Usage: security [Role name]\n"
 "\n"
@@ -732,46 +732,46 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr ""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -779,17 +779,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr ""
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -813,81 +813,82 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr ""
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr ""
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr ""
 
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678 :1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701 :1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr ""
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
 "Type \"help\" for help."
 msgstr ""
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr ""
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr ""
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/sessions_dbm.py:55
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
+#: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -900,53 +901,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392 :1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392 :1438 :1452:1470 :1516:2138 :2063 :2138:2158 :2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr ""
 
@@ -1174,22 +1197,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr ""
@@ -1273,160 +1301,167 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr ""
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, python-format
-msgid "Invalid Origin %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
+#, python-format
+msgid "Invalid Origin %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422 :1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464 :1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1492,18 +1527,18 @@
 msgstr ""
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr ""
 
@@ -1529,78 +1564,84 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></strong>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr ""
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr ""
-
 #: ../roundup/cgi/templating.py:1379
-msgid "<th>User</th>"
-msgstr ""
-
-#: ../roundup/cgi/templating.py:1380
-msgid "<th>Action</th>"
+msgid "History"
 msgstr ""
 
 #: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1382
+msgid "<th>User</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1383
+msgid "<th>Action</th>"
+msgstr ""
+
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039 :2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045 :2078
 msgid "No"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039 :2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045 :2073
 msgid "Yes"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr ""
@@ -1618,10 +1659,21 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 msgid "Valid languages: "
 msgstr ""
 
+#: ../roundup/configuration.py:504
+msgid "Expected languages: "
+msgstr ""
+
 #: ../roundup/date.py:395
 #, python-format
 msgid ""
@@ -1780,23 +1832,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -1808,49 +1860,49 @@
 "\tcontains old-style template - ignored"
 msgstr ""
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 msgid "Unsigned Message"
 msgstr ""
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -1867,7 +1919,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -1878,7 +1930,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -1895,7 +1947,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -1906,7 +1958,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -1916,7 +1968,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -1925,21 +1977,21 @@
 "Unknown address: %(from_address)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr ""
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -1949,38 +2001,38 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr ""
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
 "not find a text/plain part to use.\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr ""
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -1988,22 +2040,22 @@
 "%(error)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr ""
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2011,7 +2063,7 @@
 "   %(message)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, python-format
 msgid ""
 "\n"
@@ -2020,7 +2072,7 @@
 "  %(clsname)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2029,22 +2081,39 @@
 "  %(errors)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, python-format
+msgid "Invalid attribute %s"
+msgstr ""
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2263,58 +2332,58 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2324,7 +2393,7 @@
 "               specifics."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2333,9 +2402,10 @@
 "               specified if -d is used."
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2358,6 +2428,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2396,20 +2469,20 @@
 "   any url-unsafe characters like spaces, as these confuse IE.\n"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr ""
@@ -2541,6 +2614,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -2557,6 +2631,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -2573,6 +2648,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3388,6 +3464,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -3921,7 +3998,7 @@
 msgid "User listing"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -3929,13 +4006,13 @@
 msgid "Username"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -3944,26 +4021,26 @@
 msgid "Organisation"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr ""
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4112,67 +4189,67 @@
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr ""
 
--- a/locale/ru.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/ru.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: Roundup 1.3.2\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:21+0100\n"
 "Last-Translator: alexander smishlajev <alex@tycobka.lv>\n"
 "Language-Team: Russian\n"
@@ -29,18 +29,18 @@
 msgid "You may not retire the admin or anonymous user"
 msgstr "îÅÌØÚÑ ÕÄÁÌÑÔØ ÐÏÌØÚÏ×ÁÔÅÌÅÊ admin É anonymous."
 
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "ëÌÁÓÓ \"%(classname)s\" ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "ÁÒÇÕÍÅÎÔ \"%(arg)s\" ÄÏÌÖÅÎ ÉÍÅÔØ ×ÉÄ ÉÍÑ=ÚÎÁÞÅÎÉÅ"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -49,7 +49,7 @@
 "ïÛÉÂËÁ: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -98,12 +98,12 @@
 " roundup-admin help <command>             -- ÓÐÒÁ×ËÁ ÐÏ ËÏÍÁÎÄÅ\n"
 " roundup-admin help all                   -- ×ÓÅ ÓÐÒÁ×ÏÞÎÙÅ ÓÏÏÂÝÅÎÉÑ\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "ëÏÍÁÎÄÙ:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -117,7 +117,7 @@
 # ÎÏ ÍÎÅ ÜÔÏ ÓÏ×ÓÅÍ ÎÅ ÎÒÁ×ÉÔÓÑ.
 #
 # ÞÔÏ ÌÕÞÛÅ ÎÁÐÉÓÁÔØ ×ÍÅÓÔÏ "××ÅÓÔÉ Ó ÔÅÒÍÉÎÁÌÁ"?
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -248,12 +248,12 @@
 "\n"
 "óÐÒÁ×ËÁ ÐÏ ËÏÍÁÎÄÁÍ:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr ""
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -273,20 +273,20 @@
 "        all       -- ×ÓÅ ÓÐÒÁ×ËÉ\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "é×ÉÎÉÔÅ, ÓÐÒÁ×ËÁ \"%(topic)s\" ÎÅ ÓÕÝÅÓÔ×ÕÅÔ."
 
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "ûÁÂÌÏÎÙ:"
 
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "óÅÒ×ÅÒÙ:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
 "        Install a new Roundup tracker.\n"
@@ -338,23 +338,23 @@
 "        óÍ.ÔÁËÖÅ \"help initopts\".\n"
 "        "
 
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "îÅÄÏÓÔÁÔÏÞÎÏ ÁÒÇÕÍÅÎÔÏ×"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "ëÁÔÁÌÏÇ \"%(parent)s\" ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -365,22 +365,22 @@
 "ðÏ×ÔÏÒÎÁÑ ÕÓÔÁÎÏ×ËÁ ÕÎÉÞÔÏÖÉÔ ×ÓÅ ×ÁÛÉ ÄÁÎÎÙÅ!\n"
 "õÄÁÌÉÔØ ÓÕÝÅÓÔ×ÕÀÝÉÊ ÔÒÅËÅÒ? Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "÷ÙÂÅÒÉÔÅ ÛÁÂÌÏÎ [classic]: "
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "÷ÙÂÅÒÉÔÅ ÓÅÒ×ÅÒ [anydbm]: "
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "ïÛÉÂËÁ × ÐÁÒÁÍÅÔÒÁÈ ËÏÎÆÉÇÕÒÁÃÉÉ: \"%s\""
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, python-format
 msgid ""
 "\n"
@@ -393,12 +393,12 @@
 " ôÅÐÅÒØ ×ÁÍ ÎÕÖÎÏ ÉÓÐÒÁ×ÉÔØ ËÏÎÆÉÇÕÒÁÃÉÏÎÎÙÊ ÆÁÊÌ ÔÒÅËÅÒÁ:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... ËÁË ÍÉÎÉÍÕÍ, ×Ù ÄÏÌÖÎÙ ÕÓÔÁÎÏ×ÉÔØ ÎÁÓÔÒÏÊËÉ:"
 
 # õËÁÚÁÎÏ ÁÎÇÌÉÊÓËÏÅ ÎÁÚ×ÁÎÉÅ ÄÏËÕÍÅÎÔÁ
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, python-format
 msgid ""
 "\n"
@@ -425,7 +425,7 @@
 " ðÏÓÌÅ ÜÔÏÇÏ ×Ù ÄÏÌÖÎÙ ×ÙÐÏÌÎÉÔØ ËÏÍÁÎÄÕ \"roundup-admin initialise\".\n"
 "---------------------------------------------------------------------------\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 #, fuzzy
 msgid ""
 "Usage: genconfig <filename>\n"
@@ -438,7 +438,7 @@
 "        ÉÓÐÏÌØÚÕÑ ÎÁÓÔÒÏÊËÉ ÐÏ ÕÍÏÌÞÁÎÉÀ.\n"
 "        "
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 #, fuzzy
 msgid ""
 "Usage: updateconfig <filename>\n"
@@ -454,7 +454,7 @@
 
 #  password
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -472,23 +472,23 @@
 "        éÎÉÃÉÁÌÉÚÁÃÉÑ ÔÒÅËÅÒÁ ÄÅÌÁÅÔÓÑ ÆÕÎËÃÉÅÊ dbinit.init()\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "ðÁÒÏÌØ ÁÄÍÉÎÉÓÔÒÁÔÏÒÁ: "
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "              åÝÅ ÒÁÚ: "
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "äÏÍÁÛÎÉÊ ËÁÔÁÌÏÇ ÔÒÅËÅÒÁ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "ôÒÅËÅÒ ÎÅ ÕÓÔÁÎÏ×ÌÅÎ"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -498,7 +498,7 @@
 "ðÏ×ÔÏÒÎÁÑ ÉÎÉÃÉÁÌÉÚÁÃÉÑ ÕÎÉÞÔÏÖÉÔ ×ÓÅ ×ÁÛÉ ÄÁÎÎÙÅ!\n"
 "õÄÁÌÉÔØ ÓÕÝÅÓÔ×ÕÀÝÕÀ ÂÁÚÕ? Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -519,24 +519,24 @@
 "        ÐÅÒÅÞÉÓÌÅÎÎÙÈ × ÓÐÉÓËÅ ÏÐÉÓÁÔÅÌÅÊ.\n"
 "        "
 
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr ""
 "ëÌÀÞ '-d' ÎÅÐÒÉÍÅÎÉÍ, ÐÏÔÏÍÕ ÞÔÏ ÔÉÐ ÁÔÒÉÂÕÔÁ %s - ÎÅ Link É ÎÅ Multilink"
 
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "÷ ËÌÁÓÓÅ %(classname)s ÎÅÔ ÏÂßÅËÔÁ \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "õ ËÌÁÓÓÁ %(classname)s ÎÅÔ ÁÔÒÉÂÕÔÁ \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -571,7 +571,7 @@
 "        ÁÔÒÉÂÕÔ.  (îÁÐÒÉÍÅÒ, \"1,2,3\".)\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -592,19 +592,19 @@
 "        ËÏÔÏÒÙÊ ÓÓÙÌÁÅÔÓÑ ÁÔÒÉÂÕÔ, ÉÌÉ ËÌÀÞÏÍ ÜÔÏÇÏ ÏÂßÅËÔÁ.\n"
 "        "
 
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "ëÌÁÓÓ %(classname)s ÎÅ ÉÍÅÅÔ ÁÔÒÉÂÕÔÁ \"%(propname)s\""
 
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "ëÌÁÓÓ %(classname)s ÎÅ ÉÍÅÅÔ ÁÔÒÉÂÕÔÁ \"%(propname)s\""
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -622,7 +622,7 @@
 "        ËÏÔÏÒÙÊ ÓÓÙÌÁÅÔÓÑ ÁÔÒÉÂÕÔ, ÉÌÉ ËÌÀÞÏÍ ÜÔÏÇÏ ÏÂßÅËÔÁ.\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -636,17 +636,17 @@
 "        ÷ÙÄÁÅÔ ÓÐÉÓÏË ÁÔÒÉÂÕÔÏ× ÕËÁÚÁÎÎÏÇÏ ËÌÁÓÓÁ.\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (ËÌÀÞÅ×ÏÊ ÁÔÒÉÂÕÔ)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s (ËÌÀÞÅ×ÏÊ ÁÔÒÉÂÕÔ)"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -667,12 +667,12 @@
 "        ÚÁÄÁÎÎÙÈ ÏÐÉÓÁÔÅÌÑÍÉ.\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -690,31 +690,31 @@
 "        ÜÔÏÇÏ ÏÂßÅËÔÁ ÕËÁÚÁÎÎÙÍÉ ÚÎÁÞÅÎÉÑÍÉ.\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr " %(propname)s (ÐÁÒÏÌØ): "
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "%(propname)s (ÅÝÅ ÒÁÚ): "
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "ðÁÒÏÌÉ ÎÅ ÓÏ×ÐÁÌÉ.  ðÏÐÒÏÂÕÊÔÅ ÅÝÅ ÒÁÚ."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "áÔÒÉÂÕÔ \"%(propname)s\" ÄÏÌÖÅÎ ÂÙÔØ ÚÁÐÏÌÎÅÎ."
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -743,16 +743,16 @@
 "        ×ÙÄÁÅÔ ÓÐÉÓÏË ÚÎÁÞÅÎÉÊ ÜÔÏÇÏ ÁÔÒÉÂÕÔÁ.\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "ðÏÄÁÎÏ ÓÌÉÛËÏÍ ÍÎÏÇÏ ÐÁÒÁÍÅÔÒÏ×"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -812,17 +812,17 @@
 "        ÏÂÒÅÚÁÅÔ ÚÎÁÞÅÎÉÑ ÓÔÏÌÂÃÁ \"Name\" ÄÏ ÞÅÔÙÒÅÈ ÓÉÍ×ÏÌÏ×.\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "úÎÁÞÅÎÉÅ \"%(spec)s\" ÄÏÌÖÎÏ ÂÙÔØ ÚÁÄÁÎÏ ËÁË ÉÍÑ:ÛÉÒÉÎÁ"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -837,7 +837,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -861,7 +861,7 @@
 "        Á×ÔÏÍÁÔÉÞÅÓËÉ, ÅÓÌÉ ÐÒÉ ×ÙÐÏÌÎÅÎÉÉ ËÏÍÁÎÄÙ ÎÅ ÐÒÏÉÚÏÛÌÏ ÏÛÉÂËÉ.\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -882,7 +882,7 @@
 "        ÂÙÌÏ × ÍÏÍÅÎÔ ÐÏÓÌÅÄÎÅÊ ÚÁÐÉÓÉ.\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -904,7 +904,7 @@
 "        ÉÓÐÏÌØÚÏ×ÁÎÙ × ÄÒÕÇÉÈ ÏÂßÅËÔÁÈ.\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -923,13 +923,13 @@
 "        ÍÏÖÎÏ ÐÏÌØÚÏ×ÁÔØÓÑ ÓÎÏ×Á.\n"
 "        "
 
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "÷ ËÌÁÓÓÅ %(classname)s ÎÅÔ ÏÂßÅËÔÁ \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files.\n"
@@ -966,7 +966,7 @@
 "        exporttables.\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
 "        Export the database to colon-separated-value files, excluding the\n"
@@ -1004,7 +1004,7 @@
 "        ÐÏÌÎÏÓÔØÀ, ÉÓÐÏÌØÚÕÊÔÅ ËÏÍÁÎÄÕ export.\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -1048,7 +1048,7 @@
 "        ÉÚ ÓÕÝÅÓÔ×ÕÀÝÅÊ ÂÁÚÙ ×ÓÅ ÏÂßÅËÔÙ).\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -1056,7 +1056,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1096,11 +1096,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1116,12 +1116,12 @@
 "        ÄÁÎÎÙÈ.  ïÂÙÞÎÏ ÐÏÓÔÒÏÅÎÉÅ ÉÎÄÅËÓÏ× ÐÒÏÉÓÈÏÄÉÔ Á×ÔÏÍÁÔÉÞÅÓËÉ.\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "ÏÂßÅËÔ \"%(designator)s\" ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1134,49 +1134,49 @@
 "        ÒÏÌÑÍ.\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "òÏÌØ \"%(role)s\" ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "îÏ×ÙÅ ÐÏÌØÚÏ×ÁÔÅÌÉ web ÐÏÌÕÞÁÀÔ ÒÏÌÉ \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "îÏ×ÙÅ ÐÏÌØÚÏ×ÁÔÅÌÉ web ÐÏÌÕÞÁÀÔ ÒÏÌØ \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "îÏ×ÙÅ ÐÏÌØÚÏ×ÁÔÅÌÉ email ÐÏÌÕÞÁÀÔ ÒÏÌÉ \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "îÏ×ÙÅ ÐÏÌØÚÏ×ÁÔÅÌÉ email ÐÏÌÕÞÁÀÔ ÒÏÌØ \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "òÏÌØ \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s ÔÏÌØËÏ ÄÌÑ ËÌÁÓÓÁ \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr ""
 " %(description)s (%(name)s ÄÌÑ ËÌÁÓÓÁ \"%(klass)s\": ÔÏÌØËÏ Ó×ÏÊÓÔ×Á "
 "%(properties)s)"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1184,17 +1184,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s ÔÏÌØËÏ ÄÌÑ ËÌÁÓÓÁ \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s ÔÏÌØËÏ ÄÌÑ ËÌÁÓÓÁ \"%(klass)s\")"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1218,43 +1218,43 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "ãÅÎÔÒ ÕÐÒÁ×ÌÅÎÉÑ ÚÁÄÁÎÉÑÍÉ"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr ""
 "ëÏÍÁÎÄÁ \"%(command)s\" ÎÅÉÚ×ÅÓÔÎÁ. (\"help commands\" ×ÙÄÁÅÔ ÓÐÉÓÏË ËÏÍÁÎÄ)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "\"%(command)s\" ÓÏÏÔ×ÅÔÓÔ×ÕÅÔ ÎÅÓËÏÌØËÉÍ ËÏÍÁÎÄÁÍ: %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "äÏÍÁÛÎÉÊ ËÁÔÁÌÏÇ ÔÒÅËÅÒÁ: "
 
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "ïÛÉÂËÁ: %(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "ïÛÉÂËÁ: ôÒÅËÅÒ ÎÅ ÏÔËÒÙ×ÁÅÔÓÑ: %(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1263,41 +1263,41 @@
 "Roundup %s Ë ×ÁÛÉÍ ÕÓÌÕÇÁÍ.\n"
 "÷×ÅÄÉÔÅ \"help\" ÄÌÑ ÓÐÒÁ×ËÉ."
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "ðÒÉÍÅÞÁÎÉÅ: ÒÁÂÏÔÁÅÔ ÒÅÄÁËÔÏÒ É ÉÓÔÏÒÉÑ ËÏÍÁÎÄ"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "ÐÒÉÈÏÄÉÔÅ Ë ÎÁÍ ÅÝÅ..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "ïÊ, ÔÕÔ ÎÅÓÏÈÒÁÎÅÎÎÙÅ ÉÚÍÅÎÅÎÉÑ. úÁÐÉÓÁÔØ × ÂÁÚÕ ÄÁÎÎÙÈ (y/N)? "
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1311,53 +1311,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "ÓÏÚÄÁÎÉÅ"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "ÏÔ×ÑÚËÁ"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "ÐÒÉ×ÑÚËÁ"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "ÕÓÔÁÎÏ×ËÁ"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "ÚÁÐÒÅÝÅÎÉÅ"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "×ÏÓÓÔÁÎÏ×ÌÅÎÉÅ"
 
@@ -1597,22 +1619,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÐÁÒÏÌØ ÉÌÉ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ."
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÒÁÂÏÔÕ Ó ÓÉÓÔÅÍÏÊ"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÒÅÄÁËÔÉÒÏ×ÁÔØ %(class)s"
@@ -1718,154 +1745,154 @@
 "áÄÍÉÎÉÓÔÒÁÔÏÒÕ ÔÒÅËÅÒÁ ÏÔÏÓÌÁÎÏ ÓÏÏÂÝÅÎÉÅ Ï ÏÛÉÂËÅ.</p>\n"
 "</body></html>"
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "ïÛÉÂËÁ ÆÏÒÍÙ: "
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "ëÏÄÉÒÏ×ËÁ %r ÎÅ ÒÁÓÐÏÚÎÁÎÁ"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "áÎÏÎÉÍÎÙÍ ÐÏÌØÚÏ×ÁÔÅÌÑÍ ÎÅ ÒÁÚÒÅÛÅÎÏ ÐÏÌØÚÏ×ÁÔØÓÑ ×ÅÂ-ÉÎÔÅÒÆÅÊÓÏÍ."
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÐÁÒÏÌØ ÉÌÉ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ."
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
+#, fuzzy, python-format
+msgid "Invalid Origin %s"
+msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÐÁÒÏÌØ ÉÌÉ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ."
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÐÒÏÓÍÏÔÒ ÜÔÏÇÏ ÆÁÊÌÁ."
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr "%(starttag)súÁÔÒÁÞÅÎÎÏÅ ×ÒÅÍÑ: %(seconds)fs%(endtag)s\n"
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
@@ -1875,6 +1902,13 @@
 "%(cache_misses)d. úÁÇÒÕÚËÁ ÏÂßÅËÔÏ×: %(get_items)f ÓÅË. æÉÌØÔÒÁÃÉÑ: "
 "%(filtering)f ÓÅË.%(endtag)s\n"
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1948,18 +1982,18 @@
 # ../roundup/cgi/templating.py:673 :792 :1166 :1187 :1231 :1253 :1287 :1326
 # :1377 :1394 :1470 :1490 :1503 :1520 :1530 :1580 :1755
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[ÎÅÄÏÓÔÕÐÎÏ]"
 
@@ -1985,64 +2019,70 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "ó×ÑÚÑÎÎÙÊ ËÌÁÓÓ %(classname)s ÕÖÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # :823
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>ó×ÑÚÁÎÎÙÊ ÏÂßÅËÔ ÕÖÅ ÎÅ ÓÕÝÅÓÔ×ÕÅÔ</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (ÎÅÔ ÚÎÁÞÅÎÉÑ)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr "<strong><em>îÅÉÚ×ÅÓÔÎÙÊ ÔÉÐ ÓÏÂÙÔÉÑ!</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>ðÒÉÍÅÞÁÎÉÅ:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "éÓÔÏÒÉÑ"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>äÁÔÁ</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "éÓÔÏÒÉÑ"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>äÁÔÁ</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>ðÏÌØÚÏ×ÁÔÅÌØ</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>äÅÊÓÔ×ÉÅ</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>ðÁÒÁÍÅÔÒÙ</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "ëÏÐÉÑ: %(class)s %(id)s"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "îÅÔ"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "äÁ"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
@@ -2050,17 +2090,17 @@
 "ÚÎÁÞÅÎÉÅ ÐÏ ÕÍÏÌÞÁÎÉÀ ÄÌÑ DateHTMLProperty ÄÏÌÖÎÏ ÂÙÔØ ÏÂßÅËÔÏÍ "
 "DateHTMLProperty ÉÌÉ ÓÔÒÏËÏ×ÙÍ ÐÒÅÄÓÔÁ×ÌÅÎÉÅÍ ÄÁÔÙ."
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr "ðÏÐÙÔËÁ ÐÏÌÕÞÉÔØ ÁÔÒÉÂÕÔ \"%(attr)s\" ÎÅÓÕÝÅÓÔ×ÕÀÝÅÇÏ ÏÂßÅËÔÁ"
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, fuzzy, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr "ðÏÐÙÔËÁ ÐÏÌÕÞÉÔØ ÁÔÒÉÂÕÔ \"%(attr)s\" ÎÅÓÕÝÅÓÔ×ÕÀÝÅÇÏ ÏÂßÅËÔÁ"
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- ÎÅ ÕËÁÚÁÎÏ -</option>"
@@ -2078,11 +2118,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÆÏÒÍÁÔ"
+
 #: ../roundup/date.py:395
 #, fuzzy, python-format
 msgid ""
@@ -2257,23 +2309,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2287,44 +2339,44 @@
 "÷îéíáîéå! ëÁÔÁÌÏÇ '%s'\n"
 "\tÓÏÄÅÒÖÉÔ ÛÁÂÌÏÎ ÓÔÁÒÏÇÏ ÏÂÒÁÚÃÁ - ÐÒÏÐÕÝÅÎ"
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "îÏ×ÏÅ ÓÏÏÂÝÅÎÉÅ"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
@@ -2332,7 +2384,7 @@
 "\n"
 "÷ ÐÉÓØÍÁÈ ÄÌÑ ÔÒÅËÅÒÁ Roundup ÄÏÌÖÎÁ ÂÙÔØ ÕËÁÚÁÎÁ ÔÅÍÁ ÓÏÏÂÝÅÎÉÑ (Subject).\n"
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2361,7 +2413,7 @@
 "        1234, ËÏÔÏÒÁÑ ÕÖÅ ÓÕÝÅÓÔ×ÕÅÔ × ÔÒÅËÅÒÅ.\n"
 "ôÅÍÁ ×ÁÛÅÇÏ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2378,7 +2430,7 @@
 "éÍÅÎÁ ÓÕÝÅÓÔ×ÕÀÝÉÈ ËÌÁÓÓÏ×: %(validname)s\n"
 "ôÅÍÁ ×ÁÛÅÇÏ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2408,7 +2460,7 @@
 "\n"
 "ôÅÍÁ ×ÁÛÅÇÏ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2427,7 +2479,7 @@
 "\n"
 "ôÅÍÁ ×ÁÛÅÇÏ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2442,7 +2494,7 @@
 "\n"
 "ôÅÍÁ ×ÁÛÅÇÏ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2456,21 +2508,21 @@
 "\n"
 "îÅÉÚ×ÅÓÔÎÙÊ ÁÄÒÅÓ: %(from_address)s\n"
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÄÏÓÔÕÐ Ë ÜÔÏÍÕ ÔÒÅËÅÒÕ."
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÒÅÄÁËÔÉÒÏ×ÁÔØ %(classname)s"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÓÏÚÄÁ×ÁÔØ ÏÂßÅËÔÙ %(classname)s"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2485,27 +2537,27 @@
 "\n"
 "ôÅÍÁ ÐÉÓØÍÁ: \"%(subject)s\"\n"
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÓÏÚÄÁÎÉÅ ÆÁÊÌÏ×."
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÄÏÂÁ×ÌÑÔØ ÆÁÊÌÙ ÄÌÑ ËÌÁÓÓÁ %(classname)s."
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
@@ -2515,11 +2567,11 @@
 "óÏÏÂÝÅÎÉÑ ÄÌÑ Roundup ÄÏÌÖÎÙ ÂÙÔØ × ÔÅËÓÔÏ×ÏÍ ÆÏÒÍÁÔÅ.\n"
 "÷ ×ÁÛÅÍ ÓÏÏÂÝÅÎÉÉ ÎÅ ÎÁÊÄÅÎÁ ÞÁÓÔØ ÆÏÒÍÁÔÁ text/plain.\n"
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÎÁ ÓÏÚÄÁÎÉÅ ÓÏÏÂÝÅÎÉÊ"
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2530,22 +2582,22 @@
 "óÏÏÂÝÅÎÉÅ ÏÔÂÒÏÛÅÎÏ ÄÅÔÅËÔÏÒÏÍ.\n"
 "%(error)s\n"
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÄÏÂÁ×ÌÑÔØ ÓÏÏÂÝÅÎÉÑ ÄÌÑ ËÌÁÓÓÁ %(classname)s."
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÉÚÍÅÎÑÔØ ÁÔÒÉÂÕÔ %(prop)s ËÌÁÓÓÁ %(classname)s"
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr "õ ×ÁÓ ÎÅÔ ÒÁÚÒÅÛÅÎÉÑ ÉÚÍÅÎÑÔØ ÁÔÒÉÂÕÔ %(prop)s ËÌÁÓÓÁ %(classname)s"
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2556,7 +2608,7 @@
 "ðÒÉ ÏÂÒÁÂÏÔËÅ ×ÁÛÅÇÏ ÓÏÏÂÝÅÎÉÑ ÐÒÏÉÚÏÛÌÁ ÏÛÉÂËÁ:\n"
 "   %(message)s\n"
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -2570,7 +2622,7 @@
 "Ï ÎÅÐÒÁ×ÉÌØÎÏ ÏÐÉÓÁÎÎÏÍ ËÌÁÓÓÅ:\n"
 "  %(current_class)s\n"
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2584,24 +2636,41 @@
 "Ï ÎÅÐÒÁ×ÉÌØÎÏ ÏÐÉÓÁÎÎÙÈ ÁÔÒÉÂÕÔÁÈ:\n"
 "  %(errors)s\n"
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 "ÁÒÇÕÍÅÎÔÙ ÄÏÌÖÎÙ ÂÙÔØ × ÆÏÒÍÁÔÅ [ÉÍÑ=ÚÎÁÞÅÎÉÅ,ÚÎÁÞÅÎÉÅ,...;ÉÍÑ=ÚÎÁÞÅÎÉÅ,"
 "ÚÎÁÞÅÎÉÅ,...]"
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "îÅÐÒÁ×ÉÌØÎÙÊ ÐÁÒÏÌØ ÉÌÉ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ."
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2903,7 +2972,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr "÷îéíáîéå: ÓÏÚÄÁÅÔÓÑ ×ÒÅÍÅÎÎÙÊ ÓÅÒÔÉÆÉËÁÔ ÄÌÑ SSL"
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2911,56 +2980,56 @@
 "<html><head><title>óÐÉÓÏË ÔÒÅËÅÒÏ× Roundup</title></head>\n"
 "<body><h1>óÐÉÓÏË ÔÒÅËÅÒÏ× Roundup</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s (ËÌÀÞÅ×ÏÊ ÁÔÒÉÂÕÔ)"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr ""
 "÷îéíáîéå: ÐÁÒÁÍÅÔÒ \"-g\" ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ, ÏÎ ÒÁÚÒÅÛÅÎ ÔÏÌØËÏ ÄÌÑ "
 "ÐÏÌØÚÏ×ÁÔÅÌÑ root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "ðÏÄÍÅÎÁ ÇÒÕÐÐÙ ÎÅ×ÏÚÍÏÖÎÁ - ÎÕÖÅÎ ÍÏÄÕÌØ grp"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "çÒÕÐÐÁ %(group)s ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "úÁÐÕÓË ÓÅÒ×ÅÒÁ Ó ÐÏÌÎÏÍÏÞÉÑÍÉ ÐÏÌØÚÏ×ÁÔÅÌÑ root ÚÁÐÒÅÝÅÎ!"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr ""
 "÷îéíáîéå: ÐÁÒÁÍÅÔÒ \"-u\" ÎÅ ÉÓÐÏÌØÚÕÅÔÓÑ, ÏÎ ÒÁÚÒÅÛÅÎ ÔÏÌØËÏ ÄÌÑ "
 "ÐÏÌØÚÏ×ÁÔÅÌÑ root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "ðÏÄÍÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÑ ÎÅ×ÏÚÍÏÖÎÁ - ÎÕÖÅÎ ÍÏÄÕÌØ pwd"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "ðÏÌØÚÏ×ÁÔÅÌØ %(user)s ÎÅ ÓÕÝÅÓÔ×ÕÅÔ"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr "òÅÖÉÍ \"%s\" ÎÅÄÏÓÔÕÐÅÎ, ÐÅÒÅËÌÀÞÁÅÍÓÑ × ÏÄÎÏÚÁÄÁÞÎÙÊ ÒÅÖÉÍ"
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "îÅ×ÏÚÍÏÖÎÏ ÕÓÔÁÎÏ×ÉÔØ ÓÅÒ×ÅÒ ÎÁ ÐÏÒÔÕ %s, ÐÏÒÔ ÕÖÅ ÚÁÎÑÔ."
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 msgid ""
 " -c <Command>  Windows Service options.\n"
 "               If you want to run the server as a Windows Service, you\n"
@@ -2977,7 +3046,7 @@
 "               ÆÁÊÌ ÐÒÏÔÏËÏÌÁ.  ëÏÍÁÎÄÁ 'roundup-server -c help'\n"
 "               ×ÙÄÁÅÔ ÓÐÒÁ×ËÕ Ï ËÏÍÁÎÄÎÏÊ ÓÔÒÏËÅ ÓÅÒ×ÉÓÁ Windows."
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2991,9 +3060,10 @@
 "               É ÚÁÐÕÓÔÉÔØ ÓÅÒ×ÅÒ × ÆÏÎÏ×ÏÍ ÒÅÖÉÍÅ.  åÓÌÉ ÕËÁÚÁÎÏ \"-d\",\n"
 "               ÆÁÊÌ ÐÒÏÔÏËÏÌÁ *ÏÂÑÚÁÔÅÌØÎÏ* ÄÏÌÖÅÎ ÂÙÔØ ÚÁÄÁÎ ËÌÀÞÏÍ \"-l\""
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -3016,6 +3086,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -3110,21 +3183,21 @@
 "   ÎÅ ÍÏÇÕÔ ÉÓÐÏÌØÚÏ×ÁÔØÓÑ × URL (ÐÒÏÂÅÌÙ, ÒÕÓÓËÉÅ ÂÕË×Ù É ÐÒÏÞ.),\n"
 "   ÐÏÔÏÍÕ ÞÔÏ ÔÁËÉÅ ÉÍÅÎÁ ÓÂÉ×ÁÀÔ Ó ÔÏÌËÕ ÎÅËÏÔÏÒÙÅ ÂÒÁÕÚÅÒÙ ÔÉÐÁ IE.\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "óÐÉÓÏË ÔÒÅËÅÒÏ× ÄÏÌÖÅÎ ÂÙÔØ × ÆÏÒÍÁÔÅ ÉÍÑ=ËÁÔÁÌÏÇ"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "ëÏÎÆÉÇÕÒÁÃÉÑ ÚÁÐÉÓÁÎÁ × %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr ""
 "éÚ×ÉÎÉÔÅ, × ÜÔÏÊ ÏÐÅÒÁÃÉÏÎÎÏÊ ÓÉÓÔÅÍÅ ÒÁÂÏÔÁ × ÆÏÎÏ×ÏÍ ÒÅÖÉÍÅ ÎÅ×ÏÚÍÏÖÎÁ"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "óÅÒ×ÅÒ Roundup ÇÏÔÏ× Ë ÒÁÂÏÔÅ ÐÏ ÁÄÒÅÓÕ %(HOST)s:%(PORT)s"
@@ -3262,6 +3335,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3278,6 +3352,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3294,6 +3369,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -4125,6 +4201,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4673,7 +4750,7 @@
 msgid "User listing"
 msgstr "óÐÉÓÏË ÐÏÌØÚÏ×ÁÔÅÌÅÊ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4681,13 +4758,13 @@
 msgid "Username"
 msgstr "ðÏÌØÚÏ×ÁÔÅÌØ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "éÍÑ, ÆÁÍÉÌÉÑ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4696,26 +4773,26 @@
 msgid "Organisation"
 msgstr "ïÒÇÁÎÉÚÁÃÉÑ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "áÄÒÅÓ email"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "ôÅÌÅÆÏÎ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "õ×ÏÌÉÔØ"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4866,67 +4943,67 @@
 "ÚÁËÏÎÞÉÔØ ÒÅÇÉÓÔÒÁÃÉÀ, ×ÙÚÏ×ÉÔÅ ÕËÁÚÁÎÎÕÀ × ÐÉÓØÍÅ ÓÓÙÌËÕ."
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "ËÒÉÔÉÞÅÓËÉÊ"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "ÓÒÏÞÎÙÊ"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "ÏÛÉÂËÁ"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "ÒÁÚ×ÉÔÉÅ"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr "ÐÏÖÅÌÁÎÉÅ"
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "ÎÏ×ÙÊ"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "ÏÔÌÏÖÅÎ"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "ÏÂÓÕÖÄÅÎÉÅ"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr "ÎÕÖÅÎ ÐÒÉÍÅÒ"
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "× ÒÁÂÏÔÅ"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "ÔÅÓÔÉÒÏ×ÁÎÉÅ"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "ÓÄÅÌÁÎÏ; ÍÏÖÎÏ ÕÌÕÞÛÉÔØ"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "ÓÄÅÌÁÎÏ"
 
--- a/locale/zh_CN.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/zh_CN.po	Thu Apr 21 16:54:17 2022 -0400
@@ -8,7 +8,7 @@
 msgstr ""
 "Project-Id-Version: 0.8.3\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:22+0100\n"
 "Last-Translator: Cheer Xiao <xiaqqaix@gmail.com>\n"
 "Language-Team: Chinese Simplified <limodou@gmail.com>\n"
@@ -31,19 +31,19 @@
 msgstr "ä½ ä¸èƒ½æ’¤é™¤ç®¡ç†å‘˜æˆ–匿å用户"
 
 # ../roundup/admin.py:84 :943 :992 :1014
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "无此类别 \"%(classname)s\""
 
 # ../roundup/admin.py:94 :98
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "傿•° \"%(arg)s\" 䏿˜¯ propname=value 的形å¼"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -52,7 +52,7 @@
 "问题: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -99,12 +99,12 @@
 " roundup-admin help <command>             -- 命令详解帮助\n"
 " roundup-admin help all                   -- 所有å¯ç”¨çš„帮助\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "命令:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -112,7 +112,7 @@
 "命令å¯ä»¥è¢«ç¼©å†™ï¼Œåªè¦ç¼©å†™åªæœ‰ä¸€ä¸ªå‘½ä»¤å¯ä»¥åŒ¹é…上,\n"
 "如:l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -235,12 +235,12 @@
 "\n"
 "使用帮助:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr "%s:"
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -260,22 +260,22 @@
 "        all       -- 所有å¯ç”¨çš„帮助\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "抱歉,没有“%(topic)sâ€çš„帮助信æ¯"
 
 # ../roundup/admin.py:337 :387
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "模æ¿:"
 
 # ../roundup/admin.py:340 :398
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "åŽç«¯:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 #, fuzzy
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
@@ -317,23 +317,23 @@
 
 # ../roundup/admin.py:359 :494 :573 :623 :676 :697 :725 :796 :863 :934 :982
 # :1004 :1031 :1093 :1159
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "未æä¾›è¶³å¤Ÿçš„傿•°"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "实例目录的父目录 \"%(parent)s\" ä¸å­˜åœ¨"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -344,22 +344,22 @@
 "å¦‚æžœä½ é‡æ–°å®‰è£…,所有的数æ®å°†ä¼šä¸¢å¤±ï¼\n"
 "删除它å—?Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "é€‰æ‹©æ¨¡æ¿ [classic]:"
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "选择åŽç«¯ [anydbm]:"
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "é…置设定有错: “%sâ€"
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -371,11 +371,11 @@
 " 现在你应该修改trackerçš„é…置文件:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... 至少,你必须设置以下选项:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -399,7 +399,7 @@
 "   %(database_init_file)s\n"
 " ... 查看关于客户化的文档æ¥äº†è§£æ›´å¤šçš„ä¿¡æ¯ã€‚\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -407,7 +407,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -417,7 +417,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -435,23 +435,23 @@
 "        执行trackerçš„åˆå§‹åŒ–函数 dbinit.init()\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "管ç†å‘˜å¯†ç :"
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       确认:"
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "实例目录ä¸å­˜åœ¨"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "实例还没有安装"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -461,7 +461,7 @@
 "å¦‚æžœä½ é‡æ–°åˆå§‹åŒ–它,所有的数æ®å°†ä¼šä¸¢å¤±ï¼\n"
 "删除它å—?Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -481,24 +481,24 @@
 "        "
 
 # ../roundup/admin.py:527 :542
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr "属性 %s 䏿˜¯ Multilink 或 Link 类型,所以 -d 标志ä¸èƒ½åº”用。"
 
 # ../roundup/admin.py:550 :945 :994 :1016
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "没有这样的 %(classname)s 结点 \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "没有这样的 %(classname)s 属性 \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -531,7 +531,7 @@
 "        你需è¦ä¸ºå¤šé“¾æŽ¥æä¾›ç”¨é€—å·åˆ†éš”的数字(例如 \"1,2,3\")。\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -553,20 +553,20 @@
 "        "
 
 # ../roundup/admin.py:663 :816 :828 :882
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s 没有 \"%(propname)s\" 属性"
 
 # ../roundup/admin.py:663 :816 :828 :882
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s 没有 \"%(propname)s\" 属性"
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -584,7 +584,7 @@
 "        或者是结点的键值。\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -598,17 +598,17 @@
 "        会列出给定类型的属性。\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (关键属性)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -628,12 +628,12 @@
 "        将显示给出结点的属性和相应的值。\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -651,31 +651,31 @@
 "name=value 傿•°ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (密ç ):"
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (冿¬¡):"
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "抱歉,å†è¯•一次..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "ä½ å¿…é¡»æä¾› \"%(propname)s\" 属性。"
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -701,16 +701,16 @@
 "        定了属性,对æ¯ä¸ªç±»åž‹å®žä¾‹ä¼šæ‰“å°å‡ºè¿™ä¸ªå±žæ€§ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "æä¾›äº†å¤ªå¤šçš„傿•°äº†"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr "%(nodeid)4s: %(value)s"
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -768,17 +768,17 @@
 "        将生æˆ4个字符宽的 \"Name\" 列。\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" 䏿˜¯ åå­—:宽度"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -793,7 +793,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -814,7 +814,7 @@
 "        在命令行中的 One-off 命令如果æˆåŠŸä¼šè¢«è‡ªåŠ¨æäº¤ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -833,7 +833,7 @@
 "        产生å˜åŒ–。\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -853,7 +853,7 @@
 "        它的键值å¯ä»¥è¢«é‡ç”¨ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -872,13 +872,13 @@
 "        "
 
 # ../roundup/admin.py:550 :945 :994 :1016
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "没有这样的 %(classname)s 结点 \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 #, fuzzy
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
@@ -903,7 +903,7 @@
 "        放在指定的目标目录中。\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 #, fuzzy
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
@@ -929,7 +929,7 @@
 "        放在指定的目标目录中。\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -969,7 +969,7 @@
 "        æ—§æ•°æ®ã€‚)\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -977,7 +977,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1015,11 +1015,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "无效的格å¼"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1034,12 +1034,12 @@
 "        釿–°ç”Ÿæˆ tracker çš„æœç´¢ç´¢å¼•,它将自动进行。\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "没有这样的æ¡ç›® \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1051,47 +1051,47 @@
 "        显示一个或多个角色的æƒé™ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "没有这样的角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "新Web用户得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "新Web用户得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "新邮件用户得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "新邮件用户得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "角色 \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s 仅用于 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr " %(description)s (%(name)s 仅用于 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1099,17 +1099,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s 仅用于 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s)"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1133,42 +1133,42 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 msgid "Tracker updated"
 msgstr "Tracker å·²ç»æ›´æ–°"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr "ä¸å¿…执行è¿ç§»"
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr "未知命令 \"%(command)s\" (\"help commands\" 查看命令列表)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "å¤šå‘½ä»¤åŒ¹é… \"%(command)s\": %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "输入tracker起始目录:"
 
 # ../roundup/admin.py:1279 :1285 :1305
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "错误:%(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "错误:ä¸èƒ½æ‰“å¼€tracker:%(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1177,41 +1177,41 @@
 "Roundup %s 输入就绪。\n"
 "敲入 \"help\" 获得帮助。"
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "注æ„:命令历å²å’Œç¼–辑无效"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr "roundup>"
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "退出..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "存在未被ä¿å­˜çš„æ”¹åŠ¨ã€‚æäº¤å—(y/N)?"
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1225,53 +1225,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "创建"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "解链"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "链接"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "修改"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "撤除"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "æ¢å¤"
 
@@ -1505,22 +1527,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "无效登录"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "你没有登录的æƒé™"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "你没有查看 %(class)s çš„æƒé™"
@@ -1617,160 +1644,167 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "表格错误:"
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "无法识别的字符集:%r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "匿å用户ä¸å…许使用 web 界é¢"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "无效登录"
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
+#, python-format
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
 #, fuzzy, python-format
-msgid "Invalid HOST %s"
-msgstr "无效请求"
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "Invalid Origin %s"
+msgstr "无效登录"
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, fuzzy, python-format
+msgid "Invalid HOST %s"
+msgstr "无效请求"
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 msgid "You are not allowed to view this file."
 msgstr "你没有查看此文件的æƒé™"
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, fuzzy, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1837,18 +1871,18 @@
 msgstr "æäº¤"
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr "[éšè—]"
 
@@ -1874,80 +1908,86 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "链接的类 %(classname)s ä¸å†å­˜åœ¨"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:872 :893
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>链接的结点ä¸å†å­˜åœ¨</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (无值)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr "<strong><em>这个事件ä¸èƒ½è¢«åކ岿˜¾ç¤ºæ‰€å¤„ç†ï¼</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>注æ„:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "历å²"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>日期</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "历å²"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>日期</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>用户</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>动作</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>傿•°</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, fuzzy, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "%(class)s %(id)s 被创建"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "å¦"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "是"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
 msgstr "DateHTMLProperty 的缺çœå€¼æˆ–者是 DateHTMLProperty 或字符串的日期表示。"
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- 未选择 -</option>"
@@ -1965,11 +2005,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "无效请求"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "无效请求"
+
 #: ../roundup/date.py:395
 #, python-format
 msgid ""
@@ -2120,23 +2172,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, python-format
 msgid "Not a property name: %s"
 msgstr "䏿˜¯å±žæ€§å: %s"
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2148,50 +2200,50 @@
 "\tcontains old-style template - ignored"
 msgstr ""
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "新消æ¯"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2208,7 +2260,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2219,7 +2271,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2236,7 +2288,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2247,7 +2299,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2257,7 +2309,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2266,21 +2318,21 @@
 "Unknown address: %(from_address)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 msgid "You are not permitted to access this tracker."
 msgstr "你没有访问此 tracker çš„æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "你没有编辑 %(classname)s çš„æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "你创建 %(classname)s çš„æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2290,38 +2342,38 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 msgid "You are not permitted to create files."
 msgstr "你没有创建文件的æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "ä½ æ²¡æœ‰å‘ %(classname)s 添加文件的æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
 "not find a text/plain part to use.\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 msgid "You are not permitted to create messages."
 msgstr "你没有创建消æ¯çš„æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2329,22 +2381,22 @@
 "%(error)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "ä½ æ²¡æœ‰å‘ %(classname)s 添加消æ¯çš„æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr "你没有编辑 %(classname)s 类的 %(prop)s 属性的æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr "你没有编辑 %(classname)s 类的 %(prop)s 属性的æƒé™ã€‚"
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2352,7 +2404,7 @@
 "   %(message)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, python-format
 msgid ""
 "\n"
@@ -2361,7 +2413,7 @@
 "  %(clsname)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2370,22 +2422,39 @@
 "  %(errors)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "无效登录"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2663,7 +2732,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2671,52 +2740,52 @@
 "<html><head><title>Roundup tracker 索引</title></head>\n"
 "<body><h1>Roundup tracker 索引</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "警告:忽略 \"-g\" 傿•°ï¼Œä¸æ˜¯ root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "ä¸èƒ½ä¿®æ”¹ç»„ - æ—  grp 模å—"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "组 %(group)s ä¸å­˜åœ¨"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "ä¸èƒ½ä»¥ root è¿è¡Œï¼"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "警告:忽略 \"-u\" 傿•°ï¼Œä¸æ˜¯ root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "ä¸èƒ½ä¿®æ”¹ç”¨æˆ· - æ—  pwd 模å—"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "用户 %(user)s ä¸å­˜åœ¨"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "æ— æ³•ç»‘å®šåˆ°ç«¯å£ %s, 端å£å·²ç»è¢«å ç”¨ã€‚"
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 #, fuzzy
 msgid ""
 " -c <Command>  Windows Service options.\n"
@@ -2733,7 +2802,7 @@
 "               å˜é‡ä¸Šé…置一个tracker。这个选项与其ç»é€‰é¡¹æ˜¯äº’斥的。打入\n"
 "               \"roundup-server -c help\" æ¥äº†è§£WindowsæœåŠ¡çš„è§„èŒƒã€‚"
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2747,9 +2816,10 @@
 "去。\n"
 "               如果使用了 -d 选项,则 -l 选项 *å¿…é¡»* è¦æŒ‡å®šã€‚"
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2772,6 +2842,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2839,20 +2912,20 @@
 "   æ„æ•°é‡çš„ name=home 对。è¦ç¡®ä¿ name 部分ä¸èƒ½åŒ…括任何éžurl安全的\n"
 "   字符,象空格,因为它们会把IEæžä¹±ã€‚\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "实例必须是 实例å=实例路径"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "é…ç½®ä¿å­˜åˆ° %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr "抱歉,在这个æ“作系统上ä¸èƒ½ä»¥å®ˆæŠ¤è¿›ç¨‹çš„æ–¹å¼æ¥è¿è¡ŒæœåŠ¡"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Roundup server å¯åŠ¨äºŽ %(HOST)s:%(PORT)s"
@@ -2987,6 +3060,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3003,6 +3077,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3019,6 +3094,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3843,6 +3919,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4381,7 +4458,7 @@
 msgid "User listing"
 msgstr "用户列表"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4389,13 +4466,13 @@
 msgid "Username"
 msgstr "用户å"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "真实姓å"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4404,26 +4481,26 @@
 msgid "Organisation"
 msgstr "组织"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "邮件地å€"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "电è¯å·ç "
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "撤除"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4572,67 +4649,67 @@
 msgstr "你将很快收到一å°ç¡®è®¤ä¿¡ã€‚访问邮件中指示的链接,å³å¯å®Œæˆæ³¨å†Œã€‚"
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr "关键"
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr "紧急"
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr "bug"
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr "特性"
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr "未读"
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr "延期"
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr "讨论中"
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr "进行中"
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 msgid "testing"
 msgstr "测试中"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr "done-cbb"
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 msgid "resolved"
 msgstr "已解决"
 
--- a/locale/zh_TW.po	Fri Oct 08 00:37:16 2021 -0400
+++ b/locale/zh_TW.po	Thu Apr 21 16:54:17 2022 -0400
@@ -7,7 +7,7 @@
 msgstr ""
 "Project-Id-Version: 0.8.3\n"
 "Report-Msgid-Bugs-To: roundup-devel@lists.sourceforge.net\n"
-"POT-Creation-Date: 2021-07-12 22:10-0400\n"
+"POT-Creation-Date: 2022-03-05 18:51-0500\n"
 "PO-Revision-Date: 2013-10-31 12:23+0100\n"
 "Last-Translator: Fred Lin <gasolin@gmail>\n"
 "Language-Team: Chinese Traditional <gasolin@gmail.com>\n"
@@ -30,19 +30,19 @@
 msgstr "ä½ ä¸èƒ½åˆªé™¤ç®¡ç†å“¡æˆ–匿å用戶"
 
 # ../roundup/admin.py:84 :943 :992 :1014
-#: ../roundup/admin.py:95 ../roundup/admin.py:1173 ../roundup/admin.py:1228
-#: ../roundup/admin.py:1255 ../roundup/admin.py:95:1173 :1228:1255
+#: ../roundup/admin.py:99 ../roundup/admin.py:1199 ../roundup/admin.py:1254
+#: ../roundup/admin.py:1281 ../roundup/admin.py:99:1199 :1254:1281
 #, python-format
 msgid "no such class \"%(classname)s\""
 msgstr "無此類別 \"%(classname)s\""
 
 # ../roundup/admin.py:94 :98
-#: ../roundup/admin.py:107
+#: ../roundup/admin.py:111
 #, python-format
 msgid "argument \"%(arg)s\" not propname=value"
 msgstr "åƒæ•¸ \"%(arg)s\" 䏿˜¯ propname=value 的形å¼"
 
-#: ../roundup/admin.py:120
+#: ../roundup/admin.py:124
 #, python-format
 msgid ""
 "Problem: %(message)s\n"
@@ -51,7 +51,7 @@
 "å•題: %(message)s\n"
 "\n"
 
-#: ../roundup/admin.py:121
+#: ../roundup/admin.py:125
 #, fuzzy, python-format
 msgid ""
 "%(message)sUsage: roundup-admin [options] [<command> <arguments>]\n"
@@ -98,12 +98,12 @@
 " roundup-admin help <command>             -- 命令詳解說明\n"
 " roundup-admin help all                   -- 所有å¯ç”¨çš„說明\n"
 
-#: ../roundup/admin.py:148
+#: ../roundup/admin.py:152
 #, fuzzy
 msgid "Commands: "
 msgstr "命令:"
 
-#: ../roundup/admin.py:155
+#: ../roundup/admin.py:159
 msgid ""
 "Commands may be abbreviated as long as the abbreviation\n"
 "matches only one command, e.g. l == li == lis == list."
@@ -111,7 +111,7 @@
 "命令å¯ä»¥è¢«ç¸®å¯«ï¼Œåªè¦ç¸®å¯«åªæœ‰ä¸€å€‹å‘½ä»¤å¯ä»¥åŒ¹é…上,\n"
 "如:l == li == lis == list."
 
-#: ../roundup/admin.py:182
+#: ../roundup/admin.py:186
 msgid ""
 "\n"
 "All commands (except help) require a tracker specifier. This is just\n"
@@ -233,12 +233,12 @@
 "\n"
 "使用說明:\n"
 
-#: ../roundup/admin.py:245
+#: ../roundup/admin.py:249
 #, python-format
 msgid "%s:"
 msgstr ""
 
-#: ../roundup/admin.py:250
+#: ../roundup/admin.py:254
 msgid ""
 "Usage: help topic\n"
 "        Give help about topic.\n"
@@ -258,22 +258,22 @@
 "        all       -- 所有å¯ç”¨çš„說明\n"
 "        "
 
-#: ../roundup/admin.py:272
+#: ../roundup/admin.py:276
 #, python-format
 msgid "Sorry, no help for \"%(topic)s\""
 msgstr "æŠ±æ­‰ï¼Œæ²’æœ‰å° \"%(topic)s\" 的說明信æ¯"
 
 # ../roundup/admin.py:337 :387
-#: ../roundup/admin.py:349 ../roundup/admin.py:405 ../roundup/admin.py:349:405
+#: ../roundup/admin.py:375 ../roundup/admin.py:431 ../roundup/admin.py:375:431
 msgid "Templates:"
 msgstr "模æ¿ï¼š"
 
 # ../roundup/admin.py:340 :398
-#: ../roundup/admin.py:352 ../roundup/admin.py:415 ../roundup/admin.py:352:415
+#: ../roundup/admin.py:378 ../roundup/admin.py:441 ../roundup/admin.py:378:441
 msgid "Back ends:"
 msgstr "後端:"
 
-#: ../roundup/admin.py:355
+#: ../roundup/admin.py:381
 #, fuzzy
 msgid ""
 "Usage: install [template [backend [key=val[,key=val]]]]\n"
@@ -315,23 +315,23 @@
 
 # ../roundup/admin.py:359 :494 :573 :623 :676 :697 :725 :796 :863 :934 :982
 # :1004 :1031 :1093 :1159
-#: ../roundup/admin.py:378 ../roundup/admin.py:510 ../roundup/admin.py:583
-#: ../roundup/admin.py:674 ../roundup/admin.py:732 ../roundup/admin.py:816
-#: ../roundup/admin.py:875 ../roundup/admin.py:902 ../roundup/admin.py:929
-#: ../roundup/admin.py:1004 ../roundup/admin.py:1071 ../roundup/admin.py:1157
-#: ../roundup/admin.py:1218 ../roundup/admin.py:1245 ../roundup/admin.py:1281
-#: ../roundup/admin.py:1412 ../roundup/admin.py:1499
-#: ../roundup/admin.py:378:510 :1071 :1157:1218 :1245:1281 :1412:1499 :583:674
-#: :732:816 :875:902 :929:1004
+#: ../roundup/admin.py:404 ../roundup/admin.py:536 ../roundup/admin.py:609
+#: ../roundup/admin.py:700 ../roundup/admin.py:758 ../roundup/admin.py:842
+#: ../roundup/admin.py:901 ../roundup/admin.py:928 ../roundup/admin.py:955
+#: ../roundup/admin.py:1030 ../roundup/admin.py:1097 ../roundup/admin.py:1183
+#: ../roundup/admin.py:1244 ../roundup/admin.py:1271 ../roundup/admin.py:1307
+#: ../roundup/admin.py:1435 ../roundup/admin.py:1522
+#: ../roundup/admin.py:404:536 :1097 :1183:1244 :1271:1307 :1435:1522 :609:700
+#: :758:842 :901:928 :955:1030
 msgid "Not enough arguments supplied"
 msgstr "未æä¾›è¶³å¤ çš„åƒæ•¸"
 
-#: ../roundup/admin.py:384
+#: ../roundup/admin.py:410
 #, python-format
 msgid "Instance home parent directory \"%(parent)s\" does not exist"
 msgstr "實例目錄的父目錄 \"%(parent)s\" ä¸å­˜åœ¨"
 
-#: ../roundup/admin.py:393
+#: ../roundup/admin.py:419
 #, python-format
 msgid ""
 "WARNING: There appears to be a tracker in \"%(tracker_home)s\"!\n"
@@ -342,22 +342,22 @@
 "å¦‚æžœä½ æ‰“ç®—é‡æ–°å®‰è£å®ƒï¼Œæ‰€æœ‰çš„æ•¸æ“šå°‡æœƒä¸Ÿå¤±ï¼\n"
 "刪除它嗎?Y/N: "
 
-#: ../roundup/admin.py:406
+#: ../roundup/admin.py:432
 #, fuzzy
 msgid "Select template"
 msgstr "鏿“‡æ¨¡æ¿ [classic]:"
 
-#: ../roundup/admin.py:416
+#: ../roundup/admin.py:442
 #, fuzzy
 msgid "Select backend"
 msgstr "鏿“‡å¾Œç«¯ [anydbm]:"
 
-#: ../roundup/admin.py:427
+#: ../roundup/admin.py:453
 #, fuzzy, python-format
 msgid "Error in configuration settings: \"%s\""
 msgstr "é…ç½®ä¿å­˜åˆ° %s"
 
-#: ../roundup/admin.py:458
+#: ../roundup/admin.py:484
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -369,11 +369,11 @@
 " ç¾åœ¨ä½ æ‡‰è©²ä¿®æ”¹trackerçš„é…置文件:\n"
 "   %(config_file)s"
 
-#: ../roundup/admin.py:468
+#: ../roundup/admin.py:494
 msgid " ... at a minimum, you must set following options:"
 msgstr " ... 至少,你必須設置以下é¸é …:"
 
-#: ../roundup/admin.py:473
+#: ../roundup/admin.py:499
 #, fuzzy, python-format
 msgid ""
 "\n"
@@ -397,7 +397,7 @@
 "   %(database_init_file)s\n"
 " ... 查看關於客戶化的文檔來瞭解更多的信æ¯ã€‚\n"
 
-#: ../roundup/admin.py:505
+#: ../roundup/admin.py:531
 msgid ""
 "Usage: genconfig <filename>\n"
 "        Generate a new tracker config file (ini style) with default\n"
@@ -405,7 +405,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:520
+#: ../roundup/admin.py:546
 msgid ""
 "Usage: updateconfig <filename>\n"
 "        Generate an updated tracker config file (ini style) in\n"
@@ -415,7 +415,7 @@
 msgstr ""
 
 #. password
-#: ../roundup/admin.py:528
+#: ../roundup/admin.py:554
 msgid ""
 "Usage: initialise [adminpw]\n"
 "        Initialise a new Roundup tracker.\n"
@@ -433,23 +433,23 @@
 "        執行trackerçš„åˆå§‹åŒ–函數 dbinit.init()\n"
 "        "
 
-#: ../roundup/admin.py:542
+#: ../roundup/admin.py:568
 msgid "Admin Password: "
 msgstr "管ç†å“¡å£ä»¤ï¼š"
 
-#: ../roundup/admin.py:543
+#: ../roundup/admin.py:569
 msgid "       Confirm: "
 msgstr "       確èªï¼š"
 
-#: ../roundup/admin.py:547
+#: ../roundup/admin.py:573
 msgid "Instance home does not exist"
 msgstr "實例目錄ä¸å­˜åœ¨"
 
-#: ../roundup/admin.py:551
+#: ../roundup/admin.py:577
 msgid "Instance has not been installed"
 msgstr "實例還沒有安è£"
 
-#: ../roundup/admin.py:557
+#: ../roundup/admin.py:583
 msgid ""
 "WARNING: The database is already initialised!\n"
 "If you re-initialise it, you will lose all the data!\n"
@@ -459,7 +459,7 @@
 "å¦‚æžœä½ é‡æ–°åˆå§‹åŒ–它,所有的數據將會丟失ï¼\n"
 "刪除它嗎?Y/N: "
 
-#: ../roundup/admin.py:573
+#: ../roundup/admin.py:599
 #, fuzzy
 msgid ""
 "Usage: get property designator[,designator]*\n"
@@ -479,24 +479,24 @@
 "        "
 
 # ../roundup/admin.py:527 :542
-#: ../roundup/admin.py:616 ../roundup/admin.py:633 ../roundup/admin.py:616:633
+#: ../roundup/admin.py:642 ../roundup/admin.py:659 ../roundup/admin.py:642:659
 #, python-format
 msgid "property %s is not of type Multilink or Link so -d flag does not apply."
 msgstr "屬性 %s 䏿˜¯ Multilink 或 Link 類型,所以 -d 標誌ä¸èƒ½æ‡‰ç”¨ã€‚"
 
 # ../roundup/admin.py:550 :945 :994 :1016
-#: ../roundup/admin.py:643 ../roundup/admin.py:1175 ../roundup/admin.py:1230
-#: ../roundup/admin.py:643:1175:1230
+#: ../roundup/admin.py:669 ../roundup/admin.py:1201 ../roundup/admin.py:1256
+#: ../roundup/admin.py:669:1201:1256
 #, python-format
 msgid "no such %(classname)s node \"%(nodeid)s\""
 msgstr "沒有這樣的 %(classname)s çµé»ž \"%(nodeid)s\""
 
-#: ../roundup/admin.py:646
+#: ../roundup/admin.py:672
 #, python-format
 msgid "no such %(classname)s property \"%(propname)s\""
 msgstr "沒有這樣的 %(classname)s 屬性 \"%(propname)s\""
 
-#: ../roundup/admin.py:654
+#: ../roundup/admin.py:680
 #, fuzzy
 msgid ""
 "Usage: set items property=value property=value ...\n"
@@ -529,7 +529,7 @@
 "        你需è¦ç‚ºå¤šéˆæŽ¥æä¾›ç”¨é€—號分隔的數字(例如 \"1,2,3\")。\n"
 "        "
 
-#: ../roundup/admin.py:722
+#: ../roundup/admin.py:748
 #, fuzzy
 msgid ""
 "Usage: filter classname propname=value ...\n"
@@ -551,20 +551,20 @@
 "        "
 
 # ../roundup/admin.py:663 :816 :828 :882
-#: ../roundup/admin.py:764
+#: ../roundup/admin.py:790
 #, fuzzy, python-format
 msgid "Class %(curclassname)s has no property %(pn)s in %(propname)s."
 msgstr "%(classname)s 沒有 \"%(propname)s\" 屬性"
 
 # ../roundup/admin.py:663 :816 :828 :882
-#: ../roundup/admin.py:801 ../roundup/admin.py:862 ../roundup/admin.py:1024
-#: ../roundup/admin.py:1036 ../roundup/admin.py:1091
-#: ../roundup/admin.py:801:862 :1024:1036:1091
+#: ../roundup/admin.py:827 ../roundup/admin.py:888 ../roundup/admin.py:1050
+#: ../roundup/admin.py:1062 ../roundup/admin.py:1117
+#: ../roundup/admin.py:827:888 :1050:1062:1117
 #, python-format
 msgid "%(classname)s has no property \"%(propname)s\""
 msgstr "%(classname)s 沒有 \"%(propname)s\" 屬性"
 
-#: ../roundup/admin.py:808
+#: ../roundup/admin.py:834
 msgid ""
 "Usage: find classname propname=value ...\n"
 "        Find the nodes of the given class with a given link property value.\n"
@@ -582,7 +582,7 @@
 "        或者是çµé»žçš„éµå€¼ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:869
+#: ../roundup/admin.py:895
 msgid ""
 "Usage: specification classname\n"
 "        Show the properties for a classname.\n"
@@ -596,17 +596,17 @@
 "        會列出給定類型的屬性。\n"
 "        "
 
-#: ../roundup/admin.py:885
+#: ../roundup/admin.py:911
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s (key property)\n"
 msgstr "%(key)s: %(value)s (é—œéµå±¬æ€§)"
 
-#: ../roundup/admin.py:888
+#: ../roundup/admin.py:914
 #, fuzzy, python-format
 msgid "%(key)s: %(value)s\n"
 msgstr "%(key)s: %(value)s (é—œéµå±¬æ€§)"
 
-#: ../roundup/admin.py:891
+#: ../roundup/admin.py:917
 #, fuzzy
 msgid ""
 "Usage: display designator[,designator]*\n"
@@ -626,12 +626,12 @@
 "        將顯示給出çµé»žçš„屬性和相應的值。\n"
 "        "
 
-#: ../roundup/admin.py:918
+#: ../roundup/admin.py:944
 #, python-format
 msgid "%(key)s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:921
+#: ../roundup/admin.py:947
 msgid ""
 "Usage: create classname property=value ...\n"
 "        Create a new entry of a given class.\n"
@@ -649,31 +649,31 @@
 "name=value åƒæ•¸ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:949
+#: ../roundup/admin.py:975
 #, python-format
 msgid "%(propname)s (Password): "
 msgstr "%(propname)s (å£ä»¤):"
 
-#: ../roundup/admin.py:952
+#: ../roundup/admin.py:978
 #, python-format
 msgid "   %(propname)s (Again): "
 msgstr "   %(propname)s (冿¬¡):"
 
-#: ../roundup/admin.py:955
+#: ../roundup/admin.py:981
 msgid "Sorry, try again..."
 msgstr "抱歉,å†è©¦ä¸€æ¬¡..."
 
-#: ../roundup/admin.py:959
+#: ../roundup/admin.py:985
 #, python-format
 msgid "%(propname)s (%(proptype)s): "
 msgstr ""
 
-#: ../roundup/admin.py:977
+#: ../roundup/admin.py:1003
 #, python-format
 msgid "you must provide the \"%(propname)s\" property."
 msgstr "ä½ å¿…é ˆæä¾› \"%(propname)s\" 屬性。"
 
-#: ../roundup/admin.py:989
+#: ../roundup/admin.py:1015
 msgid ""
 "Usage: list classname [property]\n"
 "        List the instances of a class.\n"
@@ -699,16 +699,16 @@
 "        å®šäº†å±¬æ€§ï¼Œå°æ¯å€‹é¡žåž‹å¯¦ä¾‹æœƒåˆ—å°å‡ºé€™å€‹å±¬æ€§ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1002
+#: ../roundup/admin.py:1028
 msgid "Too many arguments supplied"
 msgstr "æä¾›äº†å¤ªå¤šçš„åƒæ•¸äº†"
 
-#: ../roundup/admin.py:1038
+#: ../roundup/admin.py:1064
 #, python-format
 msgid "%(nodeid)4s: %(value)s"
 msgstr ""
 
-#: ../roundup/admin.py:1042
+#: ../roundup/admin.py:1068
 msgid ""
 "Usage: table classname [property[,property]*]\n"
 "        List the instances of a class in tabular form.\n"
@@ -766,17 +766,17 @@
 "        將生æˆ4個字符寬的 \"Name\" 列。\n"
 "        "
 
-#: ../roundup/admin.py:1086
+#: ../roundup/admin.py:1112
 #, python-format
 msgid "\"%(spec)s\" not name:width"
 msgstr "\"%(spec)s\" 䏿˜¯ åå­—:寬度"
 
-#: ../roundup/admin.py:1108
+#: ../roundup/admin.py:1134
 #, python-format
 msgid "\"%(spec)s\" does not have an integer width: \"%(width)s\""
 msgstr ""
 
-#: ../roundup/admin.py:1144
+#: ../roundup/admin.py:1170
 msgid ""
 "Usage: history designator [skipquiet]\n"
 "        Show the history entries of a designator.\n"
@@ -791,7 +791,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1180
+#: ../roundup/admin.py:1206
 msgid ""
 "Usage: commit\n"
 "        Commit changes made to the database during an interactive session.\n"
@@ -812,7 +812,7 @@
 "        在命令行中的 One-off 命令如果æˆåŠŸæœƒè¢«è‡ªå‹•æäº¤ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1195
+#: ../roundup/admin.py:1221
 msgid ""
 "Usage: rollback\n"
 "        Undo all changes that are pending commit to the database.\n"
@@ -831,7 +831,7 @@
 "        產生變化。\n"
 "        "
 
-#: ../roundup/admin.py:1208
+#: ../roundup/admin.py:1234
 #, fuzzy
 msgid ""
 "Usage: retire designator[,designator]*\n"
@@ -851,7 +851,7 @@
 "        它的éµå€¼å¯ä»¥è¢«é‡ç”¨ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1236
+#: ../roundup/admin.py:1262
 #, fuzzy
 msgid ""
 "Usage: restore designator[,designator]*\n"
@@ -870,13 +870,13 @@
 "        "
 
 # ../roundup/admin.py:550 :945 :994 :1016
-#: ../roundup/admin.py:1261
+#: ../roundup/admin.py:1287
 #, fuzzy
 msgid "no such %(classname)s node \" % (nodeid)s\""
 msgstr "沒有這樣的 %(classname)s çµé»ž \"%(nodeid)s\""
 
 #. grab the directory to export to
-#: ../roundup/admin.py:1267
+#: ../roundup/admin.py:1293
 #, fuzzy
 msgid ""
 "Usage: export [[-]class[,class]] export_dir\n"
@@ -901,7 +901,7 @@
 "        放在指定的目標目錄中。\n"
 "        "
 
-#: ../roundup/admin.py:1377
+#: ../roundup/admin.py:1400
 #, fuzzy
 msgid ""
 "Usage: exporttables [[-]class[,class]] export_dir\n"
@@ -927,7 +927,7 @@
 "        放在指定的目標目錄中。\n"
 "        "
 
-#: ../roundup/admin.py:1392
+#: ../roundup/admin.py:1415
 msgid ""
 "Usage: import import_dir\n"
 "        Import a database from the directory containing CSV files,\n"
@@ -967,7 +967,7 @@
 "        舊數據。)\n"
 "        "
 
-#: ../roundup/admin.py:1474
+#: ../roundup/admin.py:1497
 msgid ""
 "Usage: importtables export_dir\n"
 "\n"
@@ -975,7 +975,7 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1481
+#: ../roundup/admin.py:1504
 msgid ""
 "Usage: pack period | date\n"
 "\n"
@@ -1013,11 +1013,11 @@
 "\n"
 "        "
 
-#: ../roundup/admin.py:1509
+#: ../roundup/admin.py:1532
 msgid "Invalid format"
 msgstr "無效的格å¼"
 
-#: ../roundup/admin.py:1520
+#: ../roundup/admin.py:1543
 msgid ""
 "Usage: reindex [classname|designator]*\n"
 "        Re-generate a tracker's search indexes.\n"
@@ -1032,12 +1032,12 @@
 "        釿–°ç”Ÿæˆ tracker çš„æœç´¢ç´¢å¼•,它將自動進行。\n"
 "        "
 
-#: ../roundup/admin.py:1534
+#: ../roundup/admin.py:1557
 #, python-format
 msgid "no such item \"%(designator)s\""
 msgstr "沒有這樣的æ¢ç›® \"%(designator)s\""
 
-#: ../roundup/admin.py:1544
+#: ../roundup/admin.py:1567
 #, fuzzy
 msgid ""
 "Usage: security [Role name]\n"
@@ -1049,47 +1049,47 @@
 "        顯示一個或多個角色的權é™ã€‚\n"
 "        "
 
-#: ../roundup/admin.py:1553
+#: ../roundup/admin.py:1576
 #, fuzzy, python-format
 msgid "No such Role \"%(role)s\"\n"
 msgstr "沒有這樣的角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1559
+#: ../roundup/admin.py:1582
 #, fuzzy, python-format
 msgid "New Web users get the Roles \"%(role)s\"\n"
 msgstr "新Web用戶得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1562
+#: ../roundup/admin.py:1585
 #, fuzzy, python-format
 msgid "New Web users get the Role \"%(role)s\"\n"
 msgstr "新Web用戶得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1566
+#: ../roundup/admin.py:1589
 #, fuzzy, python-format
 msgid "New Email users get the Roles \"%(role)s\"\n"
 msgstr "新郵件用戶得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1568
+#: ../roundup/admin.py:1591
 #, fuzzy, python-format
 msgid "New Email users get the Role \"%(role)s\"\n"
 msgstr "新郵件用戶得到角色 \"%(role)s\""
 
-#: ../roundup/admin.py:1571
+#: ../roundup/admin.py:1594
 #, fuzzy, python-format
 msgid "Role \"%(name)s\":\n"
 msgstr "角色 \"%(name)s\":"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy
 msgid " %(description)s (%(name)s for \"%(klass)s\""
 msgstr " %(description)s (%(name)s 僅用於 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1576
+#: ../roundup/admin.py:1599
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\": %(properties)s only)\n"
 msgstr " %(description)s (%(name)s 僅用於 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1588
+#: ../roundup/admin.py:1611
 #, python-format
 msgid ""
 "\n"
@@ -1097,17 +1097,17 @@
 "\n"
 msgstr ""
 
-#: ../roundup/admin.py:1591
+#: ../roundup/admin.py:1614
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s for \"%(klass)s\" only)\n"
 msgstr " %(description)s (%(name)s 僅用於 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1594
+#: ../roundup/admin.py:1617
 #, fuzzy, python-format
 msgid " %(description)s (%(name)s)\n"
 msgstr " %(description)s (%(name)s 僅用於 \"%(klass)s\")"
 
-#: ../roundup/admin.py:1598
+#: ../roundup/admin.py:1621
 msgid ""
 "Usage: migrate\n"
 "\n"
@@ -1131,43 +1131,43 @@
 "        "
 msgstr ""
 
-#: ../roundup/admin.py:1619
+#: ../roundup/admin.py:1642
 #, fuzzy
 msgid "Tracker updated"
 msgstr "Tracker根目錄"
 
-#: ../roundup/admin.py:1622
+#: ../roundup/admin.py:1645
 msgid "No migration action required"
 msgstr ""
 
-#: ../roundup/admin.py:1648
+#: ../roundup/admin.py:1671
 #, python-format
 msgid "Unknown command \"%(command)s\" (\"help commands\" for a list)"
 msgstr "未知命令 \"%(command)s\" (\"help commands\" 查看命令列表)"
 
-#: ../roundup/admin.py:1654
+#: ../roundup/admin.py:1677
 #, python-format
 msgid "Multiple commands match \"%(command)s\": %(list)s"
 msgstr "å¤šå‘½ä»¤åŒ¹é… \"%(command)s\": %(list)s"
 
-#: ../roundup/admin.py:1663
+#: ../roundup/admin.py:1686
 msgid "Enter tracker home: "
 msgstr "輸入tracker起始目錄:"
 
 # ../roundup/admin.py:1279 :1285 :1305
-#: ../roundup/admin.py:1672 ../roundup/admin.py:1678 ../roundup/admin.py:1704
-#: ../roundup/admin.py:1672:1678:1704
+#: ../roundup/admin.py:1695 ../roundup/admin.py:1701 ../roundup/admin.py:1730
+#: ../roundup/admin.py:1695:1701:1730
 #, python-format
 msgid "Error: %(message)s"
 msgstr "錯誤:%(message)s"
 
-#: ../roundup/admin.py:1686 ../roundup/admin.py:1690
-#: ../roundup/admin.py:1686:1690
+#: ../roundup/admin.py:1709 ../roundup/admin.py:1713
+#: ../roundup/admin.py:1709:1713
 #, python-format
 msgid "Error: Couldn't open tracker: %(message)s"
 msgstr "錯誤:ä¸èƒ½æ‰“é–‹tracker:%(message)s"
 
-#: ../roundup/admin.py:1717
+#: ../roundup/admin.py:1743
 #, python-format
 msgid ""
 "Roundup %s ready for input.\n"
@@ -1176,41 +1176,41 @@
 "Roundup %s 輸入就緒。\n"
 "敲入 \"help\" ç²å¾—說明。"
 
-#: ../roundup/admin.py:1722
+#: ../roundup/admin.py:1748
 msgid "Note: command history and editing not available"
 msgstr "注æ„:命令歷å²å’Œç·¨è¼¯ç„¡æ•ˆ"
 
-#: ../roundup/admin.py:1726
+#: ../roundup/admin.py:1752
 msgid "roundup> "
 msgstr ""
 
-#: ../roundup/admin.py:1728
+#: ../roundup/admin.py:1754
 msgid "exit..."
 msgstr "退出..."
 
-#: ../roundup/admin.py:1741
+#: ../roundup/admin.py:1767
 msgid "There are unsaved changes. Commit them (y/N)? "
 msgstr "存在未被ä¿å­˜çš„æ”¹å‹•。æäº¤å—Ž(y/N)?"
 
-#: ../roundup/backends/back_anydbm.py:173
-#: ../roundup/backends/rdbms_common.py:877
+#: ../roundup/backends/back_anydbm.py:173 ../roundup/backends/back_lmdb.py:251
+#: ../roundup/backends/rdbms_common.py:887
 #, python-format
 msgid "Class \"%s\" already defined."
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:234
+#: ../roundup/backends/back_anydbm.py:234 ../roundup/backends/back_lmdb.py:312
 #: ../roundup/backends/sessions_dbm.py:55
 msgid "Couldn't identify database type"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:268
+#: ../roundup/backends/back_anydbm.py:268 ../roundup/backends/back_lmdb.py:346
 #, python-format
 msgid ""
 "Couldn't open database - the required module '%s' (as dbm.gnu) is not "
 "available"
 msgstr ""
 
-#: ../roundup/backends/back_anydbm.py:271
+#: ../roundup/backends/back_anydbm.py:271 ../roundup/backends/back_lmdb.py:349
 #, python-format
 msgid "Couldn't open database - the required module '%s' is not available"
 msgstr ""
@@ -1224,53 +1224,75 @@
 #: ../roundup/backends/back_anydbm.py:1438
 #: ../roundup/backends/back_anydbm.py:2063
 #: ../roundup/backends/back_anydbm.py:827:840
-#: ../roundup/backends/rdbms_common.py:1646
-#: ../roundup/backends/rdbms_common.py:1893
-#: ../roundup/backends/rdbms_common.py:2128
-#: ../roundup/backends/rdbms_common.py:2148
-#: ../roundup/backends/rdbms_common.py:2201
-#: ../roundup/backends/rdbms_common.py:3147
-#: ../roundup/backends/rdbms_common.py:1646:1893 :1113:1148 :1374:1392:1438
-#: :2063 :2128:2148 :2201:3147
+#: ../roundup/backends/back_lmdb.py:905 ../roundup/backends/back_lmdb.py:918
+#: ../roundup/backends/back_lmdb.py:1191 ../roundup/backends/back_lmdb.py:1226
+#: ../roundup/backends/back_lmdb.py:1452 ../roundup/backends/back_lmdb.py:1470
+#: ../roundup/backends/back_lmdb.py:1516 ../roundup/backends/back_lmdb.py:2138
+#: ../roundup/backends/back_lmdb.py:905:918
+#: ../roundup/backends/rdbms_common.py:1656
+#: ../roundup/backends/rdbms_common.py:1903
+#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2158
+#: ../roundup/backends/rdbms_common.py:2211
+#: ../roundup/backends/rdbms_common.py:3157
+#: ../roundup/backends/rdbms_common.py:1656:1903 :1113:1148 :1191:1226
+#: :1374:1392:1438 :1452:1470 :1516:2138:2063 :2138:2158:2211 :3157
 msgid "Database open read-only"
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:580
+#: ../roundup/backends/indexer_postgresql_fts.py:108
+msgid ""
+"You have non-word/operator characters \"<>!&|()*\" in your query. Did you "
+"want to do a tsquery search and forgot to start it with \"ts:\"?"
+msgstr ""
+
+#: ../roundup/backends/indexer_postgresql_fts.py:135
+#, python-format
+msgid ""
+"Check tracker config.ini for a bad indexer_language setting. Error is: %s"
+msgstr ""
+
+#: ../roundup/backends/indexer_sqlite_fts.py:117
+msgid ""
+"Search failed. Try quoting any terms that include a '-' and retry the search."
+msgstr ""
+
+#: ../roundup/backends/rdbms_common.py:590
 #, python-format
 msgid "ALTER operation disallowed: %(old)r -> %(new)r."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:816
+#: ../roundup/backends/rdbms_common.py:826
 #, python-format
 msgid "CREATE operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:833
+#: ../roundup/backends/rdbms_common.py:843
 #, python-format
 msgid "DROP operation disallowed: \"%s\"."
 msgstr ""
 
-#: ../roundup/backends/rdbms_common.py:1789
+#: ../roundup/backends/rdbms_common.py:1799
 msgid "create"
 msgstr "建立"
 
-#: ../roundup/backends/rdbms_common.py:1963
+#: ../roundup/backends/rdbms_common.py:1973
 msgid "unlink"
 msgstr "解除"
 
-#: ../roundup/backends/rdbms_common.py:1967
+#: ../roundup/backends/rdbms_common.py:1977
 msgid "link"
 msgstr "éˆæŽ¥"
 
-#: ../roundup/backends/rdbms_common.py:2109
+#: ../roundup/backends/rdbms_common.py:2119
 msgid "set"
 msgstr "設置"
 
-#: ../roundup/backends/rdbms_common.py:2138
+#: ../roundup/backends/rdbms_common.py:2148
 msgid "retired"
 msgstr "收回"
 
-#: ../roundup/backends/rdbms_common.py:2168
+#: ../roundup/backends/rdbms_common.py:2178
 msgid "restored"
 msgstr "æ¢å¾©"
 
@@ -1507,22 +1529,27 @@
 msgid "Logins occurring too fast. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1369 ../roundup/cgi/actions.py:1373
-#: ../roundup/cgi/actions.py:1369:1373
+#: ../roundup/cgi/actions.py:1357
+#, python-format
+msgid "Welcome %(username)s!"
+msgstr ""
+
+#: ../roundup/cgi/actions.py:1377 ../roundup/cgi/actions.py:1381
+#: ../roundup/cgi/actions.py:1377:1381
 msgid "Invalid login"
 msgstr "無效登錄"
 
-#: ../roundup/cgi/actions.py:1379
+#: ../roundup/cgi/actions.py:1387
 msgid "You do not have permission to login"
 msgstr "你沒有登錄的權é™"
 
-#: ../roundup/cgi/actions.py:1422 ../roundup/cgi/actions.py:1587
-#: ../roundup/cgi/actions.py:1422:1587
+#: ../roundup/cgi/actions.py:1430 ../roundup/cgi/actions.py:1609
+#: ../roundup/cgi/actions.py:1430:1609
 #, python-format
 msgid "Column \"%(column)s\" not found in %(class)s"
 msgstr ""
 
-#: ../roundup/cgi/actions.py:1643
+#: ../roundup/cgi/actions.py:1680
 #, fuzzy, python-format
 msgid "You do not have permission to view %(class)s"
 msgstr "你沒有權é™ä¾†ç·¨è¼¯ %(class)s"
@@ -1619,161 +1646,168 @@
 "</body></html>"
 msgstr ""
 
-#: ../roundup/cgi/client.py:795
+#: ../roundup/cgi/client.py:837
 msgid "Form Error: "
 msgstr "表格錯誤:"
 
-#: ../roundup/cgi/client.py:885
+#: ../roundup/cgi/client.py:927
 #, python-format
 msgid "Unrecognized charset: %r"
 msgstr "無法識別的字符集:%r"
 
-#: ../roundup/cgi/client.py:1141
+#: ../roundup/cgi/client.py:1183
 msgid "Anonymous users are not allowed to use the web interface"
 msgstr "匿å用戶ä¸å…許使用web界é¢"
 
-#: ../roundup/cgi/client.py:1214
+#: ../roundup/cgi/client.py:1256
 msgid "Referer header not available."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1218
+#: ../roundup/cgi/client.py:1260
 #, python-format
 msgid "csrf key used with wrong method from: %s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1246
+#: ../roundup/cgi/client.py:1288
 #, python-format
 msgid "csrf header %s required but missing for user%s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1247
-#, python-format
-msgid "Missing header: %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1257 ../roundup/cgi/client.py:1260
-#: ../roundup/cgi/client.py:1257:1260
-#, python-format
-msgid "csrf Referer header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1258
-#, python-format
-msgid "Invalid Referer %s, %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1273 ../roundup/cgi/client.py:1276
-#: ../roundup/cgi/client.py:1273:1276
-#, python-format
-msgid "csrf Origin header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1274
-#, fuzzy, python-format
-msgid "Invalid Origin %s"
-msgstr "無效登錄"
-
-#: ../roundup/cgi/client.py:1288 ../roundup/cgi/client.py:1291
-#: ../roundup/cgi/client.py:1288:1291
-#, python-format
-msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
-msgstr ""
-
 #: ../roundup/cgi/client.py:1289
 #, python-format
-msgid "Invalid X-FORWARDED-HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1308 ../roundup/cgi/client.py:1311
-#: ../roundup/cgi/client.py:1308:1311
+msgid "Missing header: %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1299 ../roundup/cgi/client.py:1302
+#: ../roundup/cgi/client.py:1299:1302
+#, python-format
+msgid "csrf Referer header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1300
 #, python-format
-msgid "csrf HOST header check failed for user%s. Value=%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1309
+msgid "Invalid Referer %s, %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1315 ../roundup/cgi/client.py:1318
+#: ../roundup/cgi/client.py:1315:1318
 #, python-format
-msgid "Invalid HOST %s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1317
-msgid "Csrf: unable to verify sufficient headers"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1318
-msgid "Unable to verify sufficient headers"
+msgid "csrf Origin header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1316
+#, fuzzy, python-format
+msgid "Invalid Origin %s"
+msgstr "無效登錄"
+
+#: ../roundup/cgi/client.py:1330 ../roundup/cgi/client.py:1333
+#: ../roundup/cgi/client.py:1330:1333
+#, python-format
+msgid "csrf X-FORWARDED-HOST header check failed for user%s. Value=%s"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1331
 #, python-format
-msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
-msgstr ""
-
-#: ../roundup/cgi/client.py:1332
-msgid "Required Header Missing"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1369
+msgid "Invalid X-FORWARDED-HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1350 ../roundup/cgi/client.py:1353
+#: ../roundup/cgi/client.py:1350:1353
 #, python-format
-msgid "Required csrf field missing for user%s"
-msgstr ""
-
-#: ../roundup/cgi/client.py:1370 ../roundup/cgi/client.py:1422
-#: ../roundup/cgi/client.py:1432 ../roundup/cgi/client.py:1370:1422:1432
-msgid ""
-"We can't validate your session (csrf failure). Re-enter any unsaved data and "
-"try again."
+msgid "csrf HOST header check failed for user%s. Value=%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1351
+#, python-format
+msgid "Invalid HOST %s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1359
+msgid "Csrf: unable to verify sufficient headers"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1360
+msgid "Unable to verify sufficient headers"
 msgstr ""
 
 #: ../roundup/cgi/client.py:1373
 #, python-format
+msgid "csrf X-REQUESTED-WITH xmlrpc required header check failed for user%s."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1374
+msgid "Required Header Missing"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1411
+#, python-format
+msgid "Required csrf field missing for user%s"
+msgstr ""
+
+#: ../roundup/cgi/client.py:1412 ../roundup/cgi/client.py:1464
+#: ../roundup/cgi/client.py:1474 ../roundup/cgi/client.py:1412:1464:1474
+msgid ""
+"We can't validate your session (csrf failure). Re-enter any unsaved data and "
+"try again."
+msgstr ""
+
+#: ../roundup/cgi/client.py:1415
+#, python-format
 msgid "csrf field not supplied by user%s"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1420
+#: ../roundup/cgi/client.py:1462
 #, python-format
 msgid ""
 "Csrf mismatch user: current user %s != stored user %s, current session, "
 "stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1425
+#: ../roundup/cgi/client.py:1467
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current user %s != stored user %s, current "
 "session, stored session: %s,%s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1430
+#: ../roundup/cgi/client.py:1472
 #, python-format
 msgid ""
 "Csrf mismatch user: current session %s != stored session %s, current user/"
 "stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1435
+#: ../roundup/cgi/client.py:1477
 #, python-format
 msgid ""
 "logged only: Csrf mismatch user: current session %s != stored session %s, "
 "current user/stored user is: %s for key %s."
 msgstr ""
 
-#: ../roundup/cgi/client.py:1607
+#: ../roundup/cgi/client.py:1649
 #, fuzzy
 msgid "You are not allowed to view this file."
 msgstr "ä½ ä¸å…許查看此é "
 
-#: ../roundup/cgi/client.py:1886
+#: ../roundup/cgi/client.py:1938
 #, python-format
 msgid "%(starttag)sTime elapsed: %(seconds)fs%(endtag)s\n"
 msgstr ""
 
-#: ../roundup/cgi/client.py:1890
+#: ../roundup/cgi/client.py:1942
 #, python-format
 msgid ""
 "%(starttag)sCache hits: %(cache_hits)d, misses %(cache_misses)d. Loading "
 "items: %(get_items)f secs. Filtering: %(filtering)f secs.%(endtag)s\n"
 msgstr ""
 
+#: ../roundup/cgi/client.py:2472
+#, python-format
+msgid ""
+"Cache failure: compressed file %(compressed)s is older than its source file "
+"%(filename)s"
+msgstr ""
+
 #: ../roundup/cgi/form_parser.py:290
 #, fuzzy, python-format
 msgid "link \"%(key)s\" value \"%(entry)s\" not a designator"
@@ -1840,18 +1874,18 @@
 msgstr "æäº¤æ–°çš„é …"
 
 #: ../roundup/cgi/templating.py:963 ../roundup/cgi/templating.py:1134
-#: ../roundup/cgi/templating.py:1747 ../roundup/cgi/templating.py:1776
-#: ../roundup/cgi/templating.py:1796 ../roundup/cgi/templating.py:1809
-#: ../roundup/cgi/templating.py:1846 ../roundup/cgi/templating.py:1899
-#: ../roundup/cgi/templating.py:1922 ../roundup/cgi/templating.py:1929
-#: ../roundup/cgi/templating.py:1965 ../roundup/cgi/templating.py:2002
-#: ../roundup/cgi/templating.py:2035 ../roundup/cgi/templating.py:2124
-#: ../roundup/cgi/templating.py:2145 ../roundup/cgi/templating.py:2235
-#: ../roundup/cgi/templating.py:2255 ../roundup/cgi/templating.py:2277
-#: ../roundup/cgi/templating.py:2316 ../roundup/cgi/templating.py:2326
-#: ../roundup/cgi/templating.py:2390 ../roundup/cgi/templating.py:2688
-#: ../roundup/cgi/templating.py:963:1134 :1747:1776 :1796:1809 :1846:1899
-#: :1922:1929 :1965:2002 :2035:2124 :2145:2235 :2255:2277 :2316:2326 :2390:2688
+#: ../roundup/cgi/templating.py:1753 ../roundup/cgi/templating.py:1782
+#: ../roundup/cgi/templating.py:1802 ../roundup/cgi/templating.py:1815
+#: ../roundup/cgi/templating.py:1852 ../roundup/cgi/templating.py:1905
+#: ../roundup/cgi/templating.py:1928 ../roundup/cgi/templating.py:1935
+#: ../roundup/cgi/templating.py:1971 ../roundup/cgi/templating.py:2008
+#: ../roundup/cgi/templating.py:2041 ../roundup/cgi/templating.py:2130
+#: ../roundup/cgi/templating.py:2151 ../roundup/cgi/templating.py:2241
+#: ../roundup/cgi/templating.py:2261 ../roundup/cgi/templating.py:2283
+#: ../roundup/cgi/templating.py:2322 ../roundup/cgi/templating.py:2332
+#: ../roundup/cgi/templating.py:2396 ../roundup/cgi/templating.py:2695
+#: ../roundup/cgi/templating.py:963:1134 :1753:1782 :1802:1815 :1852:1905
+#: :1928:1935 :1971:2008 :2041:2130 :2151:2241 :2261:2283 :2322:2332 :2396:2695
 msgid "[hidden]"
 msgstr ""
 
@@ -1877,80 +1911,86 @@
 msgid "The linked class %(classname)s no longer exists"
 msgstr "éˆæŽ¥çš„é¡žåˆ¥ %(classname)s ä¸å†å­˜åœ¨"
 
+#: ../roundup/cgi/templating.py:1249 ../roundup/cgi/templating.py:1277
+#: ../roundup/cgi/templating.py:2405 ../roundup/cgi/templating.py:2704
+#: ../roundup/cgi/templating.py:1249:1277 :2405:2704
+msgid "[label is missing]"
+msgstr ""
+
 # ../roundup/cgi/templating.py:872 :893
-#: ../roundup/cgi/templating.py:1251 ../roundup/cgi/templating.py:1277
-#: ../roundup/cgi/templating.py:1251:1277
+#: ../roundup/cgi/templating.py:1253 ../roundup/cgi/templating.py:1280
+#: ../roundup/cgi/templating.py:1253:1280
 msgid "<strike>The linked node no longer exists</strike>"
 msgstr "<strike>éˆæŽ¥çš„çµé»žä¸å†å­˜åœ¨</strike>"
 
-#: ../roundup/cgi/templating.py:1338
+#: ../roundup/cgi/templating.py:1341
 #, python-format
 msgid "%s: (no value)"
 msgstr "%s: (無值)"
 
-#: ../roundup/cgi/templating.py:1354
+#: ../roundup/cgi/templating.py:1357
 #, fuzzy, python-format
 msgid ""
 "<strong><em>This event %s is not handled by the history display!</em></"
 "strong>"
 msgstr "<strong><em>這個事件ä¸èƒ½è¢«æ­·å²é¡¯ç¤ºæ‰€è™•ç†ï¼</em></strong>"
 
-#: ../roundup/cgi/templating.py:1367
+#: ../roundup/cgi/templating.py:1370
 msgid "<tr><td colspan=4><strong>Note:</strong></td></tr>"
 msgstr "<tr><td colspan=4><strong>注æ„:</strong></td></tr>"
 
-#: ../roundup/cgi/templating.py:1376
-msgid "History"
-msgstr "æ­·å²"
-
-#: ../roundup/cgi/templating.py:1378
-msgid "<th>Date</th>"
-msgstr "<th>日期</th>"
-
 #: ../roundup/cgi/templating.py:1379
+msgid "History"
+msgstr "æ­·å²"
+
+#: ../roundup/cgi/templating.py:1381
+msgid "<th>Date</th>"
+msgstr "<th>日期</th>"
+
+#: ../roundup/cgi/templating.py:1382
 msgid "<th>User</th>"
 msgstr "<th>用戶</th>"
 
-#: ../roundup/cgi/templating.py:1380
+#: ../roundup/cgi/templating.py:1383
 msgid "<th>Action</th>"
 msgstr "<th>動作</th>"
 
-#: ../roundup/cgi/templating.py:1381
+#: ../roundup/cgi/templating.py:1384
 msgid "<th>Args</th>"
 msgstr "<th>åƒæ•¸</th>"
 
-#: ../roundup/cgi/templating.py:1432
+#: ../roundup/cgi/templating.py:1435
 #, fuzzy, python-format
 msgid "Copy of %(class)s %(id)s"
 msgstr "%(class)s %(id)s 被建立"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2072
-#: ../roundup/cgi/templating.py:1320:2039:2072
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2078
+#: ../roundup/cgi/templating.py:1323:2045:2078
 msgid "No"
 msgstr "å¦"
 
-#: ../roundup/cgi/templating.py:2039 ../roundup/cgi/templating.py:2067
-#: ../roundup/cgi/templating.py:1320:2039:2067
+#: ../roundup/cgi/templating.py:2045 ../roundup/cgi/templating.py:2073
+#: ../roundup/cgi/templating.py:1323:2045:2073
 msgid "Yes"
 msgstr "是"
 
-#: ../roundup/cgi/templating.py:2193
+#: ../roundup/cgi/templating.py:2199
 msgid ""
 "default value for DateHTMLProperty must be either DateHTMLProperty or string "
 "date representation."
 msgstr "DateHTMLProperty çš„é è¨­å€¼æˆ–者是 DateHTMLProperty 或字符串的日期表示。"
 
-#: ../roundup/cgi/templating.py:2370
+#: ../roundup/cgi/templating.py:2376
 #, python-format
 msgid "Attempt to look up %(attr)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2381
+#: ../roundup/cgi/templating.py:2387
 #, python-format
 msgid "Attempt to look up %(item)s on a missing value"
 msgstr ""
 
-#: ../roundup/cgi/templating.py:2484
+#: ../roundup/cgi/templating.py:2491
 #, python-format
 msgid "<option %svalue=\"-1\">- no selection -</option>"
 msgstr "<option %svalue=\"-1\">- æœªé¸æ“‡ -</option>"
@@ -1968,11 +2008,23 @@
 msgid "Responding to form too quickly."
 msgstr ""
 
-#: ../roundup/configuration.py:1887
+#: ../roundup/configuration.py:274
+#, python-format
+msgid ""
+"Error in %(filepath)s with section [%(section)s] at option %(option)s: "
+"%(message)s"
+msgstr ""
+
+#: ../roundup/configuration.py:494
 #, fuzzy
 msgid "Valid languages: "
 msgstr "無效的格å¼"
 
+#: ../roundup/configuration.py:504
+#, fuzzy
+msgid "Expected languages: "
+msgstr "無效的格å¼"
+
 #: ../roundup/date.py:395
 #, python-format
 msgid ""
@@ -2123,23 +2175,23 @@
 msgid "\"%s\" not a node designator"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1472 ../roundup/hyperdb.py:1480
-#: ../roundup/hyperdb.py:1472:1480
+#: ../roundup/hyperdb.py:1473 ../roundup/hyperdb.py:1481
+#: ../roundup/hyperdb.py:1473:1481
 #, fuzzy, python-format
 msgid "Not a property name: %s"
 msgstr "䏿˜¯æ—¥æœŸæ ¼å¼ï¼š%s"
 
-#: ../roundup/hyperdb.py:1939
+#: ../roundup/hyperdb.py:1940
 #, python-format
 msgid "property %s: %r is not a %s."
 msgstr ""
 
-#: ../roundup/hyperdb.py:1942
+#: ../roundup/hyperdb.py:1943
 #, python-format
 msgid "you may only enter ID values for property %s"
 msgstr ""
 
-#: ../roundup/hyperdb.py:1976
+#: ../roundup/hyperdb.py:1977
 #, python-format
 msgid "%r is not a property of %s"
 msgstr ""
@@ -2151,50 +2203,50 @@
 "\tcontains old-style template - ignored"
 msgstr ""
 
-#: ../roundup/mailgw.py:197 ../roundup/mailgw.py:210
-#: ../roundup/mailgw.py:197:210
+#: ../roundup/mailgw.py:198 ../roundup/mailgw.py:211
+#: ../roundup/mailgw.py:198:211
 #, python-format
 msgid "Message signed with unknown key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:200
+#: ../roundup/mailgw.py:201
 #, python-format
 msgid "Message signed with an expired key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:203
+#: ../roundup/mailgw.py:204
 #, python-format
 msgid "Message signed with a revoked key: %s"
 msgstr ""
 
-#: ../roundup/mailgw.py:206
+#: ../roundup/mailgw.py:207
 msgid "Invalid PGP signature detected."
 msgstr ""
 
-#: ../roundup/mailgw.py:213
+#: ../roundup/mailgw.py:214
 #, fuzzy
 msgid "Unsigned Message"
 msgstr "æ–°ä¿¡æ¯"
 
-#: ../roundup/mailgw.py:463
+#: ../roundup/mailgw.py:464
 msgid "Unknown multipart/encrypted version."
 msgstr ""
 
-#: ../roundup/mailgw.py:472
+#: ../roundup/mailgw.py:473
 msgid "Unable to decrypt your message."
 msgstr ""
 
-#: ../roundup/mailgw.py:499
+#: ../roundup/mailgw.py:500
 msgid "No PGP signature found in message."
 msgstr ""
 
-#: ../roundup/mailgw.py:580
+#: ../roundup/mailgw.py:581
 msgid ""
 "\n"
 "Emails to Roundup trackers must include a Subject: line!\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:693
+#: ../roundup/mailgw.py:694
 #, python-format
 msgid ""
 "\n"
@@ -2211,7 +2263,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:731
+#: ../roundup/mailgw.py:732
 #, python-format
 msgid ""
 "\n"
@@ -2222,7 +2274,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:739
+#: ../roundup/mailgw.py:740
 #, python-format
 msgid ""
 "\n"
@@ -2239,7 +2291,7 @@
 "Subject was: '%(subject)s'\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:775
+#: ../roundup/mailgw.py:776
 #, python-format
 msgid ""
 "\n"
@@ -2250,7 +2302,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:808
+#: ../roundup/mailgw.py:809
 #, python-format
 msgid ""
 "\n"
@@ -2260,7 +2312,7 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:853
+#: ../roundup/mailgw.py:854
 #, python-format
 msgid ""
 "\n"
@@ -2269,22 +2321,22 @@
 "Unknown address: %(from_address)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:861
+#: ../roundup/mailgw.py:862
 #, fuzzy
 msgid "You are not permitted to access this tracker."
 msgstr "ä½ ä¸å…許查看此é "
 
-#: ../roundup/mailgw.py:872
+#: ../roundup/mailgw.py:873
 #, fuzzy, python-format
 msgid "You are not permitted to edit %(classname)s."
 msgstr "你沒有權é™ä¾†ç·¨è¼¯ %(class)s"
 
-#: ../roundup/mailgw.py:878
+#: ../roundup/mailgw.py:879
 #, fuzzy, python-format
 msgid "You are not permitted to create %(classname)s."
 msgstr "你沒有權é™ä¾†å»ºç«‹ %(class)s"
 
-#: ../roundup/mailgw.py:960
+#: ../roundup/mailgw.py:961
 #, python-format
 msgid ""
 "\n"
@@ -2294,40 +2346,40 @@
 "Subject was: \"%(subject)s\"\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1012
+#: ../roundup/mailgw.py:1013
 msgid "This tracker has been configured to require all email be PGP encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1049
+#: ../roundup/mailgw.py:1050
 msgid ""
 "\n"
 "This tracker has been configured to require all email be PGP signed or\n"
 "encrypted."
 msgstr ""
 
-#: ../roundup/mailgw.py:1080
+#: ../roundup/mailgw.py:1081
 #, fuzzy
 msgid "You are not permitted to create files."
 msgstr "ä¸å…許編輯查詢"
 
-#: ../roundup/mailgw.py:1094
+#: ../roundup/mailgw.py:1095
 #, fuzzy, python-format
 msgid "You are not permitted to add files to %(classname)s."
 msgstr "你沒有權é™ä¾† %(action)s %(classname)s 類型。"
 
-#: ../roundup/mailgw.py:1124
+#: ../roundup/mailgw.py:1125
 msgid ""
 "\n"
 "Roundup requires the submission to be plain text. The message parser could\n"
 "not find a text/plain part to use.\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1137
+#: ../roundup/mailgw.py:1138
 #, fuzzy
 msgid "You are not permitted to create messages."
 msgstr "ä¸å…許編輯查詢"
 
-#: ../roundup/mailgw.py:1145
+#: ../roundup/mailgw.py:1146
 #, python-format
 msgid ""
 "\n"
@@ -2335,22 +2387,22 @@
 "%(error)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1153
+#: ../roundup/mailgw.py:1154
 #, fuzzy, python-format
 msgid "You are not permitted to add messages to %(classname)s."
 msgstr "你沒有權é™ä¾† %(action)s %(classname)s 類型。"
 
-#: ../roundup/mailgw.py:1175
+#: ../roundup/mailgw.py:1176
 #, fuzzy, python-format
 msgid "You are not permitted to edit property %(prop)s of class %(classname)s."
 msgstr "ä½ ä¸å…許 %(action)s 類別 %(class)s 的項目"
 
-#: ../roundup/mailgw.py:1184
+#: ../roundup/mailgw.py:1185
 #, fuzzy, python-format
 msgid "You are not permitted to set property %(prop)s of class %(classname)s."
 msgstr "ä½ ä¸å…許 %(action)s 類別 %(class)s 的項目"
 
-#: ../roundup/mailgw.py:1192
+#: ../roundup/mailgw.py:1193
 #, python-format
 msgid ""
 "\n"
@@ -2358,7 +2410,7 @@
 "   %(message)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1658
+#: ../roundup/mailgw.py:1659
 #, python-format
 msgid ""
 "\n"
@@ -2367,7 +2419,7 @@
 "  %(clsname)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1689
+#: ../roundup/mailgw.py:1690
 #, python-format
 msgid ""
 "\n"
@@ -2376,22 +2428,39 @@
 "  %(errors)s\n"
 msgstr ""
 
-#: ../roundup/mailgw.py:1710
+#: ../roundup/mailgw.py:1711
 msgid "not of form [arg=value,value,...;arg=value,value,...]"
 msgstr ""
 
-#: ../roundup/rest.py:1883
+#: ../roundup/rest.py:406
+#, python-format
+msgid "Method %(m)s not allowed. Allowed: %(a)s"
+msgstr ""
+
+#: ../roundup/rest.py:1104
+#, fuzzy, python-format
+msgid "Invalid attribute %s"
+msgstr "無效登錄"
+
+#: ../roundup/rest.py:2065
 #, python-format
 msgid "Api rate limits exceeded. Please wait: %s seconds."
 msgstr ""
 
-#: ../roundup/rest.py:1918
+#: ../roundup/rest.py:2100
 #, python-format
 msgid ""
 "Unable to parse Accept Header. %(error)s. Acceptable types: "
 "%(acceptable_types)s"
 msgstr ""
 
+#: ../roundup/rest.py:2223
+#, python-format
+msgid ""
+"Unrecognized api version: %s. See /rest without specifying api version for "
+"supported versions."
+msgstr ""
+
 #: ../roundup/roundupdb.py:135
 #, python-format
 msgid "Username '%s' already exists."
@@ -2670,7 +2739,7 @@
 msgid "WARNING: generating temporary SSL certificate"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:293
+#: ../roundup/scripts/roundup_server.py:296
 msgid ""
 "<html><head><title>Roundup trackers index</title></head>\n"
 "<body><h1>Roundup trackers index</h1><ol>\n"
@@ -2678,52 +2747,52 @@
 "<html><head><title>Roundup tracker 索引</title></head>\n"
 "<body><h1>Roundup tracker 索引</h1><ol>\n"
 
-#: ../roundup/scripts/roundup_server.py:508
+#: ../roundup/scripts/roundup_server.py:525
 #, fuzzy, python-format
 msgid "Error: %(type)s: %(value)s"
 msgstr "%(key)s: %(value)s (é—œéµå±¬æ€§)"
 
-#: ../roundup/scripts/roundup_server.py:520
+#: ../roundup/scripts/roundup_server.py:537
 msgid "WARNING: ignoring \"-g\" argument, not root"
 msgstr "警告:忽略 \"-g\" åƒæ•¸ï¼Œä¸æ˜¯ root"
 
-#: ../roundup/scripts/roundup_server.py:526
+#: ../roundup/scripts/roundup_server.py:543
 msgid "Can't change groups - no grp module"
 msgstr "ä¸èƒ½ä¿®æ”¹çµ„ - ç„¡ grp 模塊"
 
-#: ../roundup/scripts/roundup_server.py:535
+#: ../roundup/scripts/roundup_server.py:552
 #, python-format
 msgid "Group %(group)s doesn't exist"
 msgstr "組 %(group)s ä¸å­˜åœ¨"
 
-#: ../roundup/scripts/roundup_server.py:547
+#: ../roundup/scripts/roundup_server.py:564
 msgid "Can't run as root!"
 msgstr "ä¸èƒ½ä»¥ root é‹è¡Œï¼"
 
-#: ../roundup/scripts/roundup_server.py:550
+#: ../roundup/scripts/roundup_server.py:567
 msgid "WARNING: ignoring \"-u\" argument, not root"
 msgstr "警告:忽略 \"-u\" åƒæ•¸ï¼Œä¸æ˜¯ root"
 
-#: ../roundup/scripts/roundup_server.py:556
+#: ../roundup/scripts/roundup_server.py:573
 msgid "Can't change users - no pwd module"
 msgstr "ä¸èƒ½ä¿®æ”¹ç”¨æˆ¶ - ç„¡ pwd 模塊"
 
-#: ../roundup/scripts/roundup_server.py:565
+#: ../roundup/scripts/roundup_server.py:582
 #, python-format
 msgid "User %(user)s doesn't exist"
 msgstr "用戶 %(user)s ä¸å­˜åœ¨"
 
-#: ../roundup/scripts/roundup_server.py:755
+#: ../roundup/scripts/roundup_server.py:778
 #, python-format
 msgid "Multiprocess mode \"%s\" is not available, switching to single-process"
 msgstr ""
 
-#: ../roundup/scripts/roundup_server.py:782
+#: ../roundup/scripts/roundup_server.py:805
 #, python-format
 msgid "Unable to bind to port %s, port already in use."
 msgstr "無法ç¶å®šåˆ°ç«¯å£ %s, 端å£å·²ç¶“被佔用。"
 
-#: ../roundup/scripts/roundup_server.py:854
+#: ../roundup/scripts/roundup_server.py:877
 #, fuzzy
 msgid ""
 " -c <Command>  Windows Service options.\n"
@@ -2740,7 +2809,7 @@
 "               變é‡ä¸Šé…置一個tracker。這個é¸é …與其經é¸é …是互斥的。打入\n"
 "               \"roundup-server -c help\" 來瞭解Windowsæœå‹™çš„è¦ç¯„。"
 
-#: ../roundup/scripts/roundup_server.py:861
+#: ../roundup/scripts/roundup_server.py:884
 msgid ""
 " -u <UID>      runs the Roundup web server as this UID\n"
 " -g <GID>      runs the Roundup web server as this GID\n"
@@ -2754,9 +2823,10 @@
 "去。\n"
 "               如果使用了 -d é¸é …,則 -l é¸é … *å¿…é ˆ* è¦æŒ‡å®šã€‚"
 
-#: ../roundup/scripts/roundup_server.py:868
+#: ../roundup/scripts/roundup_server.py:891
 #, fuzzy, python-format
 msgid ""
+"\n"
 "%(message)sUsage: roundup-server [options] [name=tracker home]*\n"
 "\n"
 "Options:\n"
@@ -2779,6 +2849,9 @@
 " -e <fname>    PEM file containing SSL key and certificate\n"
 " -t <mode>     multiprocess mode (default: %(mp_def)s).\n"
 "               Allowed values: %(mp_types)s.\n"
+" -V <version>  set HTTP version (default: HTTP/1.1).\n"
+"               Allowed values: HTTP/1.0, HTTP/1.1.\n"
+"\n"
 "%(os_part)s\n"
 "\n"
 "Long options:\n"
@@ -2846,20 +2919,20 @@
 "   æ„æ•¸é‡çš„ name=home å°ã€‚è¦ç¢ºä¿ name 部分ä¸èƒ½åŒ…括任何éžurl安全的\n"
 "   字符,åƒç©ºæ ¼ï¼Œå› ç‚ºå®ƒå€‘會把IEæžäº‚。\n"
 
-#: ../roundup/scripts/roundup_server.py:1041
+#: ../roundup/scripts/roundup_server.py:1067
 msgid "Instances must be name=home"
 msgstr "實例必須是 實例å=實例路徑"
 
-#: ../roundup/scripts/roundup_server.py:1055
+#: ../roundup/scripts/roundup_server.py:1081
 #, python-format
 msgid "Configuration saved to %s"
 msgstr "é…ç½®ä¿å­˜åˆ° %s"
 
-#: ../roundup/scripts/roundup_server.py:1073
+#: ../roundup/scripts/roundup_server.py:1099
 msgid "Sorry, you can't run the server as a daemon on this Operating System"
 msgstr "抱歉,在這個æ“作系統上ä¸èƒ½ä»¥å®ˆè­·é€²ç¨‹çš„æ–¹å¼ä¾†é‹è¡Œæœå‹™"
 
-#: ../roundup/scripts/roundup_server.py:1093
+#: ../roundup/scripts/roundup_server.py:1119
 #, python-format
 msgid "Roundup server started on %(HOST)s:%(PORT)s"
 msgstr "Roundup server 啟動於 %(HOST)s:%(PORT)s"
@@ -2994,6 +3067,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:41
 #: ../share/roundup/templates/classic/html/help.html:21
 #: ../share/roundup/templates/classic/html/issue.index.html:80
+#: ../share/roundup/templates/classic/html/user.index.html:82
 #: ../share/roundup/templates/devel/html/_generic.help.html:42
 #: ../share/roundup/templates/devel/html/bug.index.html:94
 #: ../share/roundup/templates/devel/html/help.html:51
@@ -3010,6 +3084,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:53
 #: ../share/roundup/templates/classic/html/help.html:28
 #: ../share/roundup/templates/classic/html/issue.index.html:88
+#: ../share/roundup/templates/classic/html/user.index.html:90
 #: ../share/roundup/templates/devel/html/_generic.help.html:54
 #: ../share/roundup/templates/devel/html/bug.index.html:102
 #: ../share/roundup/templates/devel/html/help.html:58
@@ -3026,6 +3101,7 @@
 #: ../share/roundup/templates/classic/html/_generic.help.html:57
 #: ../share/roundup/templates/classic/html/help.html:32
 #: ../share/roundup/templates/classic/html/issue.index.html:91
+#: ../share/roundup/templates/classic/html/user.index.html:93
 #: ../share/roundup/templates/devel/html/_generic.help.html:58
 #: ../share/roundup/templates/devel/html/bug.index.html:105
 #: ../share/roundup/templates/devel/html/help.html:62
@@ -3854,6 +3930,7 @@
 #: ../share/roundup/templates/classic/html/page.html:40
 #: ../share/roundup/templates/classic/html/page.html:92
 #: ../share/roundup/templates/classic/html/user.help-search.html:69
+#: ../share/roundup/templates/classic/html/user.index.html:38
 #: ../share/roundup/templates/devel/html/bug.search.html:292
 #: ../share/roundup/templates/devel/html/page.html:79
 #: ../share/roundup/templates/devel/html/page.html:126
@@ -4393,7 +4470,7 @@
 msgid "User listing"
 msgstr "用戶列表"
 
-#: ../share/roundup/templates/classic/html/user.index.html:19
+#: ../share/roundup/templates/classic/html/user.index.html:48
 #: ../share/roundup/templates/devel/html/user.index.html:48
 #: ../share/roundup/templates/minimal/html/user.index.html:19
 #: ../share/roundup/templates/responsive/html/page.html:180
@@ -4401,13 +4478,13 @@
 msgid "Username"
 msgstr "用戶å"
 
-#: ../share/roundup/templates/classic/html/user.index.html:20
+#: ../share/roundup/templates/classic/html/user.index.html:49
 #: ../share/roundup/templates/devel/html/user.index.html:49
 #: ../share/roundup/templates/responsive/html/user.index.html:50
 msgid "Real name"
 msgstr "真實姓å"
 
-#: ../share/roundup/templates/classic/html/user.index.html:21
+#: ../share/roundup/templates/classic/html/user.index.html:50
 #: ../share/roundup/templates/classic/html/user.register.html:47
 #: ../share/roundup/templates/devel/html/user.index.html:50
 #: ../share/roundup/templates/devel/html/user.register.html:54
@@ -4416,26 +4493,26 @@
 msgid "Organisation"
 msgstr "組織"
 
-#: ../share/roundup/templates/classic/html/user.index.html:22
+#: ../share/roundup/templates/classic/html/user.index.html:51
 #: ../share/roundup/templates/devel/html/user.index.html:51
 #: ../share/roundup/templates/minimal/html/user.index.html:20
 #: ../share/roundup/templates/responsive/html/user.index.html:52
 msgid "Email address"
 msgstr "郵件地å€"
 
-#: ../share/roundup/templates/classic/html/user.index.html:23
+#: ../share/roundup/templates/classic/html/user.index.html:52
 #: ../share/roundup/templates/devel/html/user.index.html:52
 #: ../share/roundup/templates/responsive/html/user.index.html:53
 msgid "Phone number"
 msgstr "電話號碼"
 
-#: ../share/roundup/templates/classic/html/user.index.html:24
+#: ../share/roundup/templates/classic/html/user.index.html:53
 #: ../share/roundup/templates/devel/html/user.index.html:53
 #: ../share/roundup/templates/responsive/html/user.index.html:54
 msgid "Retire"
 msgstr "收回"
 
-#: ../share/roundup/templates/classic/html/user.index.html:43
+#: ../share/roundup/templates/classic/html/user.index.html:72
 #: ../share/roundup/templates/devel/html/user.index.html:66
 #: ../share/roundup/templates/responsive/html/user.index.html:67
 msgid "retire"
@@ -4584,68 +4661,68 @@
 msgstr "你將很快收到一å°ç¢ºèªä¿¡ã€‚為了完æˆè¨»å†ŠéŽç¨‹ï¼Œè«‹è¨ªå•éƒµä»¶ä¸­æŒ‡ç¤ºçš„éˆæŽ¥ã€‚"
 
 #: ../share/roundup/templates/classic/initial_data.py:5
-#: ../share/roundup/templates/jinja2/initial_data.py:6
+#: ../share/roundup/templates/jinja2/initial_data.py:4
 msgid "critical"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:6
-#: ../share/roundup/templates/jinja2/initial_data.py:7
+#: ../share/roundup/templates/jinja2/initial_data.py:5
 msgid "urgent"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:7
-#: ../share/roundup/templates/jinja2/initial_data.py:8
+#: ../share/roundup/templates/jinja2/initial_data.py:6
 msgid "bug"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:8
-#: ../share/roundup/templates/jinja2/initial_data.py:9
+#: ../share/roundup/templates/jinja2/initial_data.py:7
 msgid "feature"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:9
-#: ../share/roundup/templates/jinja2/initial_data.py:10
+#: ../share/roundup/templates/jinja2/initial_data.py:8
 msgid "wish"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:12
-#: ../share/roundup/templates/jinja2/initial_data.py:13
+#: ../share/roundup/templates/jinja2/initial_data.py:11
 msgid "unread"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:13
-#: ../share/roundup/templates/jinja2/initial_data.py:14
+#: ../share/roundup/templates/jinja2/initial_data.py:12
 msgid "deferred"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:14
-#: ../share/roundup/templates/jinja2/initial_data.py:15
+#: ../share/roundup/templates/jinja2/initial_data.py:13
 msgid "chatting"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:15
-#: ../share/roundup/templates/jinja2/initial_data.py:16
+#: ../share/roundup/templates/jinja2/initial_data.py:14
 msgid "need-eg"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:16
-#: ../share/roundup/templates/jinja2/initial_data.py:17
+#: ../share/roundup/templates/jinja2/initial_data.py:15
 msgid "in-progress"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:17
-#: ../share/roundup/templates/jinja2/initial_data.py:18
+#: ../share/roundup/templates/jinja2/initial_data.py:16
 #, fuzzy
 msgid "testing"
 msgstr "用戶列表"
 
 #: ../share/roundup/templates/classic/initial_data.py:18
-#: ../share/roundup/templates/jinja2/initial_data.py:19
+#: ../share/roundup/templates/jinja2/initial_data.py:17
 msgid "done-cbb"
 msgstr ""
 
 #: ../share/roundup/templates/classic/initial_data.py:19
-#: ../share/roundup/templates/jinja2/initial_data.py:20
+#: ../share/roundup/templates/jinja2/initial_data.py:18
 #, fuzzy
 msgid "resolved"
 msgstr "未解決"
--- a/roundup/admin.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/admin.py	Thu Apr 21 16:54:17 2022 -0400
@@ -23,12 +23,13 @@
 
 __docformat__ = 'restructuredtext'
 
-import csv, getopt, getpass, os, re, shutil, sys, operator
+import csv, getopt, getpass, operator, os, re, shutil, sys
 
 from roundup import date, hyperdb, init, password, token
 from roundup import __version__ as roundup_version
 import roundup.instance
-from roundup.configuration import CoreConfig, NoConfigError, UserConfig
+from roundup.configuration import (CoreConfig, NoConfigError,
+                                   ParsingOptionError, UserConfig)
 from roundup.i18n import _
 from roundup.exceptions import UsageError
 from roundup.anypy.my_input import my_input
@@ -51,13 +52,16 @@
         if key in self.data:
             return [(key, self.data[key])]
         keylist = sorted(self.data)
-        l = []
+        matching_keys = []
         for ki in keylist:
             if ki.startswith(key):
-                l.append((ki, self.data[ki]))
-        if not l and default is self._marker:
+                matching_keys.append((ki, self.data[ki]))
+        if not matching_keys and default is self._marker:
             raise KeyError(key)
-        return l
+        # FIXME: what happens if default is not self._marker but
+        # there are no matching keys? Should (default, self.data[default])
+        # be returned???
+        return matching_keys
 
 
 class AdminTool:
@@ -101,12 +105,12 @@
         """
         props = {}
         for arg in args:
-            l = arg.split('=', 1)
+            key_val = arg.split('=', 1)
             # if = not in string, will return one element
-            if len(l) < 2:
+            if len(key_val) < 2:
                 raise UsageError(_('argument "%(arg)s" not propname=value') %
                                  locals())
-            key, value = l
+            key, value = key_val
             if value:
                 props[key] = value
             else:
@@ -117,7 +121,7 @@
         """ Display a simple usage message.
         """
         if message:
-            message = _('Problem: %(message)s\n\n')% locals()
+            message = _('Problem: %(message)s\n\n') % locals()
         sys.stdout.write(_("""%(message)sUsage: roundup-admin [options] [<command> <arguments>]
 
 Options:
@@ -267,13 +271,13 @@
 
         # try command docstrings
         try:
-            l = self.commands.get(topic)
+            cmd_docs = self.commands.get(topic)
         except KeyError:
             print(_('Sorry, no help for "%(topic)s"') % locals())
             return 1
 
         # display the help for each match, removing the docstring indent
-        for _name, help in l:
+        for _name, help in cmd_docs:
             lines = nl_re.split(_(help.__doc__))
             print(lines[0])
             indent = indent_re.match(lines[1])
@@ -295,12 +299,15 @@
          2. <prefix>/share/roundup/templates/*
             this should be the standard place to find them when Roundup is
             installed
-         3. <roundup.admin.__file__>/../templates/*
+         3. <roundup.admin.__file__>/../../<sys.prefix>/share/\
+                 roundup/templates/* which is where they will be found if
+            roundup is installed as a wheel using pip install
+         4. <roundup.admin.__file__>/../templates/*
             this will be used if Roundup's run in the distro (aka. source)
             directory
-         4. <current working dir>/*
+         5. <current working dir>/*
             this is for when someone unpacks a 3rd-party template
-         5. <current working dir>
+         6. <current working dir>
             this is for someone who "cd"s to the 3rd-party template dir
         """
         # OK, try <prefix>/share/roundup/templates
@@ -324,6 +331,25 @@
                 templates = init.listTemplates(tdir)
                 break
 
+        # search for data files parallel to the roundup
+        # install dir. E.G. a wheel install
+        #  use roundup.__path__ and go up a level then use sys.prefix
+        #  to create a base path for searching.
+
+        import sys
+        # __file__ should be something like:
+        #    /usr/local/lib/python3.10/site-packages/roundup/admin.py
+        # os.prefix should be /usr, /usr/local or root of virtualenv
+        #    strip leading / to make os.path.join work right.
+        path = __file__
+        for _N in 1, 2:
+            path = os.path.dirname(path)
+        # path is /usr/local/lib/python3.10/site-packages
+        tdir = os.path.join(path, sys.prefix[1:], 'share',
+                            'roundup', 'templates')
+        if os.path.isdir(tdir):
+            templates.update(init.listTemplates(tdir))
+
         # OK, now try as if we're in the roundup source distribution
         # directory, so this module will be in .../roundup-*/roundup/admin.py
         # and we're interested in the .../roundup-*/ part.
@@ -435,7 +461,7 @@
         # it sets parameters like template_engine that are
         # template specific.
         template_config = UserConfig(templates[template]['path'] +
-                                   "/config_ini.ini")
+                                     "/config_ini.ini")
         for k in template_config.keys():
             if k == 'HOME':  # ignore home. It is a default param.
                 continue
@@ -583,7 +609,7 @@
             raise UsageError(_('Not enough arguments supplied'))
         propname = args[0]
         designators = args[1].split(',')
-        l = []
+        linked_props = []
         for designator in designators:
             # decode the node designator
             try:
@@ -619,11 +645,11 @@
                         propclassname = self.db.getclass(property.classname).classname
                         id = cl.get(nodeid, propname)
                         for i in id:
-                            l.append(propclassname + i)
+                            linked_props.append(propclassname + i)
                     else:
                         id = cl.get(nodeid, propname)
                         for i in id:
-                            l.append(i)
+                            linked_props.append(i)
                 else:
                     if self.print_designator:
                         properties = cl.getprops()
@@ -646,7 +672,7 @@
                 raise UsageError(_('no such %(classname)s property '
                                    '"%(propname)s"') % locals())
         if self.separator:
-            print(self.separator.join(l))
+            print(self.separator.join(linked_props))
 
         return 0
 
@@ -743,20 +769,20 @@
             if ',' in value:
                 values = value.split(',')
             else:
-                values = [ value ]
+                values = [value]
 
             props[propname] = []
             # start handling transitive props
             # given filter issue assignedto.roles=Admin
             # start at issue
             curclass = cl
-            lastprop = propname # handle case 'issue assignedto=admin'
+            lastprop = propname  # handle case 'issue assignedto=admin'
             if '.' in propname:
                 # start splitting transitive prop into components
                 # we end when we have no more links
                 for pn in propname.split('.'):
                     try:
-                        lastprop=pn # get current component
+                        lastprop = pn  # get current component
                         # get classname for this link
                         try:
                             curclassname = curclass.getprops()[pn].classname
@@ -779,7 +805,7 @@
         try:
             id = []
             designator = []
-            props = { "filterspec": props }
+            props = {"filterspec": props}
 
             if self.separator:
                 if self.print_designator:
@@ -967,7 +993,7 @@
         for propname in props:
             try:
                 props[propname] = hyperdb.rawToHyperdb(self.db, cl, None,
-                    propname, props[propname])
+                                                    propname, props[propname])
             except hyperdb.HyperdbValueError as message:
                 raise UsageError(message)
 
@@ -975,7 +1001,7 @@
         propname = cl.getkey()
         if propname and propname not in props:
             raise UsageError(_('you must provide the "%(propname)s" '
-                'property.') % locals())
+                               'property.') % locals())
 
         # do the actual create
         try:
@@ -1099,7 +1125,7 @@
             if ':' in spec:
                 name, width = spec.split(':')
                 if width == '':
-                    # spec includes trailing :, use label/name width 
+                    # spec includes trailing :, use label/name width
                     props.append((name, len(name)))
                 else:
                     try:
@@ -1123,7 +1149,7 @@
 
         # and the table data
         for nodeid in cl.list():
-            l = []
+            table_columns = []
             for name, width in props:
                 if name != 'id':
                     try:
@@ -1136,8 +1162,8 @@
                 else:
                     value = str(nodeid)
                 f = '%%-%ds' % width
-                l.append(f % value[:width])
-            print(' '.join(l))
+                table_columns.append(f % value[:width])
+            print(' '.join(table_columns))
         return 0
 
     def do_history(self, args):
@@ -1259,7 +1285,7 @@
                 raise UsageError(e.args[0])
             except IndexError:
                 raise UsageError(_('no such %(classname)s node '
-                                   '" % (nodeid)s"')%locals())
+                                   '" % (nodeid)s"') % locals())
         self.db_uncommitted = True
         return 0
 
@@ -1286,7 +1312,7 @@
         if len(args) == 2:
             if args[0].startswith('-'):
                 classes = [c for c in self.db.classes
-                            if c not in args[0][1:].split(',')]
+                           if c not in args[0][1:].split(',')]
             else:
                 classes = args[0].split(',')
         else:
@@ -1308,12 +1334,11 @@
 
             if not export_files and hasattr(cl, 'export_files'):
                 sys.stdout.write('Exporting %s WITHOUT the files\r\n' %
-                    classname)
+                                 classname)
 
             with open(os.path.join(dir, classname+'.csv'), 'w') as f:
                 writer = csv.writer(f, colon_separated)
 
-                properties = cl.getprops()
                 propnames = cl.export_propnames()
                 fields = propnames[:]
                 fields.append('is retired')
@@ -1329,7 +1354,7 @@
                 all_nodes = cl.getnodeids()
 
                 classkey = cl.getkey()
-                if classkey: # False sorts before True, so negate is_retired
+                if classkey:  # False sorts before True, so negate is_retired
                     keysort = lambda i: (cl.get(i, classkey),
                                          not cl.is_retired(i))
                     all_nodes.sort(key=keysort)
@@ -1337,12 +1362,13 @@
 
                 for nodeid in all_nodes:
                     if self.verbose:
-                        sys.stdout.write('\rExporting %s - %s' % 
+                        sys.stdout.write('\rExporting %s - %s' %
                                          (classname, nodeid))
                         sys.stdout.flush()
                     node = cl.getnode(nodeid)
                     exp = cl.export_list(propnames, nodeid)
-                    lensum = sum([len(repr_export(node[p])) for p in propnames])
+                    lensum = sum([len(repr_export(node[p])) for
+                                  p in propnames])
                     # for a safe upper bound of field length we add
                     # difference between CSV len and sum of all field lengths
                     d = sum([len(x) for x in exp]) - lensum
@@ -1359,7 +1385,8 @@
             # export the journals
             with open(os.path.join(dir, classname+'-journals.csv'), 'w') as jf:
                 if self.verbose:
-                    sys.stdout.write("\nExporting Journal for %s\n" % classname)
+                    sys.stdout.write("\nExporting Journal for %s\n" %
+                                     classname)
                     sys.stdout.flush()
                 journals = csv.writer(jf, colon_separated)
                 for row in cl.export_journals():
@@ -1642,12 +1669,12 @@
         except KeyError:
             # not a valid command
             print(_('Unknown command "%(command)s" ("help commands" for a '
-                'list)') % locals())
+                    'list)') % locals())
             return 1
 
         # check for multiple matches
         if len(functions) > 1:
-            print(_('Multiple commands match "%(command)s": %(list)s') % \
+            print(_('Multiple commands match "%(command)s": %(list)s') %
                   {'command': command,
                    'list': ', '.join([i[0] for i in functions])})
             return 1
@@ -1685,6 +1712,9 @@
             self.tracker_home = ''
             print(_("Error: Couldn't open tracker: %(message)s") % locals())
             return 1
+        except ParsingOptionError as message: # message used via locals
+            print("%(message)s" % locals())
+            return 1
 
         # only open the database once!
         if not self.db:
@@ -1751,10 +1781,10 @@
         self.name = 'admin'
         self.password = ''  # unused
         if 'ROUNDUP_LOGIN' in os.environ:
-            l = os.environ['ROUNDUP_LOGIN'].split(':')
-            self.name = l[0]
-            if len(l) > 1:
-                self.password = l[1]
+            login_env = os.environ['ROUNDUP_LOGIN'].split(':')
+            self.name = login_env[0]
+            if len(login_env) > 1:
+                self.password = login_env[1]
         self.separator = None
         self.print_designator = 0
         self.verbose = 0
@@ -1788,10 +1818,10 @@
             elif opt == '-d':
                 self.print_designator = 1
             elif opt == '-u':
-                l = arg.split(':')
-                self.name = l[0]
-                if len(l) > 1:
-                    self.password = l[1]
+                login_opt = arg.split(':')
+                self.name = login_opt[0]
+                if len(login_opt) > 1:
+                    self.password = login_opt[1]
 
         # if no command - go interactive
         # wrap in a try/finally so we always close off the db
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roundup/anypy/ssl_.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,6 @@
+try:
+    # Python 3+
+    from ssl import SSLError
+except (ImportError, AttributeError):
+    # Python 2.5-2.7
+    from socket import sslerror as SSLError
--- a/roundup/anypy/strings.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/anypy/strings.py	Thu Apr 21 16:54:17 2022 -0400
@@ -142,7 +142,15 @@
 def eval_import(s):
     """Evaluate a Python-2-style value imported from a CSV file."""
     if _py3:
-        v = eval(s)
+        try:
+            v = eval(s)
+        except SyntaxError:
+            # handle case where link operation reports id a long int
+            # ('issue', 5002L, "status") rather than as a string.
+            # This was a bug that existed and was fixed before or with v1.2.0
+            import re
+            v = eval(re.sub(r', ([0-9]+)L,',r', \1,', s))
+
         if isinstance(v, str):
             return v.encode('iso-8859-1').decode('utf-8')
         elif isinstance(v, dict):
--- a/roundup/backends/back_mysql.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/back_mysql.py	Thu Apr 21 16:54:17 2022 -0400
@@ -234,8 +234,10 @@
         self.sql('''CREATE TABLE __textids (_class VARCHAR(255),
             _itemid VARCHAR(255), _prop VARCHAR(255), _textid INT)
             ENGINE=%s'''%self.mysql_backend)
-        self.sql('''CREATE TABLE __words (_word VARCHAR(30),
-            _textid INT) ENGINE=%s'''%self.mysql_backend)
+        self.sql('''CREATE TABLE __words (_word VARCHAR(%s),
+            _textid INT) ENGINE=%s''' % ((self.indexer.maxlength + 5),
+                                         self.mysql_backend)
+            )
         self.sql('CREATE INDEX words_word_ids ON __words(_word)')
         self.sql('CREATE INDEX words_by_id ON __words (_textid)')
         self.sql('CREATE UNIQUE INDEX __textids_by_props ON '
@@ -410,6 +412,15 @@
         else:
             self.log_info('No changes needed.')
 
+    def fix_version_6_tables(self):
+        # Modify length for __words._word column.
+        c = self.cursor
+        sql = "alter table __words change column _word _word varchar(%s)" % (
+                                                                   self.arg)
+        # Why magic number 5? It was the original offset between
+        #   column length and maxlength.
+        c.execute(sql, (self.indexer.maxlength + 5,))
+
     def __repr__(self):
         return '<myroundsql 0x%x>'%id(self)
 
--- a/roundup/backends/back_postgresql.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/back_postgresql.py	Thu Apr 21 16:54:17 2022 -0400
@@ -196,25 +196,40 @@
             self.sql("CREATE TABLE dual (dummy integer)")
             self.sql("insert into dual values (1)")
             self.create_version_2_tables()
+            self.fix_version_3_tables()
             # Need to commit here, otherwise otk/session will not find
             # the necessary tables (in a parallel connection!)
             self.commit()
-
-    def checkpoint_data(self):
-        """Commit the state of the database. Allows recovery/retry
-           of operation in exception handler because postgres
-           requires a rollback in case of error generating exception
-        """
-        self.commit()
+            self._add_fts_table()
+            self.commit()
 
-    def restore_connection_on_error(self):
-        """Postgres leaves a cursor in an unusable state after
-           an error. Rollback the transaction to recover and
-           permit a retry of the failed statement. Used with
-           checkpoint_data to handle uniqueness conflict in
-           import_table()
+    def checkpoint_data(self, savepoint="importing"):
+        """Create a subtransaction savepoint. Allows recovery/retry
+           of operation in exception handler because
+           postgres requires a rollback in case of error
+           generating exception.  Used with
+           restore_connecion_on_error to handle uniqueness
+           conflict in import_table().
         """
-        self.rollback()
+        # Savepoints take resources. Postgres keeps all
+        # savepoints (rather than overwriting) until a
+        # commit(). If an import fails because of a resource
+        # issue with savepoints, uncomment this line. I
+        # expect it will slow down the import but it should
+        # eliminate any issue with stored savepoints and
+        # resource use.
+        #
+        # self.sql('RELEASE SAVEPOINT %s' % savepoint)
+        self.sql('SAVEPOINT %s' % savepoint)
+
+    def restore_connection_on_error(self, savepoint="importing"):
+        """Postgres leaves a connection/cursor in an unusable state
+           after an error. Rollback the transaction to a
+           previous savepoint and permit a retry of the
+           failed statement. Used with checkpoint_data to
+           handle uniqueness conflict in import_table().
+        """
+        self.sql('ROLLBACK TO %s' % savepoint)
 
     def create_version_2_tables(self):
         # OTK store
@@ -234,8 +249,8 @@
         self.sql('''CREATE TABLE __textids (
             _textid integer primary key, _class VARCHAR(255),
             _itemid VARCHAR(255), _prop VARCHAR(255))''')
-        self.sql('''CREATE TABLE __words (_word VARCHAR(30),
-            _textid integer)''')
+        self.sql('''CREATE TABLE __words (_word VARCHAR(%s),
+            _textid integer)''' % (self.indexer.maxlength + 5))
         self.sql('CREATE INDEX words_word_idx ON __words(_word)')
         self.sql('CREATE INDEX words_by_id ON __words (_textid)')
         self.sql('CREATE UNIQUE INDEX __textids_by_props ON '
@@ -263,6 +278,24 @@
         self.sql('''CREATE INDEX words_both_idx ON public.__words
             USING btree (_word, _textid)''')
 
+    def _add_fts_table(self):
+        self.sql('CREATE TABLE __fts (_class VARCHAR(255), '
+                 '_itemid VARCHAR(255), _prop VARCHAR(255), _tsv tsvector)'
+        )
+
+        self.sql('CREATE INDEX __fts_idx ON __fts USING GIN (_tsv)')
+
+    def fix_version_6_tables(self):
+        # Modify length for __words._word column.
+        c = self.cursor
+        sql = 'alter table __words alter column _word type varchar(%s)' % (
+                                                                  self.arg)
+        # Why magic number 5? It was the original offset between
+        #   column length and maxlength.
+        c.execute(sql, (self.indexer.maxlength + 5,))
+
+        self._add_fts_table()
+
     def add_actor_column(self):
         # update existing tables to have the new actor column
         tables = self.database_schema['tables']
--- a/roundup/backends/back_sqlite.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/back_sqlite.py	Thu Apr 21 16:54:17 2022 -0400
@@ -174,6 +174,7 @@
             self.sql('create table ids (name varchar, num integer)')
             self.sql('create index ids_name_idx on ids(name)')
             self.create_version_2_tables()
+            self._add_fts5_table()
 
     def create_version_2_tables(self):
         self.sql('create table otks (otk_key varchar, '
@@ -212,6 +213,17 @@
         # NOOP - no restriction on column length here
         pass
 
+    def _add_fts5_table(self):
+        self.sql('CREATE virtual TABLE __fts USING fts5(_class, '
+                 '_itemid, _prop, _textblob)'
+        )
+
+    def fix_version_6_tables(self):
+        # note sqlite has no limit on column size so v6 fixes
+        # to __words._word length are not needed.
+        # Add native full-text indexing table
+        self._add_fts5_table()
+
     def update_class(self, spec, old_spec, force=0, adding_v2=0):
         """ Determine the differences between the current spec and the
             database version of the spec, and update where necessary.
--- a/roundup/backends/indexer_common.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/indexer_common.py	Thu Apr 21 16:54:17 2022 -0400
@@ -19,11 +19,15 @@
         self.stopwords = set(STOPWORDS)
         for word in db.config[('main', 'indexer_stopwords')]:
             self.stopwords.add(word)
-        # Do not index anything longer than 25 characters since that'll be
-        # gibberish (encoded text or somesuch) or shorter than 2 characters
+        # Do not index anything longer than maxlength characters since
+        # that'll be gibberish (encoded text or somesuch) or shorter
+        # than 2 characters
         self.minlength = 2
-        self.maxlength = 25
+        self.maxlength = 50
         self.language = db.config[('main','indexer_language')]
+        # Some indexers have a query language. If that is the case,
+        # we don't parse the user supplied query into a wordlist.
+        self.query_language = False
 
     def is_stopword(self, word):
         return word in self.stopwords
@@ -134,6 +138,19 @@
         from .indexer_whoosh import Indexer
         return Indexer(db)
 
+    if indexer_name == "native-fts":
+        if db.dbtype not in ("sqlite", "postgres"):
+            raise AssertionError("Indexer native-fts is configured, but only sqlite and postgres support it. Database is: %r" % db.dbtype)
+
+        if db.dbtype == "sqlite":
+            from roundup.backends.indexer_sqlite_fts import Indexer
+            return Indexer(db)
+
+        if db.dbtype == "postgres":
+            raise NotImplementedError("Postgres FTS not available")
+            from roundup.backends.indexer_postgres_fts import Indexer
+            return Indexer(db)
+
     if indexer_name == "native":
         # load proper native indexing based on database type
         if db.dbtype == "anydbm":
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roundup/backends/indexer_postgresql_fts.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,141 @@
+""" This implements the PostgreSQL full-text indexer.
+The table consists of (Class, propname, itemid) instances as columns
+along with an _tsv tsvector column. The _tsv column is searched using
+@@ and the instances returned.
+"""
+
+import re
+
+from roundup.backends.indexer_common import Indexer as IndexerBase
+from roundup.i18n import _
+from roundup.cgi.exceptions import IndexerQueryError
+
+from psycopg2.errors import InFailedSqlTransaction, SyntaxError, \
+                            UndefinedObject
+
+
+class Indexer(IndexerBase):
+    def __init__(self, db):
+        IndexerBase.__init__(self, db)
+        self.db = db
+        if db.conn.server_version < 110000:
+            db.sql("select version()")
+            server_descr = db.cursor.fetchone()
+            raise ValueError("Postgres native_fts indexing requires postgres "
+                             "11.0 or newer. Server is version: %s" %
+                             server_descr)
+        self.reindex = 0
+        self.query_language = True
+
+    def close(self):
+        """close the indexing database"""
+        # just nuke the circular reference
+        self.db = None
+
+    def save_index(self):
+        """Save the changes to the index."""
+        # not necessary - the RDBMS connection will handle this for us
+        pass
+
+    def force_reindex(self):
+        """Force a reindexing of the database.  This essentially
+        empties the __fts table and sets a flag so
+        that the databases are reindexed"""
+        self.reindex = 1
+
+    def should_reindex(self):
+        """returns True if the indexes need to be rebuilt"""
+        return self.reindex
+
+    def add_text(self, identifier, text, mime_type='text/plain'):
+        """ "identifier" is  (classname, itemid, property) """
+        if mime_type != 'text/plain':
+            return
+
+        # Ensure all elements of the identifier are strings 'cos the itemid
+        # column is varchar even if item ids may be numbers elsewhere in the
+        # code. ugh.
+        identifier = tuple(map(str, identifier))
+
+        # removed pre-processing of text that incudes only words with:
+        # self.minlength <= len(word) <= self.maxlength
+        # Not sure if that is correct.
+
+        # first, find the rowid of the (classname, itemid, property)
+        a = self.db.arg  # arg is the token for positional parameters
+        sql = 'select ctid from __fts where _class=%s and '\
+            '_itemid=%s and _prop=%s' % (a, a, a)
+        self.db.cursor.execute(sql, identifier)
+        r = self.db.cursor.fetchone()
+        if not r:
+            # not previously indexed
+            sql = 'insert into __fts (_class, _itemid, _prop, _tsv)'\
+                ' values (%s, %s, %s, to_tsvector(%s, %s))' % (a, a, a, a, a)
+            self.db.cursor.execute(sql, identifier +
+                                   (self.db.config['INDEXER_LANGUAGE'], text))
+        else:
+            id = r[0]
+            sql = 'update __fts set _tsv=to_tsvector(%s, %s) where ctid=%s' % \
+                  (a, a, a)
+            self.db.cursor.execute(sql, (self.db.config['INDEXER_LANGUAGE'],
+                                         text, id))
+
+    def find(self, wordlist):
+        """look up all the words in the wordlist.
+           For testing wordlist is actually a list.
+           In production, wordlist is a list of a single string
+           that is a postgresql websearch_to_tsquery() query.
+
+           https://www.postgresql.org/docs/14/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES
+        """
+
+        if not wordlist:
+            return []
+
+        a = self.db.arg  # arg is the token for positional parameters
+
+        # removed filtering of word in wordlist to include only
+        # words with:  self.minlength <= len(word) <= self.maxlength
+        if wordlist[0].startswith("ts:"):
+            wordlist[0] = wordlist[0][3:]
+            sql = ('select _class, _itemid, _prop from __fts '
+                   'where _tsv @@ to_tsquery(%s, %s)' % (a, a))
+
+        else:
+            if re.search(r'[<>!&|()*]', " ".join(wordlist)):
+                # assume this is a ts query processed by websearch_to_tsquery.
+                # since it has operator characters in it.
+                raise IndexerQueryError(_('You have non-word/operator '
+                'characters "<>!&|()*" in your query. Did you want to '
+                'do a tsquery search and forgot to start it with "ts:"?'))
+            else:
+                sql = 'select _class, _itemid, _prop from __fts '\
+                      'where _tsv @@ websearch_to_tsquery(%s, %s)' % (a, a)
+
+        try:
+            # tests supply a multi element word list. Join them.
+            self.db.cursor.execute(sql, (self.db.config['INDEXER_LANGUAGE'],
+                                         " ".join(wordlist),))
+        except SyntaxError as e:
+            # reset the cursor as it's invalid currently
+            # reuse causes an InFailedSqlTransaction
+            self.db.rollback()
+
+            raise IndexerQueryError(e.args[0])
+        except InFailedSqlTransaction:
+            # reset the cursor as it's invalid currently
+            self.db.rollback()
+            raise
+        except UndefinedObject as e:
+            # try for a nicer user error
+            self.db.rollback()
+            lookfor = ('text search configuration "%s" does '
+                       'not exist' % self.db.config['INDEXER_LANGUAGE'])
+            if lookfor in e.args[0]:
+                raise ValueError(_("Check tracker config.ini for a bad "
+                                   "indexer_language setting. Error is: %s") %
+                                 e)
+            else:
+                raise
+
+        return self.db.cursor.fetchall()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/roundup/backends/indexer_sqlite_fts.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,123 @@
+""" This implements the full-text indexer using fts5 in sqlite.
+The table consists of (Class, propname, itemid) instances as columns
+along with a textblob column. The textblob column is searched using
+MATCH and the instances returned.
+
+sqlite test commands to manage schema version change required by
+this update.
+
+-- check length before and after
+select length(schema) from schema;
+
+-- reset from version 7 (with fts index) to version 6
+ update schema set schema = (select replace(schema,
+   '''version'': 7','''version'': 6') as new_schema from schema);
+
+-- check version. Good thing it's at the front of the schema
+ select substr(schema,0,15) from schema;
+ {'version': 6,
+"""
+
+from roundup.backends.indexer_common import Indexer as IndexerBase
+from roundup.i18n import _
+from roundup.cgi.exceptions import IndexerQueryError
+
+try:
+    import sqlite3 as sqlite
+    if sqlite.sqlite_version_info < (3, 9, 0):
+        raise ValueError('sqlite minimum version for FTS5 is 3.9.0+ '
+                         '- %s found' % sqlite.sqlite_version)
+except ImportError:
+    raise ValueError('Unable to import sqlite3 to support FTS.')
+
+
+class Indexer(IndexerBase):
+    def __init__(self, db):
+        IndexerBase.__init__(self, db)
+        self.db = db
+        self.reindex = 0
+        self.query_language = True
+
+    def close(self):
+        """close the indexing database"""
+        # just nuke the circular reference
+        self.db = None
+
+    def save_index(self):
+        """Save the changes to the index."""
+        # not necessary - the RDBMS connection will handle this for us
+        pass
+
+    def force_reindex(self):
+        """Force a reindexing of the database.  This essentially
+        empties the __fts table and sets a flag so
+        that the databases are reindexed"""
+        self.reindex = 1
+
+    def should_reindex(self):
+        """returns True if the indexes need to be rebuilt"""
+        return self.reindex
+
+    def add_text(self, identifier, text, mime_type='text/plain'):
+        """ "identifier" is  (classname, itemid, property) """
+        if mime_type != 'text/plain':
+            return
+
+        # Ensure all elements of the identifier are strings 'cos the itemid
+        # column is varchar even if item ids may be numbers elsewhere in the
+        # code. ugh.
+        identifier = tuple(map(str, identifier))
+
+        # removed pre-processing of text that incudes only words with:
+        # self.minlength <= len(word) <= self.maxlength
+        # Not sure if that is correct.
+
+        # first, find the rowid of the (classname, itemid, property)
+        a = self.db.arg  # arg is the token for positional parameters
+        sql = 'select rowid from __fts where _class=%s and '\
+            '_itemid=%s and _prop=%s' % (a, a, a)
+        self.db.cursor.execute(sql, identifier)
+        r = self.db.cursor.fetchone()
+        if not r:
+            # not previously indexed
+            sql = 'insert into __fts (_class, _itemid, _prop, _textblob)'\
+                ' values (%s, %s, %s, %s)' % (a, a, a, a)
+            self.db.cursor.execute(sql, identifier + (text,))
+        else:
+            id = int(r[0])
+            sql = 'update __fts set _textblob=%s where rowid=%s' % \
+                  (a, a)
+            self.db.cursor.execute(sql, (text, id))
+
+    def find(self, wordlist):
+        """look up all the words in the wordlist.
+           For testing wordlist is actually a list.
+           In production, wordlist is a list of a single string
+           that is a sqlite MATCH query.
+
+           https://www.sqlite.org/fts5.html#full_text_query_syntax
+        """
+        if not wordlist:
+            return []
+
+        a = self.db.arg  # arg is the token for positional parameters
+
+        # removed filtering of word in wordlist to include only
+        # words with:  self.minlength <= len(word) <= self.maxlength
+
+        sql = 'select _class, _itemid, _prop from __fts '\
+              'where _textblob MATCH %s' % a
+
+        try:
+            # tests supply a multi element word list. Join them.
+            self.db.cursor.execute(sql, (" ".join(wordlist),))
+        except sqlite.OperationalError as e:
+            if 'no such column' in e.args[0]:
+                raise IndexerQueryError(
+                    _("Search failed. Try quoting any terms that "
+                      "include a '-' and retry the search."))
+            else:
+                raise IndexerQueryError(e.args[0].replace("fts5:",
+                                                          "Query error:"))
+
+        return self.db.cursor.fetchall()
--- a/roundup/backends/rdbms_common.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/rdbms_common.py	Thu Apr 21 16:54:17 2022 -0400
@@ -329,8 +329,8 @@
         self.sql_commit()
 
     # update this number when we need to make changes to the SQL structure
-    # of the backen database
-    current_db_version = 6
+    # of the backend database
+    current_db_version = 7
     db_version_updated = False
 
     def upgrade_db(self):
@@ -376,10 +376,18 @@
             self.log_info('upgrade to version 6')
             self.fix_version_5_tables()
 
+        if version < 7:
+            self.log_info('upgrade to version 7')
+            self.fix_version_6_tables()
+
         self.database_schema['version'] = self.current_db_version
         self.db_version_updated = True
         return 1
 
+    def fix_version_2_tables(self):
+        # Default (used by sqlite): NOOP
+        pass
+
     def fix_version_3_tables(self):
         # drop the shorter VARCHAR OTK column and add a new TEXT one
         for name in ('otk', 'session'):
@@ -387,10 +395,6 @@
             self.sql('ALTER TABLE %ss DROP %s_value' % (name, name))
             self.sql('ALTER TABLE %ss ADD %s_value TEXT' % (name, name))
 
-    def fix_version_2_tables(self):
-        # Default (used by sqlite): NOOP
-        pass
-
     def fix_version_4_tables(self):
         # note this is an explicit call now
         c = self.cursor
@@ -411,6 +415,12 @@
         # as version 5.
         pass
 
+    def fix_version_6_tables(self):
+        # Default (used by nobody): NOOP
+        # Each backend mysql, postgres, sqlite overrides this
+        # You would think ALTER commands would be the same but nooo.
+        pass
+
     def _convert_journal_tables(self):
         """Get current journal table contents, drop the table and re-create"""
         c = self.cursor
--- a/roundup/backends/sessions_dbm.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/backends/sessions_dbm.py	Thu Apr 21 16:54:17 2022 -0400
@@ -6,7 +6,7 @@
 """
 __docformat__ = 'restructuredtext'
 
-import os, marshal, time
+import os, marshal, time, logging, random
 
 from roundup.anypy.html import html_escape as escape
 
@@ -132,21 +132,24 @@
         dbm = __import__(db_type)
 
         retries_left = 15
+        logger = logging.getLogger('roundup.hyperdb.backend.sessions')
         while True:
             try:
                 handle = dbm.open(path, mode)
                 break
-            except OSError:
+            except OSError as e:
                 # Primarily we want to catch and retry:
                 #   [Errno 11] Resource temporarily unavailable retry
                 # FIXME: make this more specific
+                if retries_left < 10:
+                    logger.warning('dbm.open failed, retrying %s left: %s'%(retries_left,e))
                 if retries_left < 0:
                     # We have used up the retries. Reraise the exception
                     # that got us here.
                     raise
                 else:
-                    # delay retry a bit
-                    time.sleep(0.01)
+                    # stagger retry to try to get around thundering herd issue.
+                    time.sleep(random.randint(0,25)*.005)
                     retries_left = retries_left - 1
                     continue  # the while loop
         return handle
--- a/roundup/cgi/actions.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/cgi/actions.py	Thu Apr 21 16:54:17 2022 -0400
@@ -464,7 +464,7 @@
         different from 'index'
         """
         template = self.getFromForm('template')
-        if template and template != 'index':
+        if template and template not in ['index', 'index|search']:
             return req.indexargs_url('', {'@template': template})[1:]
         return req.indexargs_url('', {})[1:]
 
@@ -1433,8 +1433,22 @@
 
         # full-text search
         if request.search_text:
-            matches = self.db.indexer.search(
-                re.findall(r'\b\w{2,25}\b', request.search_text), klass)
+            indexer = self.db.indexer
+            if self.db.indexer.query_language:
+                try:
+                    matches = indexer.search(
+                        [request.search_text], klass)
+                except Exception as e:
+                    error = " ".join(e.args)
+                    self.client.add_error_message(error)
+                    self.client.response_code = 400
+                    # trigger error reporting. NotFound isn't right but...
+                    raise exceptions.NotFound(error)
+            else:
+                matches = indexer.search(
+                    re.findall(r'\b\w{%s,%s}\b' % (indexer.minlength,
+                                                   indexer.maxlength),
+                               request.search_text), klass)
         else:
             matches = None
 
@@ -1598,8 +1612,23 @@
 
         # full-text search
         if request.search_text:
-            matches = self.db.indexer.search(
-                re.findall(r'\b\w{2,25}\b', request.search_text), klass)
+            indexer = self.db.indexer
+            if indexer.query_language:
+                try:
+                    matches = indexer.search(
+                        [request.search_text], klass)
+                except Exception as e:
+                    error = " ".join(e.args)
+                    self.client.add_error_message(error)
+                    self.client.response_code = 400
+                    # trigger error reporting. NotFound isn't right but...
+                    raise exceptions.NotFound(error)
+            else:
+                matches = indexer.search(
+                    re.findall(r'\b\w{%s,%s}\b' % (indexer.minlength,
+                                                   indexer.maxlength),
+                               request.search_text),
+                    klass)
         else:
             matches = None
 
--- a/roundup/cgi/client.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/cgi/client.py	Thu Apr 21 16:54:17 2022 -0400
@@ -31,8 +31,8 @@
 from roundup.exceptions import LoginError, Reject, RejectRaw, \
                                Unauthorised, UsageError
 from roundup.cgi.exceptions import (
-    FormError, NotFound, NotModified, Redirect, SendFile, SendStaticFile,
-    DetectorError, SeriousError)
+    FormError, IndexerQueryError, NotFound, NotModified, Redirect,
+    SendFile, SendStaticFile, DetectorError, SeriousError)
 from roundup.cgi.form_parser import FormParser
 from roundup.mailer import Mailer, MessageSendError
 from roundup.cgi import accept_language
@@ -340,7 +340,10 @@
     # Key can be explicitly file basename - value applied to just that file
     #     takes precedence over mime type.
     # Key can be mime type - all files of that mimetype will get the value
-    Cache_Control = {}
+    Cache_Control = {
+        'application/javascript': "public, max-age=1209600", # 2 weeks
+        'text/css':               "public, max-age=4838400", # 8 weeks/2 months
+    }
 
     # list of valid http compression (Content-Encoding) algorithms
     # we have available
@@ -645,8 +648,11 @@
 
         # type header set by rest handler
         # self.setHeader("Content-Type", "text/xml")
-        self.setHeader("Content-Length", str(len(output)))
-        self.write(output)
+        if self.response_code == 204: # no body with 204
+            self.write("")
+        else:
+            self.setHeader("Content-Length", str(len(output)))
+            self.write(output)
 
     def add_ok_message(self, msg, escape=True):
         add_message(self._ok_message, msg, escape)
@@ -848,7 +854,7 @@
             else:
                 # in debug mode, only write error to screen.
                 self.write_html(e.html)
-        except:
+        except Exception as e:
             # Something has gone badly wrong.  Therefore, we should
             # make sure that the response code indicates failure.
             if self.response_code == http_.client.OK:
@@ -1775,7 +1781,6 @@
         """
 
         # spit out headers
-        self.additional_headers['Content-Type'] = mime_type
         self.additional_headers['Last-Modified'] = email.utils.formatdate(lmt)
 
         ims = None
@@ -1796,6 +1801,9 @@
                     self.setVary("Accept-Encoding")
                 raise NotModified
 
+        # don't set until we are sure we are sending a response body.
+        self.additional_headers['Content-Type'] = mime_type
+
         if filename:
             self.write_file(filename)
         else:
@@ -1915,7 +1923,11 @@
             }
             pt = self.instance.templates.load(tplname)
             # let the template render figure stuff out
-            result = pt.render(self, None, None, **args)
+            try:
+                result = pt.render(self, None, None, **args)
+            except IndexerQueryError as e:
+                result = self.renderError(e.args[0])
+
             self.additional_headers['Content-Type'] = pt.content_type
             if self.env.get('CGI_SHOW_TIMING', ''):
                 if self.env['CGI_SHOW_TIMING'].upper() == 'COMMENT':
@@ -1962,6 +1974,46 @@
                 else:
                     exec('raise exc_info[0], exc_info[1], exc_info[2]')  # nosec
 
+    def renderError(self, error, response_code=400, use_template=True):
+        self.response_code = response_code
+
+        # see if error message already logged add if not
+        if error not in self._error_message:
+            self.add_error_message(error, escape=True)
+
+        # allow use of template for a specific code
+        trial_templates = []
+        if use_template:
+            if response_code == 400:
+                trial_templates = [ "400" ]
+            else:
+                trial_templates = [ str(response_code), "400" ]
+
+        tplname = None
+        for rcode in trial_templates:
+            try:
+                tplname = self.selectTemplate(self.classname, rcode)
+                break
+            except templating.NoTemplate:
+                pass
+
+        if not tplname:
+            # call string of serious error to get basic html
+            # response.
+            return str(SeriousError(error))
+
+        args = {
+            'ok_message': self._ok_message,
+            'error_message': self._error_message
+        }
+
+        try:
+            pt = self.instance.templates.load(tplname)
+            return pt.render(self, None, None, **args)
+        except Exception:
+            # report original error
+            return str(SeriousError(error))
+
     # these are the actions that are available
     actions = (
         ('edit',        actions.EditItemAction),
@@ -2163,6 +2215,14 @@
             self.additional_headers['Content-Length'] = str(len(new_content))
             self.additional_headers['Content-Encoding'] = encoder
             self.setVary('Accept-Encoding')
+            try:
+                current_etag = self.additional_headers['ETag']
+            except KeyError:
+                pass  # etag not set for non-rest endpoints
+            else:
+                etag_end = current_etag.rindex('"')
+                self.additional_headers['ETag'] = ( current_etag[:etag_end] +
+                                    '-' + encoder + current_etag[etag_end:])
 
         return new_content
 
@@ -2196,6 +2256,8 @@
             if 'Content-Type' not in self.additional_headers:
                 self.additional_headers['Content-Type'] = \
                     'text/html; charset=%s' % self.charset
+            if 'Content-Length' not in self.additional_headers:
+                self.additional_headers['Content-Length'] = str(len(content))
             self.header()
 
         if self.env['REQUEST_METHOD'] == 'HEAD':
@@ -2479,9 +2541,15 @@
         self.write(content)
 
     def setHeader(self, header, value):
-        """Override a header to be returned to the user's browser.
+        """Override or delete a header to be returned to the user's browser.
         """
-        self.additional_headers[header] = value
+        if value is None:
+            try:
+                del(self.additional_headers[header])
+            except KeyError:
+                pass
+        else:
+            self.additional_headers[header] = value
 
     def header(self, headers=None, response=None):
         """Put up the appropriate header.
@@ -2497,6 +2565,9 @@
         if headers.get('Content-Type', 'text/html') == 'text/html':
             headers['Content-Type'] = 'text/html; charset=utf-8'
 
+        if response in [ 204, 304]: # has no body so no content-type
+            del(headers['Content-Type'])
+
         headers = list(headers.items())
 
         for ((path, name), (value, expire)) in self._cookies.items():
--- a/roundup/cgi/exceptions.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/cgi/exceptions.py	Thu Apr 21 16:54:17 2022 -0400
@@ -54,6 +54,11 @@
     """
     pass
 
+class IndexerQueryError(RoundupException):
+    """Raised to handle errors from FTS searches due to query
+       syntax errors.
+    """
+    pass
 
 class SendFile(RoundupException):
     """Send a file from the database."""
--- a/roundup/cgi/templating.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/cgi/templating.py	Thu Apr 21 16:54:17 2022 -0400
@@ -1244,7 +1244,9 @@
                                 try:
                                     if labelprop is not None and \
                                             labelprop != 'id':
-                                        label = linkcl.get(linkid, labelprop)
+                                        label = linkcl.get(linkid, labelprop,
+                                                     default=self._(
+                                                        "[label is missing]"))
                                         label = html_escape(label)
                                 except IndexError:
                                     comments['no_link'] = self._(
@@ -1271,7 +1273,8 @@
                         if labelprop is not None and labelprop != 'id':
                             try:
                                 label = html_escape(linkcl.get(args[k],
-                                    labelprop))
+                                    labelprop, default=self._(
+                                        "[label is missing]")))
                             except IndexError:
                                 comments['no_link'] = self._(
                                     "<strike>The linked node"
@@ -1281,7 +1284,7 @@
                                 label = None
                         if label is not None:
                             if hrefable:
-                                old = '<a ref="nofollow noopener" href="%s%s">%s</a>'%(classname,
+                                old = '<a rel="nofollow noopener" href="%s%s">%s</a>'%(classname,
                                     args[k], label)
                             else:
                                 old = label;
@@ -1612,7 +1615,7 @@
          (/[\w\-$.+!*(),;:@&=?/~\\#%]*)?   # path etc.
         )|
         (?P<email>[-+=%/\w\.]+@[\w\.\-]+)|
-        (?P<item>(?P<class>[A-Za-z_]+)(\s*)(?P<id>\d+))
+        (?P<item>(?P<class>[A-Za-z_]+)(\s*)(?P<id>\d+)(?P<fragment>\#[^][\#%^{}"<>\s]+)?)
     )''', re.X | re.I)
     protocol_re = re.compile('^(ht|f)tp(s?)://', re.I)
 
@@ -1630,7 +1633,7 @@
             return self._hyper_repl_email(match, '<a href="mailto:%s">%s</a>')
         elif len(match.group('id')) < 10:
             return self._hyper_repl_item(match,
-                '<a href="%(cls)s%(id)s">%(item)s</a>')
+                '<a href="%(cls)s%(id)s%(fragment)s">%(item)s</a>')
         else:
             # just return the matched text
             return match.group(0)
@@ -1664,6 +1667,9 @@
         item = match.group('item')
         cls = match.group('class').lower()
         id = match.group('id')
+        fragment = match.group('fragment')
+        if fragment is None:
+            fragment=""
         try:
             # make sure cls is a valid tracker classname
             cl = self._db.getclass(cls)
@@ -2422,7 +2428,8 @@
         k = linkcl.labelprop(1)
         if num_re.match(self._value):
             try:
-                value = str(linkcl.get(self._value, k))
+                value = str(linkcl.get(self._value, k,
+                                       default=self._("[label is missing]")))
             except IndexError:
                 value = self._value
         else :
@@ -2720,7 +2727,8 @@
         for v in self._value:
             if num_re.match(v):
                 try:
-                    label = linkcl.get(v, k)
+                    label = linkcl.get(v, k,
+                                       default=self._("[label is missing]"))
                 except IndexError:
                     label = None
                 # fall back to designator if label is None
@@ -3343,11 +3351,21 @@
         # get the list of ids we're batching over
         klass = self.client.db.getclass(self.classname)
         if self.search_text:
-            matches = self.client.db.indexer.search(
-                [u2s(w.upper()) for w in re.findall(
-                    r'(?u)\b\w{2,25}\b',
-                    s2u(self.search_text, "replace")
-                )], klass)
+            indexer = self.client.db.indexer
+            if indexer.query_language:
+                try:
+                    matches = indexer.search(
+                        [self.search_text], klass)
+                except Exception as e:
+                    self.client.add_error_message(" ".join(e.args))
+                    raise
+            else:
+                matches = indexer.search(
+                    [u2s(w.upper()) for w in re.findall(
+                        r'(?u)\b\w{%s,%s}\b' % (indexer.minlength,
+                                                indexer.maxlength),
+                        s2u(self.search_text, "replace")
+                    )], klass)
         else:
             matches = None
 
--- a/roundup/configuration.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/configuration.py	Thu Apr 21 16:54:17 2022 -0400
@@ -9,7 +9,9 @@
 # used here instead of try/except.
 import sys
 import getopt
-import logging, logging.config
+import errno
+import logging
+import logging.config
 import os
 import re
 import time
@@ -31,8 +33,6 @@
 
 from roundup.exceptions import RoundupException
 
-# XXX i don't think this module needs string translation, does it?
-
 ### Exceptions
 
 
@@ -40,6 +40,11 @@
     pass
 
 
+class ParsingOptionError(ConfigurationError):
+    def __str__(self):
+        return self.args[0]
+
+
 class NoConfigError(ConfigurationError):
 
     """Raised when configuration loading fails
@@ -261,8 +266,17 @@
 
     def load_ini(self, config):
         """Load value from ConfigParser object"""
-        if config.has_option(self.section, self.setting):
-            self.set(config.get(self.section, self.setting))
+        try:
+            if config.has_option(self.section, self.setting):
+                self.set(config.get(self.section, self.setting))
+        except configparser.InterpolationSyntaxError as e:
+            raise ParsingOptionError(
+                _("Error in %(filepath)s with section [%(section)s] at "
+                  "option %(option)s: %(message)s") % {
+                      "filepath": self.config.filepath,
+                      "section": e.section,
+                      "option": e.option,
+                      "message": str(e)})
 
 
 class BooleanOption(Option):
@@ -408,19 +422,91 @@
             return _val
         raise OptionValueError(self, value, self.class_description)
 
+
 class IndexerOption(Option):
     """Valid options for indexer"""
 
-    allowed = ['', 'xapian', 'whoosh', 'native']
+    allowed = ['', 'xapian', 'whoosh', 'native', 'native-fts']
     class_description = "Allowed values: %s" % ', '.join("'%s'" % a
                                                          for a in allowed)
 
+    # FIXME this is the result of running:
+    #    SELECT cfgname FROM pg_ts_config;
+    # on a postgresql 14.1 server.
+    # So the best we can do is hardcode this.
+    valid_langs = [ "simple",
+                    "custom1",
+                    "custom2",
+                    "custom3",
+                    "custom4",
+                    "custom5",
+                    "arabic",
+                    "armenian",
+                    "basque",
+                    "catalan",
+                    "danish",
+                    "dutch",
+                    "english",
+                    "finnish",
+                    "french",
+                    "german",
+                    "greek",
+                    "hindi",
+                    "hungarian",
+                    "indonesian",
+                    "irish",
+                    "italian",
+                    "lithuanian",
+                    "nepali",
+                    "norwegian",
+                    "portuguese",
+                    "romanian",
+                    "russian",
+                    "serbian",
+                    "spanish",
+                    "swedish",
+                    "tamil",
+                    "turkish",
+                    "yiddish" ]
+                                                         
     def str2value(self, value):
         _val = value.lower()
         if _val in self.allowed:
             return _val
         raise OptionValueError(self, value, self.class_description)
 
+    def validate(self, options):
+
+        if self._value in ("", "xapian"):
+            try:
+                import xapian
+            except ImportError:
+                # indexer is probably '' and xapian isn't present
+                # so just return at end of method
+                pass
+            else:
+                try:
+                    lang = options["INDEXER_LANGUAGE"]._value
+                    xapian.Stem(lang)
+                except xapian.InvalidArgumentError:
+                    import textwrap
+                    lang_avail = b2s(xapian.Stem.get_available_languages())
+                    languages = textwrap.fill(_("Valid languages: ") +
+                                              lang_avail, 75,
+                                              subsequent_indent="   ")
+                    raise OptionValueError(options["INDEXER_LANGUAGE"],
+                                            lang, languages)
+
+        if self._value == "native-fts":
+            lang = options["INDEXER_LANGUAGE"]._value
+            if lang not in self.valid_langs:
+                import textwrap
+                languages = textwrap.fill(_("Expected languages: ") +
+                                            " ".join(self.valid_langs), 75,
+                                            subsequent_indent="   ")
+                raise OptionValueError(options["INDEXER_LANGUAGE"],
+                                       lang, languages)
+
 class MailAddressOption(Option):
 
     """Email address
@@ -552,6 +638,62 @@
             return value
 
 
+class SecretOption(Option):
+    """A string not beginning with file:// or a file starting with file://
+
+    Paths may be either absolute or relative to the HOME.
+    Value for option is the first line in the file.
+    It is mean to store secret information in the config file but
+    allow the config file to be stored in version control without
+    storing the secret there.
+
+    """
+
+    class_description = \
+      "A string that starts with 'file://' is interpreted as a file path \n" \
+      "relative to the tracker home. Using 'file:///' defines an absolute \n" \
+      "path. The first line of the file will be used as the value. Any \n" \
+      "string that does not start with 'file://' is used as is. It \n" \
+      "removes any whitespace at the end of the line, so a newline can \n" \
+      "be put in the file.\n"
+
+    def get(self):
+        _val = Option.get(self)
+        if isinstance(_val, str) and _val.startswith('file://'):
+            filepath = _val[7:]
+            if filepath and not os.path.isabs(filepath):
+                filepath = os.path.join(self.config["HOME"], filepath.strip())
+            try:
+                with open(filepath) as f:
+                    _val = f.readline().rstrip()
+            # except FileNotFoundError: py2/py3
+            # compatible version
+            except EnvironmentError as e:
+                if e.errno != errno.ENOENT:
+                    raise
+                else:
+                    raise OptionValueError(self, _val,
+                        "Unable to read value for %s. Error opening "
+                        "%s: %s." % (self.name, e.filename, e.args[1]))
+        return self.str2value(_val)
+
+    def validate(self, options):
+        if self.name == 'MAIL_PASSWORD':
+            if options['MAIL_USERNAME']._value:
+                # MAIL_PASSWORD is an exception. It is mandatory only
+                # if MAIL_USERNAME is set. So check only if username
+                # is set.
+                try:
+                    self.get()
+                except OptionUnsetError:
+                    # provide error message with link to MAIL_USERNAME
+                    raise OptionValueError(options["MAIL_PASSWORD"],
+                                           "not defined",
+                            "Mail username is set, so this must be defined.")
+        else:
+            self.get()
+
+
 class WebUrlOption(Option):
     """URL MUST start with http/https scheme and end with '/'"""
 
@@ -614,6 +756,18 @@
     # everything else taken from NullableOption (inheritance order)
 
 
+class SecretMandatoryOption(MandatoryOption, SecretOption):
+    # use get from SecretOption and rest from MandatoryOption
+    get = SecretOption.get
+    class_description = SecretOption.class_description
+
+
+class SecretNullableOption(NullableOption, SecretOption):
+    # use get from SecretOption and rest from NullableOption
+    get = SecretOption.get
+    class_description = SecretOption.class_description
+
+
 class TimezoneOption(Option):
 
     class_description = \
@@ -639,6 +793,17 @@
         return value
 
 
+class HttpVersionOption(Option):
+    """Used by roundup-server to verify http version is set to valid
+       string."""
+
+    def str2value(self, value):
+        if value not in ["HTTP/1.0", "HTTP/1.1"]:
+            raise OptionValueError(self, value,
+                "Valid vaues for -V or --http_version are: HTTP/1.0, HTTP/1.1")
+        return value
+
+
 class RegExpOption(Option):
 
     """Regular Expression option (value is Regular Expression Object)"""
@@ -758,17 +923,20 @@
             "Force Roundup to use a particular text indexer.\n"
             "If no indexer is supplied, the first available indexer\n"
             "will be used in the following order:\n"
-            "Possible values: xapian, whoosh, native (internal)."),
+            "Possible values: xapian, whoosh, native (internal), "
+            "native-fts.\nNote 'native-fts' will only be used if set."),
         (Option, "indexer_language", "english",
             "Used to determine what language should be used by the\n"
-            "indexer above. Currently only affects Xapian indexer. It\n"
-            "sets the language for the stemmer.\n"
+            "indexer above. Applies to Xapian and PostgreSQL native-fts\n"
+            "indexer. It sets the language for the stemmer, and PostgreSQL\n"
+            "native-fts stopwords and other dictionaries.\n"
             "Possible values: must be a valid language for the indexer,\n"
             "see indexer documentation for details."),
         (WordListOption, "indexer_stopwords", "",
             "Additional stop-words for the full-text indexer specific to\n"
             "your tracker. See the indexer source for the default list of\n"
-            "stop-words (eg. A,AND,ARE,AS,AT,BE,BUT,BY, ...)"),
+            "stop-words (eg. A,AND,ARE,AS,AT,BE,BUT,BY, ...). This is\n"
+            "not used by the native-fts indexer."),
         (OctalNumberOption, "umask", "0o002",
             "Defines the file creation mode mask."),
         (IntegerNumberGeqZeroOption, 'csv_field_size', '131072',
@@ -1038,7 +1206,7 @@
             "Setting this option makes Roundup migrate passwords with\n"
             "an insecure password-scheme to a more secure scheme\n"
             "when the user logs in via the web-interface."),
-        (MandatoryOption, "secret_key", create_token(),
+        (SecretMandatoryOption, "secret_key", create_token(),
             "A per tracker secret used in etag calculations for\n"
             "an object. It must not be empty.\n"
             "It prevents reverse engineering hidden data in an object\n"
@@ -1050,7 +1218,7 @@
             "(Note the default value changes every time\n"
             "     roundup-admin updateconfig\n"
             "is run, so it must be explicitly set to a non-empty string.\n"),
-        (MandatoryOption, "jwt_secret", "disabled",
+        (SecretNullableOption, "jwt_secret", "disabled",
             "This is used to generate/validate json web tokens (jwt).\n"
             "Even if you don't use jwts it must not be empty.\n"
             "If less than 256 bits (32 characters) in length it will\n"
@@ -1076,7 +1244,7 @@
         (NullableOption, 'user', 'roundup',
             "Database user name that Roundup should use.",
             ['MYSQL_DBUSER']),
-        (NullableOption, 'password', 'roundup',
+        (SecretNullableOption, 'password', 'roundup',
             "Database user password.",
             ['MYSQL_DBPASSWORD']),
         (NullableOption, 'read_default_file', '~/.my.cnf',
@@ -1157,7 +1325,7 @@
         (Option, "username", "", "SMTP login name.\n"
             "Set this if your mail host requires authenticated access.\n"
             "If username is not empty, password (below) MUST be set!"),
-        (Option, "password", NODEFAULT, "SMTP login password.\n"
+        (SecretMandatoryOption, "password", NODEFAULT, "SMTP login password.\n"
             "Set this if your mail host requires authenticated access."),
         (IntegerNumberGeqZeroOption, "port", smtplib.SMTP_PORT,
             "Default port to send SMTP on.\n"
@@ -1400,7 +1568,11 @@
     # actual name of the config file.  set on load.
     filepath = os.path.join(HOME, INI_FILE)
 
-    def __init__(self, config_path=None, layout=None, settings={}):
+    # List of option names that need additional validation after
+    # all options are loaded.
+    option_validators = []
+
+    def __init__(self, config_path=None, layout=None, settings=None):
         """Initialize confing instance
 
         Parameters:
@@ -1417,6 +1589,8 @@
                 The overrides are applied after loading config file.
 
         """
+        if settings is None:
+            settings = {}
         # initialize option containers:
         self.sections = []
         self.section_descriptions = {}
@@ -1471,6 +1645,9 @@
         for _name in option.aliases:
             self.options[_name] = option
 
+        if hasattr(option, 'validate'):
+            self.option_validators.append(option.name)
+
     def update_option(self, name, klass,
                       default=NODEFAULT, description=None):
         """Override behaviour of early created option.
@@ -1815,7 +1992,9 @@
     ext = None
     detectors = None
 
-    def __init__(self, home_dir=None, settings={}):
+    def __init__(self, home_dir=None, settings=None):
+        if settings is None:
+            settings = {}
         Config.__init__(self, home_dir, layout=SETTINGS, settings=settings)
         # load the config if home_dir given
         if home_dir is None:
@@ -1882,25 +2061,10 @@
             on each other. E.G. indexer_language can only be
             validated if xapian indexer is used.
         """
-        if options['INDEXER']._value in ("", "xapian"):
-            try:
-                import xapian
-            except ImportError:
-                # indexer is probably '' and xapian isn't present
-                # so just return at end of method
-                pass
-            else:
-                try:
-                    lang = options["INDEXER_LANGUAGE"]._value
-                    xapian.Stem(lang)
-                except xapian.InvalidArgumentError:
-                    import textwrap
-                    lang_avail = b2s(xapian.Stem.get_available_languages())
-                    languages = textwrap.fill(_("Valid languages: ") +
-                                              lang_avail, 75,
-                                              subsequent_indent="   ")
-                    raise OptionValueError( options["INDEXER_LANGUAGE"],
-                                            lang, languages)
+
+        for option in self.option_validators:
+            # validate() should throw an exception if there is an issue.
+            options[option].validate(options)
 
     def load(self, home_dir):
         """Load configuration from path designated by home_dir argument"""
--- a/roundup/demo.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/demo.py	Thu Apr 21 16:54:17 2022 -0400
@@ -39,7 +39,13 @@
     from roundup import init, instance, password
 
     # set up the config for this tracker
-    config = configuration.CoreConfig()
+    template_dir = os.path.join('share', 'roundup', 'templates', template)
+
+    # Load optional override ini file. Missing ini file is ignored.
+    template_cfg = configuration.UserConfig(template_dir + "/config_ini.ini")
+    config = configuration.CoreConfig(settings={
+        i.name: i.get() for i in template_cfg.items()
+    })
     config['TRACKER_HOME'] = home
     config['MAIL_DOMAIN'] = 'localhost'
     config['DATABASE'] = 'db'
@@ -64,8 +70,18 @@
             print("    %s" % home)
             sys.exit(1)
 
-    template_dir = os.path.join('share', 'roundup', 'templates', template)
     init.install(home, template_dir)
+    # Remove config_ini.ini file from tracker_home (not template dir).
+    # Ignore file not found - not all templates have
+    #   config_ini.ini files.
+    try:
+        os.remove(home + "/config_ini.ini")
+    except OSError as e:  # FileNotFound exception under py3
+        if e.errno == 2:
+            pass
+        else:
+            raise
+
     # don't have email flying around
     nosyreaction = os.path.join(home, 'detectors', 'nosyreaction.py')
     if os.path.exists(nosyreaction):
@@ -97,12 +113,6 @@
 
     # write the config
     config['INSTANT_REGISTRATION'] = 1
-    # FIXME: Move template-specific demo initialization into the templates.
-    if template == 'responsive':
-        config['STATIC_FILES'] = "static"
-    if template == 'jinja2':
-        config['TEMPLATE_ENGINE'] = 'jinja2'
-        config['STATIC_FILES'] = "static"
     config.save(os.path.join(home, config.INI_FILE))
 
     # open the tracker and initialise
@@ -113,7 +123,7 @@
     db = tracker.open('admin')
     # FIXME: Move tracker-specific demo initialization into the tracker
     # templates.
-    if template == 'minimal':
+    if os.path.basename(template) == 'minimal':
         db.user.create(username='demo', password=password.Password('demo'),
                        roles='User')
     else:
--- a/roundup/hyperdb.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/hyperdb.py	Thu Apr 21 16:54:17 2022 -0400
@@ -1019,8 +1019,9 @@
         for cn in self.getclasses():
             cl = self.getclass(cn)
             # This will change properties if a back-multilink happens to
-            # have the same class, so we need to iterate over .keys()
-            for p in cl.properties.keys():
+            # have the same class, so we need to iterate over a list made
+            # from .keys()
+            for p in list(cl.properties.keys()):
                 prop = cl.properties[p]
                 if not isinstance (prop, (Link, Multilink)):
                     continue
@@ -1167,7 +1168,7 @@
         This method must be called at the end of processing.
 
         """
-
+        raise NotImplementedError
 
 def iter_roles(roles):
     ''' handle the text processing of turning the roles list
--- a/roundup/i18n.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/i18n.py	Thu Apr 21 16:54:17 2022 -0400
@@ -58,6 +58,20 @@
     LOCALE_DIRS.append(_mo_path)
 del _mo_path
 
+import sys
+# __file__ should be something like:
+#    /usr/local/lib/python3.10/site-packages/roundup/i18n.py
+# os.prefix should be /usr, /usr/local or root of virtualenv
+#    strip leading / to make os.path.join work right.
+path = __file__
+for N in 1, 2:
+    path = os.path.dirname(path)
+    # path is /usr/local/lib/python3.10/site-packages
+_ldir = os.path.join(path, sys.prefix[1:], 'share', 'locale')
+if os.path.isdir(_ldir):
+    LOCALE_DIRS.append(_ldir)
+del _ldir
+
 # Roundup text domain
 DOMAIN = "roundup"
 
--- a/roundup/instance.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/instance.py	Thu Apr 21 16:54:17 2022 -0400
@@ -134,6 +134,8 @@
                 extension(self)
             detectors = self.get_extensions('detectors')
         db = env['db']
+        # *Must* call post_init! It is not an error if called multiple times.
+        db.post_init ()
         db.tx_Source = None
 
         # apply the detectors
--- a/roundup/mailgw.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/mailgw.py	Thu Apr 21 16:54:17 2022 -0400
@@ -112,6 +112,7 @@
 from roundup.hyperdb import iter_roles
 from roundup.anypy.strings import StringIO, b2s, u2s
 import roundup.anypy.random_ as random_
+import roundup.anypy.ssl_ as ssl_
 
 try:
     import gpg, gpg.core, gpg.constants, gpg.constants.sigsum
@@ -1373,7 +1374,7 @@
             else:
                 self.logger.debug('Trying server %r without ssl' % server)
                 server = imaplib.IMAP4(server)
-        except (imaplib.IMAP4.error, socket.error, socket.sslerror):
+        except (imaplib.IMAP4.error, socket.error, ssl_.SSLError):
             self.logger.exception('IMAP server error')
             return 1
 
@@ -1415,7 +1416,7 @@
         finally:
             try:
                 server.expunge()
-            except (imaplib.IMAP4.error, socket.error, socket.sslerror):
+            except (imaplib.IMAP4.error, socket.error, ssl_.SSLError):
                 pass
             server.logout()
 
@@ -1461,7 +1462,7 @@
             else:
                 klass = poplib.POP3
             server = klass(server)
-        except socket.error:
+        except (socket.error, ssl_.SSLError):
             self.logger.exception('POP server error')
             return 1
         if apop:
--- a/roundup/password.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/password.py	Thu Apr 21 16:54:17 2022 -0400
@@ -201,7 +201,10 @@
         s = sha1(s2b(plaintext)).hexdigest()  # nosec
     elif scheme == 'MD5':
         s = md5(s2b(plaintext)).hexdigest()  # nosec
-    elif scheme == 'crypt' and crypt is not None:
+    elif scheme == 'crypt':
+        if crypt is None:
+            raise PasswordValueError(
+                'Unsupported encryption scheme %r' % scheme)
         if other is not None:
             salt = other
         else:
@@ -355,6 +358,8 @@
             raise ValueError('Password not set')
         return '{%s}%s' % (self.scheme, self.password)
 
+def test_missing_crypt():
+    p = encodePassword('sekrit', 'crypt')
 
 def test():
     # SHA
@@ -415,5 +420,6 @@
 
 if __name__ == '__main__':
     test()
+    test_missing_crypt()
 
 # vim: set filetype=python sts=4 sw=4 et si :
--- a/roundup/rest.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/rest.py	Thu Apr 21 16:54:17 2022 -0400
@@ -123,8 +123,51 @@
                 'data': data
             }
         return result
+
+    format_object.wrapped_func = func
     return format_object
 
+def openapi_doc(d):
+    """Annotate rest routes with openapi data. Takes a dict
+       for the openapi spec. It can be used standalone
+       as the openapi spec paths.<path>.<method> =
+
+     {
+        "summary": "this path gets a value",
+        "description": "a longer description",
+        "responses": {
+          "200": {
+            "description": "normal response",
+            "content": {
+              "application/json": {},
+              "application/xml": {}
+            }
+          },
+          "406": {
+            "description": "Unable to provide requested content type",
+            "content": {
+              "application/json": {}
+            }
+          }
+        },
+        "parameters": [
+          {
+            "$ref": "#components/parameters/generic_.stats"
+          },
+          {
+            "$ref": "#components/parameters/generic_.apiver"
+          },
+          {
+            "$ref": "#components/parameters/generic_.verbose"
+          }
+        ]
+     }
+    """
+
+    def wrapper(f):
+        f.openapi_doc = d
+        return f
+    return wrapper
 
 def calculate_etag(node, key, classname="Missing", id="0",
                    repr_format="json"):
@@ -175,8 +218,20 @@
                                repr_format=repr_format)
 
     for etag in etags:
-        if etag is not None:
-            if etag != node_etag:
+        # etag includes doublequotes around tag:
+        #   '"a46a5572190e4fad63958c135f3746fa"'
+        # but can include content-encoding suffix like:
+        #   '"a46a5572190e4fad63958c135f3746fa-gzip"'
+        # turn the latter into the former as we don't care what
+        # encoding was used to send the body with the etag.
+        try:
+            suffix_start = etag.rindex('-')
+            clean_etag = etag[:suffix_start] + '"'
+        except (ValueError, AttributeError):
+            # - not in etag or etag is None
+            clean_etag = etag
+        if clean_etag is not None:
+            if clean_etag != node_etag:
                 return False
             have_etag_match = True
 
@@ -347,7 +402,13 @@
                 try:
                     func_obj = funcs[method]
                 except KeyError:
-                    raise Reject('Method %s not allowed' % method)
+                    valid_methods = ', '.join(sorted(funcs.keys()))
+                    raise Reject(_('Method %(m)s not allowed. '
+                                   'Allowed: %(a)s')% {
+                                       'm': method,
+                                       'a': valid_methods
+                                   },
+                                   valid_methods)
 
                 # retrieve the vars list and the function caller
                 list_vars = func_obj['vars']
@@ -502,13 +563,13 @@
                 for pn in p.split('.'):
                     # Tried to dereference a non-Link property
                     if cn is None:
-                        raise AttributeError("Unknown: %s" % p)
+                        raise UsageError("Property %(base)s can not be dereferenced in %(p)s." % { "base": p[:-(len(pn)+1)], "p": p})
                     cls = self.db.getclass(cn)
                     # This raises a KeyError for unknown prop:
                     try:
                         prop = cls.getprops(protected=True)[pn]
                     except KeyError:
-                        raise AttributeError("Unknown: %s" % p)
+                        raise KeyError("Unknown property: %s" % p)
                     if isinstance(prop, hyperdb.Multilink):
                         raise UsageError(
                             'Multilink Traversal not allowed: %s' % p)
@@ -521,6 +582,13 @@
                         cn = prop.classname
                     except AttributeError:
                         cn = None
+            else:
+                cls = self.db.getclass(cn)
+                # This raises a KeyError for unknown prop:
+                try:
+                    prop = cls.getprops(protected=True)[pn]
+                except KeyError:
+                    raise KeyError("Unknown property: %s" % pn)
             checked_props.append (p)
         return checked_props
 
@@ -741,11 +809,9 @@
                 f = value.split(",")
                 if len(f) == 1:
                     f = value.split(":")
-                allprops = class_obj.getprops(protected=True)
                 display_props.update(self.transitive_props(class_name, f))
             elif key == "@sort":
                 f = value.split(",")
-                allprops = class_obj.getprops(protected=True)
                 for p in f:
                     if not p:
                         raise UsageError("Empty property "
@@ -784,6 +850,10 @@
                 except KeyError:
                     raise UsageError("Field %s is not valid for %s class." %
                                      (p, class_name))
+                # Call this for the side effect of validating the key
+                # use _discard as _ is apparently a global for the translation
+                # service.
+                _discard = self.transitive_props(class_name, [ key ])
                 # We drop properties without search permission silently
                 # This reflects the current behavior of other roundup
                 # interfaces
@@ -891,6 +961,7 @@
 
         result['@total_size'] = result_len
         self.client.setHeader("X-Count-Total", str(result_len))
+        self.client.setHeader("Allow", "OPTIONS, GET, POST")
         return 200, result
 
     @Routing.route("/data/<:class_name>/<:item_id>", 'GET')
@@ -962,7 +1033,6 @@
                 f = value.split(",")
                 if len(f) == 1:
                     f = value.split(":")
-                allprops = class_obj.getprops(protected=True)
                 props.update(self.transitive_props(class_name, f))
             elif key == "@protected":
                 # allow client to request read only
@@ -1028,7 +1098,10 @@
         node = class_obj.getnode(item_id)
         etag = calculate_etag(node, self.db.config.WEB_SECRET_KEY,
                               class_name, item_id,  repr_format="json")
-        data = node.__getattr__(attr_name)
+        try:
+            data = node.__getattr__(attr_name)
+        except AttributeError as e:
+            raise UsageError(_("Invalid attribute %s"%attr_name))
         result = {
             'id': item_id,
             'type': str(type(data)),
@@ -1189,6 +1262,15 @@
         link = '%s/%s/%s' % (self.data_path, class_name, item_id)
         self.client.setHeader("Location", link)
 
+        self.client.setHeader(
+            "Allow",
+            None
+        )
+        self.client.setHeader(
+            "Access-Control-Allow-Methods",
+            None
+        )
+
         # set the response body
         result = {
             'id': item_id,
@@ -1643,6 +1725,11 @@
             "Allow",
             "OPTIONS, GET, POST"
         )
+
+        self.client.setHeader(
+            "Access-Control-Allow-Methods",
+            "OPTIONS, GET, POST"
+        )
         return 204, ""
 
     @Routing.route("/data/<:class_name>/<:item_id>", 'OPTIONS')
@@ -1698,19 +1785,114 @@
                 attr_name, class_name))
         return 204, ""
 
+    @openapi_doc({"summary": "Describe Roundup rest endpoint.",
+                  "description": ("Report all supported api versions "
+                                  "and default api version. "
+                                  "Also report next level of link "
+                                  "endpoints below /rest endpoint"),
+                  "responses": {
+                      "200": {
+                          "description": "Successful response.",
+                          "content": {
+                              "application/json": {
+                              "examples": {
+                                  "success": {
+                                      "summary": "Normal json data.",
+                                      "value": """{
+  "data": {
+    "default_version": 1,
+    "supported_versions": [
+      1
+    ],
+    "links": [
+      {
+        "uri": "https://tracker.example.com/demo/rest",
+        "rel": "self"
+      },
+      {
+        "uri": "https://tracker.example.com/demo/rest/data",
+        "rel": "data"
+      },
+      {
+        "uri": "https://tracker.example.com/demo/rest/summary",
+        "rel": "summary"
+      }
+    ]
+  }
+}"""
+                                  }
+                              }
+                          },
+                          "application/xml": {
+                              "examples": {
+                                  "success": {
+                                      "summary": "Normal xml data",
+                                      "value": """<dataf type="dict">
+  <default_version type="int">1</default_version>
+  <supported_versions type="list">
+    <item type="int">1</item>
+  </supported_versions>
+  <links type="list">
+    <item type="dict">
+      <uri type="str">https://rouilj.dynamic-dns.net/sysadmin/rest</uri>
+      <rel type="str">self</rel>
+    </item>
+    <item type="dict">
+      <uri type="str">https://rouilj.dynamic-dns.net/sysadmin/rest/data</uri>
+      <rel type="str">data</rel>
+    </item>
+    <item type="dict">
+      <uri type="str">https://rouilj.dynamic-dns.net/sysadmin/rest/summary</uri>
+      <rel type="str">summary</rel>
+    </item>
+    <item type="dict">
+      <uri type="str">https://rouilj.dynamic-dns.net/sysadmin/rest/summary2</uri>
+      <rel type="str">summary2</rel>
+    </item>
+  </links>
+</dataf>"""
+                                  }
+                              }
+                          }
+                        }
+                      }
+                  }
+    }
+    )
     @Routing.route("/")
     @_data_decorator
     def describe(self, input):
-        """Describe the rest endpoint"""
+        """Describe the rest endpoint. Return direct children in
+           links list.
+        """
+
+        # paths looks like ['^rest/$', '^rest/summary$',
+        #                   '^rest/data/<:class>$', ...]
+        paths = Routing._Routing__route_map.keys()
+
+        links = []
+        # p[1:-1] removes ^ and $ from regexp
+        # if p has only 1 /, it's a child of rest/ root.
+        child_paths = sorted([ p[1:-1] for p in paths if
+                               p.count('/') == 1 ])
+        for p in child_paths:
+            # p.split('/')[1] is the residual path after
+            # removing rest/. child_paths look like:
+            # ['rest/', 'rest/summary'] etc.
+            rel = p.split('/')[1]
+            if rel:
+                rel_path = "/" + rel
+            else:
+                rel_path = rel
+                rel = "self"
+            links.append( {"uri": self.base_path + rel_path,
+                           "rel": rel
+                           })
+
         result = {
             "default_version": self.__default_api_version,
             "supported_versions": self.__supported_api_versions,
-            "links": [{"uri": self.base_path + "/summary",
-                       "rel": "summary"},
-                      {"uri": self.base_path,
-                       "rel": "self"},
-                      {"uri": self.base_path + "/data",
-                       "rel": "data"}]
+            "links": links
         }
 
         return 200, result
@@ -1949,8 +2131,8 @@
                     self.api_version = None
                 except (ValueError, TypeError):
                     # TypeError if int(None)
-                    msg = ("Unrecognized version: %s. "
-                           "See /rest without specifying version "
+                    msg = ("Unrecognized api version: %s. "
+                           "See /rest without specifying api version "
                            "for supported versions." % (
                                part[1]['version']))
                     output = self.error_obj(400, msg)
@@ -1961,22 +2143,29 @@
         #            default (application/json)
         ext_type = os.path.splitext(urlparse(uri).path)[1][1:]
 
+        # Check to see if the length of the extension is less than 6.
+        # this allows use of .vcard for a future use in downloading
+        # user info. It also allows passing through larger items like
+        # JWT that has a final component > 6 items. This method also
+        # allow detection of mistyped types like jon for json.
+        if ext_type  and (len(ext_type) < 6):
+            # strip extension so uri make sense
+            # .../issue.json -> .../issue
+            uri = uri[:-(len(ext_type) + 1)]
+        else:
+            ext_type = None
+
         # headers.get('Accept') is never empty if called here.
         # accept_type will be set to json if there is no Accept header
         # accept_type wil be empty only if there is an Accept header
         # with invalid values.
         data_type = ext_type or accept_type or headers.get('Accept') or "invalid"
 
-        if (ext_type):
-            # strip extension so uri make sense
-            # .../issue.json -> .../issue
-            uri = uri[:-(len(ext_type) + 1)]
-
         # add access-control-allow-* to support CORS
         self.client.setHeader("Access-Control-Allow-Origin", "*")
         self.client.setHeader(
             "Access-Control-Allow-Headers",
-            "Content-Type, Authorization, X-HTTP-Method-Override"
+            "Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override"
         )
         self.client.setHeader(
             "Allow",
@@ -1984,7 +2173,7 @@
         )
         self.client.setHeader(
             "Access-Control-Allow-Methods",
-            "HEAD, OPTIONS, GET, PUT, DELETE, PATCH"
+            "HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH"
         )
         # Is there an input.value with format json data?
         # If so turn it into an object that emulates enough
@@ -2023,15 +2212,16 @@
 
         # check for runtime statistics
         try:
+            # self.report_stats initialized to False
             self.report_stats = input['@stats'].value.lower() == "true"
         # Can also return a TypeError ("not indexable")
         # In case the FieldStorage could not parse the result
         except (KeyError, TypeError):
-            report_stats = False
+            pass
 
         # check for @apiver in query string
-        msg = ("Unrecognized version: %s. "
-               "See /rest without specifying version "
+        msg = _("Unrecognized api version: %s. "
+               "See /rest without specifying api version "
                "for supported versions.")
         try:
             if not self.api_version:
@@ -2052,7 +2242,7 @@
             #    Use default if not specified for now.
             self.api_version = self.__default_api_version
         elif self.api_version not in self.__supported_api_versions:
-            raise UsageError(msg % self.api_version)
+            output = self.error_obj(400, msg % self.api_version)
 
         # sadly del doesn't work on FieldStorage which can be the type of
         # input. So we have to ignore keys starting with @ at other
@@ -2069,7 +2259,8 @@
         except NotFound as msg:
             output = self.error_obj(404, msg)
         except Reject as msg:
-            output = self.error_obj(405, msg)
+            output = self.error_obj(405, msg.args[0])
+            self.client.setHeader("Allow", msg.args[1])
 
         # Format the content type
         if data_type.lower() == "json":
--- a/roundup/scripts/roundup_server.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/roundup/scripts/roundup_server.py	Thu Apr 21 16:54:17 2022 -0400
@@ -321,6 +321,8 @@
 
             self.send_response(200)
             self.send_header('Content-Type', 'image/x-icon')
+            self.send_header('Content-Length', len(favico))
+            self.send_header('Cache-Control', "public, max-age=86400")
             self.end_headers()
 
             # this bufsize is completely arbitrary, I picked 4K because
@@ -635,9 +637,12 @@
             (configuration.WordListOption, "include_headers", "",
                 "Comma separated list of extra headers that should\n"
                 "be copied into the CGI environment.\n"
-                "E.G. if you want to acces the REMOTE_USER and\n"
+                "E.G. if you want to access the REMOTE_USER and\n"
                 "X-Proxy-User headers in the back end,\n"
                 "set to the value REMOTE_USER,X-Proxy-User."),
+            (configuration.HttpVersionOption, "http_version", "HTTP/1.1",
+                "Change to HTTP/1.0 if needed. This disables keepalive."),
+
         )),
         ("trackers", (), "Roundup trackers to serve.\n"
             "Each option in this section defines single Roundup tracker.\n"
@@ -663,6 +668,7 @@
         "ssl": "s",
         "pem": "e:",
         "include_headers": "I:",
+        "http_version": 'V:',
     }
 
     def __init__(self, config_file=None):
@@ -732,6 +738,8 @@
                     # internal state correctly so that later closing SSL
                     # socket works (with SSL end-handshake started)
                     self.request.do_handshake()
+                RoundupRequestHandler.protocol_version = \
+                                         self.CONFIG["HTTP_VERSION"]
                 RoundupRequestHandler.setup(self)
 
             def finish(self):
@@ -864,8 +872,8 @@
                to the file indicated by PIDfile. The -l option *must* be
                specified if -d is used.'''
     if message:
-        message += '\n'
-    print(_('''%(message)sUsage: roundup-server [options] [name=tracker home]*
+        message += '\n\n'
+    print(_('''\n%(message)sUsage: roundup-server [options] [name=tracker home]*
 
 Options:
  -v            print the Roundup version number and exit
@@ -886,6 +894,9 @@
  -e <fname>    PEM file containing SSL key and certificate
  -t <mode>     multiprocess mode (default: %(mp_def)s).
                Allowed values: %(mp_types)s.
+ -V <version>  set HTTP version (default: HTTP/1.1).
+               Allowed values: HTTP/1.0, HTTP/1.1.
+
 %(os_part)s
 
 Long options:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/Docker/Dockerfile	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,152 @@
+# build in root dir using:
+#
+#     docker build -t roundup-app --rm -f scripts/Dockerfile .
+#
+# run using:
+#
+#    docker run --rm -v /.../issue.tracker:/usr/src/app/tracker \
+#           -p 9017:8080 roundup-app:latest
+
+
+# Global vars for all build stages
+
+# application directory
+ARG appdir=/usr/src/app
+
+# support roundup install from 'local' directory,
+# 'local_pip' local directory using pip to install or
+# latest release from 'pypi'
+ARG source=local
+
+FROM python:3-alpine as build
+
+# Inherit global values https://github.com/moby/moby/issues/37345
+ARG appdir
+
+WORKDIR $appdir
+
+# Add packages needed to compile mysql, pgsql and other python modules.
+# Can't use apk to add them as that installs a 3.9 python version.
+#        g++ installs cc1plus needed by pip install
+RUN apk add \
+    g++ \
+    gcc \
+    gpgme-dev \
+    libxapian \
+    linux-headers \
+    make \
+    musl-dev \
+    mysql-dev \
+    postgresql-dev \
+    swig \
+    xapian-core-dev
+
+# build xapian bindings:
+# file with sphinx build dependencies to remove after build
+# they are over 70MB of space.
+COPY scripts/Docker/sphinxdeps.txt .
+
+RUN set -xv && CWD=$PWD && \
+    VER=$(apk list -I 'xapian-core-dev' | \
+          sed 's/^xapian-core-dev-\([0-9.]*\)-.*/\1/') && \
+    cd /tmp && \
+    wget https://oligarchy.co.uk/xapian/$VER/xapian-bindings-$VER.tar.xz && \
+    tar -Jxvf xapian-bindings-$VER.tar.xz && \
+    cd xapian-bindings-$VER/ && \
+    pip --no-cache-dir install sphinx==1.8.5 && \
+    ./configure --prefix=/usr/local --with-python3 --disable-documentation && \
+    make && make install && \
+    pip uninstall --no-cache-dir -y -r $CWD/sphinxdeps.txt
+
+# add requirements for pip here, e.g. Whoosh, gpg, zstd or other
+#   modules not installed in the base library.
+# ignore warnings from pip to use virtualenv
+COPY scripts/Docker/requirements.txt .
+RUN pip install --no-cache-dir -r requirements.txt
+
+# copy the elements of the release directory to the docker image
+COPY setup.py install/
+COPY doc install/doc/
+COPY frontends install/frontends/
+COPY locale install/locale/
+COPY roundup install/roundup/
+COPY share install/share/
+
+# verify source has one of two valid values then
+# install in python3 standard directories from local copy
+# or install in python3 standard directories from pypi using pip
+# import from global/command line
+ARG source
+RUN set -xv && if [ "$source" = "local" ] ||  \
+                  [ "$source" = "pypi"  ] || \
+                  [ "$source" = "local_pip"   ]; then :; \
+           else echo "invalid value for source: $source"; \
+                echo "must be local or pypi"; exit 1; fi; \
+    if [ "$source" = "local" ]; then cd install && ./setup.py install; fi; \
+    if [ "$source" = "local_pip" ]; then cd install && pip install \
+                            --use-feature=in-tree-build . ; fi; \
+    if [ "$source" = "pypi" ]; then pip install roundup; \
+       cp -ril /usr/local/lib/python3.10/site-packages/usr/local/share/* \
+	   /usr/local/share; fi
+
+# build a new smaller docker image for execution. Build image above
+# is 1G in size.
+FROM python:3-alpine
+
+# import from global
+ARG appdir
+
+WORKDIR $appdir
+
+# add libraries needed to run gpg/mysql/pgsql/brotli
+RUN apk add \
+     gpgme \
+     mariadb-connector-c \
+     libpq \
+     libstdc++ \
+     libxapian
+
+ARG source
+LABEL "org.roundup-tracker.vendor"="Roundup Issue Tracker Team" \
+      "org.roundup-tracker.description"="Roundup Issue Tracker using sqlite" \
+      "version"="2.1.0 $source" \
+      "org.opencontainers.image.authors"="roundup-devel@lists.sourceforge.net"
+
+
+# pull over built assets
+COPY --from=build /usr/local/lib/python3.10/site-packages /usr/local/lib/python3.10/site-packages/
+COPY --from=build /usr/local/bin/roundup* /usr/local/bin/
+COPY --from=build /usr/local/share /usr/local/share/
+COPY scripts/Docker/roundup_start .
+
+# map port 8080 to your local port
+EXPOSE 8080/tcp
+
+# mount a trackerdir on tracker location
+RUN mkdir tracker
+VOLUME $appdir/tracker
+
+HEALTHCHECK --start-period=1m \
+   CMD wget -q -O /dev/null --no-verbose http://localhost:8080/issues/
+
+# do not run roundup as root
+RUN adduser -D -h /usr/src/app roundup
+USER roundup
+
+# run the server, disable output buffering so we can see logs.
+ENV PYTHONUNBUFFERED=1
+#ENTRYPOINT [ "roundup-server", "-n", "0.0.0.0" ]
+ENTRYPOINT [ "./roundup_start" ]
+
+# allow the invoker to override cmd with multiple trackers
+# in each subdirectory under $appdir/tracker. E.G.
+# docker run .... \
+#   issues=tracker/issues foo=tracker/foo
+#
+# note using "issue=$appdir/tracker" results in error:
+#
+#  No valid configuration files found in directory /usr/src/app/$appdir/tracker
+#
+# so $appdir not expanded and $PWD prefixed onto the (relative path)
+#   $appdir/tracker. Hence use relative path for spec.
+CMD [  "issues=tracker" ]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/Docker/docker-compose.yml	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,81 @@
+# docker-roundup
+# roundup issue tracker application with mariadb running as docker container
+#
+# docker-compose.yml
+#
+# Build components:
+#    docker-compose  -f scripts/Docker/docker-compose.yml build
+# 
+# Install tracker template:
+#   $ docker-compose  -f scripts/Docker/docker-compose.yml run \
+#        --rm --entrypoint roundup-admin --no-deps roundup-app \
+#        -i tracker install
+#
+# Edit scripts/Docker/tracker/config.ini configure database settings
+# and any NO DEFAULT settings.
+#
+# Initialize the database, wait 1 minute so 
+#   
+#   $ docker-compose  -f scripts/Docker/docker-compose.yml run \
+#        --rm --entrypoint roundup-admin roundup-app \
+#        -i tracker
+#
+# wait 1 minute for mariadb to initialize
+# init tracker at roundup prompt
+#
+#   roundup> init
+#   roundup> exit
+#
+# may need ^\ to get roundup-admin to exit.
+#
+# run
+#    docker-compose -f scripts/Docker/docker-compose.yml up
+#
+# tracker should be running at port 9017.
+
+# Note: mysql volume and tracker directories will be put in the
+# scripts/Docker subdir.
+# Paths for volumes are relative to docker-compose.yml location not
+# docker-compose cwd or build context directory.
+
+version: '3'
+services:
+  mariadb:
+    image: lscr.io/linuxserver/mariadb
+    container_name: mariadb
+    restart: unless-stopped
+    environment:
+      - PUID=1000
+      - PGID=1000
+      - TZ=America/New_York
+      - MYSQL_ROOT_PASSWORD=myPassword
+      - MYSQL_DATABASE=roundup
+      - MYSQL_USER=roundup_user
+      - MYSQL_PASSWORD=roundup_pass
+#    ports:
+#      - 3306:3306
+    volumes:
+      - ./dbData:/config
+
+  roundup-app:
+    container_name: roundup-app
+    build:
+       context: ../..
+       dockerfile: scripts/Docker/Dockerfile
+       args:
+         source: local_pip
+         #source: local
+         #source: pypi
+    command: "issues=tracker"
+    restart: unless-stopped
+    environment:
+      - TZ=America/New_York
+    ports:
+      - 9017:8080
+    links:
+      - mariadb
+    depends_on:
+      - mariadb
+    volumes:
+      # will be placed in Docker subdir next to this file
+      - ./tracker:/usr/src/app/tracker
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/Docker/requirements.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,14 @@
+# human timezones
+pytz
+# indexer
+Whoosh
+# extra database support
+psycopg2
+mysqlclient
+# encryption
+gpg
+# java web tokens
+PyJWT
+# extra HTTP compression methods
+Brotli
+zstd
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/Docker/roundup_start	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,61 @@
+#! /bin/sh
+
+# When container starts verify that the trackers are configured.
+# If they are, start the server otherwise run roundup-admin
+# for installation and initialization.
+
+# "$@" should be a set of tracker=directory pairs.
+
+if ! [ -z "$SHELL_DEBUG" ]; then
+    set -xv
+fi
+
+trap exit INT
+
+do_exit=0
+
+for tracker_spec in "$@"; do
+    # IFS== set a=b doesn't assign $1 and $2 in busybox ash
+    # it also clobbers '$@'. 'echo mumble | read' starts read in a
+    # subshell so vars are not available in parent.
+    IFS="=" read tracker directory <<- EOE
+    $tracker_spec
+	EOE
+    # ^ is a tab for use with <<-
+
+    # was $tracker_spec in the form of a=b, if not ignore it.
+    # allows setting CMD to -i index_template issue=tracker for example.
+    if [ -z "$directory" ]; then continue; fi
+
+    # something is specified or built wrong. Don't start.
+    if [ ! -d "$directory" ]; then
+        printf "Unable to find directory %s. Exiting\n" "$directory"
+	exit 1
+    fi
+
+    # user must define web in config.ini.
+    if ! grep '^\s*web\s\s*=\s\s*' "$directory/config.ini" > /dev/null; then
+        roundup-admin -i "$directory" install
+        do_exit=1
+    fi
+
+    # we have a valid config.ini so init database if not done
+    if [ $do_exit == 0 -a ! -e "$directory/.init_done" ]; then
+        if roundup-admin -i "$directory" init; then
+	  cat > "$directory/.init_done" <<- EOD
+	  Don't delete this file. The docker startup needs it so it won't
+	  re-initialze the database destroying all the data.
+	EOD
+	else
+	    do_exit=1
+	fi
+    fi
+done
+
+# if any config.ini needs editing don't start up.
+if [ $do_exit == 0 ]; then
+   # make roundup-server process 1 with exec
+   exec roundup-server -n 0.0.0.0 "$@"
+fi
+
+exit 0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/Docker/sphinxdeps.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,19 @@
+Babel
+Jinja2
+MarkupSafe
+Pygments
+alabaster
+certifi
+charset-normalizer
+docutils
+idna
+imagesize
+packaging
+pyparsing
+requests
+six
+snowballstemmer
+sphinxcontrib-serializinghtml
+sphinxcontrib-websupport
+urllib3
+
--- a/scripts/README.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/scripts/README.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -7,6 +7,10 @@
 copy-user.py
  Copy one or more Roundup users from one tracker instance to another. 
 
+dump_dbm_sessions_db.py
+ Simple script to dump a session style dbm database e.g. db/otks or
+ db/sessions in readable form.
+ 
 imapServer.py
  This IMAP server script that runs in the background and checks for new
  email from a variety of mailboxes.
@@ -31,6 +35,10 @@
  Remove file attachment spam from a tracker. (Warning destructive,
  read script well.)
 
+stats.xmlrpc.py
+ Script using the xmlrpc interface to retrieve info. Generates report
+ on what values are used by the various issues on bugs.python.org.
+
 weekly-report
  Generate a simple report outlining the activity in one tracker for the
  most recent week.
@@ -56,3 +64,18 @@
 contributors.py
  Analyzes Mercurial log, filters and compiles list of committers with years
  of contribution. Can be useful for updating COPYING.txt
+
+----
+
+Docker
+  Directory for docker setup. More info on how to use it is in
+  doc/installation.txt.
+
+Docker/Dockerfile - Create roundup docker.
+
+Docker/requirements.txt - Python requirements built into docker.
+
+Docker/roundup-start - Startup script for roundup in docker.
+
+Docker/docker-compose.yml - Manage two docker containers for roundup
+      and mysql.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/dump_dbm_sessions_db.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,35 @@
+#! /usr/bin/env python3
+"""Usage: dump_dbm_sessions_db.py [filename]
+
+Simple script to dump the otks and sessions dbm databases.  Dumps
+sessions db in current directory if no argument is given.
+
+Dump format:
+
+   key: <timestamp> data
+
+where <timestamp> is the human readable __timestamp decoded from the
+data object.
+
+"""
+
+import dbm, marshal, sys
+from datetime import datetime
+
+try:
+  file = sys.argv[1]
+except IndexError:
+  file="sessions"
+
+try:
+   db = dbm.open(file)
+except Exception:
+   print("Unable to open database: %s"%file)
+   exit(1)
+
+k = db.firstkey()
+while k is not None:
+    d = marshal.loads(db[k])
+    t = datetime.fromtimestamp(d['__timestamp'])
+    print("%s: %s %s"%(k, t, d))
+    k = db.nextkey(k)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/scripts/stats.xmlrpc.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,95 @@
+"""Count how many issues use each bpo field and print a report."""
+""" sample output: https://github.com/psf/gh-migration/issues/5#issuecomment-935697646"""
+
+import xmlrpc.client
+
+from collections import defaultdict
+
+class SpecialTransport(xmlrpc.client.SafeTransport):
+    def send_content(self, connection, request_body):
+        connection.putheader("Referer", "https://bugs.python.org/")
+        connection.putheader("Origin", "https://bugs.python.org")
+        connection.putheader("X-Requested-With", "XMLHttpRequest")
+        xmlrpc.client.SafeTransport.send_content(self, connection, request_body)
+
+# connect to bpo
+roundup = xmlrpc.client.ServerProxy('https://bugs.python.org/xmlrpc',
+                                    transport=SpecialTransport(),
+                                    allow_none=True)
+
+# map bpo classes -> propname
+# the class is the name of the class (e.g. issue_type, keyword --
+# also used in e.g. in https://bugs.python.org/keyword)
+# the propname is the name used as attribute on the issue class
+# (e.g. issue.type, issue.keywords)
+classes = {
+    # 'status': 'status',  # skip this
+    'issue_type': 'type',
+    'stage': 'stage',
+    'component': 'components',
+    'version': 'versions',
+    'resolution': 'resolution',
+    'priority': 'priority',
+    'keyword': 'keywords',
+}
+
+# find the id for the 'open' status
+open_id = roundup.lookup('status', 'open')
+
+print(f'* Counting total issues...')
+total_issues_num = len(roundup.filter('issue', None, {}))
+
+print(f'* Counting open issues...')
+# use this list to filter only the open issues
+open_issues = roundup.filter('issue', None, {'status': open_id})
+open_issues_num = len(open_issues)
+
+# save the totals in a dict with this structure:
+#   totals[propname][open/all][num/perc][name]
+# where propname is e.g. 'keyword' and name is e.g. 'easy'
+totals = defaultdict(lambda: {'all': {'perc': {}, 'num': {}},
+                              'open': {'perc': {}, 'num': {}}})
+for cls, propname in classes.items():
+    print(f'* Counting <{cls}>...')
+    # get the list of ids/names for the given class (e.g. 'easy' is 6)
+    ids = roundup.list(cls, 'id')
+    names = roundup.list(cls, 'name')
+    for id, name in zip(ids, names):
+        # filter and count on *all* issues with the given propname
+        tot_all = len(roundup.filter('issue', None, {propname: id}))
+        totals[propname]['all']['num'][name] = tot_all
+        totals[propname]['all']['perc'][name] = tot_all / total_issues_num
+        # filter and count on *open* issues with the given propname
+        tot_open = len(roundup.filter('issue', open_issues, {propname: id}))
+        totals[propname]['open']['num'][name] = tot_open
+        totals[propname]['open']['perc'][name] = tot_open / open_issues_num
+
+
+print(f'Issues (open/all): {open_issues_num}/{total_issues_num}')
+
+# print a list of markdown tables for each bpo class name
+for propname in classes.values():
+    print(f'### {propname}')
+    print('| bpo field | open | all |')
+    print('| :--- | ---: | ---: |')
+    # pick the dict for the given propname (e.g. keywords)
+    proptots = totals[propname]
+    names = proptots['open']['num']
+    # sort the names (e.g. 'easy') in reverse order
+    # based on the number of open issues
+    for name in sorted(names, key=names.get, reverse=True):
+        # get and print num/perc for all/open issues
+        issues_all = proptots['all']['num'][name]
+        issues_open = proptots['open']['num'][name]
+        perc_all = proptots['all']['perc'][name]
+        perc_open = proptots['open']['perc'][name]
+        print(f'| {name:20} | {issues_open:>5} ({perc_open:5.1%}) |'
+              f' {issues_all:>5} ({perc_all:5.1%}) |')
+    # calc and print num/perc for all/open issues
+    tot_issues_all = sum(proptots['all']['num'].values())
+    tot_issues_open = sum(proptots['open']['num'].values())
+    tot_perc_all = sum(proptots['all']['perc'].values())
+    tot_perc_open = sum(proptots['open']['perc'].values())
+    print(f'| **Total**            | {tot_issues_open:>5} ({tot_perc_open:5.1%}) |'
+            f' {tot_issues_all:>5} ({tot_perc_all:5.1%}) |')
+
--- a/setup.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/setup.py	Thu Apr 21 16:54:17 2022 -0400
@@ -87,13 +87,13 @@
     if prefix:
         return prefix
     else:
-        # get the platform lib path.
+        # get the platform lib path. Must start with / else infinite loop.
         plp = get_path('platlib')
         # nuke suffix that matches lib/* and return prefix
         head, tail = os.path.split(plp)
-        while tail != 'lib' and head != '':
+        while tail not in ['lib', 'lib64' ] and head != '/':
             head, tail = os.path.split(head)
-        if not head:
+        if head == '/':
             head = sys.prefix
         return head
 
@@ -143,6 +143,19 @@
 
     data_files = make_data_files_absolute(data_files, get_prefix())
 
+    # when running under python2, even if called from setup, it tries
+    # and fails to perform an egg easy install even though it shouldn't:
+    # https://issues.roundup-tracker.org/issue2551185
+    # Add this argument if we are an install to prevent this.
+    # This works right under python3.
+    # FIXME there has to be a better way than this
+    # https://issues.roundup-tracker.org/issue2551185
+
+    if sys.version_info[0] < 3:
+        for arg in sys.argv:
+            if arg == 'install':
+                sys.argv.append('--old-and-unmanageable')
+
     # perform the setup action
     from roundup import __version__
 
@@ -216,6 +229,16 @@
           data_files=data_files)
 
 if __name__ == '__main__':
+
+    # Prevent `pip install roundup` from building bdist_wheel.
+    # Man pages, templates, locales installed under site-packages not
+    #  in normal system locations.
+    # https://stackoverflow.com/questions/36846260/can-python-setuptools-install-files-outside-dist-packages
+    '''
+    if 'bdist_wheel' in sys.argv:
+        raise RuntimeError("This setup.py does not support wheels")
+    '''
+
     os.chdir(os.path.dirname(__file__) or '.')
     main()
 
--- a/share/man/man1/roundup-server.1	Fri Oct 08 00:37:16 2021 -0400
+++ b/share/man/man1/roundup-server.1	Thu Apr 21 16:54:17 2022 -0400
@@ -35,8 +35,15 @@
 The variable "trackers" is available to the template and is a dict of all
 configured trackers.
 .TP
+\fB-I\fP \fIheader1[,header2,...]\fP
+Pass the header(s) and their values to the backend. This allow-list
+of header variables can be used by custom code in the tracker or with
+a tracker's \fBhttp_auth_header\fP configuration option to allows a
+front end server to authenticate a user and pass the user identity to
+roundup.
+.TP
 \fB-s\fP
-Enables to use of SSL.
+Enables use of SSL.
 .TP
 \fB-e\fP \fIfile\fP
 Sets a filename containing the PEM file to use for SSL. If left blank, a
@@ -45,6 +52,10 @@
 \fB-N\fP
 Log client machine names instead of IP addresses (much slower).
 .TP
+\fB-V\fP \fIHTTPVER\fP
+By default roundup-server uses HTTP/1.1 to enable keepalives for faster
+response. HTTPVER can be set to \fBHTTP/1.0\fP to disable keepalives.
+.TP
 \fB-u\fP \fIUID\fP
 Runs the Roundup web server as this UID.
 .TP
--- a/share/roundup/templates/jinja2/initial_data.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/share/roundup/templates/jinja2/initial_data.py	Thu Apr 21 16:54:17 2022 -0400
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
 from roundup import password, date
 
 pri = db.getclass('priority')
--- a/test/db_test_base.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/db_test_base.py	Thu Apr 21 16:54:17 2022 -0400
@@ -252,9 +252,21 @@
         self.db.issue.create(title="flebble frooz")
         self.db.commit()
 
-        self.assertEqual(self.db.database_schema['version'], 6,
-                         "This test only runs for database version 6")
-        self.db.database_schema['version'] = 5
+        if self.db.database_schema['version'] > 6:
+            # make testUpgrades run the downgrade code only.
+            if hasattr(self, "downgrade_only"):
+                # we are being called by an earlier test
+                self.testUpgrade_6_to_7()
+                self.assertEqual(self.db.database_schema['version'], 6)
+            else:
+                # we are being called directly
+                self.downgrade_only = True
+                self.testUpgrade_6_to_7()
+                self.assertEqual(self.db.database_schema['version'], 6)
+                del(self.downgrade_only)
+        elif self.db.database_schema['version'] != 6:
+            self.skipTest("This test only runs for database version 6")
+
         if self.db.dbtype == 'mysql':
             # version 6 has 5 indexes
             self.db.sql('show indexes from _user;')
@@ -268,6 +280,11 @@
             self.db.sql('show indexes from _user;')
             self.assertEqual(3,len(self.db.cursor.fetchall()))
 
+            self.db.database_schema['version'] = 5
+
+            if hasattr(self, "downgrade_only"):
+                return
+
             # test upgrade adding index
             self.db.post_init()
 
@@ -284,10 +301,16 @@
             self.db.sql('show indexes from _user;')
             self.assertEqual(5,len(self.db.cursor.fetchall()))
         else:
+            if hasattr(self, "downgrade_only"):
+                return
             # this should be a no-op
             # test upgrade
             self.db.post_init()
 
+        # we should be at the current db version
+        self.assertEqual(self.db.database_schema['version'],
+                         self.db.current_db_version)
+
     def drop_key_retired_idx(self):
         c = self.db.cursor
         for cn, klass in self.db.classes.items():
--- a/test/rest_common.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/rest_common.py	Thu Apr 21 16:54:17 2022 -0400
@@ -391,6 +391,68 @@
         results = self.server.get_collection('issue', form)
         self.assertDictEqual(expected, results)
 
+    def testGetBadTransitive(self):
+        """
+        Mess up the names of various properties and make sure we get a 400
+        and a somewhat useful error message.
+        """
+        base_path = self.db.config['TRACKER_WEB'] + 'rest/data/'
+        #self.maxDiff=None
+        self.create_sampledata()
+        self.db.issue.set('2', status=self.db.status.lookup('closed'))
+        self.db.issue.set('3', status=self.db.status.lookup('chatting'))
+        expected = [
+            {'error': {'msg': KeyError('Unknown property: assignedto.isse',),
+             'status': 400}},
+            {'error': {'msg': KeyError('Unknown property: stat',),
+             'status': 400}},
+            {'error': {'msg': KeyError('Unknown property: status.nam',),
+             'status': 400}},
+        ]
+
+        ## test invalid transitive property in @fields
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('status.name', 'o'),
+            cgi.MiniFieldStorage('@fields', 'status,assignedto.isse'),
+            cgi.MiniFieldStorage('@sort', 'status.name'),
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 400)
+        self.assertEqual(repr(expected[0]['error']['msg']),
+                         repr(results['error']['msg']))
+        self.assertEqual(expected[0]['error']['status'],
+                         results['error']['status'])
+
+        ## test invalid property in @fields
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('status.name', 'o'),
+            cgi.MiniFieldStorage('@fields', 'stat,assignedto.isuse'),
+            cgi.MiniFieldStorage('@sort', 'status.name'),
+        ]
+        results = self.server.get_collection('issue', form)
+        self.assertEqual(self.dummy_client.response_code, 400)
+        self.assertEqual(repr(expected[1]['error']['msg']),
+                         repr(results['error']['msg']))
+        self.assertEqual(expected[1]['error']['status'],
+                         results['error']['status'])
+
+        ## test invalid transitive property in filter TODO
+        form = cgi.FieldStorage()
+        form.list = [
+            cgi.MiniFieldStorage('status.nam', 'o'),
+            cgi.MiniFieldStorage('@fields', 'status,assignedto.isuse'),
+            cgi.MiniFieldStorage('@sort', 'status.name'),
+        ]
+        results = self.server.get_collection('issue', form)
+        # is currently 403 not 400
+        self.assertEqual(self.dummy_client.response_code, 400)
+        self.assertEqual(repr(expected[2]['error']['msg']),
+                         repr(results['error']['msg']))
+        self.assertEqual(expected[2]['error']['status'],
+                         results['error']['status'])
+
     def testGetExactMatch(self):
         """ Retrieve all issues with an exact title
         """
@@ -1180,8 +1242,8 @@
         each one broke and no etag. Use the put command
         to trigger the etag checking code.
         '''
-        for mode in ('header', 'etag', 'both',
-                     'brokenheader', 'brokenetag', 'none'):
+        for mode in ('header', 'header-gzip', 'etag', 'etag-br',
+                     'both', 'brokenheader', 'brokenetag', 'none'):
             try:
                 # clean up any old header
                 del(self.headers)
@@ -1198,9 +1260,17 @@
             if mode == 'header':
                 print("Mode = %s"%mode)
                 self.headers = {'if-match': etag}
+            elif mode == 'header-gzip':
+                print("Mode = %s"%mode)
+                gzip_etag = etag[:-1] + "-gzip" + etag[-1:]
+                self.headers = {'if-match': gzip_etag}
             elif mode == 'etag':
                 print("Mode = %s"%mode)
                 form.list.append(cgi.MiniFieldStorage('@etag', etag))
+            elif mode == 'etag-br':
+                print("Mode = %s"%mode)
+                br_etag = etag[:-1] + "-br" + etag[-1:]
+                form.list.append(cgi.MiniFieldStorage('@etag', br_etag))
             elif mode == 'both':
                 print("Mode = %s"%mode)
                 self.headers = {'etag': etag}
@@ -1216,7 +1286,7 @@
             elif mode == 'none':
                 print( "Mode = %s"%mode)
             else:
-                self.fail("unknown mode found")
+                self.fail("unknown mode '%s' found"%mode)
 
             results = self.server.put_attribute(
                 'user', self.joeid, 'realname', form
@@ -2010,8 +2080,8 @@
         json_dict = json.loads(b2s(results))
         self.assertEqual(json_dict['error']['status'], 400)
         self.assertEqual(json_dict['error']['msg'],
-              "Unrecognized version: L. See /rest without "
-              "specifying version for supported versions.")
+              "Unrecognized api version: L. See /rest without "
+              "specifying api version for supported versions.")
 
         headers={"accept": "application/json; version=z" }
         self.headers=headers
@@ -2022,8 +2092,8 @@
         json_dict = json.loads(b2s(results))
         self.assertEqual(json_dict['error']['status'], 400)
         self.assertEqual(json_dict['error']['msg'],
-              "Unrecognized version: z. See /rest without "
-              "specifying version for supported versions.")
+              "Unrecognized api version: z. See /rest without "
+              "specifying api version for supported versions.")
 
         headers={"accept": "application/vnd.roundup.test-vz+json" }
         self.headers=headers
@@ -2035,8 +2105,8 @@
         json_dict = json.loads(b2s(results))
         self.assertEqual(json_dict['error']['status'], 400)
         self.assertEqual(json_dict['error']['msg'],
-              "Unrecognized version: z. See /rest without "
-              "specifying version for supported versions.")
+              "Unrecognized api version: z. See /rest without "
+              "specifying api version for supported versions.")
 
         # verify that version priority is correct; should be version=...
         headers={"accept": "application/vnd.roundup.test-vz+json; version=a"
@@ -2050,8 +2120,8 @@
         json_dict = json.loads(b2s(results))
         self.assertEqual(json_dict['error']['status'], 400)
         self.assertEqual(json_dict['error']['msg'],
-              "Unrecognized version: a. See /rest without "
-              "specifying version for supported versions.")
+              "Unrecognized api version: a. See /rest without "
+              "specifying api version for supported versions.")
 
         # TEST #10
         # check /rest and /rest/summary and /rest/notthere
@@ -2063,16 +2133,16 @@
               "default_version": 1,
               "links": [
                   {
-                      "rel": "summary",
-                      "uri": "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/summary"
-                  },
-                  {
                       "rel": "self",
                       "uri": "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest"
                   },
                   {
                       "rel": "data",
                       "uri": "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/data"
+                  },
+                  {
+                      "rel": "summary",
+                      "uri": "http://tracker.example/cgi-bin/roundup.cgi/bugs/rest/summary"
                   }
               ]
           }
@@ -2272,15 +2342,18 @@
         headers={"accept": "application/json; version=99"
         }
         self.headers=headers
-        with self.assertRaises(UsageError) as ctx:
-            results = self.server.dispatch('GET',
-                                           "/rest/data/status/1",
-                                           self.empty_form)
+        results = self.server.dispatch('GET',
+                                       "/rest/data/status/1",
+                                       self.empty_form)
         print(results)
-        self.assertEqual(self.server.client.response_code, 200)
-        self.assertEqual(ctx.exception.args[0],
-                         "Unrecognized version: 99. See /rest without "
-                         "specifying version for supported versions.")
+        json_dict = json.loads(b2s(results))
+        self.assertEqual(self.server.client.response_code, 400)
+        self.assertEqual(self.server.client.additional_headers['Content-Type'],
+                         "application/json")
+        self.assertEqual(json_dict['error']['msg'],
+                         "Unrecognized api version: 99. See /rest "
+                         "without specifying api version for "
+                         "supported versions.")
 
     def testMethodOverride(self):
         # TEST #1
--- a/test/test_actions.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_actions.py	Thu Apr 21 16:54:17 2022 -0400
@@ -82,6 +82,16 @@
         self.assertRaisesMessage(ValueError, action.handle,
             'No type specified')
 
+    def testShowActionBadNumber(self):
+        action = ShowAction(self.client)
+        self.assertRaises(ValueError, action.handle)
+        self.form.value.append(MiniFieldStorage('@number', 'A'))
+        self.form.value.append(MiniFieldStorage('@type', 'issue'))
+        with self.assertRaises(SeriousError) as ctx:
+            action.handle()
+        self.assertEqual('"A" is not an ID (issue ID required)',
+                         ctx.exception.args[0])
+
 class RetireActionTestCase(ActionTestCase):
     def testRetireAction(self):
         self.client.db.security.hasPermission = true
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/test_anypy.py	Thu Apr 21 16:54:17 2022 -0400
@@ -0,0 +1,43 @@
+"""Random tests for anypy modules"""
+
+
+import unittest
+from roundup.anypy.strings import repr_export, eval_import
+
+import sys
+_py3 = sys.version_info[0] > 2
+
+class StringsTest(unittest.TestCase):
+
+    def test_import_params(self):
+        """ issue2551170 - handle long int in history/journal
+            params tuple
+        """
+        # python2 export with id as number
+        val = eval_import("('issue', 2345L, 'status')")
+        self.assertSequenceEqual(val, ('issue', 2345, 'status'))
+
+        # python3 export with id as number
+        val = eval_import("('issue', 2345, 'status')")
+        self.assertSequenceEqual(val, ('issue', 2345, 'status'))
+
+        # python2 or python3 export with id as string
+        val = eval_import("('issue', '2345', 'status')")
+        self.assertSequenceEqual(val, ('issue', '2345', 'status'))
+
+    def test_export_params(self):
+        """ issue2551170 - handle long int in history/journal
+            params tuple
+        """
+        # python2 export with id as number
+        if _py3:
+            val = repr_export(('issue', 2345, 'status'))
+            self.assertEqual(val, "('issue', 2345, 'status')")
+        else:
+            val = repr_export(('issue', long(2345), 'status'))
+            self.assertEqual(val, "('issue', 2345L, 'status')")
+
+        # python2 or python3 export with id as string
+        val = repr_export(('issue', '2345', 'status'))
+        self.assertEqual(val, "('issue', '2345', 'status')")
+            
--- a/test/test_cgi.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_cgi.py	Thu Apr 21 16:54:17 2022 -0400
@@ -33,6 +33,9 @@
 from . import db_test_base
 from .db_test_base import FormTestParent, setupTracker, FileUpload
 from .cmp_helper import StringFragmentCmpHelper
+from .test_postgresql import skip_postgresql
+from .test_mysql import skip_mysql
+
 
 class FileList:
     def __init__(self, name, *files):
@@ -42,6 +45,24 @@
         for f in self.files:
             yield (self.name, f)
 
+class testFtsQuery(object):
+
+    def testRenderContextFtsQuery(self):
+        self.db.issue.create(title='i1 is found', status="chatting")
+
+        self.client.form=db_test_base.makeForm(
+            { "@ok_message": "ok message", "@template": "index",
+            "@search_text": "found"})
+        self.client.path = 'issue'
+        self.client.determine_context()
+
+        result = self.client.renderContext()
+
+        expected = '">i1 is found</a>'
+
+        self.assertIn(expected, result)
+        self.assertEqual(self.client.response_code, 200)
+
 cm = client.add_message
 class MessageTestCase(unittest.TestCase):
     # Note: Escaping is now handled on a message-by-message basis at a
@@ -79,7 +100,86 @@
         self.assertEqual(cm([],'<i>x</i>\n<b>x</b>',False),
             ['<i>x</i><br />\n<b>x</b>'])
 
-class FormTestCase(FormTestParent, StringFragmentCmpHelper, unittest.TestCase):
+class testCsvExport(object):
+
+    def testCSVExportBase(self):
+        cl = self._make_client(
+            {'@columns': 'id,title,status,keyword,assignedto,nosy,creation'},
+            nodeid=None, userid='1')
+        cl.classname = 'issue'
+
+        demo_id=self.db.user.create(username='demo', address='demo@test.test',
+            roles='User', realname='demo')
+        key_id1=self.db.keyword.create(name='keyword1')
+        key_id2=self.db.keyword.create(name='keyword2')
+
+        originalDate = date.Date
+        dummy=date.Date('2000-06-26.00:34:02.0')
+        # is a closure the best way to return a static Date object??
+        def dummyDate(adate=None):
+            def dummyClosure(adate=None, translator=None):
+                return dummy
+            return dummyClosure
+        date.Date = dummyDate()
+
+        self.db.issue.create(title='foo1', status='2', assignedto='4', nosy=['3',demo_id])
+        self.db.issue.create(title='bar2', status='1', assignedto='3', keyword=[key_id1,key_id2])
+        self.db.issue.create(title='baz32', status='4')
+        output = io.BytesIO()
+        cl.request = MockNull()
+        cl.request.wfile = output
+        # call export version that outputs names
+        actions.ExportCSVAction(cl).handle()
+        should_be=(s2b('"id","title","status","keyword","assignedto","nosy","creation"\r\n'
+                       '"1","foo1","deferred","","Contrary, Mary","Bork, Chef;Contrary, Mary;demo","2000-06-26 00:34"\r\n'
+                       '"2","bar2","unread","keyword1;keyword2","Bork, Chef","Bork, Chef","2000-06-26 00:34"\r\n'
+                       '"3","baz32","need-eg","","","","2000-06-26 00:34"\r\n'))
+
+
+        #print(should_be)
+        #print(output.getvalue())
+        self.assertEqual(output.getvalue(), should_be)
+        output = io.BytesIO()
+        cl.request = MockNull()
+        cl.request.wfile = output
+        # call export version that outputs id numbers
+        actions.ExportCSVWithIdAction(cl).handle()
+        should_be = s2b('"id","title","status","keyword","assignedto","nosy","creation"\r\n'
+                        '''"1","foo1","2","[]","4","['3', '4', '5']","2000-06-26.00:34:02"\r\n'''
+                        '''"2","bar2","1","['1', '2']","3","['3']","2000-06-26.00:34:02"\r\n'''
+                        '''"3","baz32","4","[]","None","[]","2000-06-26.00:34:02"\r\n''')
+        #print(should_be)
+        #print(output.getvalue())
+        self.assertEqual(output.getvalue(), should_be)
+
+        # reset the real date command
+        date.Date = originalDate
+
+        # test full text search
+        # call export version that outputs names
+        cl = self._make_client(
+            {'@columns': 'id,title,status,keyword,assignedto,nosy',
+             "@search_text": "bar2"}, nodeid=None, userid='1')
+        cl.classname = 'issue'
+        output = io.BytesIO()
+        cl.request = MockNull()
+        cl.request.wfile = output
+        actions.ExportCSVAction(cl).handle()
+        should_be=(s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
+                       '"2","bar2","unread","keyword1;keyword2","Bork, Chef","Bork, Chef"\r\n'))
+
+        self.assertEqual(output.getvalue(), should_be)
+
+        # call export version that outputs id numbers
+        output = io.BytesIO()
+        cl.request = MockNull()
+        cl.request.wfile = output
+        actions.ExportCSVWithIdAction(cl).handle()
+        should_be = s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
+                        "\"2\",\"bar2\",\"1\",\"['1', '2']\",\"3\",\"['3']\"\r\n")
+        self.assertEqual(output.getvalue(), should_be)
+
+class FormTestCase(FormTestParent, StringFragmentCmpHelper, testCsvExport, unittest.TestCase):
 
     def setUp(self):
         FormTestParent.setUp(self)
@@ -1789,44 +1889,6 @@
         self.db.user.set('1', roles='')
         self.assertTrue(not item.hasRole(''))
 
-    def testCSVExport(self):
-        cl = self._make_client(
-            {'@columns': 'id,title,status,keyword,assignedto,nosy'},
-            nodeid=None, userid='1')
-        cl.classname = 'issue'
-
-        demo_id=self.db.user.create(username='demo', address='demo@test.test',
-            roles='User', realname='demo')
-        key_id1=self.db.keyword.create(name='keyword1')
-        key_id2=self.db.keyword.create(name='keyword2')
-        self.db.issue.create(title='foo1', status='2', assignedto='4', nosy=['3',demo_id])
-        self.db.issue.create(title='bar2', status='1', assignedto='3', keyword=[key_id1,key_id2])
-        self.db.issue.create(title='baz32', status='4')
-        output = io.BytesIO()
-        cl.request = MockNull()
-        cl.request.wfile = output
-        # call export version that outputs names
-        actions.ExportCSVAction(cl).handle()
-        should_be=(s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
-                       '"1","foo1","deferred","","Contrary, Mary","Bork, Chef;Contrary, Mary;demo"\r\n'
-                       '"2","bar2","unread","keyword1;keyword2","Bork, Chef","Bork, Chef"\r\n'
-                       '"3","baz32","need-eg","","",""\r\n'))
-        #print(should_be)
-        print(output.getvalue())
-        self.assertEqual(output.getvalue(), should_be)
-        output = io.BytesIO()
-        cl.request = MockNull()
-        cl.request.wfile = output
-        # call export version that outputs id numbers
-        actions.ExportCSVWithIdAction(cl).handle()
-        should_be = s2b('"id","title","status","keyword","assignedto","nosy"\r\n'
-                        "\"1\",\"foo1\",\"2\",\"[]\",\"4\",\"['3', '4', '5']\"\r\n"
-                        "\"2\",\"bar2\",\"1\",\"['1', '2']\",\"3\",\"['3']\"\r\n"
-                        '\"3\","baz32",\"4\","[]","None","[]"\r\n')
-        #print(should_be)
-        print(output.getvalue())
-        self.assertEqual(output.getvalue(), should_be)
-
     def testCSVExportCharset(self):
         cl = self._make_client(
             {'@columns': 'id,title,status,keyword,assignedto,nosy'},
@@ -1976,7 +2038,7 @@
         self.assertRaises(exceptions.Unauthorised,
             actions.ExportCSVWithIdAction(cl).handle)
 
-class TemplateHtmlRendering(unittest.TestCase):
+class TemplateHtmlRendering(unittest.TestCase, testFtsQuery):
     ''' try to test the rendering code for tal '''
     def setUp(self):
         self.dirname = '_test_template'
@@ -2036,6 +2098,61 @@
         self.assertNotEqual(-1,
            self.output[0].index('<!-- SHA: c87a4e18d59a527331f1d367c0c6cc67ee123e63 -->'))
 
+    def testRenderError(self):
+        # set up the client;
+        # run determine_context to set the required client attributes
+        # run renderError(); check result for proper page
+
+        self.client.form=db_test_base.makeForm({})
+        self.client.path = ''
+        self.client.determine_context()
+
+        error = "Houston, we have a problem"
+
+
+        # template rendering will fail and return fallback html
+        out = self.client.renderError(error, 404)
+
+        expected_fallback = (
+            '\n<html><head><title>Roundup issue tracker: '
+            'An error has occurred</title>\n'
+            ' <link rel="stylesheet" type="text/css" href="@@file/style.css">\n'
+            '</head>\n'
+            '<body class="body" marginwidth="0" marginheight="0">\n'
+            ' <p class="error-message">Houston, we have a problem</p>\n'
+            '</body></html>\n')
+
+        self.assertEqual(out, expected_fallback)
+        self.assertIn(error, self.client._error_message)
+        self.assertEqual(self.client.response_code, 404)
+
+        ### next test
+        # Set this so template rendering works.
+        self.client.classname = 'issue'
+
+        out = self.client.renderError("Houston, we have a problem", 404)
+        # match hard coded line in 404 template
+        expected = ('There is no <span>issue</span> with id')
+        
+        self.assertIn(expected, out)
+        self.assertEqual(self.client.response_code, 404)
+
+
+        ### next test
+        # disable template use get fallback
+        out = self.client.renderError("Houston, we have a problem", 404,
+                                      use_template=False)
+        
+        self.assertEqual(out, expected_fallback)
+        self.assertEqual(self.client.response_code, 404)
+
+        ### next test
+        # no 400 template (default 2nd param) so we get fallback
+        out = self.client.renderError("Houston, we have a problem")
+        self.assertEqual(out, expected_fallback)
+        self.assertIn(error, self.client._error_message)
+        self.assertEqual(self.client.response_code, 400)
+
     def testrenderContext(self):
         # set up the client;
         # run determine_context to set the required client attributes
@@ -2288,4 +2405,252 @@
         r = t.selectTemplate("user", "subdir/item")
         self.assertEqual("subdir/user.item", r)
 
+class SqliteNativeFtsCgiTest(unittest.TestCase, testFtsQuery, testCsvExport):
+    """All of the rest of the tests use anydbm as the backend.
+       In addtion to normal fts test, this class tests renderError
+       when renderContext fails.
+       Triggering this error requires the native-fts backend for
+       the sqlite db.
+    """
+
+    def setUp(self):
+        self.dirname = '_test_template'
+        # set up and open a tracker
+        self.instance = setupTracker(self.dirname, backend="sqlite")
+
+        self.instance.config.INDEXER = "native-fts"
+
+        # open the database
+        self.db = self.instance.open('admin')
+        self.db.tx_Source = "web"
+        self.db.user.create(username='Chef', address='chef@bork.bork.bork',
+            realname='Bork, Chef', roles='User')
+        self.db.user.create(username='mary', address='mary@test.test',
+            roles='User', realname='Contrary, Mary')
+        self.db.post_init()
+
+        # create a client instance and hijack write_html
+        self.client = client.Client(self.instance, "user",
+                {'PATH_INFO':'/user', 'REQUEST_METHOD':'POST'},
+                form=db_test_base.makeForm({"@template": "item"}))
+
+        self.client._error_message = []
+        self.client._ok_message = []
+        self.client.db = self.db
+        self.client.userid = '1'
+        self.client.language = ('en',)
+        self.client.session_api = MockNull(_sid="1234567890")
+
+        self.output = []
+        # ugly hack to get html_write to return data here.
+        def html_write(s):
+            self.output.append(s)
+
+        # hijack html_write
+        self.client.write_html = html_write
+
+    def tearDown(self):
+        self.db.close()
+        try:
+            shutil.rmtree(self.dirname)
+        except OSError as error:
+            if error.errno not in (errno.ENOENT, errno.ESRCH): raise
+
+    def testRenderContextBadFtsQuery(self):
+        # only test for sqlite
+        if self.db.dbtype not in [ "sqlite" ]:
+            pytest.skip("Not tested for backends without native FTS")
+
+        # generate a bad fts query
+        self.client.form=db_test_base.makeForm(
+            { "@ok_message": "ok message", "@template": "index",
+            "@search_text": "foo-bar"})
+        self.client.path = 'issue'
+        self.client.determine_context()
+
+        result = self.client.renderContext()
+
+        expected = '\n<html><head><title>Roundup issue tracker: An error has occurred</title>\n <link rel="stylesheet" type="text/css" href="@@file/style.css">\n</head>\n<body class="body" marginwidth="0" marginheight="0">\n <p class="error-message">Search failed. Try quoting any terms that include a \'-\' and retry the search.</p>\n</body></html>\n'
+
+        self.assertEqual(result, expected)
+        self.assertEqual(self.client.response_code, 400)
+
+    #
+    # SECURITY
+    #
+    # XXX test all default permissions
+    def _make_client(self, form, classname='user', nodeid='1',
+           userid='2', template='item'):
+        cl = client.Client(self.instance, None, {'PATH_INFO':'/',
+            'REQUEST_METHOD':'POST'}, db_test_base.makeForm(form))
+        cl.classname = classname
+        if nodeid is not None:
+            cl.nodeid = nodeid
+        cl.db = self.db
+        #cl.db.Otk = MockNull()
+        #cl.db.Otk.data = {}
+        #cl.db.Otk.getall = self.data_get
+        #cl.db.Otk.set = self.data_set
+        cl.userid = userid
+        cl.language = ('en',)
+        cl._error_message = []
+        cl._ok_message = []
+        cl.template = template
+        return cl
+
+    def testCSVExportSearchError(self):
+        # test full text search
+        cl = self._make_client(
+            {'@columns': 'id,title,status,keyword,assignedto,nosy',
+             "@search_text": "foo + ^bar2"}, nodeid=None, userid='1')
+        cl.classname = 'issue'
+        output = io.BytesIO()
+        cl.request = MockNull()
+        cl.request.wfile = output
+
+        # note NotFound isn't quite right. however this exception
+        # passes up the stack to where it is handled with a suitable
+        # display of the error.
+        # call export version that outputs names
+        with self.assertRaises(NotFound) as cm:        
+            actions.ExportCSVAction(cl).handle()
+
+        # call export version that outputs id numbers
+        with self.assertRaises(NotFound) as cm:
+            actions.ExportCSVWithIdAction(cl).handle()
+
+class SqliteNativeCgiTest(unittest.TestCase, testFtsQuery):
+    """All of the rest of the tests use anydbm as the backend.
+       This class tests renderContext for fulltext search.
+       Run with sqlite and native indexer.
+    """
+
+    def setUp(self):
+        self.dirname = '_test_template'
+        # set up and open a tracker
+        self.instance = setupTracker(self.dirname, backend="sqlite")
+
+        self.instance.config.INDEXER = "native"
+
+        # open the database
+        self.db = self.instance.open('admin')
+        self.db.tx_Source = "web"
+
+        # create a client instance and hijack write_html
+        self.client = client.Client(self.instance, "user",
+                {'PATH_INFO':'/user', 'REQUEST_METHOD':'POST'},
+                form=db_test_base.makeForm({"@template": "item"}))
+
+        self.client._error_message = []
+        self.client._ok_message = []
+        self.client.db = self.db
+        self.client.userid = '1'
+        self.client.language = ('en',)
+        self.client.session_api = MockNull(_sid="1234567890")
+
+        self.output = []
+        # ugly hack to get html_write to return data here.
+        def html_write(s):
+            self.output.append(s)
+
+        # hijack html_write
+        self.client.write_html = html_write
+
+    def tearDown(self):
+        self.db.close()
+        try:
+            shutil.rmtree(self.dirname)
+        except OSError as error:
+            if error.errno not in (errno.ENOENT, errno.ESRCH): raise
+
+@skip_postgresql
+class PostgresqlNativeCgiTest(unittest.TestCase, testFtsQuery):
+    """All of the rest of the tests use anydbm as the backend.
+       This class tests renderContext for fulltext search.
+       Run with postgresql and native indexer.
+    """
+
+    def setUp(self):
+        self.dirname = '_test_template'
+        # set up and open a tracker
+        self.instance = setupTracker(self.dirname, backend="postgresql")
+
+        self.instance.config.INDEXER = "native"
+
+        # open the database
+        self.db = self.instance.open('admin')
+        self.db.tx_Source = "web"
+
+        # create a client instance and hijack write_html
+        self.client = client.Client(self.instance, "user",
+                {'PATH_INFO':'/user', 'REQUEST_METHOD':'POST'},
+                form=db_test_base.makeForm({"@template": "item"}))
+
+        self.client._error_message = []
+        self.client._ok_message = []
+        self.client.db = self.db
+        self.client.userid = '1'
+        self.client.language = ('en',)
+        self.client.session_api = MockNull(_sid="1234567890")
+
+        self.output = []
+        # ugly hack to get html_write to return data here.
+        def html_write(s):
+            self.output.append(s)
+
+        # hijack html_write
+        self.client.write_html = html_write
+
+    def tearDown(self):
+        self.db.close()
+        try:
+            shutil.rmtree(self.dirname)
+        except OSError as error:
+            if error.errno not in (errno.ENOENT, errno.ESRCH): raise
+
+@skip_mysql
+class MysqlNativeCgiTest(unittest.TestCase, testFtsQuery):
+    """All of the rest of the tests use anydbm as the backend.
+       This class tests renderContext for fulltext search.
+       Run with mysql and native indexer.
+    """
+
+    def setUp(self):
+        self.dirname = '_test_template'
+        # set up and open a tracker
+        self.instance = setupTracker(self.dirname, backend="mysql")
+
+        self.instance.config.INDEXER = "native"
+
+        # open the database
+        self.db = self.instance.open('admin')
+        self.db.tx_Source = "web"
+
+        # create a client instance and hijack write_html
+        self.client = client.Client(self.instance, "user",
+                {'PATH_INFO':'/user', 'REQUEST_METHOD':'POST'},
+                form=db_test_base.makeForm({"@template": "item"}))
+
+        self.client._error_message = []
+        self.client._ok_message = []
+        self.client.db = self.db
+        self.client.userid = '1'
+        self.client.language = ('en',)
+        self.client.session_api = MockNull(_sid="1234567890")
+
+        self.output = []
+        # ugly hack to get html_write to return data here.
+        def html_write(s):
+            self.output.append(s)
+
+        # hijack html_write
+        self.client.write_html = html_write
+
+    def tearDown(self):
+        self.db.close()
+        try:
+            shutil.rmtree(self.dirname)
+        except OSError as error:
+            if error.errno not in (errno.ENOENT, errno.ESRCH): raise
+
 # vim: set filetype=python sts=4 sw=4 et si :
--- a/test/test_config.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_config.py	Thu Apr 21 16:54:17 2022 -0400
@@ -19,7 +19,7 @@
 import logging
 import fileinput
 
-import os, shutil, errno
+import os, shutil, errno, sys
 
 import pytest
 from roundup import configuration
@@ -37,7 +37,17 @@
     skip_xapian = mark_class(pytest.mark.skip(
         "Skipping Xapian indexer tests: 'xapian' not installed"))
     include_no_xapian = lambda func, *args, **kwargs: func
-    
+
+_py3 = sys.version_info[0] > 2
+if _py3:
+    skip_py2 = lambda func, *args, **kwargs: func
+else:
+    # FIX: workaround for a bug in pytest.mark.skip():
+    #   https://github.com/pytest-dev/pytest/issues/568
+    from .pytest_patcher import mark_class
+    skip_py2 = mark_class(pytest.mark.skip(
+        reason='Skipping test under python2.'))
+
 
 config = configuration.CoreConfig()
 config.DATABASE = "db"
@@ -339,34 +349,59 @@
         except OSError as error:
             if error.errno not in (errno.ENOENT, errno.ESRCH): raise
 
-    def munge_configini(self, mods = None):
+    def munge_configini(self, mods = None, section=None):
         """ modify config.ini to meet testing requirements
 
             mods is a list of tuples:
-               [ ( "a = ", "b" ), ("c = ", None) ]
+               [ ( "a = ", "b" ), ("c = ", None), ("d = ", "b", "z = ") ]
             Match line with first tuple element e.g. "a = ". Note specify
             trailing "=" and space to delimit keyword and properly format
-            replacement line. If first tuple element matches, the line is
+            replacement line. If there are two elements in the tuple,
+            and the first element matches, the line is
             replaced with the concatenation of the first and second elements.
             If second element is None ("" doesn't work), the line will be
-            deleted.
+            deleted. If there are three elements in the tuple, the line
+            is replaced with the contcatentation of the third and second
+            elements (used to replace commented out parameters).
 
-            Note the key/first element of tuple must be unique in config.ini.
-            It is possible to have duplicates in different sections. This
-            method doesn't handle that. TBD option third element of tuple
-            defining section if needed.
+            Note if the key/first element of tuple is not unique in
+            config.ini, you must set the section to match the bracketed
+            section name.
         """
 
         if mods is None:
             return
 
+        # if section is defined, the tests in the loop will turn
+        # it off on [main] if section != '[main]'.
+        in_section = True 
+
         for line in fileinput.input(os.path.join(self.dirname, "config.ini"),
                                     inplace=True):
-            for match, value in mods:
-                if line.startswith(match):
-                    if value is not None:
-                        print(match + value)
-                    break
+            if section:
+                if line.startswith('['):
+                    in_section = False
+
+                if line.startswith(section):
+                    in_section = True
+
+            if in_section:
+                for rule in mods:
+                    if len(rule) == 3:
+                        match, value, repl = rule
+                    else:
+                        match, value = rule
+                        repl = None
+
+                    if line.startswith(match):
+                        if value is not None:
+                            if repl:
+                                print(repl + value)
+                            else:
+                                print(match + value)
+                        break
+                else:
+                    print(line[:-1]) # remove trailing \n
             else:
                 print(line[:-1]) # remove trailing \n
 
@@ -387,6 +422,183 @@
         self.assertEqual("RDBMS_BACKEND is not set"
                       " and has no default", cm.exception.__str__())
 
+    def testUnsetMailPassword_with_set_username(self):
+        """ Set [mail] username but don't set the 
+            [mail] password. Should get an OptionValueError. 
+        """
+        # SETUP: set mail username
+        self.munge_configini(mods=[ ("username = ", "foo"), ],
+                             section="[mail]")
+
+        config = configuration.CoreConfig()
+
+        with self.assertRaises(configuration.OptionValueError) as cm:
+            config.load(self.dirname)
+
+        print(cm.exception)
+        # test repr. The type is right since it passed assertRaises.
+        self.assertIn("OptionValueError", repr(cm.exception))
+        # look for 'not defined'
+        self.assertEqual("not defined", cm.exception.args[1])
+
+
+    def testUnsetMailPassword_with_unset_username(self):
+        """ Set [mail] username but don't set the 
+            [mail] password. Should get an OptionValueError. 
+        """
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        self.assertEqual(config['MAIL_USERNAME'], '')
+
+        with self.assertRaises(configuration.OptionUnsetError) as cm:
+            self.assertEqual(config['MAIL_PASSWORD'], 'NO DEFAULT')
+
+    def testSecretMandatory_missing_file(self):
+
+        # SETUP: 
+        self.munge_configini(mods=[ ("secret_key = ", "file://secret_key"), ])
+
+        config = configuration.CoreConfig()
+
+        with self.assertRaises(configuration.OptionValueError) as cm:
+            config.load(self.dirname)
+
+        print(cm.exception)
+        self.assertEqual(cm.exception.args[0].setting, "secret_key")
+
+    def testSecretMandatory_load_from_file(self):
+
+        # SETUP: 
+        self.munge_configini(mods=[ ("secret_key = ", "file://secret_key"), ])
+
+        secret = "ASDQWEZXCRFVBGTYHNMJU"
+        with open(self.dirname + "/secret_key", "w") as f:
+            f.write(secret + "\n")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        self.assertEqual(config['WEB_SECRET_KEY'], secret)
+
+
+    def testSecretMandatory_load_from_abs_file(self):
+
+        abs_file = "/tmp/secret_key.%s"%os.getpid()
+
+        # SETUP: 
+        self.munge_configini(mods=[ ("secret_key = ", "file://%s"%abs_file), ])
+
+        secret = "ASDQWEZXCRFVBGTYHNMJU"
+        with open(abs_file, "w") as f:
+            f.write(secret + "\n")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        self.assertEqual(config['WEB_SECRET_KEY'], secret)
+
+        os.remove(abs_file)
+
+    def testSecretMandatory_empty_file(self):
+
+        self.munge_configini(mods=[ ("secret_key = ", "file:// secret_key"), ])
+
+        # file with no value just newline.
+        with open(self.dirname + "/secret_key", "w") as f:
+            f.write("\n")
+
+        config = configuration.CoreConfig()
+
+        with self.assertRaises(configuration.OptionValueError) as cm:
+            config.load(self.dirname)
+
+        print(cm.exception.args)
+        self.assertEqual(cm.exception.args[2],"Value must not be empty.")
+
+    def testNullableSecret_empty_file(self):
+
+        self.munge_configini(mods=[ ("password = ", "file://db_password"), ])
+
+        # file with no value just newline.
+        with open(self.dirname + "/db_password", "w") as f:
+            f.write("\n")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        v = config['RDBMS_PASSWORD']
+
+        self.assertEqual(v, None)
+
+    def testNullableSecret_with_file_value(self):
+
+        self.munge_configini(mods=[ ("password = ", "file://db_password"), ])
+
+        # file with no value just newline.
+        with open(self.dirname + "/db_password", "w") as f:
+            f.write("test\n")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        v = config['RDBMS_PASSWORD']
+
+        self.assertEqual(v, "test")
+
+    def testNullableSecret_with_value(self):
+
+        self.munge_configini(mods=[ ("password = ", "test"), ])
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        v = config['RDBMS_PASSWORD']
+
+        self.assertEqual(v, "test")
+
+    def testSetMailPassword_with_set_username(self):
+        """ Set [mail] username and set the password.
+            Should have both values set.
+        """
+        # SETUP: set mail username
+        self.munge_configini(mods=[ ("username = ", "foo"),
+                                    ("#password = ", "passwordfoo",
+                                    "password = ") ],
+                             section="[mail]")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        self.assertEqual(config['MAIL_USERNAME'], 'foo')
+        self.assertEqual(config['MAIL_PASSWORD'], 'passwordfoo')
+
+    def testSetMailPassword_from_file(self):
+        """ Set [mail] username and set the password.
+            Should have both values set.
+        """
+        # SETUP: set mail username
+        self.munge_configini(mods=[ ("username = ", "foo"),
+                                    ("#password = ", "file://password",
+                                     "password = ") ],
+                             section="[mail]")
+        with open(self.dirname + "/password", "w") as f:
+            f.write("passwordfoo\n")
+
+        config = configuration.CoreConfig()
+
+        config.load(self.dirname)
+
+        self.assertEqual(config['MAIL_USERNAME'], 'foo')
+        self.assertEqual(config['MAIL_PASSWORD'], 'passwordfoo')
+
     @skip_xapian
     def testInvalidIndexerLanguage_w_empty(self):
         """ make sure we have a reasonable error message if
@@ -492,6 +704,24 @@
         # if exception not generated assertRaises
         # will generate failure.
 
+    def testInvalidIndexerLanguage_w_native_fts(self):
+        """ Use explicit native-fts indexer. Verify exception is
+            generated.
+        """
+
+        self.munge_configini(mods=[ ("indexer = ", "native-fts"),
+            ("indexer_language = ", "NO_LANG") ])
+
+        with self.assertRaises(configuration.OptionValueError) as cm:
+            config.load(self.dirname)
+
+        # test repr. The type is right since it passed assertRaises.
+        self.assertIn("OptionValueError", repr(cm.exception))
+        # look for failing language
+        self.assertIn("NO_LANG", cm.exception.args[1])
+        # look for supported language
+        self.assertIn("basque", cm.exception.args[2])
+
     def testLoadConfig(self):
         """ run load to validate config """
 
@@ -553,6 +783,43 @@
         # this should work
         self.assertEqual(config_copy['HTML_VERSION'], 'xhtml')
 
+    @skip_py2
+    def testConfigValueInterpolateError(self):
+        ''' error is not raised using ConfigParser under Python 2.
+            Unknown cause, so skip it if running python 2.
+        '''
+
+        self.munge_configini(mods=[ ("admin_email = ", "a bare % is invalid") ])
+
+        config = configuration.CoreConfig()
+
+        # load config generates:
+        '''
+E           roundup.configuration.ParsingOptionError: Error in _test_instance/config.ini with section [main] at option admin_email: '%' must be followed by '%' or '(', found: '% is invalid'
+        '''
+
+        with self.assertRaises(configuration.ParsingOptionError) as cm:
+            config.load(self.dirname)
+
+        print(cm.exception)
+        self.assertIn("'%' must be followed by '%' or '(', found: '% is invalid'", cm.exception.args[0])
+        self.assertIn("_test_instance/config.ini with section [main] at option admin_email", cm.exception.args[0])
+
+
+        from roundup.admin import AdminTool
+        from .test_admin import captured_output
+
+        admin=AdminTool()
+        with captured_output() as (out, err):
+            sys.argv=['main', '-i', self.dirname, 'get', 'tile', 'issue1']
+            ret = admin.main()
+
+        expected_err = "Error in _test_instance/config.ini with section [main] at option admin_email: '%' must be followed by '%' or '(', found: '% is invalid'"
+
+        self.assertEqual(ret, 1)
+        out = out.getvalue().strip()
+        self.assertEqual(out, expected_err)
+
     def testInvalidIndexerValue(self):
         """ Mistype native indexer. Verify exception is
             generated.
@@ -576,5 +843,3 @@
         print(string_rep)
         self.assertIn("nati", string_rep)
         self.assertIn("'whoosh'", string_rep)
-
-
--- a/test/test_demo.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_demo.py	Thu Apr 21 16:54:17 2022 -0400
@@ -33,7 +33,7 @@
         except FileNotFoundError:
             pass
         
-    def testDemo(self):
+    def testDemoClassic(self):
         with captured_output() as (out, err):
             install_demo(self.home, 'anydbm', 'classic')
         output = out.getvalue().strip()
@@ -61,4 +61,71 @@
         # last line in the output.
         self.assertIn("Keyboard Interrupt: exiting", output.split('\n'))
 
+    def testDemoMinimal(self):
+        with captured_output() as (out, err):
+            # use a modified path that resolves when 
+            install_demo(self.home, 'sqlite', '../templates/minimal')
+        output = out.getvalue().strip()
+        print(output)
 
+        # verify that db was set properly by reading config
+        with open(self.home + "/config.ini", "r") as f:
+            config_lines = f.readlines()
+
+        self.assertIn("backend = sqlite\n", config_lines)
+
+        # dummy up the return of get_server so the serve_forever method
+        # raises keyboard interrupt exiting the server so the test exits.
+        gs = roundup.scripts.roundup_server.ServerConfig.get_server
+        def raise_KeyboardInterrupt():
+            raise KeyboardInterrupt
+
+        def test_get_server(self):
+            httpd = gs(self)
+            httpd.serve_forever = raise_KeyboardInterrupt
+            return httpd
+
+        roundup.scripts.roundup_server.ServerConfig.get_server = test_get_server
+
+        # Run under context manager to capture output of startup text.
+        with captured_output() as (out, err):
+            run_demo(self.home)
+        output = out.getvalue().strip()
+        print(output)
+        # if the server installed and started this will be the
+        # last line in the output.
+        self.assertIn("Keyboard Interrupt: exiting", output.split('\n'))
+
+    def testDemoJinja(self):
+        with captured_output() as (out, err):
+            install_demo(self.home, 'anydbm', 'jinja2')
+        output = out.getvalue().strip()
+        print(output)
+
+        # verify that template was set to jinja2 by reading config
+        with open(self.home + "/config.ini", "r") as f:
+            config_lines = f.readlines()
+
+        self.assertIn("template_engine = jinja2\n", config_lines)
+
+        # dummy up the return of get_server so the serve_forever method
+        # raises keyboard interrupt exiting the server so the test exits.
+        gs = roundup.scripts.roundup_server.ServerConfig.get_server
+        def raise_KeyboardInterrupt():
+            raise KeyboardInterrupt
+
+        def test_get_server(self):
+            httpd = gs(self)
+            httpd.serve_forever = raise_KeyboardInterrupt
+            return httpd
+
+        roundup.scripts.roundup_server.ServerConfig.get_server = test_get_server
+
+        # Run under context manager to capture output of startup text.
+        with captured_output() as (out, err):
+            run_demo(self.home)
+        output = out.getvalue().strip()
+        print(output)
+        # if the server installed and started this will be the
+        # last line in the output.
+        self.assertIn("Keyboard Interrupt: exiting", output.split('\n'))
--- a/test/test_indexer.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_indexer.py	Thu Apr 21 16:54:17 2022 -0400
@@ -24,6 +24,8 @@
 from roundup.backends import get_backend, have_backend
 from roundup.backends.indexer_rdbms import Indexer
 
+from roundup.cgi.exceptions import IndexerQueryError
+
 # borrow from other tests
 from .db_test_base import setupSchema, config
 from .test_postgresql import postgresqlOpener, skip_postgresql
@@ -115,8 +117,14 @@
                                                      ('test', '2', 'bar')])
     def test_extremewords(self):
         """Testing too short or too long words."""
+
+        # skip this for FTS test
+        if ( isinstance(self,sqliteFtsIndexerTest) or
+             isinstance(self,postgresqlFtsIndexerTest)):
+            pytest.skip("extremewords not tested for native FTS backends")
+
         short = "b"
-        long = "abcdefghijklmnopqrstuvwxyz"
+        long = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
         self.dex.add_text(('test', '1', 'a'), '%s hello world' % short)
         self.dex.add_text(('test', '2', 'a'), 'blah a %s world' % short)
         self.dex.add_text(('test', '3', 'a'), 'blah Blub river')
@@ -133,7 +141,7 @@
                                                         % (short, long))
         self.assertSeqEqual(self.dex.find(["py"]), [('test', '5', 'a')])
 
-    def test_casesensitity(self):
+    def test_casesensitivity(self):
         """Test if searches are case-in-sensitive."""
         self.dex.add_text(('test', '1', 'a'), 'aaaa bbbb')
         self.dex.add_text(('test', '2', 'a'), 'aAaa BBBB')
@@ -220,6 +228,214 @@
         postgresqlOpener.tearDown(self)
 
 
+@skip_postgresql
+class postgresqlFtsIndexerTest(postgresqlOpener, RDBMSIndexerTest, IndexerTest):
+    def setUp(self):
+        postgresqlOpener.setUp(self)
+        RDBMSIndexerTest.setUp(self)
+        from roundup.backends.indexer_postgresql_fts import Indexer
+        self.dex = Indexer(self.db)
+        self.dex.db = self.db
+
+    def tearDown(self):
+        RDBMSIndexerTest.tearDown(self)
+        postgresqlOpener.tearDown(self)
+
+    def test_websearch_syntax(self):
+        """Test searches using websearch_to_tsquery. These never throw
+           errors regardless of how wacky the input.
+        """
+
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+        self.dex.add_text(('test', '5', 'foo'), 'a car drove')
+        self.dex.add_text(('test', '6', 'foo'), 'a car driving itself')
+        self.dex.add_text(('test', '7', 'foo'), "let's drive in the car")
+        self.dex.add_text(('test', '8', 'foo'), 'a drive-in movie')
+
+        # test two separate words for sanity
+        self.assertSeqEqual(self.dex.find(['"hello" "world"']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo')
+                                                    ])
+        # now check the phrase
+        self.assertSeqEqual(self.dex.find(['"hello world"']),
+                                                    [('test', '1', 'foo'),
+                                                     ])
+
+        # test negation
+        self.assertSeqEqual(self.dex.find(['hello world -blech']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                    ])
+
+        # phrase negation
+        self.assertSeqEqual(self.dex.find(['hello world -"blah hello"']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+        # test without or
+        self.assertSeqEqual(self.dex.find(['blah blech']),
+                                                    [('test', '4', 'foo'),
+                                                    ])
+
+        # test with or
+        self.assertSeqEqual(self.dex.find(['blah or blech']),
+                                                    [ ('test', '2', 'foo'),
+                                                      ('test', '3', 'foo'),
+                                                      ('test', '4', 'foo'),
+                                                    ])
+
+        # stemmer test for english
+        self.assertSeqEqual(self.dex.find(['ts:drive']),
+                                                    [('test', '6', 'foo'),
+                                                     ('test', '7', 'foo'),
+                                                     ('test', '8', 'foo')
+                                                    ])
+
+        # stemmer is not disabled by quotes 8-(
+        self.assertSeqEqual(self.dex.find(['ts:"drive"']),
+                                                    [('test', '6', 'foo'),
+                                                     ('test', '7', 'foo'),
+                                                     ('test', '8', 'foo')
+                                                    ])
+
+
+        # this is missing ts: at the start, so uses the websearch
+        # parser. We search for operator characters and wanr the user
+        # Otherwise "hello <-> world" is the same as "hello world"
+        # and is not a phrase search.
+        with self.assertRaises(IndexerQueryError) as ctx:
+            self.dex.find(['hello <-> world'])
+
+        self.assertIn('do a tsquery search', ctx.exception.args[0])
+
+    def test_tsquery_syntax(self):
+        """Because websearch_to_tsquery doesn't allow prefix searches,
+           near searches with any value except 1 (phrase search), allow
+           use of to_tsquery by prefixing the search term wih ts:.
+
+           However, unlike websearch_to_tsquery, this will throw a
+           psycopg2.errors.SyntaxError on bad input. SyntaxError is
+           re-raised as IndexerQueryError.  But it makes a bunch of
+           useful expert functionality available.
+
+        """
+
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+        self.dex.add_text(('test', '5', 'foo'), 'a car drove')
+        self.dex.add_text(('test', '6', 'foo'), 'a car driving itself')
+        self.dex.add_text(('test', '7', 'foo'), "let's drive in the car")
+        self.dex.add_text(('test', '8', 'foo'), 'a drive-in movie')
+        self.dex.db.commit()
+
+        # test two separate words for sanity
+        self.assertSeqEqual(self.dex.find(['ts:hello & world']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo')
+                                                    ])
+        # now check the phrase
+        self.assertSeqEqual(self.dex.find(['ts:hello <-> world']),
+                                                    [('test', '1', 'foo'),
+                                                     ])
+
+        # test negation
+        self.assertSeqEqual(self.dex.find(['ts:hello & world & !blech']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                    ])
+
+        self.assertSeqEqual(self.dex.find(
+            ['ts:hello & world & !(blah <-> hello)']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+        # test without or
+        self.assertSeqEqual(self.dex.find(['ts:blah & blech']),
+                                                    [('test', '4', 'foo'),
+                                                    ])
+
+        # test with or
+        self.assertSeqEqual(self.dex.find(['ts:blah | blech']),
+                                                    [ ('test', '2', 'foo'),
+                                                      ('test', '3', 'foo'),
+                                                      ('test', '4', 'foo'),
+                                                    ])
+        # stemmer test for english
+        self.assertSeqEqual(self.dex.find(['ts:drive']),
+                                                    [('test', '6', 'foo'),
+                                                     ('test', '7', 'foo'),
+                                                     ('test', '8', 'foo')
+                                                    ])
+
+        # stemmer is not disabled by quotes 8-(
+        self.assertSeqEqual(self.dex.find(['ts:"drive"']),
+                                                    [('test', '6', 'foo'),
+                                                     ('test', '7', 'foo'),
+                                                     ('test', '8', 'foo')
+                                                    ])
+
+
+        # test with syntax error
+        with self.assertRaises(IndexerQueryError) as ctx:
+            self.dex.find(['ts:blah blech'])
+
+        self.assertEqual(ctx.exception.args[0],
+                         'syntax error in tsquery: "blah blech"\n')
+
+        # now check the phrase Note unlike sqlite, order matters,
+        # hello must come first.
+        self.assertSeqEqual(self.dex.find(['ts:hello <-> world']),
+                                                    [('test', '1', 'foo'),
+                                                     ])
+
+        # now check the phrase with explicitly 1 intervening item
+        self.assertSeqEqual(self.dex.find(['ts:hello <2> world']),
+                                                    [('test', '3', 'foo'),
+                                                     ])
+        # now check the phrase with near explicitly 1 or 3 intervening items
+        self.assertSeqEqual(self.dex.find([
+            'ts:(hello <4> world) | (hello<2>world)']),
+                                                    [('test', '3', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                     ])
+
+        # now check the phrase with near explicitly 3 intervening item
+        # with prefix for world.
+        self.assertSeqEqual(self.dex.find(['ts:hello <4> wor:*']),
+                                                    [('test', '4', 'foo'),
+                                                     ])
+
+    def test_invalid_language(self):
+        import psycopg2
+
+        from roundup.configuration import IndexerOption
+        IndexerOption.valid_langs.append("foo")
+        self.db.config["INDEXER_LANGUAGE"] = "foo"
+
+        with self.assertRaises(psycopg2.errors.UndefinedObject) as ctx:
+            # psycopg2.errors.UndefinedObject: text search configuration
+            #  "foo" does not exist
+            self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.assertIn('search configuration "foo" does', ctx.exception.args[0])
+        self.db.rollback()
+
+        with self.assertRaises(ValueError) as ctx:
+            self.dex.find(['"hello" "world"'])
+        self.assertIn('search configuration "foo" does', ctx.exception.args[0])
+        self.db.rollback()
+
+        self.db.config["INDEXER_LANGUAGE"] = "english"
+
 @skip_mysql
 class mysqlIndexerTest(mysqlOpener, RDBMSIndexerTest, IndexerTest):
     def setUp(self):
@@ -233,4 +449,129 @@
 class sqliteIndexerTest(sqliteOpener, RDBMSIndexerTest, IndexerTest):
     pass
 
+class sqliteFtsIndexerTest(sqliteOpener, RDBMSIndexerTest, IndexerTest):
+    def setUp(self):
+        RDBMSIndexerTest.setUp(self)
+        from roundup.backends.indexer_sqlite_fts import Indexer
+        self.dex = Indexer(self.db)
+        self.dex.db = self.db
+
+    def test_phrase_and_near(self):
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+
+        # test two separate words for sanity
+        self.assertSeqEqual(self.dex.find(['"hello" "world"']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo')
+                                                    ])
+        # now check the phrase
+        self.assertSeqEqual(self.dex.find(['"hello world"']),
+                                                    [('test', '1', 'foo'),
+                                                     ])
+
+        # now check the phrase with near explicitly 0 intervening items
+        self.assertSeqEqual(self.dex.find(['NEAR(hello world, 0)']),
+                                                    [('test', '1', 'foo'),
+                                                     ])
+
+        # now check the phrase with near explicitly 1 intervening item
+        self.assertSeqEqual(self.dex.find(['NEAR(hello world, 1)']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ])
+        # now check the phrase with near explicitly 3 intervening item
+        self.assertSeqEqual(self.dex.find(['NEAR(hello world, 3)']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                     ])
+
+    def test_prefix(self):
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+
+        self.assertSeqEqual(self.dex.find(['hel*']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '2', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo')
+                                                    ])
+
+
+    def test_bool_start(self):
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+
+        self.assertSeqEqual(self.dex.find(['hel* NOT helh NOT blech']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                    ])
+
+        self.assertSeqEqual(self.dex.find(['hel* NOT helh NOT blech OR the']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '2', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+        self.assertSeqEqual(self.dex.find(['helh OR hello']),
+                                                    [('test', '1', 'foo'),
+                                                     ('test', '2', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+
+        self.assertSeqEqual(self.dex.find(['helh AND hello']),
+                                                    [])
+        # matches if line starts with hello
+        self.assertSeqEqual(self.dex.find(['^hello']),
+                                                    [
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+        self.assertSeqEqual(self.dex.find(['hello']),
+                                                    [
+                                                     ('test', '1', 'foo'),
+                                                     ('test', '3', 'foo'),
+                                                     ('test', '4', 'foo'),
+                                                    ])
+
+    def test_query_errors(self):
+        """test query phrases that generate an error. Also test the
+           correction"""
+
+        self.dex.add_text(('test', '1', 'foo'), 'a the hello-world')
+        self.dex.add_text(('test', '2', 'foo'), 'helh blah blah the world')
+        self.dex.add_text(('test', '3', 'foo'), 'blah hello the world')
+        self.dex.add_text(('test', '4', 'foo'), 'hello blah blech the world')
+
+        # handle known error that roundup recognizes and tries to diagnose
+        with self.assertRaises(IndexerQueryError) as ctx:
+            self.dex.find(['the hello-world'])
+
+        error = ( "Search failed. Try quoting any terms that include a '-' "
+                  "and retry the search.")
+        self.assertEqual(str(ctx.exception), error)
+
+
+        self.assertSeqEqual(self.dex.find(['the "hello-world"']),
+                                                    [('test', '1', 'foo'),
+                                                    ])
+
+        # handle known error that roundup recognizes and tries to diagnose
+        with self.assertRaises(IndexerQueryError) as ctx:
+                self.dex.find(['hello world + ^the'])
+
+        error = 'Query error: syntax error near "^"'
+        self.assertEqual(str(ctx.exception), error)
+
 # vim: set filetype=python ts=4 sw=4 et si
--- a/test/test_liveserver.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_liveserver.py	Thu Apr 21 16:54:17 2022 -0400
@@ -1,10 +1,12 @@
-import shutil, errno, pytest, json, gzip, os
+import shutil, errno, pytest, json, gzip, os, re
 
 from roundup.anypy.strings import b2s
 from roundup.cgi.wsgi_handler import RequestDispatcher
 from .wsgi_liveserver import LiveServerTestCase
 from . import db_test_base
 
+from wsgiref.validate import validator
+
 try:
     import requests
     skip_requests = lambda func, *args, **kwargs: func
@@ -30,6 +32,10 @@
     skip_zstd = mark_class(pytest.mark.skip(
         reason='Skipping zstd tests: zstd library not available'))
 
+import sys
+
+_py3 = sys.version_info[0] > 2
+
 @skip_requests
 class SimpleTest(LiveServerTestCase):
     # have chicken and egg issue here. Need to encode the base_url
@@ -60,7 +66,7 @@
         # set up mailhost so errors get reported to debuging capture file
         cls.db.config.MAILHOST = "localhost"
         cls.db.config.MAIL_HOST = "localhost"
-        cls.db.config.MAIL_DEBUG = "../mail.log.t"
+        cls.db.config.MAIL_DEBUG = "../_test_tracker_mail.log"
 
         # enable static precompressed files
         cls.db.config.WEB_USE_PRECOMPRESSED_FILES = 1
@@ -84,7 +90,13 @@
 
     def create_app(self):
         '''The wsgi app to start'''
-        return RequestDispatcher(self.dirname)
+        if _py3:
+            return validator(RequestDispatcher(self.dirname))
+        else:
+            # wsgiref/validator.py InputWrapper::readline is broke and
+            # doesn't support the max bytes to read argument.
+            return RequestDispatcher(self.dirname)
+
 
     def test_start_page(self):
         """ simple test that verifies that the server can serve a start page.
@@ -95,6 +107,33 @@
         self.assertTrue(b'Creator' in f.content)
 
 
+    def test_rest_invalid_method_collection(self):
+        # use basic auth for rest endpoint
+        f = requests.put(self.url_base() + '/rest/data/user',
+                             auth=('admin', 'sekrit'),
+                             headers = {'content-type': "",
+                             'x-requested-with': "rest"})
+        print(f.status_code)
+        print(f.headers)
+        print(f.content)
+
+        self.assertEqual(f.status_code, 405)
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
+                     'Allow': 'DELETE, GET, OPTIONS, POST',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
+        }
+
+        print(f.headers)
+        # use dict comprehension to remove fields like date,
+        # content-length etc. from f.headers.
+        self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected)
+
+        content = json.loads(f.content)
+
+        exp_content = "Method PUT not allowed. Allowed: DELETE, GET, OPTIONS, POST"
+        self.assertEqual(exp_content, content['error']['msg'])
+
     def test_http_options(self):
         """ options returns an unimplemented error for this case."""
         
@@ -113,11 +152,10 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 204)
-        expected = { 'Content-Type': 'application/json',
-                     'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         # use dict comprehension to remove fields like date,
@@ -134,11 +172,10 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 204)
-        expected = { 'Content-Type': 'application/json',
-                     'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         # use dict comprehension to remove fields like date,
@@ -154,11 +191,10 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 204)
-        expected = { 'Content-Type': 'application/json',
-                     'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'OPTIONS, GET, POST',
         }
 
         # use dict comprehension to remove fields like date,
@@ -175,11 +211,10 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 204)
-        expected = { 'Content-Type': 'application/json',
-                     'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         # use dict comprehension to remove fields like date,
@@ -195,11 +230,10 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 204)
-        expected = { 'Content-Type': 'application/json',
-                     'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+        expected = { 'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         # use dict comprehension to remove fields like date,
@@ -264,8 +298,7 @@
         print(f.headers)
 
         self.assertEqual(f.status_code, 304)
-        expected = { 'Content-Type': 'application/javascript',
-                     'Vary': 'Accept-Encoding',
+        expected = { 'Vary': 'Accept-Encoding',
                      'Content-Length': '0',
         }
 
@@ -374,6 +407,57 @@
         # cleanup
         os.remove(gzfile)
 
+    def test_compression_none_etag(self):
+        # use basic auth for rest endpoint
+        f = requests.get(self.url_base() + '/rest/data/user/1/username',
+                             auth=('admin', 'sekrit'),
+                             headers = {'content-type': "",
+                                        'Accept-Encoding': "",
+                                        'Accept': '*/*'})
+        print(f.status_code)
+        print(f.headers)
+
+        self.assertEqual(f.status_code, 200)
+        expected = { 'Content-Type': 'application/json',
+                     'Access-Control-Allow-Origin': '*',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
+                     'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH'
+        }
+
+        content_str = '''{ "data": {
+                        "id": "1",
+                        "link": "http://localhost:9001/rest/data/user/1/username",
+                        "data": "admin"
+                    }
+        }'''
+        content = json.loads(content_str)
+
+
+        if (type("") == type(f.content)):
+            json_dict = json.loads(f.content)
+        else:
+            json_dict = json.loads(b2s(f.content))
+
+        # etag wil not match, creation date different
+        del(json_dict['data']['@etag']) 
+
+        # type is "class 'str'" under py3, "type 'str'" py2
+        # just skip comparing it.
+        del(json_dict['data']['type']) 
+
+        self.assertDictEqual(json_dict, content)
+
+        # verify that ETag header has no - delimiter
+        print(f.headers['ETag'])
+        with self.assertRaises(ValueError):
+            f.headers['ETag'].index('-')
+
+        # use dict comprehension to remove fields like date,
+        # content-length etc. from f.headers.
+        self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected)
+
+
     def test_compression_gzip(self):
         # use basic auth for rest endpoint
         f = requests.get(self.url_base() + '/rest/data/user/1/username',
@@ -387,9 +471,9 @@
         self.assertEqual(f.status_code, 200)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
                      'Content-Encoding': 'gzip',
                      'Vary': 'Accept-Encoding',
         }
@@ -417,6 +501,13 @@
 
         self.assertDictEqual(json_dict, content)
 
+        # verify that ETag header ends with -gzip
+        try:
+            self.assertRegex(f.headers['ETag'], r'^"[0-9a-f]{32}-gzip"$')
+        except AttributeError:
+            # python2 no assertRegex so try substring match
+            self.assertEqual(33, f.headers['ETag'].rindex('-gzip"'))
+
         # use dict comprehension to remove fields like date,
         # content-length etc. from f.headers.
         self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected)
@@ -432,20 +523,19 @@
         print(f.status_code)
         print(f.headers)
 
-        # ERROR: attribute error turns into 405, not sure that's right.
         # NOTE: not compressed payload too small
-        self.assertEqual(f.status_code, 405)
+        self.assertEqual(f.status_code, 400)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         content = { "error":
                     {
-                        "status": 405,
-                        "msg": "'foo'"
+                        "status": 400,
+                        "msg": "Invalid attribute foo"
                     }
         }
 
@@ -514,9 +604,9 @@
         self.assertEqual(f.status_code, 200)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
                      'Content-Encoding': 'br',
                      'Vary': 'Accept-Encoding',
         }
@@ -547,6 +637,13 @@
 
         self.assertDictEqual(json_dict, content)
 
+        # verify that ETag header ends with -br
+        try:
+            self.assertRegex(f.headers['ETag'], r'^"[0-9a-f]{32}-br"$')
+        except AttributeError:
+            # python2 no assertRegex so try substring match
+            self.assertEqual(33, f.headers['ETag'].rindex('-br"'))
+
         # use dict comprehension to remove fields like date,
         # content-length etc. from f.headers.
         self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected)
@@ -560,20 +657,20 @@
                                         'Accept': '*/*'})
         print(f.status_code)
         print(f.headers)
-        # ERROR: attribute error turns into 405, not sure that's right.
+
         # Note: not compressed payload too small
-        self.assertEqual(f.status_code, 405)
+        self.assertEqual(f.status_code, 400)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         content = { "error":
                     {
-                        "status": 405,
-                        "msg": "'foo'"
+                        "status": 400,
+                        "msg": "Invalid attribute foo"
                     }
         }
         json_dict = json.loads(b2s(f.content))
@@ -660,9 +757,9 @@
         self.assertEqual(f.status_code, 200)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
                      'Content-Encoding': 'zstd',
                      'Vary': 'Accept-Encoding',
         }
@@ -693,6 +790,13 @@
 
         self.assertDictEqual(json_dict, content)
 
+        # verify that ETag header ends with -zstd
+        try:
+            self.assertRegex(f.headers['ETag'], r'^"[0-9a-f]{32}-zstd"$')
+        except AttributeError:
+            # python2 no assertRegex so try substring match
+            self.assertEqual(33, f.headers['ETag'].rindex('-zstd"'))
+
         # use dict comprehension to remove fields like date,
         # content-length etc. from f.headers.
         self.assertDictEqual({ key: value for (key, value) in f.headers.items() if key in expected }, expected)
@@ -708,20 +812,19 @@
         print(f.status_code)
         print(f.headers)
 
-        # ERROR: attribute error turns into 405, not sure that's right.
         # Note: not compressed, payload too small
-        self.assertEqual(f.status_code, 405)
+        self.assertEqual(f.status_code, 400)
         expected = { 'Content-Type': 'application/json',
                      'Access-Control-Allow-Origin': '*',
-                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-HTTP-Method-Override',
+                     'Access-Control-Allow-Headers': 'Content-Type, Authorization, X-Requested-With, X-HTTP-Method-Override',
                      'Allow': 'OPTIONS, GET, POST, PUT, DELETE, PATCH',
-                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, PUT, DELETE, PATCH',
+                     'Access-Control-Allow-Methods': 'HEAD, OPTIONS, GET, POST, PUT, DELETE, PATCH',
         }
 
         content = { "error":
                     {
-                        "status": 405,
-                        "msg": "'foo'"
+                        "status": 400,
+                        "msg": "Invalid attribute foo"
                     }
         }
 
@@ -776,3 +879,111 @@
         self.assertDictEqual({ key: value for (key, value) in
                                f.headers.items() if key in expected },
                              expected)
+
+    @pytest.mark.xfail(reason="Fails with 3600 age on circle ci not sure why")
+    def test_cache_control_css(self):
+        f = requests.get(self.url_base() + '/@@file/style.css',
+                             headers = {'content-type': "",
+                                        'Accept': '*/*'})
+        print(f.status_code)
+        print(f.headers)
+
+        self.assertEqual(f.status_code, 200)
+        self.assertEqual(f.headers['Cache-Control'], 'public, max-age=4838400')
+
+    def test_cache_control_js(self):
+        f = requests.get(self.url_base() + '/@@file/help_controls.js',
+                             headers = {'content-type': "",
+                                        'Accept': '*/*'})
+        print(f.status_code)
+        print(f.headers)
+
+        self.assertEqual(f.status_code, 200)
+        self.assertEqual(f.headers['Cache-Control'], 'public, max-age=1209600')
+
+    def test_new_issue_with_file_upload(self):
+        # Set up session to manage cookies <insert blue monster here>
+        session = requests.Session()
+
+        # login using form
+        login = {"__login_name": 'admin', '__login_password': 'sekrit', 
+                 "@action": "login"}
+        f = session.post(self.url_base()+'/', data=login)
+        # look for change in text in sidebar post login
+        self.assertIn('Hello, admin', f.text)
+
+        # create a new issue and upload a file
+        file_content = 'this is a test file\n'
+        file = {"@file": ('test1.txt', file_content, "text/plain") }
+        issue = {"title": "my title", "priority": "1", "@action": "new"}
+        f = session.post(self.url_base()+'/issue?@template=item', data=issue, files=file)
+
+        # use redirected url to determine which issue and file were created.
+        m = re.search(r'[0-9]/issue(?P<issue>[0-9]+)\?@ok_message.*file%20(?P<file>[0-9]+)%20', f.url)
+
+        # verify message in redirected url: file 1 created\nissue 1 created
+        # warning may fail if another test loads tracker with files.
+        # Escape % signs in string by doubling them. This verifies the
+        # search is working correctly.
+        # use groupdict for python2.
+        self.assertEqual('http://localhost:9001/issue%(issue)s?@ok_message=file%%20%(file)s%%20created%%0Aissue%%20%(issue)s%%20created&@template=item'%m.groupdict(), f.url)
+
+        # we have an issue display, verify filename is listed there
+        # seach for unique filename given to it.
+        self.assertIn("test1.txt", f.text)
+
+        # download file and verify content
+        f = session.get(self.url_base()+'/file%(file)s/text1.txt'%m.groupdict())
+        self.assertEqual(f.text, file_content)
+        print(f.text)
+
+    def test_new_file_via_rest(self):
+
+        session = requests.Session()
+        session.auth = ('admin', 'sekrit')
+
+        url = self.url_base() + '/rest/data/'
+        fname   = 'a-bigger-testfile'
+        d = dict(name = fname, type='application/octet-stream')
+        c = dict (content = r'xyzzy')
+        r = session.post(url + 'file', files = c, data = d,
+                          headers = {'x-requested-with': "rest"}
+        )
+
+        # was a 500 before fix for issue2551178
+        self.assertEqual(r.status_code, 201)
+        # just compare the path leave off the number
+        self.assertIn('http://localhost:9001/rest/data/file/',
+                      r.headers["location"])
+        json_dict = json.loads(r.text)
+        self.assertEqual(json_dict["data"]["link"], r.headers["location"])
+
+        # download file and verify content
+        r = session.get(r.headers["location"] +'/content')
+        json_dict = json.loads(r.text)
+        self.assertEqual(json_dict['data']['data'], c["content"])
+        print(r.text)
+
+        # Upload a file via rest interface - no auth 
+        session.auth = None
+        r = session.post(url + 'file', files = c, data = d,
+                          headers = {'x-requested-with': "rest"}
+        )
+        self.assertEqual(r.status_code, 403)
+
+        # get session variable from web form login
+        #   and use it to upload file
+        # login using form
+        login = {"__login_name": 'admin', '__login_password': 'sekrit', 
+                 "@action": "login"}
+        f = session.post(self.url_base()+'/', data=login)
+        # look for change in text in sidebar post login
+        self.assertIn('Hello, admin', f.text)
+
+        r = session.post(url + 'file', files = c, data = d,
+                          headers = {'x-requested-with': "rest"}
+        )
+        self.assertEqual(r.status_code, 201)
+        print(r.status_code)
+
+
--- a/test/test_mysql.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_mysql.py	Thu Apr 21 16:54:17 2022 -0400
@@ -65,6 +65,51 @@
         mysqlOpener.setUp(self)
         DBTest.setUp(self)
 
+    def testUpgrade_6_to_7(self):
+
+        # load the database
+        self.db.issue.create(title="flebble frooz")
+        self.db.commit()
+
+        if self.db.database_schema['version'] != 7:
+            self.skipTest("This test only runs for database version 7")
+
+
+        # test by shrinking _words and trying to insert a long value
+        #    it should fail.
+        # run post-init
+        #    same test should succeed.
+
+        self.db.sql("alter table __words change column "
+                    "_word _word varchar(10)")
+
+        long_string = "a" * (self.db.indexer.maxlength + 5)
+
+        with self.assertRaises(MySQLdb.DataError) as ctx:
+            # DataError : Data too long for column '_word' at row 1
+            self.db.sql("insert into __words VALUES('%s',1)" % long_string)
+
+        self.assertIn("Data too long for column '_word'",
+                      ctx.exception.args[1])
+
+        self.db.database_schema['version'] = 6
+
+        if hasattr(self,"downgrade_only"):
+            return
+
+        # test upgrade altering row
+        self.db.post_init()
+
+        # This insert with text of expected column size should succeed
+        self.db.sql("insert into __words VALUES('%s',1)" % long_string)
+
+        # Verify it fails at one more than the expected column size
+        too_long_string = "a" * (self.db.indexer.maxlength + 6)
+        with self.assertRaises(MySQLdb.DataError) as ctx:
+            self.db.sql("insert into __words VALUES('%s',1)" % too_long_string)
+
+        self.assertEqual(self.db.database_schema['version'],
+                         self.db.current_db_version)
 
 @skip_mysql
 class mysqlROTest(mysqlOpener, ROTest, unittest.TestCase):
--- a/test/test_postgresql.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_postgresql.py	Thu Apr 21 16:54:17 2022 -0400
@@ -47,6 +47,16 @@
     if have_backend('postgresql'):
         module = get_backend('postgresql')
 
+    def setup_class(cls):
+        # nuke the db once for the class. Handles the case
+        # where an aborted test run (^C during setUp for example)
+        # leaves the database in an unusable, partly configured state.
+        try:
+            cls.nuke_database(cls)
+        except:
+            # ignore failure to nuke the database.
+            pass
+
     def setUp(self):
         pass
 
@@ -68,6 +78,67 @@
         DBTest.tearDown(self)
         postgresqlOpener.tearDown(self)
 
+    def testUpgrade_6_to_7(self):
+
+        # load the database
+        self.db.issue.create(title="flebble frooz")
+        self.db.commit()
+
+        if self.db.database_schema['version'] != 7:
+            # consider calling next testUpgrade script to roll back
+            # schema to version 7.
+            self.skipTest("This test only runs for database version 7")
+
+        # remove __fts table/index; shrink length of  __words._words
+        #  trying to insert a long word in __words._words should fail.
+        #  trying to select from __fts should fail
+        #  looking for the index should fail
+        # run post-init
+        #    tests should succeed.
+
+        self.db.sql("drop table __fts")  # also drops __fts_idx
+        self.db.sql("alter table __words ALTER column _word type varchar(10)")
+        self.db.commit()
+
+        self.db.database_schema['version'] = 6
+
+        long_string = "a" * (self.db.indexer.maxlength + 5)
+        with self.assertRaises(psycopg2.DataError) as ctx:
+            # DataError : value too long for type character varying(10)
+            self.db.sql("insert into __words VALUES('%s',1)" % long_string)
+
+        self.assertIn("varying(10)", ctx.exception.args[0])
+        self.db.rollback()  # clear cursor error so db.sql can be used again
+
+        with self.assertRaises(psycopg2.errors.UndefinedTable) as ctx:
+            self.db.sql("select * from _fts")
+        self.db.rollback()
+
+        self.assertFalse(self.db.sql_index_exists('__fts', '__fts_idx'))
+
+        if hasattr(self, "downgrade_only"):
+            return
+
+        # test upgrade path
+        self.db.post_init()
+
+        # This insert with text of expected column size should succeed
+        self.db.sql("insert into __words VALUES('%s',1)" % long_string)
+
+        # verify it fails at one more than the expected column size
+        too_long_string = "a" * (self.db.indexer.maxlength + 6)
+        with self.assertRaises(psycopg2.DataError) as ctx:
+            self.db.sql("insert into __words VALUES('%s',1)" % too_long_string)
+
+        # clean db handle
+        self.db.rollback()
+
+        self.assertTrue(self.db.sql_index_exists('__fts', '__fts_idx'))
+
+        self.db.sql("select * from __fts")
+
+        self.assertEqual(self.db.database_schema['version'],
+                         self.db.current_db_version)
 
 @skip_postgresql
 class postgresqlROTest(postgresqlOpener, ROTest, unittest.TestCase):
--- a/test/test_security.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_security.py	Thu Apr 21 16:54:17 2022 -0400
@@ -411,8 +411,15 @@
         self.assertEqual(has(uimu, 'issue', 'messages.recipients'), 1)
         self.assertEqual(has(uimu, 'issue', 'messages.recipients.username'), 1)
 
-    # roundup.password has its own built-in test, call it.
+    # roundup.password has its own built-in tests, call them.
     def test_password(self):
         roundup.password.test()
 
+        # pretend import of crypt failed
+        orig_crypt = roundup.password.crypt
+        roundup.password.crypt = None
+        with self.assertRaises(roundup.password.PasswordValueError) as ctx:
+            roundup.password.test_missing_crypt()
+        roundup.password.crypt = orig_crypt
+
 # vim: set filetype=python sts=4 sw=4 et si :
--- a/test/test_sqlite.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_sqlite.py	Thu Apr 21 16:54:17 2022 -0400
@@ -16,6 +16,8 @@
 # SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 
 import unittest, os, shutil, time
+import sqlite3 as sqlite
+
 from roundup.backends import get_backend, have_backend
 
 from .db_test_base import DBTest, ROTest, SchemaTest, ClassicInitTest, config
@@ -32,8 +34,43 @@
 
 
 class sqliteDBTest(sqliteOpener, DBTest, unittest.TestCase):
-    pass
+
+    def testUpgrade_6_to_7(self):
+
+        # load the database
+        self.db.issue.create(title="flebble frooz")
+        self.db.commit()
+
+        if self.db.database_schema['version'] != 7:
+            self.skipTest("This test only runs for database version 7")
+
+        self.db.database_schema['version'] = 6
+
+        # dropping _fts
+        #  select * from _fts
+        #    it should fail.
+        # run post-init
+        #    same select should succeed (with no rows returned)
 
+        self.db.sql("drop table __fts")
+
+        with self.assertRaises(sqlite.OperationalError) as ctx:
+            self.db.sql("select * from __fts")
+
+        self.assertIn("no such table: __fts", ctx.exception.args[0])
+
+        if hasattr(self, "downgrade_only"):
+            return
+
+        # test upgrade adding __fts table
+        self.db.post_init()
+
+        # select should now work.
+        self.db.sql("select * from __fts")
+
+        # we should be at the current db version
+        self.assertEqual(self.db.database_schema['version'],
+                         self.db.current_db_version)
 
 class sqliteROTest(sqliteOpener, ROTest, unittest.TestCase):
     pass
--- a/test/test_templating.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/test/test_templating.py	Thu Apr 21 16:54:17 2022 -0400
@@ -422,6 +422,7 @@
                     groups[g], s))
 
         #t('123.321.123.321', 'url')
+        t('https://example.com/demo/issue8#24MRV9BZYx:V:1B~sssssssssssssss~4~4', url="https://example.com/demo/issue8#24MRV9BZYx:V:1B~sssssssssssssss~4~4")
         t('http://localhost/', url='http://localhost/')
         t('http://roundup.net/', url='http://roundup.net/')
         t('http://richard@localhost/', url='http://richard@localhost/')
@@ -439,6 +440,7 @@
         t('r@a.com', email='r@a.com')
         t('i1', **{'class':'i', 'id':'1'})
         t('item123', **{'class':'item', 'id':'123'})
+        t('item 123', **{'class':'item', 'id':'123'})
         t('www.user:pass@host.net', email='pass@host.net')
         t('user:pass@www.host.net', url='user:pass@www.host.net')
         t('123.35', nothing=True)
@@ -448,6 +450,12 @@
         p = StringHTMLProperty(self.client, 'test', '1', None, 'test', '')
         def t(s): return p.hyper_re.sub(p._hyper_repl, s)
         ae = self.assertEqual
+        ae(t('issue5#msg10'), '<a href="issue5#msg10">issue5#msg10</a>')
+        ae(t('issue5'), '<a href="issue5">issue5</a>')
+        ae(t('issue2255'), 'issue2255')
+        ae(t('foo https://example.com/demo/issue8#24MRV9BZYx:V:1B~sssssssssssssss~4~4 bar'),
+           'foo <a href="https://example.com/demo/issue8#24MRV9BZYx:V:1B~sssssssssssssss~4~4" rel="nofollow noopener">'
+           'https://example.com/demo/issue8#24MRV9BZYx:V:1B~sssssssssssssss~4~4</a> bar')
         ae(t('item123123123123'), 'item123123123123')
         ae(t('http://roundup.net/'),
            '<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>')
@@ -478,9 +486,19 @@
             # trailing punctuation is not included
             ae(t('http://roundup.net/%c ' % c),
                '<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>%c ' % c)
+            # trailing punctuation is not included without trailing space
+            ae(t('http://roundup.net/%c' % c),
+               '<a href="http://roundup.net/" rel="nofollow noopener">http://roundup.net/</a>%c' % c)
             # but it's included if it's part of the URL
             ae(t('http://roundup.net/%c/' % c),
                '<a href="http://roundup.net/%c/" rel="nofollow noopener">http://roundup.net/%c/</a>' % (c, c))
+            # including with a non / terminated path
+            ae(t('http://roundup.net/test%c ' % c),
+               '<a href="http://roundup.net/test" rel="nofollow noopener">http://roundup.net/test</a>%c ' % c)
+            # but it's included if it's part of the URL path
+            ae(t('http://roundup.net/%ctest' % c),
+               '<a href="http://roundup.net/%ctest" rel="nofollow noopener">http://roundup.net/%ctest</a>' % (c, c))
+
 
     def test_input_html4(self):
         # boolean attributes are just the attribute name
--- a/website/issues/extensions/templating.py	Fri Oct 08 00:37:16 2021 -0400
+++ b/website/issues/extensions/templating.py	Thu Apr 21 16:54:17 2022 -0400
@@ -17,12 +17,18 @@
             if module == 'pyme':
                 from pyme import version
                 version="version %s"%version.versionstr
+            elif module == 'MySQLdb':
+                from MySQLdb import version_info
+                version="version %s"%".".join([str(v) for v in version_info])
             elif module == 'pychart':
                 from pychart import version
                 version="version %s"%version.version
             elif module == 'sqlite3':
                 from sqlite3 import version
                 version="version %s"%version
+            elif module == "whoosh":
+                from whoosh import versionstring
+                version="version %s"%versionstring()
             elif module == 'xapian':
                 from xapian import version_string
                 version="version %s"%version_string()
--- a/website/www/index.txt	Fri Oct 08 00:37:16 2021 -0400
+++ b/website/www/index.txt	Thu Apr 21 16:54:17 2022 -0400
@@ -1,15 +1,32 @@
 Roundup Issue Tracker
 =====================
 
+.. raw:: foo
+
+   meta::
+   :title: Roundup Issue Tracker
+   :description: A simple-to-use and -install issue-tracking system
+       with command-line, web, REST, XML-RPC and e-mail interfaces.
+       Adaptable to many uses cases. Allows you to customise the look
+       and feel and implement different workflows.
+   :og:type: website
+   :og:url: https://www.roundup-tracker.org/
+   :og:title: Roundup Issue Tracker
+   :og:description: A simple-to-use and -install issue-tracking system
+       with command-line, web, REST, XML-RPC and e-mail interfaces.
+       Adaptable to many uses cases. Allows you to customise the look
+       and feel and implement different workflows.
+   :og:image: https://www.roundup-tracker.org/_images/index_logged_out.png
+
 .. raw:: html
 
    <div class="release_info note">Download:
    <a href="https://pypi.org/project/roundup/">latest</a></div>
 
 Roundup is a simple-to-use and -install issue-tracking system with
-command-line, web and e-mail interfaces.  It is based on the winning
-design from Ka-Ping Yee in the Software Carpentry "Track" design
-competition.
+command-line, web, REST, XML-RPC and e-mail interfaces.  It is based
+on the winning design from Ka-Ping Yee in the Software Carpentry
+"Track" design competition.
 
 The current stable version of Roundup is 2.1.0. It is a bug fix
 and minor feature release for the major 2.0.0 release which

Roundup Issue Tracker: http://roundup-tracker.org/