From ee7dfa63166bfd01d3d7cf456f2dcb67484032ce Mon Sep 17 00:00:00 2001 From: Aleksey Date: Fri, 24 May 2024 09:13:51 +0000 Subject: [PATCH] init commit --- django_filter-24.2.dist-info/INSTALLER | 1 + django_filter-24.2.dist-info/LICENSE | 24 + django_filter-24.2.dist-info/METADATA | 150 +++ django_filter-24.2.dist-info/RECORD | 79 ++ django_filter-24.2.dist-info/REQUESTED | 0 django_filter-24.2.dist-info/WHEEL | 4 + django_filters/__init__.py | 39 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1296 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 700 bytes .../__pycache__/conf.cpython-312.pyc | Bin 0 -> 3847 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 254 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 736 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 16304 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 38072 bytes .../__pycache__/filterset.cpython-312.pyc | Bin 0 -> 20547 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 14258 bytes .../__pycache__/views.cpython-312.pyc | Bin 0 -> 5647 bytes .../__pycache__/widgets.cpython-312.pyc | Bin 0 -> 14758 bytes django_filters/compat.py | 25 + django_filters/conf.py | 102 +++ django_filters/constants.py | 4 + django_filters/exceptions.py | 8 + django_filters/fields.py | 324 +++++++ django_filters/filters.py | 852 ++++++++++++++++++ django_filters/filterset.py | 473 ++++++++++ .../locale/ar/LC_MESSAGES/django.mo | Bin 0 -> 2568 bytes .../locale/ar/LC_MESSAGES/django.po | 192 ++++ .../locale/be/LC_MESSAGES/django.mo | Bin 0 -> 2819 bytes .../locale/be/LC_MESSAGES/django.po | 191 ++++ .../locale/bg/LC_MESSAGES/django.mo | Bin 0 -> 2711 bytes .../locale/bg/LC_MESSAGES/django.po | 190 ++++ .../locale/cs/LC_MESSAGES/django.mo | Bin 0 -> 2368 bytes .../locale/cs/LC_MESSAGES/django.po | 190 ++++ .../locale/da/LC_MESSAGES/django.mo | Bin 0 -> 2166 bytes .../locale/da/LC_MESSAGES/django.po | 190 ++++ .../locale/de/LC_MESSAGES/django.mo | Bin 0 -> 2277 bytes .../locale/de/LC_MESSAGES/django.po | 193 ++++ .../locale/el/LC_MESSAGES/django.mo | Bin 0 -> 2836 bytes .../locale/el/LC_MESSAGES/django.po | 193 ++++ .../locale/es/LC_MESSAGES/django.mo | Bin 0 -> 2279 bytes .../locale/es/LC_MESSAGES/django.po | 195 ++++ .../locale/es_AR/LC_MESSAGES/django.mo | Bin 0 -> 703 bytes .../locale/es_AR/LC_MESSAGES/django.po | 201 +++++ .../locale/fa/LC_MESSAGES/django.mo | Bin 0 -> 2624 bytes .../locale/fa/LC_MESSAGES/django.po | 190 ++++ .../locale/fi/LC_MESSAGES/django.po | 191 ++++ .../locale/fr/LC_MESSAGES/django.mo | Bin 0 -> 2344 bytes .../locale/fr/LC_MESSAGES/django.po | 194 ++++ .../locale/it/LC_MESSAGES/django.mo | Bin 0 -> 2268 bytes .../locale/it/LC_MESSAGES/django.po | 194 ++++ .../locale/nl/LC_MESSAGES/django.mo | Bin 0 -> 2277 bytes .../locale/nl/LC_MESSAGES/django.po | 189 ++++ .../locale/pl/LC_MESSAGES/django.mo | Bin 0 -> 1859 bytes .../locale/pl/LC_MESSAGES/django.po | 199 ++++ .../locale/pt_BR/LC_MESSAGES/django.mo | Bin 0 -> 2263 bytes .../locale/pt_BR/LC_MESSAGES/django.po | 194 ++++ .../locale/ro/LC_MESSAGES/django.po | 192 ++++ .../locale/ru/LC_MESSAGES/django.mo | Bin 0 -> 2796 bytes .../locale/ru/LC_MESSAGES/django.po | 195 ++++ .../locale/sk/LC_MESSAGES/django.mo | Bin 0 -> 2394 bytes .../locale/sk/LC_MESSAGES/django.po | 196 ++++ .../locale/uk/LC_MESSAGES/django.mo | Bin 0 -> 2912 bytes .../locale/uk/LC_MESSAGES/django.po | 193 ++++ .../locale/zh_CN/LC_MESSAGES/django.mo | Bin 0 -> 852 bytes .../locale/zh_CN/LC_MESSAGES/django.po | 194 ++++ django_filters/rest_framework/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 314 bytes .../__pycache__/backends.cpython-312.pyc | Bin 0 -> 7407 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 883 bytes .../__pycache__/filterset.cpython-312.pyc | Bin 0 -> 1907 bytes django_filters/rest_framework/backends.py | 165 ++++ django_filters/rest_framework/filters.py | 13 + django_filters/rest_framework/filterset.py | 41 + .../rest_framework/crispy_form.html | 5 + .../django_filters/rest_framework/form.html | 6 + .../django_filters/widgets/multiwidget.html | 1 + django_filters/utils.py | 350 +++++++ django_filters/views.py | 129 +++ django_filters/widgets.py | 270 ++++++ 79 files changed, 7125 insertions(+) create mode 100644 django_filter-24.2.dist-info/INSTALLER create mode 100644 django_filter-24.2.dist-info/LICENSE create mode 100644 django_filter-24.2.dist-info/METADATA create mode 100644 django_filter-24.2.dist-info/RECORD create mode 100644 django_filter-24.2.dist-info/REQUESTED create mode 100644 django_filter-24.2.dist-info/WHEEL create mode 100644 django_filters/__init__.py create mode 100644 django_filters/__pycache__/__init__.cpython-312.pyc create mode 100644 django_filters/__pycache__/compat.cpython-312.pyc create mode 100644 django_filters/__pycache__/conf.cpython-312.pyc create mode 100644 django_filters/__pycache__/constants.cpython-312.pyc create mode 100644 django_filters/__pycache__/exceptions.cpython-312.pyc create mode 100644 django_filters/__pycache__/fields.cpython-312.pyc create mode 100644 django_filters/__pycache__/filters.cpython-312.pyc create mode 100644 django_filters/__pycache__/filterset.cpython-312.pyc create mode 100644 django_filters/__pycache__/utils.cpython-312.pyc create mode 100644 django_filters/__pycache__/views.cpython-312.pyc create mode 100644 django_filters/__pycache__/widgets.cpython-312.pyc create mode 100644 django_filters/compat.py create mode 100644 django_filters/conf.py create mode 100644 django_filters/constants.py create mode 100644 django_filters/exceptions.py create mode 100644 django_filters/fields.py create mode 100644 django_filters/filters.py create mode 100644 django_filters/filterset.py create mode 100644 django_filters/locale/ar/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/ar/LC_MESSAGES/django.po create mode 100644 django_filters/locale/be/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/be/LC_MESSAGES/django.po create mode 100644 django_filters/locale/bg/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/bg/LC_MESSAGES/django.po create mode 100644 django_filters/locale/cs/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/cs/LC_MESSAGES/django.po create mode 100644 django_filters/locale/da/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/da/LC_MESSAGES/django.po create mode 100644 django_filters/locale/de/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/de/LC_MESSAGES/django.po create mode 100644 django_filters/locale/el/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/el/LC_MESSAGES/django.po create mode 100644 django_filters/locale/es/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/es/LC_MESSAGES/django.po create mode 100644 django_filters/locale/es_AR/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/es_AR/LC_MESSAGES/django.po create mode 100644 django_filters/locale/fa/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/fa/LC_MESSAGES/django.po create mode 100644 django_filters/locale/fi/LC_MESSAGES/django.po create mode 100644 django_filters/locale/fr/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/fr/LC_MESSAGES/django.po create mode 100644 django_filters/locale/it/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/it/LC_MESSAGES/django.po create mode 100644 django_filters/locale/nl/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/nl/LC_MESSAGES/django.po create mode 100644 django_filters/locale/pl/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/pl/LC_MESSAGES/django.po create mode 100644 django_filters/locale/pt_BR/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/pt_BR/LC_MESSAGES/django.po create mode 100644 django_filters/locale/ro/LC_MESSAGES/django.po create mode 100644 django_filters/locale/ru/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/ru/LC_MESSAGES/django.po create mode 100644 django_filters/locale/sk/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/sk/LC_MESSAGES/django.po create mode 100644 django_filters/locale/uk/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/uk/LC_MESSAGES/django.po create mode 100644 django_filters/locale/zh_CN/LC_MESSAGES/django.mo create mode 100644 django_filters/locale/zh_CN/LC_MESSAGES/django.po create mode 100644 django_filters/rest_framework/__init__.py create mode 100644 django_filters/rest_framework/__pycache__/__init__.cpython-312.pyc create mode 100644 django_filters/rest_framework/__pycache__/backends.cpython-312.pyc create mode 100644 django_filters/rest_framework/__pycache__/filters.cpython-312.pyc create mode 100644 django_filters/rest_framework/__pycache__/filterset.cpython-312.pyc create mode 100644 django_filters/rest_framework/backends.py create mode 100644 django_filters/rest_framework/filters.py create mode 100644 django_filters/rest_framework/filterset.py create mode 100644 django_filters/templates/django_filters/rest_framework/crispy_form.html create mode 100644 django_filters/templates/django_filters/rest_framework/form.html create mode 100644 django_filters/templates/django_filters/widgets/multiwidget.html create mode 100644 django_filters/utils.py create mode 100644 django_filters/views.py create mode 100644 django_filters/widgets.py diff --git a/django_filter-24.2.dist-info/INSTALLER b/django_filter-24.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/django_filter-24.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/django_filter-24.2.dist-info/LICENSE b/django_filter-24.2.dist-info/LICENSE new file mode 100644 index 0000000..4b73093 --- /dev/null +++ b/django_filter-24.2.dist-info/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) Alex Gaynor and individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * The names of its contributors may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/django_filter-24.2.dist-info/METADATA b/django_filter-24.2.dist-info/METADATA new file mode 100644 index 0000000..074aa4c --- /dev/null +++ b/django_filter-24.2.dist-info/METADATA @@ -0,0 +1,150 @@ +Metadata-Version: 2.1 +Name: django-filter +Version: 24.2 +Summary: Django-filter is a reusable Django application for allowing users to filter querysets dynamically. +Author-email: Alex Gaynor +Maintainer-email: Carlton Gibson +Requires-Python: >=3.8 +Description-Content-Type: text/x-rst +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Framework :: Django +Classifier: Framework :: Django :: 4.2 +Classifier: Framework :: Django :: 5.0 +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Requires-Dist: Django>=4.2 +Project-URL: Bug Tracker, https://github.com/carltongibson/django-filter/issues +Project-URL: Changelog, https://github.com/carltongibson/django-filter/blob/main/CHANGES.rst +Project-URL: Documentation, https://django-filter.readthedocs.io/en/main/ +Project-URL: Homepage, https://github.com/carltongibson/django-filter/tree/main +Project-URL: Source Code, https://github.com/carltongibson/django-filter + +Django Filter +============= + +Django-filter is a reusable Django application allowing users to declaratively +add dynamic ``QuerySet`` filtering from URL parameters. + +Full documentation on `read the docs`_. + +.. image:: https://raw.githubusercontent.com/carltongibson/django-filter/python-coverage-comment-action-data/badge.svg + :target: https://github.com/carltongibson/django-filter/tree/python-coverage-comment-action-data + +.. image:: https://badge.fury.io/py/django-filter.svg + :target: http://badge.fury.io/py/django-filter + + +Versioning and stability policy +------------------------------- + +Django-Filter is a mature and stable package. It uses a two-part CalVer +versioning scheme, such as ``21.1``. The first number is the year. The second +is the release number within that year. + +On an on-going basis, Django-Filter aims to support all current Django +versions, the matching current Python versions, and the latest version of +Django REST Framework. + +Please see: + +* `Status of supported Python versions `_ +* `List of supported Django versions `_ + +Support for Python and Django versions will be dropped when they reach +end-of-life. Support for Python versions will be dropped when they reach +end-of-life, even when still supported by a current version of Django. + +Other breaking changes are rare. Where required, every effort will be made to +apply a "Year plus two" deprecation period. For example, a change initially +introduced in ``23.x`` would offer a fallback where feasible and finally be +removed in ``25.1``. Where fallbacks are not feasible, breaking changes without +deprecation will be called out in the release notes. + + +Installation +------------ + +Install using pip: + +.. code-block:: sh + + pip install django-filter + +Then add ``'django_filters'`` to your ``INSTALLED_APPS``. + +.. code-block:: python + + INSTALLED_APPS = [ + ... + 'django_filters', + ] + + +Usage +----- + +Django-filter can be used for generating interfaces similar to the Django +admin's ``list_filter`` interface. It has an API very similar to Django's +``ModelForms``. For example, if you had a Product model you could have a +filterset for it with the code: + +.. code-block:: python + + import django_filters + + class ProductFilter(django_filters.FilterSet): + class Meta: + model = Product + fields = ['name', 'price', 'manufacturer'] + + +And then in your view you could do: + +.. code-block:: python + + def product_list(request): + filter = ProductFilter(request.GET, queryset=Product.objects.all()) + return render(request, 'my_app/template.html', {'filter': filter}) + + +Usage with Django REST Framework +-------------------------------- + +Django-filter provides a custom ``FilterSet`` and filter backend for use with +Django REST Framework. + +To use this adjust your import to use +``django_filters.rest_framework.FilterSet``. + +.. code-block:: python + + from django_filters import rest_framework as filters + + class ProductFilter(filters.FilterSet): + class Meta: + model = Product + fields = ('category', 'in_stock') + + +For more details see the `DRF integration docs`_. + + +Support +------- + +If you need help you can start a `discussion`_. For commercial support, please +`contact Carlton Gibson via his website `_. + +.. _`discussion`: https://github.com/carltongibson/django-filter/discussions +.. _`read the docs`: https://django-filter.readthedocs.io/en/main/ +.. _`DRF integration docs`: https://django-filter.readthedocs.io/en/stable/guide/rest_framework.html + diff --git a/django_filter-24.2.dist-info/RECORD b/django_filter-24.2.dist-info/RECORD new file mode 100644 index 0000000..0cca409 --- /dev/null +++ b/django_filter-24.2.dist-info/RECORD @@ -0,0 +1,79 @@ +django_filter-24.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +django_filter-24.2.dist-info/LICENSE,sha256=4UQ8qx2nFmTo4lASXOByK3RcVWDurx7_w9HozSy9mAI,1487 +django_filter-24.2.dist-info/METADATA,sha256=hjINlT2OR3cAAhT_hdIFWfqdt6WMx08BPasyr3d-Go0,5120 +django_filter-24.2.dist-info/RECORD,, +django_filter-24.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +django_filter-24.2.dist-info/WHEEL,sha256=rSgq_JpHF9fHR1lx53qwg_1-2LypZE_qmcuXbVUq948,81 +django_filters/__init__.py,sha256=HWgLpY-Ohqbs5SXhmhxMWR9txYylyds8oxmBaTc3gXY,796 +django_filters/__pycache__/__init__.cpython-312.pyc,, +django_filters/__pycache__/compat.cpython-312.pyc,, +django_filters/__pycache__/conf.cpython-312.pyc,, +django_filters/__pycache__/constants.cpython-312.pyc,, +django_filters/__pycache__/exceptions.cpython-312.pyc,, +django_filters/__pycache__/fields.cpython-312.pyc,, +django_filters/__pycache__/filters.cpython-312.pyc,, +django_filters/__pycache__/filterset.cpython-312.pyc,, +django_filters/__pycache__/utils.cpython-312.pyc,, +django_filters/__pycache__/views.cpython-312.pyc,, +django_filters/__pycache__/widgets.cpython-312.pyc,, +django_filters/compat.py,sha256=eatCom2gnXt-HgpU9gyMKqh6Q5ok5RvxdBiL2dFZwas,545 +django_filters/conf.py,sha256=VIxhOioS9Z6qM8PfNaaMtK8A1XSGqvD8tUAH3tmMGkM,3049 +django_filters/constants.py,sha256=N36ZSZJKbcFJIh4DC4Oe7HvkKmYNyRhAHpaQiD5i6SM,63 +django_filters/exceptions.py,sha256=c8EYPU4mY93QAIVGpf7datTHvQt6nrxYJO1SutzFzf4,253 +django_filters/fields.py,sha256=F-iQW7OhtfO4BKe_Jm7bzBRUlcfOut8VxVm19-fGmtg,10373 +django_filters/filters.py,sha256=inMCUojSetasYLF6wBuUv7FGmjOJBQryaCmyo9JBzCU,25326 +django_filters/filterset.py,sha256=iCblMAcHJzl7Wrzv-Ija44t3FJDNoYl_lb81bQ4RnKQ,16239 +django_filters/locale/ar/LC_MESSAGES/django.mo,sha256=utzbP4BsdW91KwGgFwyvXVY1uNZ8otdcUDoZZpIZ9Pg,2568 +django_filters/locale/ar/LC_MESSAGES/django.po,sha256=P-SHUseAhEXgKNQDm2DWB4nFk5Nyh6DAXXSMmBEfx4g,3625 +django_filters/locale/be/LC_MESSAGES/django.mo,sha256=lbp-b9nTHDvBb8ozSkyHWGlmi4X3WyKaObT9GB2fe9E,2819 +django_filters/locale/be/LC_MESSAGES/django.po,sha256=gRsiOMvJ7K8tsa6rOLs2v5ROv5toyFtN6qnh1rppO1c,3696 +django_filters/locale/bg/LC_MESSAGES/django.mo,sha256=ZPmu82dqvj3yd3-J0KLK-hxfwETzqKmq0c-Anozn5Go,2711 +django_filters/locale/bg/LC_MESSAGES/django.po,sha256=zpGSdxLb1erXzUd3GdY6IfC4UlhrbEeNcNKjq3UkjeI,3740 +django_filters/locale/cs/LC_MESSAGES/django.mo,sha256=vZuyiklIF_I3qs9pdhb3OTT2d63aIttgtcHY1b9Gsps,2368 +django_filters/locale/cs/LC_MESSAGES/django.po,sha256=Su0bgXYM0-jA6hDrF_mPLxZSlw0j1waDapguCYnw-Gs,3242 +django_filters/locale/da/LC_MESSAGES/django.mo,sha256=gPy5CaNJWYbCPqeqb6XPr1uynW9FEn8zV_-85RMJaZc,2166 +django_filters/locale/da/LC_MESSAGES/django.po,sha256=mt_ypD4Mt0895YMZWN1bSwkqSI4tAKnPSLizrYD2h3g,3173 +django_filters/locale/de/LC_MESSAGES/django.mo,sha256=IvgqQ0BQ7AiJSmdcGpKWheuLrzrXqs-lbp4Bac2jOdI,2277 +django_filters/locale/de/LC_MESSAGES/django.po,sha256=QFubrkm9Vi0HmoS_5i_JJWGENMiw0MMfn8Kg_FzMYv8,3338 +django_filters/locale/el/LC_MESSAGES/django.mo,sha256=2--juTiXF9v6u95krY9VwZCv2cXoJai6CXi4RWpi39w,2836 +django_filters/locale/el/LC_MESSAGES/django.po,sha256=6tjIPpTNaiJueY3C0N2_vSc_7cY5XkTR2Zl9HWvH15c,3909 +django_filters/locale/es/LC_MESSAGES/django.mo,sha256=5KCl_uUwge5RuGStcyMSsVPD6AOunjNvjuE-32PqWis,2279 +django_filters/locale/es/LC_MESSAGES/django.po,sha256=y-fdqEXzSqbErT58yZYAsAfPdqT0gKShHJZClE3IScc,3426 +django_filters/locale/es_AR/LC_MESSAGES/django.mo,sha256=OCKAVbT3ct5gf2_t5XsKryjlkIQDYZjC67Oz0j-YE6s,703 +django_filters/locale/es_AR/LC_MESSAGES/django.po,sha256=GKRqcNqmulrygz9VxkDRyGS_uG2K0QNT2gyILEcU9BM,3035 +django_filters/locale/fa/LC_MESSAGES/django.mo,sha256=HfEWFF_2l2ypvCJFCzbRf_CKgXlVyzvtVM0sZAl_KQU,2624 +django_filters/locale/fa/LC_MESSAGES/django.po,sha256=n1vb3fQKigB-rUa6oTFJ2Tba7c5qzKRwgHuQn0zJIuM,3623 +django_filters/locale/fi/LC_MESSAGES/django.po,sha256=Odsfeswbdf9hnwZIl24JE36MwOKnnE2yyvcaVzCOvPw,3433 +django_filters/locale/fr/LC_MESSAGES/django.mo,sha256=c87Ugu3u0juDMskRegFA76SkfF5TMi-fexzHb8uWw9w,2344 +django_filters/locale/fr/LC_MESSAGES/django.po,sha256=eF5fMIXDe98C3KMzUOkv7BppBg0YkvuhyLUlylyKnY8,3520 +django_filters/locale/it/LC_MESSAGES/django.mo,sha256=TKIdnZSuYtyCpnl8X9jDyKFuIX6G69CmCvVaWpcuPXM,2268 +django_filters/locale/it/LC_MESSAGES/django.po,sha256=5k7t_TvofiAmV5UlmpAH0t4d-ce7bySWFih0KIxkP_o,3380 +django_filters/locale/nl/LC_MESSAGES/django.mo,sha256=TdtnxLBMuoMY1c0NxZwbGQX3xl4cI7xNP6iBQXpmm6I,2277 +django_filters/locale/nl/LC_MESSAGES/django.po,sha256=ikeFeWaz2_CmWNzNwDHkm-m0Nkuksq9qgQ_oqH_SEeI,3287 +django_filters/locale/pl/LC_MESSAGES/django.mo,sha256=-9taafe4N3mKLdZ4fEXkrj-azO-L4F0fGoxnDgTBuwU,1859 +django_filters/locale/pl/LC_MESSAGES/django.po,sha256=kIM9yYIScAMrQ_W-Pt9DjNPKzeHxBtfOsRgovEBoroU,3720 +django_filters/locale/pt_BR/LC_MESSAGES/django.mo,sha256=GLakV-03XUsCNKaofuG2fGCBIRGVYEMJiC-kD1UX4D0,2263 +django_filters/locale/pt_BR/LC_MESSAGES/django.po,sha256=Qfc9NufXTeQrBLAxbnDZCeRl9TimgQPXTKHnEEiBcdQ,3434 +django_filters/locale/ro/LC_MESSAGES/django.po,sha256=cCCKgqNv1deUxPdV2lRwniApgjPCA9Ft7QYm0rbmJdw,3478 +django_filters/locale/ru/LC_MESSAGES/django.mo,sha256=1KrtkfLhq0BiDskKFffF5i53pM7Tp-bwsbPDe9F4Co0,2796 +django_filters/locale/ru/LC_MESSAGES/django.po,sha256=t6hfrDsO95WwvfKuovZyAmTXz8LIuLULTGmXvfZ6PIQ,3863 +django_filters/locale/sk/LC_MESSAGES/django.mo,sha256=em13cqJIPA3JLTp6JXPXuNNeDqJ7uaEuxxqtOvl9PLk,2394 +django_filters/locale/sk/LC_MESSAGES/django.po,sha256=jg7V3CvkNYjJDMuu9GmfeSj-cC92ja58WdugKsc8GaY,3582 +django_filters/locale/uk/LC_MESSAGES/django.mo,sha256=zgC01vyDPPS81GiD3C4WeQxtCt4_ift_pU-j_2l_LrU,2912 +django_filters/locale/uk/LC_MESSAGES/django.po,sha256=LdEFmgfqczUfYUUdHHbv1SE-ljZ6oqEherQa39mZiwU,3919 +django_filters/locale/zh_CN/LC_MESSAGES/django.mo,sha256=2aSG7Whwpj7iRY_7QcTV-ReuCm8JKsV-ktlRaAbYC0U,852 +django_filters/locale/zh_CN/LC_MESSAGES/django.po,sha256=rogASVeUU81FcYxGClnyXOAhXJc-wBl2AQHYkWUg85E,3354 +django_filters/rest_framework/__init__.py,sha256=HpNAGIdsBRJSkyM1QmqyOTb7I9VVwoMTbexbD21X6vE,113 +django_filters/rest_framework/__pycache__/__init__.cpython-312.pyc,, +django_filters/rest_framework/__pycache__/backends.cpython-312.pyc,, +django_filters/rest_framework/__pycache__/filters.cpython-312.pyc,, +django_filters/rest_framework/__pycache__/filterset.cpython-312.pyc,, +django_filters/rest_framework/backends.py,sha256=2kVwpeH7SRfyO0rQhH9Wq8xY30c3hxuCT2IvVU3ETRc,5744 +django_filters/rest_framework/filters.py,sha256=mh0XhgwhE95HXVOTE3SetP2uCnHjaDmutf3GdThy1l0,312 +django_filters/rest_framework/filterset.py,sha256=3kbngqrt8vg0ckVEXSTeuNhvZbqsk648xS7qGooouxU,1174 +django_filters/templates/django_filters/rest_framework/crispy_form.html,sha256=_Mg40d_4sWAuy7_Mzf1HRACbRgeheu0pGXy2UKpzd3s,108 +django_filters/templates/django_filters/rest_framework/form.html,sha256=KoVGtezI-pWnC18jpCKy3vufR23QLpXXooCgmEFXjAA,211 +django_filters/templates/django_filters/widgets/multiwidget.html,sha256=W0RT7BL9-sF-hCA_Ut4MfWaDwE8Z32syJs3anyurceg,118 +django_filters/utils.py,sha256=ekqKtbEetmY7e3c6FK1fjbLwbmqy2UuYd_faswZW-Tg,11262 +django_filters/views.py,sha256=dZ9uDeCHG7ee_pk1xgchbQp21G9acv84ELBHNBwFs3U,4034 +django_filters/widgets.py,sha256=5DkHm5xcVzzkDO0y6nykx8TqrNCI7Q9V8Ql37yhKRRc,9251 diff --git a/django_filter-24.2.dist-info/REQUESTED b/django_filter-24.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/django_filter-24.2.dist-info/WHEEL b/django_filter-24.2.dist-info/WHEEL new file mode 100644 index 0000000..db4a255 --- /dev/null +++ b/django_filter-24.2.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.8.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/django_filters/__init__.py b/django_filters/__init__.py new file mode 100644 index 0000000..ca1f82d --- /dev/null +++ b/django_filters/__init__.py @@ -0,0 +1,39 @@ +# flake8: noqa +from importlib import util as importlib_util + +from .filters import * +from .filterset import FilterSet + +# We make the `rest_framework` module available without an additional import. +# If DRF is not installed, no-op. +if importlib_util.find_spec("rest_framework"): + from . import rest_framework +del importlib_util + +__version__ = "24.2" + + +def parse_version(version): + """ + '0.1.2.dev1' -> (0, 1, 2, 'dev1') + '0.1.2' -> (0, 1, 2) + """ + v = version.split(".") + ret = [] + for p in v: + if p.isdigit(): + ret.append(int(p)) + else: + ret.append(p) + return tuple(ret) + + +VERSION = parse_version(__version__) + + + +assert VERSION < (25,0), "Remove deprecated code" + + +class RemovedInDjangoFilter25Warning(DeprecationWarning): + pass diff --git a/django_filters/__pycache__/__init__.cpython-312.pyc b/django_filters/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ebe5a308a65b3027aa397840774eb2097f05d083 GIT binary patch literal 1296 zcmZuw&2Jk;6o0e3_IlTAxAY_ZNEGdX5*9h$+JI02MIZvG5u~V*ie!WaJw zwNWBRvQQ306eSW!>5(gn_%FC|2?T^SQl(0TLvEodmz`SD;`#|y= zKrCwQ3dT}uh1G&nJdmb?xYmt5|3Drn9Q2Y<#(SP0Q?^87USu?i@iMEo=@%Wg;vl9A z;F?x_rCe={NyoP)c|mHDO)pqj~sr4q#pFtF1A)1exgc z8f>z!w9@jP0>qNcNcw7;Ih_&QFaLkk307d<(jYdTWl_@TC2*9rdD9j$bG=+CSIdO< zDl_)%oc-eUl3gj;)sj6kT60dJ{sTxhj#1gk@Jtl?Ud(kbB3@G%*?Jh#fN<3dVxEb+ zp-&x+>pjXMuM=?8<0=#7M`5H1a+1dJ2kzZYo4VbIGB*~l;`V6JbA9h~H(ZVHc7m77 zm8u(gF`W(Tjg@+nMlNa9gJuUWkDfDfG4=v4#<(1=@1 z1mo;hVY9H^*w0-Zygf9n!8^l3@d;>|t6!mE-rBmcdE@>YL+i}e!sfzv(Sypjz2B|r zM~T0E@0$+~4FP>>g7w_?`LAE!(=Hx~%%Z9XSH#3br^4FAZQAbis7+|dXrmreVmCU3 zHY6~Ww2O}9KiL5aHAJAMtRhF@(@8wJ8O)C^nzU{8)sO2e@Pg)|qw*Zaf#_X~xruSR zL%P1SEsXDV>wdEH1F(xCH#;xYewPLUg4JM6Gnl%C0^<;7<{ zmVb%sG~_Qo$nTra4|D;~o!OrFRll?cmAxyKeWCSBPqPRad)Hq32gE#L F@GlP{EWH2# literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/compat.cpython-312.pyc b/django_filters/__pycache__/compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..36c4acd2f71abf39b234bab21a6f206c954b74b5 GIT binary patch literal 700 zcmZuuJ#W)c6usBaiSt2&Xw)QBtpsW$lz~`*hzUiiL_n>g5Gf4AOB5U@afxH=JvVJO z6frO`uplJF#(>xu7~vPN6c!>ECMGtkSx~z0p6d*tUg=(+d(QKD$MTnzl?3p*uQqyD zC4gUIS(Y4v`ILiK(1k7z!9ooY;$oAAk|uS@Q_$pak7$t)MYZTe+5&^*fku#@)ua|Y z&mO=bX~6;hqeQr}ajp_=!9-dr1^KrKR6sAr4A(VBeOA}Qh{1#B2f}-Piw~X`-GCNj zPiX(u7!Hv}5!~f>LK6y7-MgSulR1-i&!!eD5GpLa)K0zmV7peU-f3?)8ciDE(7T`ABsp?!X@1ES7Gl%yff2)~36H%q&=*U-e90hZpiScqy0RwUQ@qF;CtpCGr7F MP=+C#~W~WSf$O$dqcyt|K7XuDEMzr6sA% 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 HTXX9#oXoq{ literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/fields.cpython-312.pyc b/django_filters/__pycache__/fields.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bdceb97dddf28ebf313aaebe943b20d8d10afe61 GIT binary patch literal 16304 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 OxvCQm>p#};$p0^VWB$?r literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/filters.cpython-312.pyc b/django_filters/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..313b82b79a4535fd43eadac836d640264344e6be GIT binary patch literal 38072 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%0DVU^c+E#;lZoFU>Vq<6gQuE+^Q7ZdMYhg zmYkH>ncpV^d3gKeB@g>4c)1AJ7XNtf{k6|cpO}$v?E5f~s@Zj~ z`uLph1P<0dg-`6H<+a_paJ~l63GDB@Or<(epM%I~uCGI@&vDs>i?t5ge?iKc`=a&9 zh_zP3by3c&8oN+q9(Ej8!lMrhJ_B!%!)S&3TE5l_q`2%JcjLo|G=ikO%{3h7xIe zGBN@Mt|N$38A@Fm#mbUc-q`X3I=?66uqRP$+CeKIZO4H`oFvM;-LWHJ`zX>RYjR*a zi)dX<-^?imRsJN-X9fx;dpcU41+9R%GXW>FTS~``$ft@T7gt zcX-x)_|v6w)c5I<8yP-@qO$*p94|&MzPDjdqw6Q$jeFW$f9CV=S?_8qw3JNpOni+d zhDDJ~RIu2Qg_494R2n;Lg&-2nspR}A(GA`3uoSY=>3+0Xs#rC~T@PbFC(ZEO)*rYjQ~P{&knfc|;bXMk+IiKjR_vP7i-}F{6r2%0sk!!;}lu zg8H3d7B1?GxIb^q39x$=`I0~6eUOC#^bK3^V1gUx!ztq3j`PzoD08FS|HvIrvT zFk`C{cnDj8frd{!neQjRg1N!|M$0Ab6Qx2wR(w-DYp(JvjRbEP43d^5D-Z2VO;DfnAhp}NU5Ls5L7u6H#Htn~ckrsBP2k0FJQju7Y+9RQDeIQW#rlIR zg^mcIn3fU1sQ(J}C*5MjC@sl0jch&_KtTa*;VL5fB%RBX_#DE-mae3|wXLNuS>1bS zM0{INt0a@Qxc?d2AfW#o`Sz1T?Na{{Id73eM#&hn z>%6yHU;iRyH{!GTZZ0rcDw?C=0x>FEF{$ytKn9kj;Op*Nr?yVGLC|^2CJ)fJKks{* z7D}t>Ln*V~1|sxUEgye5@OUqgI+rlvXP4e$0DY=DaP4)nA+Eyv=$Q zc@CX~r8V ze%qby#|5&p{;>;RZN@h5DtctAbymf{9oR+W91kNV|j{hxh_>g{IVjLxpe`2p(a4HLem0Py4mV z(CIEdc8aS+4yCJdgYhv8@#Vre-wH^VXbFU-$Y>&hs=bu6T#MkKE^1;D24mUuPr5QY z4o3FkxR8pzs)PYlqAlp7@WW?>sbc!J9)B${E+iN%0i>0#mXcFO4&A_1>3W0sOa^#s zT-YP0iX6yUB=LcqTJn(wecCA+TSoy31>j3MycdX%bGK0VT5`ZRiVv&uS4{a+IsAbc z{(uXADTP12!QZyvk4UiXX|_$wR)N`CDVus^TYGHbj<4YJ<#fIw&eyd0t~B2%RU4?v zMsk|SAt2&oR3@4jxN@KlhRrZ-_-y%3m8|9BzZCzkaABfdmVY5N{z7W{g|y}uQuTk5 zDt{quX8*=tNbSFnntvf}{ZCRA(tKhol5L+zy7O1;TO-L^9y{thwkvs`^vJKua>*l! z+~wUUxnZ&bm#*Z7Ww$K1P0|G{xoz29ByXMEx{Tagmm3f;?b5={>5s{B?KBe6?{df{ z%Nu8v&6I8?c|pzeC@K^BR5VLElc=WuCY$@iF>15`$&Sbd`@=C?X#5~x1(SX z<@RO2EU!Zqvs({QY3r8VC2}>j5uCtsa8vMjOpljHVIx#F<|hw;b% E3umXqJOBUy literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/filterset.cpython-312.pyc b/django_filters/__pycache__/filterset.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9addc142da71705fbe4e3e315bfc021b8049fda GIT binary patch literal 20547 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 literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/views.cpython-312.pyc b/django_filters/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1fa5d1dffed728fa86e24e4962309b0d4e55f9f4 GIT binary patch literal 5647 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 Mt@{RqLtHuk1)V4YH2?qr literal 0 HcmV?d00001 diff --git a/django_filters/__pycache__/widgets.cpython-312.pyc b/django_filters/__pycache__/widgets.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..79d5b6e173a7d22b601aa542e2892cd3aea6f827 GIT binary patch literal 14758 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. + + ex:: + + BaseCSVFilter._field_class_name(DateTimeField, 'year__in') + + returns 'DateTimeYearInField' + + """ + # DateTimeField => DateTime + type_name = field_class.__name__ + if type_name.endswith("Field"): + type_name = type_name[:-5] + + # year__in => YearIn + parts = lookup_expr.split(LOOKUP_SEP) + expression_name = "".join(p.capitalize() for p in parts) + + # DateTimeYearInField + return str("%s%sField" % (type_name, expression_name)) + + +class BaseInFilter(BaseCSVFilter): + def __init__(self, *args, **kwargs): + kwargs.setdefault("lookup_expr", "in") + super().__init__(*args, **kwargs) + + +class BaseRangeFilter(BaseCSVFilter): + base_field_class = BaseRangeField + + def __init__(self, *args, **kwargs): + kwargs.setdefault("lookup_expr", "range") + super().__init__(*args, **kwargs) + + +class LookupChoiceFilter(Filter): + """ + A combined filter that allows users to select the lookup expression from a dropdown. + + * ``lookup_choices`` is an optional argument that accepts multiple input + formats, and is ultimately normalized as the choices used in the lookup + dropdown. See ``.get_lookup_choices()`` for more information. + + * ``field_class`` is an optional argument that allows you to set the inner + form field class used to validate the value. Default: ``forms.CharField`` + + ex:: + + price = django_filters.LookupChoiceFilter( + field_class=forms.DecimalField, + lookup_choices=[ + ('exact', 'Equals'), + ('gt', 'Greater than'), + ('lt', 'Less than'), + ] + ) + + """ + + field_class = forms.CharField + outer_class = LookupChoiceField + + def __init__( + self, field_name=None, lookup_choices=None, field_class=None, **kwargs + ): + self.empty_label = kwargs.pop("empty_label", settings.EMPTY_CHOICE_LABEL) + + super(LookupChoiceFilter, self).__init__(field_name=field_name, **kwargs) + + self.lookup_choices = lookup_choices + if field_class is not None: + self.field_class = field_class + + @classmethod + def normalize_lookup(cls, lookup): + """ + Normalize the lookup into a tuple of ``(lookup expression, display value)`` + + If the ``lookup`` is already a tuple, the tuple is not altered. + If the ``lookup`` is a string, a tuple is returned with the lookup + expression used as the basis for the display value. + + ex:: + + >>> LookupChoiceFilter.normalize_lookup(('exact', 'Equals')) + ('exact', 'Equals') + + >>> LookupChoiceFilter.normalize_lookup('has_key') + ('has_key', 'Has key') + + """ + if isinstance(lookup, str): + return (lookup, pretty_name(lookup)) + return (lookup[0], lookup[1]) + + def get_lookup_choices(self): + """ + Get the lookup choices in a format suitable for ``django.forms.ChoiceField``. + If the filter is initialized with ``lookup_choices``, this value is normalized + and passed to the underlying ``LookupChoiceField``. If no choices are provided, + they are generated from the corresponding model field's registered lookups. + """ + lookups = self.lookup_choices + if lookups is None: + field = get_model_field(self.model, self.field_name) + lookups = field.get_lookups() + + return [self.normalize_lookup(lookup) for lookup in lookups] + + @property + def field(self): + if not hasattr(self, "_field"): + inner_field = super().field + lookups = self.get_lookup_choices() + + self._field = self.outer_class( + inner_field, + lookups, + label=self.label, + empty_label=self.empty_label, + required=self.extra["required"], + ) + + return self._field + + def filter(self, qs, lookup): + if not lookup: + return super().filter(qs, None) + + self.lookup_expr = lookup.lookup_expr + return super().filter(qs, lookup.value) + + +class OrderingFilter(BaseCSVFilter, ChoiceFilter): + """ + Enable queryset ordering. As an extension of ``ChoiceFilter`` it accepts + two additional arguments that are used to build the ordering choices. + + * ``fields`` is a mapping of {model field name: parameter name}. The + parameter names are exposed in the choices and mask/alias the field + names used in the ``order_by()`` call. Similar to field ``choices``, + ``fields`` accepts the 'list of two-tuples' syntax that retains order. + ``fields`` may also just be an iterable of strings. In this case, the + field names simply double as the exposed parameter names. + + * ``field_labels`` is an optional argument that allows you to customize + the display label for the corresponding parameter. It accepts a mapping + of {field name: human readable label}. Keep in mind that the key is the + field name, and not the exposed parameter name. + + Additionally, you can just provide your own ``choices`` if you require + explicit control over the exposed options. For example, when you might + want to disable descending sort options. + + This filter is also CSV-based, and accepts multiple ordering params. The + default select widget does not enable the use of this, but it is useful + for APIs. + + """ + + descending_fmt = _("%s (descending)") + + def __init__(self, *args, **kwargs): + """ + ``fields`` may be either a mapping or an iterable. + ``field_labels`` must be a map of field names to display labels + """ + fields = kwargs.pop("fields", {}) + fields = self.normalize_fields(fields) + field_labels = kwargs.pop("field_labels", {}) + + self.param_map = {v: k for k, v in fields.items()} + + if "choices" not in kwargs: + kwargs["choices"] = self.build_choices(fields, field_labels) + + kwargs.setdefault("label", _("Ordering")) + kwargs.setdefault("help_text", "") + kwargs.setdefault("null_label", None) + super().__init__(*args, **kwargs) + + def get_ordering_value(self, param): + descending = param.startswith("-") + param = param[1:] if descending else param + field_name = self.param_map.get(param, param) + + return "-%s" % field_name if descending else field_name + + def filter(self, qs, value): + if value in EMPTY_VALUES: + return qs + + ordering = [ + self.get_ordering_value(param) + for param in value + if param not in EMPTY_VALUES + ] + return qs.order_by(*ordering) + + @classmethod + def normalize_fields(cls, fields): + """ + Normalize the fields into an ordered map of {field name: param name} + """ + # fields is a mapping, copy into new OrderedDict + if isinstance(fields, dict): + return OrderedDict(fields) + + # convert iterable of values => iterable of pairs (field name, param name) + assert isinstance( + fields, Iterable + ), "'fields' must be an iterable (e.g., a list, tuple, or mapping)." + + # fields is an iterable of field names + assert all( + isinstance(field, str) + or isinstance(field, Iterable) + and len(field) == 2 # may need to be wrapped in parens + for field in fields + ), "'fields' must contain strings or (field name, param name) pairs." + + return OrderedDict([(f, f) if isinstance(f, str) else f for f in fields]) + + def build_choices(self, fields, labels): + ascending = [ + (param, labels.get(field, _(pretty_name(param)))) + for field, param in fields.items() + ] + descending = [ + ("-%s" % param, labels.get("-%s" % param, self.descending_fmt % label)) + for param, label in ascending + ] + + # interleave the ascending and descending choices + return [val for pair in zip(ascending, descending) for val in pair] + + +class FilterMethod: + """ + This helper is used to override Filter.filter() when a 'method' argument + is passed. It proxies the call to the actual method on the filter's parent. + """ + + def __init__(self, filter_instance): + self.f = filter_instance + + def __call__(self, qs, value): + if value in EMPTY_VALUES: + return qs + + return self.method(qs, self.f.field_name, value) + + @property + def method(self): + """ + Resolve the method on the parent filterset. + """ + instance = self.f + + # noop if 'method' is a function + if callable(instance.method): + return instance.method + + # otherwise, method is the name of a method on the parent FilterSet. + assert hasattr( + instance, "parent" + ), "Filter '%s' must have a parent FilterSet to find '.%s()'" % ( + instance.field_name, + instance.method, + ) + + parent = instance.parent + method = getattr(parent, instance.method, None) + + assert callable( + method + ), "Expected parent FilterSet '%s.%s' to have a '.%s()' method." % ( + parent.__class__.__module__, + parent.__class__.__name__, + instance.method, + ) + + return method diff --git a/django_filters/filterset.py b/django_filters/filterset.py new file mode 100644 index 0000000..6c7019e --- /dev/null +++ b/django_filters/filterset.py @@ -0,0 +1,473 @@ +import copy +from collections import OrderedDict + +from django import forms +from django.db import models +from django.db.models.constants import LOOKUP_SEP +from django.db.models.fields.related import ManyToManyRel, ManyToOneRel, OneToOneRel +from django.utils.datastructures import MultiValueDict + +from .conf import settings +from .constants import ALL_FIELDS +from .filters import ( + BaseInFilter, + BaseRangeFilter, + BooleanFilter, + CharFilter, + ChoiceFilter, + DateFilter, + DateTimeFilter, + DurationFilter, + Filter, + ModelChoiceFilter, + ModelMultipleChoiceFilter, + NumberFilter, + TimeFilter, + UUIDFilter, +) +from .utils import get_all_model_fields, get_model_field, resolve_field, try_dbfield + + +def remote_queryset(field): + """ + Get the queryset for the other side of a relationship. This works + for both `RelatedField`s and `ForeignObjectRel`s. + """ + model = field.related_model + + # Reverse relationships do not have choice limits + if not hasattr(field, "get_limit_choices_to"): + return model._default_manager.all() + + limit_choices_to = field.get_limit_choices_to() + return model._default_manager.complex_filter(limit_choices_to) + + +class FilterSetOptions: + def __init__(self, options=None): + self.model = getattr(options, "model", None) + self.fields = getattr(options, "fields", None) + self.exclude = getattr(options, "exclude", None) + + self.filter_overrides = getattr(options, "filter_overrides", {}) + + self.form = getattr(options, "form", forms.Form) + + +class FilterSetMetaclass(type): + def __new__(cls, name, bases, attrs): + attrs["declared_filters"] = cls.get_declared_filters(bases, attrs) + + new_class = super().__new__(cls, name, bases, attrs) + new_class._meta = FilterSetOptions(getattr(new_class, "Meta", None)) + new_class.base_filters = new_class.get_filters() + + return new_class + + @classmethod + def get_declared_filters(cls, bases, attrs): + filters = [ + (filter_name, attrs.pop(filter_name)) + for filter_name, obj in list(attrs.items()) + if isinstance(obj, Filter) + ] + + # Default the `filter.field_name` to the attribute name on the filterset + for filter_name, f in filters: + if getattr(f, "field_name", None) is None: + f.field_name = filter_name + + filters.sort(key=lambda x: x[1].creation_counter) + + # Ensures a base class field doesn't override cls attrs, and maintains + # field precedence when inheriting multiple parents. e.g. if there is a + # class C(A, B), and A and B both define 'field', use 'field' from A. + known = set(attrs) + + def visit(name): + known.add(name) + return name + + base_filters = [ + (visit(name), f) + for base in bases + if hasattr(base, "declared_filters") + for name, f in base.declared_filters.items() + if name not in known + ] + + return OrderedDict(base_filters + filters) + + +FILTER_FOR_DBFIELD_DEFAULTS = { + models.AutoField: {"filter_class": NumberFilter}, + models.CharField: {"filter_class": CharFilter}, + models.TextField: {"filter_class": CharFilter}, + models.BooleanField: {"filter_class": BooleanFilter}, + models.DateField: {"filter_class": DateFilter}, + models.DateTimeField: {"filter_class": DateTimeFilter}, + models.TimeField: {"filter_class": TimeFilter}, + models.DurationField: {"filter_class": DurationFilter}, + models.DecimalField: {"filter_class": NumberFilter}, + models.SmallIntegerField: {"filter_class": NumberFilter}, + models.IntegerField: {"filter_class": NumberFilter}, + models.PositiveIntegerField: {"filter_class": NumberFilter}, + models.PositiveSmallIntegerField: {"filter_class": NumberFilter}, + models.FloatField: {"filter_class": NumberFilter}, + models.NullBooleanField: {"filter_class": BooleanFilter}, + models.SlugField: {"filter_class": CharFilter}, + models.EmailField: {"filter_class": CharFilter}, + models.FilePathField: {"filter_class": CharFilter}, + models.URLField: {"filter_class": CharFilter}, + models.GenericIPAddressField: {"filter_class": CharFilter}, + models.CommaSeparatedIntegerField: {"filter_class": CharFilter}, + models.UUIDField: {"filter_class": UUIDFilter}, + # Forward relationships + models.OneToOneField: { + "filter_class": ModelChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + "to_field_name": f.remote_field.field_name, + "null_label": settings.NULL_CHOICE_LABEL if f.null else None, + }, + }, + models.ForeignKey: { + "filter_class": ModelChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + "to_field_name": f.remote_field.field_name, + "null_label": settings.NULL_CHOICE_LABEL if f.null else None, + }, + }, + models.ManyToManyField: { + "filter_class": ModelMultipleChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + }, + }, + # Reverse relationships + OneToOneRel: { + "filter_class": ModelChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + "null_label": settings.NULL_CHOICE_LABEL if f.null else None, + }, + }, + ManyToOneRel: { + "filter_class": ModelMultipleChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + }, + }, + ManyToManyRel: { + "filter_class": ModelMultipleChoiceFilter, + "extra": lambda f: { + "queryset": remote_queryset(f), + }, + }, +} + + +class BaseFilterSet: + FILTER_DEFAULTS = FILTER_FOR_DBFIELD_DEFAULTS + + def __init__(self, data=None, queryset=None, *, request=None, prefix=None): + if queryset is None: + queryset = self._meta.model._default_manager.all() + model = queryset.model + + self.is_bound = data is not None + self.data = data or MultiValueDict() + self.queryset = queryset + self.request = request + self.form_prefix = prefix + + self.filters = copy.deepcopy(self.base_filters) + + # propagate the model and filterset to the filters + for filter_ in self.filters.values(): + filter_.model = model + filter_.parent = self + + def is_valid(self): + """ + Return True if the underlying form has no errors, or False otherwise. + """ + return self.is_bound and self.form.is_valid() + + @property + def errors(self): + """ + Return an ErrorDict for the data provided for the underlying form. + """ + return self.form.errors + + def filter_queryset(self, queryset): + """ + Filter the queryset with the underlying form's `cleaned_data`. You must + call `is_valid()` or `errors` before calling this method. + + This method should be overridden if additional filtering needs to be + applied to the queryset before it is cached. + """ + for name, value in self.form.cleaned_data.items(): + queryset = self.filters[name].filter(queryset, value) + assert isinstance( + queryset, models.QuerySet + ), "Expected '%s.%s' to return a QuerySet, but got a %s instead." % ( + type(self).__name__, + name, + type(queryset).__name__, + ) + return queryset + + @property + def qs(self): + if not hasattr(self, "_qs"): + qs = self.queryset.all() + if self.is_bound: + # ensure form validation before filtering + self.errors + qs = self.filter_queryset(qs) + self._qs = qs + return self._qs + + def get_form_class(self): + """ + Returns a django Form suitable of validating the filterset data. + + This method should be overridden if the form class needs to be + customized relative to the filterset instance. + """ + fields = OrderedDict( + [(name, filter_.field) for name, filter_ in self.filters.items()] + ) + + return type(str("%sForm" % self.__class__.__name__), (self._meta.form,), fields) + + @property + def form(self): + if not hasattr(self, "_form"): + Form = self.get_form_class() + if self.is_bound: + self._form = Form(self.data, prefix=self.form_prefix) + else: + self._form = Form(prefix=self.form_prefix) + return self._form + + @classmethod + def get_fields(cls): + """ + Resolve the 'fields' argument that should be used for generating filters on the + filterset. This is 'Meta.fields' sans the fields in 'Meta.exclude'. + """ + model = cls._meta.model + fields = cls._meta.fields + exclude = cls._meta.exclude + + assert not (fields is None and exclude is None), ( + "Setting 'Meta.model' without either 'Meta.fields' or 'Meta.exclude' " + "has been deprecated since 0.15.0 and is now disallowed. Add an explicit " + "'Meta.fields' or 'Meta.exclude' to the %s class." % cls.__name__ + ) + + # Setting exclude with no fields implies all other fields. + if exclude is not None and fields is None: + fields = ALL_FIELDS + + # Resolve ALL_FIELDS into all fields for the filterset's model. + if fields == ALL_FIELDS: + fields = get_all_model_fields(model) + + # Remove excluded fields + exclude = exclude or [] + if not isinstance(fields, dict): + fields = [ + (f, [settings.DEFAULT_LOOKUP_EXPR]) for f in fields if f not in exclude + ] + else: + fields = [(f, lookups) for f, lookups in fields.items() if f not in exclude] + + return OrderedDict(fields) + + @classmethod + def get_filter_name(cls, field_name, lookup_expr): + """ + Combine a field name and lookup expression into a usable filter name. + Exact lookups are the implicit default, so "exact" is stripped from the + end of the filter name. + """ + filter_name = LOOKUP_SEP.join([field_name, lookup_expr]) + + # This also works with transformed exact lookups, such as 'date__exact' + _default_expr = LOOKUP_SEP + settings.DEFAULT_LOOKUP_EXPR + if filter_name.endswith(_default_expr): + filter_name = filter_name[: -len(_default_expr)] + + return filter_name + + @classmethod + def get_filters(cls): + """ + Get all filters for the filterset. This is the combination of declared and + generated filters. + """ + + # No model specified - skip filter generation + if not cls._meta.model: + return cls.declared_filters.copy() + + # Determine the filters that should be included on the filterset. + filters = OrderedDict() + fields = cls.get_fields() + undefined = [] + + for field_name, lookups in fields.items(): + field = get_model_field(cls._meta.model, field_name) + + # warn if the field doesn't exist. + if field is None: + undefined.append(field_name) + + for lookup_expr in lookups: + filter_name = cls.get_filter_name(field_name, lookup_expr) + + # If the filter is explicitly declared on the class, skip generation + if filter_name in cls.declared_filters: + filters[filter_name] = cls.declared_filters[filter_name] + continue + + if field is not None: + filters[filter_name] = cls.filter_for_field( + field, field_name, lookup_expr + ) + + # Allow Meta.fields to contain declared filters *only* when a list/tuple + if isinstance(cls._meta.fields, (list, tuple)): + undefined = [f for f in undefined if f not in cls.declared_filters] + + if undefined: + raise TypeError( + "'Meta.fields' must not contain non-model field names: %s" + % ", ".join(undefined) + ) + + # Add in declared filters. This is necessary since we don't enforce adding + # declared filters to the 'Meta.fields' option + filters.update(cls.declared_filters) + return filters + + @classmethod + def filter_for_field(cls, field, field_name, lookup_expr=None): + if lookup_expr is None: + lookup_expr = settings.DEFAULT_LOOKUP_EXPR + field, lookup_type = resolve_field(field, lookup_expr) + + default = { + "field_name": field_name, + "lookup_expr": lookup_expr, + } + + filter_class, params = cls.filter_for_lookup(field, lookup_type) + default.update(params) + + assert filter_class is not None, ( + "%s resolved field '%s' with '%s' lookup to an unrecognized field " + "type %s. Try adding an override to 'Meta.filter_overrides'. See: " + "https://django-filter.readthedocs.io/en/main/ref/filterset.html" + "#customise-filter-generation-with-filter-overrides" + ) % (cls.__name__, field_name, lookup_expr, field.__class__.__name__) + + return filter_class(**default) + + @classmethod + def filter_for_lookup(cls, field, lookup_type): + DEFAULTS = dict(cls.FILTER_DEFAULTS) + if hasattr(cls, "_meta"): + DEFAULTS.update(cls._meta.filter_overrides) + + data = try_dbfield(DEFAULTS.get, field.__class__) or {} + filter_class = data.get("filter_class") + params = data.get("extra", lambda field: {})(field) + + # if there is no filter class, exit early + if not filter_class: + return None, {} + + # perform lookup specific checks + if lookup_type == "exact" and getattr(field, "choices", None): + return ChoiceFilter, {"choices": field.choices} + + if lookup_type == "isnull": + data = try_dbfield(DEFAULTS.get, models.BooleanField) + + filter_class = data.get("filter_class") + params = data.get("extra", lambda field: {})(field) + return filter_class, params + + if lookup_type == "in": + + class ConcreteInFilter(BaseInFilter, filter_class): + pass + + ConcreteInFilter.__name__ = cls._csv_filter_class_name( + filter_class, lookup_type + ) + + return ConcreteInFilter, params + + if lookup_type == "range": + + class ConcreteRangeFilter(BaseRangeFilter, filter_class): + pass + + ConcreteRangeFilter.__name__ = cls._csv_filter_class_name( + filter_class, lookup_type + ) + + return ConcreteRangeFilter, params + + return filter_class, params + + @classmethod + def _csv_filter_class_name(cls, filter_class, lookup_type): + """ + Generate a suitable class name for a concrete filter class. This is not + completely reliable, as not all filter class names are of the format + Filter. + + ex:: + + FilterSet._csv_filter_class_name(DateTimeFilter, 'in') + + returns 'DateTimeInFilter' + + """ + # DateTimeFilter => DateTime + type_name = filter_class.__name__ + if type_name.endswith("Filter"): + type_name = type_name[:-6] + + # in => In + lookup_name = lookup_type.capitalize() + + # DateTimeInFilter + return str("%s%sFilter" % (type_name, lookup_name)) + + +class FilterSet(BaseFilterSet, metaclass=FilterSetMetaclass): + pass + + +def filterset_factory(model, filterset=FilterSet, fields=None): + attrs = {"model": model} + if fields is None: + if getattr(getattr(filterset, "Meta", {}), "fields", None) is None: + attrs["fields"] = ALL_FIELDS + else: + attrs["fields"] = fields + bases = (filterset.Meta,) if hasattr(filterset, "Meta") else () + Meta = type("Meta", bases, attrs) + return type(filterset)( + str("%sFilterSet" % model._meta.object_name), (filterset,), {"Meta": Meta} + ) diff --git a/django_filters/locale/ar/LC_MESSAGES/django.mo b/django_filters/locale/ar/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..b1b876f573a3011cc6617615b5327c09c7f5efe9 GIT binary patch literal 2568 zcmZXTO>7%Q6vwBud>Klhd=~=4M@!mjUE67CIKcnyj+;^@-u=ycGw;p+z1jS_ zW823JV=ta(@t9i}>jl5Q3onf3R>nHO6%aqRf!B8M8*m@^JxE*s1n&d?0v`akZe#3u zumgM;+z;LZ9t9)d0C+z*2Hp+63*HM(fk?qlt91*cyt5#FYz{A4uYnX_2Py6X_#pU+ zvR6QgYk~N&8+cJ2-zxqDJ_GwENaz0zlI|@qD9?8ADR3u9^>%}#KMmr?-oT6U4=evk z#rHtUBh>mC5UJVw;C1x&1Mm^p2O*mL1K^Wj7VH7@%Ks_&5bR~J3%mk$gTH{Jrvrym zA3H(H*QJj;6?rX z2MqM!GCE;*f@JrCbk3l%-%;xZxEuZ@ko2#Cq;CVHzJI6eAJzKLAocSmNaz2q*0&%S z?F_U~e0%J|gmloL?~lF}x<~r9ci?FcTmyRv4_A&CLDEe%)A#%w9vW0TolAr2p}V5* znKbReL*wZXK|gRkL0w%S)d{)5cnt5oc&J9|FMWG7UI@WnR(wK{@QRw#cfxkLyelu< zoUrnSRoKJQrpfvZVdnWM!}NsXvZ0FU8D&%Ov$|OkE-&d-J|(y-%DSU_BG0F)JZG0m zx*KJ~HXCvB!a*uFs=FRP#PfR9Wn;Qk5d2IFwTzVjtygBUE4a;SDNW-hjP?*bS z3}g_qIkS=%tf;$Ox2k+vKp7dBvrR{74i{%Cy2(A8 z){J0>VR47*CXXpxRIEa88UKkZ>0Yjg{yL%{W?9LwDySf=-99TEQ!l&BMg6%V0Cjoh zdb)!~2F1+?F-^T@L5oHm`!pJ=4d%5IxI@FXl6*9M?9KE*hM&lcjSr3tN5(|ic06s! zEf{(2^-96jChR1SjE-ny;;cb2+Hq8zd#K)^3@Wi9*Qq7z*oTAB1CGYd!A+gHytx#3DeaxU_D(8_S_YkH_9Z;)xE#Mu zD$k+#79~bEZnx;b^VB$M2=p@w;AmGvu2GqRMIBH*Mzp*xZ*1ne&H8_?I$exx;%cai z=*b3*I)Vc;D4pc32e&m(%~rR7i@c?weQg&JR6{iCtHZZ0m#L9qcf*9ssG^CoH<%3X F?q7tpGRyz~ literal 0 HcmV?d00001 diff --git a/django_filters/locale/ar/LC_MESSAGES/django.po b/django_filters/locale/ar/LC_MESSAGES/django.po new file mode 100644 index 0000000..9e5caee --- /dev/null +++ b/django_filters/locale/ar/LC_MESSAGES/django.po @@ -0,0 +1,192 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# FULL NAME , 2020. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2020-03-24 00:48+0100\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 " +"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n" +"X-Generator: Gtranslator 2.91.7\n" + +#: conf.py:16 +msgid "date" +msgstr "تاريخ" + +#: conf.py:17 +msgid "year" +msgstr "سنة" + +#: conf.py:18 +msgid "month" +msgstr "شهر" + +#: conf.py:19 +msgid "day" +msgstr "يوم" + +#: conf.py:20 +msgid "week day" +msgstr "يوم الأسبوع" + +#: conf.py:21 +msgid "hour" +msgstr "ساعة" + +#: conf.py:22 +msgid "minute" +msgstr "دقيقة" + +#: conf.py:23 +msgid "second" +msgstr "ثانية" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "يحتوي على" + +#: conf.py:29 +msgid "is in" +msgstr "في داخل" + +#: conf.py:30 +msgid "is greater than" +msgstr "أكبر من" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "أكبر من أو يساوي" + +#: conf.py:32 +msgid "is less than" +msgstr "أصغر من" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "أصغر من أو يساوي" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "يبدأ ب" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "ينتهي ب" + +#: conf.py:38 +msgid "is in range" +msgstr "في النطاق" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "يطابق التعبير العادي" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "بحث" + +#: conf.py:44 +msgid "is contained by" +msgstr "موجود في" + +#: conf.py:45 +msgid "overlaps" +msgstr "يتداخل" + +#: conf.py:46 +msgid "has key" +msgstr "لديه مفتاح" + +#: conf.py:47 +msgid "has keys" +msgstr "لديه مفاتيح" + +#: conf.py:48 +msgid "has any keys" +msgstr "لديه أي مفاتيح" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "حدد بحث" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "إستعلام النطاق يتوقع قيمتين" + +#: filters.py:437 +msgid "Today" +msgstr "اليوم" + +#: filters.py:438 +msgid "Yesterday" +msgstr "أمس" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "الأيام السبعة الماضية" + +#: filters.py:440 +msgid "This month" +msgstr "هذا الشهر" + +#: filters.py:441 +msgid "This year" +msgstr "هذه السنة" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "يمكن فصل القيم المتعددة بفواصل." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (تنازلي)" + +#: filters.py:737 +msgid "Ordering" +msgstr "الترتيب" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "إرسال" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "مرشحات الحقل" + +#: utils.py:308 +msgid "exclude" +msgstr "استبعاد" + +#: widgets.py:58 +msgid "All" +msgstr "كل" + +#: widgets.py:162 +msgid "Unknown" +msgstr "مجهول" + +#: widgets.py:162 +msgid "Yes" +msgstr "نعم" + +#: widgets.py:162 +msgid "No" +msgstr "لا" diff --git a/django_filters/locale/be/LC_MESSAGES/django.mo b/django_filters/locale/be/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..595dad9efb1bc1d7c37a0b9fb3b8cc9a36e9cab3 GIT binary patch literal 2819 zcmZXTUu+ab9LGli(G&kr74iR|f-PjvyHcUO_6jJ}pjH|@h>~Eky&LY9?(H7Cdu=Zv z2HNl^Y2hTn`XEAxK8P>2g-c_(YmE>7d7DX0^vT2*AB=B4X?*beo84XkCpY_<`OW

slHN5CKQ@aGUL4L-zY3 z`M!t;L9%l=I=4WWWFGhrYC8f_ojn9i_Nw3`;1u{Q_$By0_#;U6Tk&}iOoC5uC@|FtL<$=88oZv%)UmWbqCAlcasJ_;TNb(|p8tqQIM zuYjaK13nIZ6Ul!8>HZ%ey@SHJ%e z;!z;k`yHgZ{R^U;`VF8|&9Sk$3f~>Q70QcZqk1h3vhe~Yj|9(y)Mtu;;-|MkgL*@L zX;A)@^TU|b<2Fnh)EDX<pK(Ibb*g1a0vIF7ytiNmrR>>B8*tE;S=S8!^ z2L<;<$@FkL#|JAs>lTZqA7^j7Y@e4C9&EA!(+~J|SgiPLzv<)!KUNlAg^SUW$Ob+S zM%>6`oV`;XELs7}6fD?xouCjdE5h_x#)S!Xz!`Gf5r@4ee42=iq*>fGEyrg%ZjvA& zpO09uAV#xxIVV`b^tp-Dh6Dnk4Hip;z%6?WUL#979opwTf#f_M6inyNJ$F4Wj+ITD z2QHmi`iA9jkJ2QGEqo*xsWvya=@rc&TR=HIkr$(^XgOt6KFr-67M^XEeC8wnYym)Y zIpznZhq~$HMuZrm(lTA50na^(ni_j^#zC~qa-9^<9Yrv%5q2@QUzA)gF#7$xl`~!~ z=Y1pNrg&^%pRr#ITcly^M!qTDo=9#p5?w}n7f&Wr9ox4gwk8s>x6n%?gY@{>+I0&LrLX-iNUoP2beK*e*OwSiV`aq`7=v=-> z!5$HwvB$}}^u|-XbI=N619sUnZKKciihhbaCB6029o;-!rdyqj$wWGx+qz@#8m|jS;NM22A80~nLjOn$DW$F^YEYLobrR{HM&X)bS;rD?bV^KKrD))@s!OEP zMxF~Optejw!7qhCWb&e#pf;RA{z#LBT|$p2;2ML~s2yR&8WhwVjwqJ~E|HxYVm(c| zvuXkdH`RI4rZ3q>6)9^-bqjQ@^_5!=Bc=+}S6}7bQks%T|{5|F@yzqH@ln*C-Q`#7jL#4-S!3 z;f?BCCqJkQws;NX_Y}7DvXKzg?3SJ`qLOrNo?iUzm0d*WXJL4r(H{mk#-R\n" +"Language-Team: TextTempearture\n" +"Language: be\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" +"X-Generator: Poedit 1.8.9\n" + +#: conf.py:16 +msgid "date" +msgstr "дата" + +#: conf.py:17 +msgid "year" +msgstr "год" + +#: conf.py:18 +msgid "month" +msgstr "месяц" + +#: conf.py:19 +msgid "day" +msgstr "дзень" + +#: conf.py:20 +msgid "week day" +msgstr "дзень тыдня" + +#: conf.py:21 +msgid "hour" +msgstr "гадзіну" + +#: conf.py:22 +msgid "minute" +msgstr "хвіліна" + +#: conf.py:23 +msgid "second" +msgstr "секунда" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "змяшчае" + +#: conf.py:29 +msgid "is in" +msgstr "у" + +#: conf.py:30 +msgid "is greater than" +msgstr "больш чым" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "больш або роўна" + +#: conf.py:32 +msgid "is less than" +msgstr "менш чым" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "менш або роўна" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "пачынаецца" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "заканчваецца" + +#: conf.py:38 +msgid "is in range" +msgstr "у дыяпазоне" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "адпавядае рэгулярнаму выразу" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "пошук" + +#: conf.py:44 +msgid "is contained by" +msgstr "змяшчаецца ў" + +#: conf.py:45 +msgid "overlaps" +msgstr "перакрываецца" + +#: conf.py:46 +msgid "has key" +msgstr "мае ключ" + +#: conf.py:47 +msgid "has keys" +msgstr "мае ключы" + +#: conf.py:48 +msgid "has any keys" +msgstr "мае любыя ключы" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Запыт дыяпазону чакае два значэння." + +#: filters.py:437 +msgid "Today" +msgstr "Сёння" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Учора" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Мінулыя 7 дзён" + +#: filters.py:440 +msgid "This month" +msgstr "За гэты месяц" + +#: filters.py:441 +msgid "This year" +msgstr "У гэтым годзе" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Некалькі значэнняў могуць быць падзеленыя коскамі." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (па змяншэнні)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Парадак" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Адправіць" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Фільтры па палях" + +#: utils.py:308 +msgid "exclude" +msgstr "выключаючы" + +#: widgets.py:58 +msgid "All" +msgstr "Усе" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Не было прапанавана" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ды" + +#: widgets.py:162 +msgid "No" +msgstr "Няма" + +#~ msgid "Any date" +#~ msgstr "Любая дата" diff --git a/django_filters/locale/bg/LC_MESSAGES/django.mo b/django_filters/locale/bg/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..122fe4df853fbe889cc25faa3a31edb2dafb5ee3 GIT binary patch literal 2711 zcmZ{j-)|IE6vr=uimQO)ZxFqRAcah6OTv$>C7|*%7HTahiBYG!m+jEmnPp~{wk9fV z6BHgGK}>vrm>6T^!K7VUDWxs(*#~D$e8s=OXAQpiId^xZpx(@#&)i?Tp6O^rgz{T)3d>AfVq|^&=8GICO zf)Bu*Fa!6(hhR6nAHEA8guM_G>Ue!UfMRzL@~B~6vVI!M`Lj^YU4)OoOZD*;DCfo@ zkDBHsI&RkaGhE5|Hz@x9f)e)v24ZIkd z6A;ttLwK0negdCn{42)9&+qU>cpJVCS0P6Be*`6OBXAY`9KH$1q2zTT&X>bA@Nu{W zJ_!#%9`ymQC!hz#-p5e#J_?t@bC5?}<|Vqmg<|J>D1Lv0YvC_Y^7bbb`-@4s?0+6g ze%3dUDqe122$r0bctVlNt2w2ZfO#SXp#I# zjYW^NXKS!|qC8g5dbo~`Oxr};2D;S@X%% z4CefD-l#q|)^0GQ`wfxFfR6^52+NVeYu%F7C*wk7Fd6Bj&kgP!>oC&hMA`Lq63Uuq zcX)x0M7PZNCPs1n=s$zI&K2Dx*GGOMQ!s<7=mljI)U<~uP2{_!SjFhi^#P*Gt2l8Z z5^2Q^7}GDgRyIXlQFxq$I{Wj^5o+j#L00FF6HMsT%9`mmr7%jI&bZ*^omb0+*y#zg zI@5K?={6@lIpMsH-mGqGY2EI$wmEIBx^;VY^OlV*Z7nUCHz=;tgS^;xlQ7EaeUTR@ zq2B8zG3oF3^ectN=gvaW_55b;$PUg0g|b^PPLFYm_-l-_y0?(&+~2wTPQ0znEt%IS zrwQ;hR3enb3?`dOKJ{(axjr|FP113=XOFY(&OV9gn2DU-K`xXFoz>fVy(H7+mm}AA z_JmO}&g!6KhjB++yRLn9tPk|+4&B<+o_WXFYXZZ~7FAuL$$N=zZQjPYoeI;CZ|PH(1jY@e)-q+`-mdWreD z^arMfnW&_5+J4NX*JZ(eb9Sb-N2e1Q!Na7+=2&`-@gyG3S4ZU7+3K)nZVWFq59d{S zIh|DLR~(<<#3cL2#VZq7ArK~JiFX8xTg5s9m41z-Q{si87@D(j%kq>pE{^BYS&#b5_ zc17kiX+DP)gvtbE*HYv3I;Y7GF-d8V-`F{Cmpys!n6t#GFgb<~Q7D<47n`O=BT6iC zX&ft=N~bgbKhI?&ka}KGWAB_wE7nNmU-c6u4eRzA<9+%b>+|OS+q#XpLWpBF0o*|R zPo`I^qw-tW@7hJNVO>*Xj, 2019. +# +msgid "" +msgstr "" +"Project-Id-Version: django-filter\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2019-12-21 19:36+0200\n" +"Last-Translator: Hristo Gatsinski \n" +"Language-Team: \n" +"Language: bg\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.8.9\n" + +#: conf.py:16 +msgid "date" +msgstr "дата" + +#: conf.py:17 +msgid "year" +msgstr "година" + +#: conf.py:18 +msgid "month" +msgstr "месец" + +#: conf.py:19 +msgid "day" +msgstr "ден" + +#: conf.py:20 +msgid "week day" +msgstr "ден от седмицата" + +#: conf.py:21 +msgid "hour" +msgstr "час" + +#: conf.py:22 +msgid "minute" +msgstr "минута" + +#: conf.py:23 +msgid "second" +msgstr "секунда" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "съдържа" + +#: conf.py:29 +msgid "is in" +msgstr "в" + +#: conf.py:30 +msgid "is greater than" +msgstr "е по-голям от" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "е по-голям или равен на" + +#: conf.py:32 +msgid "is less than" +msgstr "е по-малък от" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "е по-малък или равен на" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "започва с" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "завършва с" + +#: conf.py:38 +msgid "is in range" +msgstr "е в диапазона" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "съвпада с регуларен израз" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "търсене" + +#: conf.py:44 +msgid "is contained by" +msgstr "се съдържа от" + +#: conf.py:45 +msgid "overlaps" +msgstr "припокрива" + +#: conf.py:46 +msgid "has key" +msgstr "има ключ" + +#: conf.py:47 +msgid "has keys" +msgstr "има ключове" + +#: conf.py:48 +msgid "has any keys" +msgstr "има който и да е ключ" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Изберете справка" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Търсенето по диапазон изисква две стойности" + +#: filters.py:437 +msgid "Today" +msgstr "Днес" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Вчера" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Последните 7 дни" + +#: filters.py:440 +msgid "This month" +msgstr "Този месец" + +#: filters.py:441 +msgid "This year" +msgstr "Тази година" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Множество стойности може да се разделят със запетая" + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (намалавящ)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Подредба" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Изпращане" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Филтри на полетата" + +#: utils.py:308 +msgid "exclude" +msgstr "изключва" + +#: widgets.py:58 +msgid "All" +msgstr "Всичко" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Неизвестен" + +#: widgets.py:162 +msgid "Yes" +msgstr "Да" + +#: widgets.py:162 +msgid "No" +msgstr "Не" diff --git a/django_filters/locale/cs/LC_MESSAGES/django.mo b/django_filters/locale/cs/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..54a8915c0957e01903e4ab8416aef2f8d3f87466 GIT binary patch literal 2368 zcmZXUOKclO7{`Y`c$k()fKs4^uRuaWS=UJ`nmA1#(57ldnkcvtMdC2=PVJ3%XSOrD zn>Ys!NZhEz0i;$rS)hs>Dj^Oaq^3f03|9_FoZ!YCsRzUX!T(!tS_&)A{O0w&XZ-8H zwoe7VSJC#Mh4%?D0p8q#4&N7Bg?JQP1Mw5zqI(cr2X}(sg9pH$z+7Zoe}60ZFxGc~ zFMzwj`@u1=1Re(;0?&cl!5a7g_$~-lVxic-1hTyt#80%*@&5ZD%YOi}+(+OJ@RMTR z0a`zOeHwqtQOH~?~-2SE0J9K=tYK*##0iuIX- z^C0VauhoYE%b)`}pI1Tr#45T0@H21-{JL2G z1!Vtz134eJLALi7$nkE05zf~D$o}sF+3sF+a77G(y#E>q5m5oz|1t1M@D#}Px>&6H zAnS=iw!2j9e+WK-`Ntr_6rY3a&vlUXeOc_^1o=Mv2(q5vLALt`$ol>UIX^ogjG@>A zvYtV7T$h6&`+F2*JG{s8o8RE(0AxFSmg~rOoAbB%vF(@8s91OrWc$yeao+iE@W(Md zm5=)Mc^YG`7soVQtUm)jkH-0CpZB8eM;k)p-0{b`V~4rsj_WS%dx5_j*=x)s4R=O z(}gHVM6DS>ztKsvKWr;$Ma@8kxS(6wENO93Id1TbSL-+{1MNiaH?JTdM@s=TsO5T? z`bspVBZ<&j3XbpugH2+=q*lOcp(ziC=MAe6oTa2G^?&DNEUC+>3@I_Z7vv`bO_syt zl~6eZScu-4+#?ssq~1h2t!k)c5d}I$=KHamOxaMzPB_G0Zvybn7cP+&dCP-aQmVzN z6?uwgtyx4)y|cbIkCFvOSIJ+5Gsf#zu{5V*V-s)MH3HvzBW*aZW~x-0o$=;W7O;eO z3h`EHv@-I#R~h$4$7y7wdicnJ%Arc7^cHIA)exQwWnyfVPNxl}B~1sdrfi2n%Vd&{ zs(i5=1x*?B*G@Dd49mD4$Dl(uQrS>mP06TAHMN}7R1_n`B(>_!c9rU`G<|mZ^xaTK z%9YZasI<~>q8-D_1i}a75T&1>dQ)1blF19TDR1oVId=AvvfgQ3H+;vdG`0{VrP(mG zGW4d5ja-#A0#wV9xIQR^5^JqtJ7F-tPYF$UPslN+K6+q z)m>|uFv$32rV*ZInBWZ|^|1-NH*h)T(JN{iUz>!&6-CDPH&#RF-ni23*p`d}yh|l| zSGygbR>Z7vq4G7$^6SJv%$XG@o8+5BuB2o(uBcYGlXW}fXB(@9>ULSo;12`k7d6zu zP_(h?prn{t(-NmN-sX7)jqnebHB*S-B-%VQS}Du|tfY&IA1gxfl@=|d;pGkCDC@2- z22snTB7$LLVUa_p7J`IyzStlCYlyearA@^mqK5L`Eu|?FS)LKCdbb4pPkJ48NG%w$ zcvxEC07e`!+ggJu?BZ;s^gTy)cTE^SHc;oYOSm!JPKfBDl)bgcRsY!nMK0prHPy1+ p^-L}zsI1*Yrt?g4ma|0lt_50(70EH{ZiiDq8719yA3<;m{{e?9Kl=ax literal 0 HcmV?d00001 diff --git a/django_filters/locale/cs/LC_MESSAGES/django.po b/django_filters/locale/cs/LC_MESSAGES/django.po new file mode 100644 index 0000000..36d3d88 --- /dev/null +++ b/django_filters/locale/cs/LC_MESSAGES/django.po @@ -0,0 +1,190 @@ +# +msgid "" +msgstr "" +"Project-Id-Version: django-filter\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2016-09-29 11:47+0300\n" +"Last-Translator: Eugena Mikhaylikova \n" +"Language-Team: TextTempearture\n" +"Language: cs\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n " +"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n" +"X-Generator: Poedit 1.8.9\n" + +#: conf.py:16 +msgid "date" +msgstr "datum" + +#: conf.py:17 +msgid "year" +msgstr "rok" + +#: conf.py:18 +msgid "month" +msgstr "měsíc" + +#: conf.py:19 +msgid "day" +msgstr "den" + +#: conf.py:20 +msgid "week day" +msgstr "den v týdnu" + +#: conf.py:21 +msgid "hour" +msgstr "hodinu" + +#: conf.py:22 +msgid "minute" +msgstr "minutu" + +#: conf.py:23 +msgid "second" +msgstr "vteřina" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "obsahuje" + +#: conf.py:29 +msgid "is in" +msgstr "v" + +#: conf.py:30 +msgid "is greater than" +msgstr "více než" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "větší nebo roven" + +#: conf.py:32 +msgid "is less than" +msgstr "méně než" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "menší nebo rovné" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "začíná" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "končí" + +#: conf.py:38 +msgid "is in range" +msgstr "v rozsahu" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "odpovídá normálnímu výrazu" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "vyhledávání" + +#: conf.py:44 +msgid "is contained by" +msgstr "je obsažen v" + +#: conf.py:45 +msgid "overlaps" +msgstr "překrývají" + +#: conf.py:46 +msgid "has key" +msgstr "má klíč" + +#: conf.py:47 +msgid "has keys" +msgstr "má klíče" + +#: conf.py:48 +msgid "has any keys" +msgstr "má nějaké klíče" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Rozsah dotazu očekává dvě hodnoty." + +#: filters.py:437 +msgid "Today" +msgstr "Dnes" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Včera" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Posledních 7 dní" + +#: filters.py:440 +msgid "This month" +msgstr "Tento měsíc" + +#: filters.py:441 +msgid "This year" +msgstr "Tento rok" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Více hodnot lze oddělit čárkami." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (sestupně)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Řád z" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Odeslat" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtry na polích" + +#: utils.py:308 +msgid "exclude" +msgstr "s výjimkou" + +#: widgets.py:58 +msgid "All" +msgstr "Všechno" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Není nastaveno" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ano" + +#: widgets.py:162 +msgid "No" +msgstr "Ne" + +#~ msgid "Any date" +#~ msgstr "Jakékoliv datum" diff --git a/django_filters/locale/da/LC_MESSAGES/django.mo b/django_filters/locale/da/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..84f7e940ed2568fbb8d009c7378617b2c5a90833 GIT binary patch literal 2166 zcma)*J!~9B6o7{${Nx}I0s#U6CWH_N*u%CIB|2kBgk#4MCMI!E5RuU2_W5pod%NeE zJ=;e|0R;t}8$>~qR4Jf~B2gdxMQ$-%r1Ek1JCmZ9GF8r1dc)%;gb_g#aUzi*)W{~grzKUVXeq*r+=1$^horCE1IiecsLd1f5f!So4<4$< znxn_7v8|~7sPCG`$LRVlU!otNZ?@+cXuKM$wmo$9<4L;uuXpw|U1K^-FJp!3yS|$j z>DpePYkZm;ZO;x-zS)C1J{0UoETJh`oMf#d=46_hli9$=t`IZVPm83Nid}JOUxMwr zfxRp?NY8oZV|#gEn|ZhELfyQRo3lO^j}1Y4}; zmC3qUXeSuXv!Xp54#au0kh9lZ$U0fRnwj?{XfMR8w#izTWWkg!ss`VKT}`kcYt6JD zi)p)H9Z_@y4^&{VNfdeC8&0h(m2s%t@kmT!;aNQYj2Sl$%<%U(36HOWUY9umy)Ro+iW`@q?o+0FdZG=T8Hal zQG9eNYvy|U4SW1@Qq(R+Gm;4xoco5I&m~R@J6<2HkJaXVzQhGav+>r+@e&Ehqs1g8 zb+xw<`mV+Ku|o)Wqo<@pV^c2663dIwcM|ODvC1dPKdVY*J?^}5+e)+`uG_Hxcia5g z=$x!1nvrOVn{3$e(XnIE*l09C6X1!7jlj9S1IGh~G?14!;c4VSf z7KK|Zhy$m}nh{@0z6;F9=T=j9n%jvkxx;S)_lm}o}5@$PF z9#n@cne(|PMOq){lbF|BRtRrrmTU7=m|e`hgxWI3Tk}MP3 z-MErTj8I@`\n" +"Language-Team: Danni Randeris \n" +"Language: da\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: Poedit 2.0.1\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: conf.py:16 +msgid "date" +msgstr "dato" + +#: conf.py:17 +msgid "year" +msgstr "år" + +#: conf.py:18 +msgid "month" +msgstr "måned" + +#: conf.py:19 +msgid "day" +msgstr "dag" + +#: conf.py:20 +msgid "week day" +msgstr "ugedag" + +#: conf.py:21 +msgid "hour" +msgstr "time" + +#: conf.py:22 +msgid "minute" +msgstr "minut" + +#: conf.py:23 +msgid "second" +msgstr "sekund" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "indeholder" + +#: conf.py:29 +msgid "is in" +msgstr "er i" + +#: conf.py:30 +msgid "is greater than" +msgstr "er større end" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "er større end eller lig med" + +#: conf.py:32 +msgid "is less than" +msgstr "er mindre end" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "er mindre end eller lig med" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "starter med" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "slutter med" + +#: conf.py:38 +msgid "is in range" +msgstr "er i intervallet" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "matcher regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "søg" + +#: conf.py:44 +msgid "is contained by" +msgstr "er indeholdt af" + +#: conf.py:45 +msgid "overlaps" +msgstr "overlapper" + +#: conf.py:46 +msgid "has key" +msgstr "har string" + +#: conf.py:47 +msgid "has keys" +msgstr "har stringe" + +#: conf.py:48 +msgid "has any keys" +msgstr "har hvilken som helst string" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Interval forespørgslen forventer to værdier." + +#: filters.py:437 +msgid "Today" +msgstr "I dag" + +#: filters.py:438 +msgid "Yesterday" +msgstr "I går" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Sidste 7 dage" + +#: filters.py:440 +msgid "This month" +msgstr "Denne måned" + +#: filters.py:441 +msgid "This year" +msgstr "Dette år" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Flere værdier kan adskilles via komma." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (aftagende)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Sortering" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +#, fuzzy +msgid "Submit" +msgstr "Indsend" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +#, fuzzy +msgid "Field filters" +msgstr "Felt filtre" + +#: utils.py:308 +msgid "exclude" +msgstr "udelad" + +#: widgets.py:58 +msgid "All" +msgstr "Alle" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Ukendt" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ja" + +#: widgets.py:162 +msgid "No" +msgstr "Nej" + +#~ msgid "Any date" +#~ msgstr "Hvilken som helst dag" diff --git a/django_filters/locale/de/LC_MESSAGES/django.mo b/django_filters/locale/de/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..9a48a0a90a2d53629acb8b809eef835006080073 GIT binary patch literal 2277 zcmZ{kJ8T?97{>>a@HoON;Ss`X0tD=sJ?;!B&N+rSBn~k-Y}w}o5EOH_pLZv>H+z|x z&G`bNphKdAR1^q-5TOE!Adry|Mj%l@gP=h`K~I4wpyL1S?j?Z4XlH*rkMBA2?N8e_ zpA~3(&~HOeE)ilHT)z}Aw0AcNaV>Zb#3Me&>k9Bw@M`c&a02`e%tbaA>zlx`>o0;V{}RY@uYg;@*UIsm zAj_Qt@rV!c;y6Ak`4xC8#y@~;|96o6{S#z8TQIo;+y-)-6CnG)55yx5;Klmq%K3$o z$3fQfT)D16s1z1Ff!q#2_TyV9QO@+9UoC81o^i6`qsGfTYgCnQg+BqJw#YAD+z9rcyP z?ohUevXl0D%2maasaUWfS?Cmt%6YjL8i!6SDHD-Am607vTI*BCJLv~$sj@1TvvyB= z(TX+nr^d&{=a7^YtrRN6is_nkV8qkpxWhA^?O?Cc#);f-oR5gy=UL`0@R7JC>=HbShJc^eM0De1|sDa+o}mkVAl_ z=!L<*fOnyAURmTV4{kuz<JJ9Bsi0ny^~uKMzKL4BR;wJtSq3eH=Mv>p+mLffYPB+Qwx1?RYLKY?tHsm-HJYkY z_6Q_Rl&Oe<7O5UAj>d41D$S$K!xufSS8J8WaG+#hYuJY~p4R*W{RAgGEjzKYj{M9@ zYc80&xQ~5WB^w+zos_R~Lr%4|uPi2+RY@?H+Ma7j)6a))W^!5gKsFNbWqDiqOOY#I+PqMpl z-WW16%y544iM%>wMBb7y9;KrVY6Wkxj8oBMGt|p5@@F8rSGJHYaY&Oq2!*;6JJnvb zn3H4&xB=wlnE~m-QdP{h9ejf`kieI0rbhW<;N-lDt$3XHYORQ{rKVQg8%uC%HB_*HjVguj3k@#r*PwBpL yFs-sxxs+F0v#7KpO&ja&ywv)LZ#hFfie>8N{ literal 0 HcmV?d00001 diff --git a/django_filters/locale/de/LC_MESSAGES/django.po b/django_filters/locale/de/LC_MESSAGES/django.po new file mode 100644 index 0000000..8a8c48f --- /dev/null +++ b/django_filters/locale/de/LC_MESSAGES/django.po @@ -0,0 +1,193 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-filter\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2013-08-10 12:29+0100\n" +"Last-Translator: Florian Apolloner \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.5.4\n" + +#: conf.py:16 +msgid "date" +msgstr "Datum" + +#: conf.py:17 +msgid "year" +msgstr "Jahr" + +#: conf.py:18 +msgid "month" +msgstr "Monat" + +#: conf.py:19 +msgid "day" +msgstr "Tag" + +#: conf.py:20 +msgid "week day" +msgstr "Wochentag" + +#: conf.py:21 +msgid "hour" +msgstr "Stunde" + +#: conf.py:22 +msgid "minute" +msgstr "Minute" + +#: conf.py:23 +msgid "second" +msgstr "Sekunde" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "enthält" + +#: conf.py:29 +msgid "is in" +msgstr "ist in" + +#: conf.py:30 +msgid "is greater than" +msgstr "ist größer als" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "ist größer oder gleich" + +#: conf.py:32 +msgid "is less than" +msgstr "ist kleiner als" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "ist kleiner oder gleich" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "beginnt mit" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "endet mit" + +#: conf.py:38 +msgid "is in range" +msgstr "ist im Bereich" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "passt auf Regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "Suche" + +#: conf.py:44 +msgid "is contained by" +msgstr "ist enthalten in" + +#: conf.py:45 +msgid "overlaps" +msgstr "überlappen" + +#: conf.py:46 +msgid "has key" +msgstr "hat Schlüssel" + +#: conf.py:47 +msgid "has keys" +msgstr "hat Schlüssel" + +#: conf.py:48 +msgid "has any keys" +msgstr "hat beliebige Schlüssel" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Die Bereichsabfrage erwartet zwei Werte." + +#: filters.py:437 +msgid "Today" +msgstr "Heute" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Gestern" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Letzte 7 Tage" + +#: filters.py:440 +msgid "This month" +msgstr "Diesen Monat" + +#: filters.py:441 +msgid "This year" +msgstr "Dieses Jahr" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Mehrere Werte können durch Kommas getrennt sein." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (absteigend)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Sortierung" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Absenden" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Feldfilter" + +#: utils.py:308 +msgid "exclude" +msgstr "ausschließen" + +#: widgets.py:58 +msgid "All" +msgstr "Alle" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Unbekannte" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ja" + +#: widgets.py:162 +msgid "No" +msgstr "Nein" + +#~ msgid "Any date" +#~ msgstr "Alle Daten" diff --git a/django_filters/locale/el/LC_MESSAGES/django.mo b/django_filters/locale/el/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..4e2258bdbe3bc9d5b56792bf4fcf840cc50676ae GIT binary patch literal 2836 zcmai!TWl0n7=VugUJBk21@8wH<>HnuQNSV!C^Z<61`1vh5~jPS+kx4cWoDMLF9x}W zq>yOvK@($)H%MrkMM~Y$(kJ!pOkzlU(g&ly_~?^we*f&WrD$}rGvAr>pa1^P{ycy7 z2a0Ps_ru)YO-ikUV>k2QIyXzHyWn}qPc?Yl2FKwY@H@ByUW2L1?52DcoXh?^_!wLS zZ-HxJ3w#OQ4qtCdHUL ziGL3i`93IiYLK5g%;Ro&3X0v2p!8!1E`+0SKKucSzu(}4Z~?`Z`B(|X-c~5_?u1Xl zGHioqp`7~`E`z_oC*eGth`l_Nc=tl_+n4bO6hEh-_&*1w{#W2V@ER05ze7S&b15?A zOlN>nOkGQ+R?WGSSrI!Dlh~cSB!?%sb+++1ls-!gGRHC-a^1^)U%G0>AvKcvNslEz zxugz{a?5;4Y>#j+<(9e-ZhA?rmvc*Rq%SfPaxHEm%}th4o5}0xY{AGVwItF@izX@< zzv%jcwuwGy0(8RZXPJPEB_k9hr&~a=NIy zYq}7W%TCm)UJumvuxLVTs!k`0^%^YJBDKTuOGY24ny{wLp^7QQk&gR<%w((DS?w;n zvFhq|u^;$xZ*y5QPN=#9OsHM{en05*)mtW#o5*Chz*)!jBbCN2J0uk8J{Jq-P{FGf zjp}tG?U34jLm=|PVv=kG)llIzvy`SI@1@X?T&Uw-$G`Di2cb3xs*b1QKxA%u!u541 zY08dgA`;A0r(S00m7TcIOF2VRGKW;z^{Z6AnR{^1gq~B0R7C!TUO;q36~#_S-O}Xx zjM*=xRcVPj!(bmZ&21^>cGEI9@Y{89AHf8thxQrU66R)*q5H2qT5DVbcCamskywq@Jq=^*p1Z7na;L*rw< zR>6O44#g`g9!*`R3%yPlnRxxKu8!Q=>2nfBj|p>|{X!tq+pgDkyYZAKQa3G~UNv;Q zTt^U=qjv3A(${GHs&%@#T)))Ui`VP?vUM$Q=3X^E>7;pe2Bzr7I^Vjw^|_YxD@jh+ zZ|smAw-d?nizb~t$#(HQG-R5|-4xRM-W zyRJDpjLJ}Q%8p~jHe_c4n^Hg1!X$tfg5_A=Vz zDAX|}&b1v)`dN(GdMnW;Cv8L7&k}4%$>FqEz{@a#HO*`W z5c4X>C$!|2oWYyqNhrg~Y0;)OM|2uLQ6L?*LxhR7iR)5%M%gdYTrZ~i4l4T|ddHG} zIfLmjJ1F_xxIG|J@&6g}W^p-lf^f&Fz)_JZ`>~|2>{sHOvr;bNYEZb71cT&X`y!i? zUR{YEwdZJZM$*q}snVPV>}V!CYKPUNO-)q)Is)0@v`rVLk4vERrfEqgV1|fVPKz4$ zf}+Z4U^6nohP0XX5eG$ zlp-Cvi?%l+n6Mp-1J@u@}, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: django-filter\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2017-11-16 10:04+0200\n" +"Last-Translator: Serafeim Papastefanos \n" +"Language-Team: \n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.6.5\n" + +#: conf.py:16 +msgid "date" +msgstr "ημερομηνία" + +#: conf.py:17 +msgid "year" +msgstr "έτος" + +#: conf.py:18 +msgid "month" +msgstr "μήνας" + +#: conf.py:19 +msgid "day" +msgstr "ημέρα" + +#: conf.py:20 +msgid "week day" +msgstr "ημέρα της εβδομάδας" + +#: conf.py:21 +msgid "hour" +msgstr "ώρα" + +#: conf.py:22 +msgid "minute" +msgstr "λεπτό" + +#: conf.py:23 +msgid "second" +msgstr "δευτερόλεπτο" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "περιέχει" + +#: conf.py:29 +msgid "is in" +msgstr "είναι εντός των" + +#: conf.py:30 +msgid "is greater than" +msgstr "είναι μεγαλύτερο από" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "είναι μεγαλύτερο ή ίσο του" + +#: conf.py:32 +msgid "is less than" +msgstr "είναι μικρότερο από" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "είναι μικρότερο ή ίσο του" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "ξεκινά με" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "τελειώνει με" + +#: conf.py:38 +msgid "is in range" +msgstr "είναι εντος του εύρους" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "περιέχει regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "αναζήτηση" + +#: conf.py:44 +msgid "is contained by" +msgstr "περιέχεται σε" + +#: conf.py:45 +msgid "overlaps" +msgstr "επικαλύπτεται" + +#: conf.py:46 +msgid "has key" +msgstr "έχει το κλειδί" + +#: conf.py:47 +msgid "has keys" +msgstr "έχει τα κλειδιά" + +#: conf.py:48 +msgid "has any keys" +msgstr "έχει οποιαδήποτε κλειδιά" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Το ερώτημα εύρους απαιτεί δύο τιμές," + +#: filters.py:437 +msgid "Today" +msgstr "Σήμερα" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Χτες" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Τις προηγούμενες 7 ημέρες" + +#: filters.py:440 +msgid "This month" +msgstr "Αυτό το μήνα" + +#: filters.py:441 +msgid "This year" +msgstr "Αυτό το έτος" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Οι πολλαπλές τιμές πρέπει να διαχωρίζονται με κόμμα." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (φθίνουσα" + +#: filters.py:737 +msgid "Ordering" +msgstr "Ταξινόμηση" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Υποβολή" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Φίλτρα πεδίων" + +#: utils.py:308 +msgid "exclude" +msgstr "απέκλεισε" + +#: widgets.py:58 +msgid "All" +msgstr "Όλα" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Άγνωστο" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ναι" + +#: widgets.py:162 +msgid "No" +msgstr "Όχι" + +#~ msgid "Any date" +#~ msgstr "Οποιαδήποτε ημερομηνία" diff --git a/django_filters/locale/es/LC_MESSAGES/django.mo b/django_filters/locale/es/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..3338ff7a7789d12ed5c5444aab75f4a0b73fabb0 GIT binary patch literal 2279 zcmZ9MO>7-C5XYyqPkVwD~G1)r%rg+N7;S(kLHLB!uMbPTt$bYj5n` zB(DM?gv0@H1P&DkxBvxJsDcBOufscXCSgrSGkH_Pgv1fnn z+w~6Nc^vHlG_!+f9Q@`6eDHj{lV~q^3B*fZ;j;()7JLHy0Tk80z?;Fp!CS$dyNDhF z_kwqTL*Px|(_jNU1>OSAfj5FLg1f;b5GLq+J#Rs=y8+^**YJ_~H$YkcCMfIP25$r3 ztH+l>S$74*OIPucIKHoW4LpGHZ=me|4=8@`z(DNm0q+C%gA(siQ2aj*;-%C0i2a#b z{(Q}sK(WL1{3;03bOAhp+`bA*KDsa_@}EE%{{kKX{{SVQeF#eI?*nE2AlMHMfscUa zK&aBopy<60NX2${2?g&eFBR9XCPdmFKhXCpy+o&ymSqp2f?4gJHbD} zyTIL8EOrink|zbqz7Z&TW1!eMQ**JN*Y*4g_%P;Q0mc9KLGkw^5HEdN%fA4{kFP=5 zrwfYxA3@pwcM$2U)`*?W=P)|rw>)zH#I~HH-0eQJ%|~LFJgQnCKFK-nN0a;?M3YBi z-dFW{``?ScoQK3XP|NSHDfdf!miyh0_86MvMxMLTq{bwc+tK9i$#bX&dbH*}H3diN zzQjw1gX&K>#B7t)wg%|9F*KF3Nz`&`3ig4fOH-t|VYQ}B$w6hhqn20&&b8MCCu*sq zVwYt)4AP9Fvp!)DQ#7kXp~h6AJAvl3ZLwM{*>@Cg9vWboXrV7rb!bA342(CnR|cHo0l9Y$wP6bHf=XD$I?EkRcdz#9Bgk!b9w*o< zjRaaqxYWkB(y$svx)-q|!#v8PdszoUR2>|EqtmWKCsFLqx;TX&^WDpIyu-dKn-n>tWk#w= zoFZIyTtY1|^h&40TY5^HR*5<6YfwP3(QDWUb_=lrSx>ZGvZd8_URM)r;e%pJ_@f{O z{2l6^Qz`C|sU$fPD(M$Jwu((vQ;ssWn`^4x_BF9fE#j+kBEH~{11o9wbL5s=r9pD4 o@)9ekDTmUMQ&}oQjHv(>iy_Vp!CdGiKr+&c7N?tOtEo!pzXRM3mjD0& literal 0 HcmV?d00001 diff --git a/django_filters/locale/es/LC_MESSAGES/django.po b/django_filters/locale/es/LC_MESSAGES/django.po new file mode 100644 index 0000000..ef5b2ed --- /dev/null +++ b/django_filters/locale/es/LC_MESSAGES/django.po @@ -0,0 +1,195 @@ +# Django Filter translation. +# Copyright (C) 2013 +# This file is distributed under the same license as the django_filter package. +# Carlos Goce, 2017. +# Nicolás Stuardo, 2020 +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2023-02-12 14:36+0000\n" +"Last-Translator: gallegonovato \n" +"Language-Team: Spanish \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.16-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "fecha" + +#: conf.py:17 +msgid "year" +msgstr "año" + +#: conf.py:18 +msgid "month" +msgstr "mes" + +#: conf.py:19 +msgid "day" +msgstr "día" + +#: conf.py:20 +msgid "week day" +msgstr "día de la semana" + +#: conf.py:21 +msgid "hour" +msgstr "hora" + +#: conf.py:22 +msgid "minute" +msgstr "minuto" + +#: conf.py:23 +msgid "second" +msgstr "segundo" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "contiene" + +#: conf.py:29 +msgid "is in" +msgstr "presente en" + +#: conf.py:30 +msgid "is greater than" +msgstr "mayor que" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "mayor o igual que" + +#: conf.py:32 +msgid "is less than" +msgstr "menor que" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "menor o igual que" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "comienza por" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "termina por" + +#: conf.py:38 +msgid "is in range" +msgstr "en el rango" + +#: conf.py:39 +msgid "is null" +msgstr "es nulo" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "coincide con la expresión regular" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "buscar" + +#: conf.py:44 +msgid "is contained by" +msgstr "contenido en" + +#: conf.py:45 +msgid "overlaps" +msgstr "solapado" + +#: conf.py:46 +msgid "has key" +msgstr "contiene la clave" + +#: conf.py:47 +msgid "has keys" +msgstr "contiene las claves" + +#: conf.py:48 +msgid "has any keys" +msgstr "contiene alguna de las claves" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Seleccione un operador de consulta." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Consultar un rango requiere dos valores." + +#: filters.py:437 +msgid "Today" +msgstr "Hoy" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Ayer" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Últimos 7 días" + +#: filters.py:440 +msgid "This month" +msgstr "Este mes" + +#: filters.py:441 +msgid "This year" +msgstr "Este año" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Múltiples valores separados por comas." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (descendente)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Ordenado" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Enviar" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtros de campo" + +#: utils.py:308 +msgid "exclude" +msgstr "excluye" + +#: widgets.py:58 +msgid "All" +msgstr "Todo" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Desconocido" + +#: widgets.py:162 +msgid "Yes" +msgstr "Sí" + +#: widgets.py:162 +msgid "No" +msgstr "No" + +#~ msgid "Any date" +#~ msgstr "Cualquier fecha" diff --git a/django_filters/locale/es_AR/LC_MESSAGES/django.mo b/django_filters/locale/es_AR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7f4778af14252d65c1cadde0ab8ff71a27fb134e GIT binary patch literal 703 zcmYL`zm5|z5XKE0|CRy-6#@y<-4zbIcRDz2lp=TJ!bwC#VL=o~$YduQBgYQ57cM*j zFF=EM02+!DC1n~YXelXp5X9%~i5u-t-`F!_k9U4wUHiab7r;&M99#mQK(z1R4EOf!~9_@T{0B&+$pa>2R!TudLw{r31Mp zHnS#78+Snxn-+C!=2v*D_d_^S(9jq_%vw_Q86@O;yW^L_uHl$?`)(H$j&gF)}4!K{@gdw34AMX{KpkwAyx&Rk1n+I&2f&Qs_- zDfY$ANnY${LQeF|*p|vvIp2AyLNe5~lUnRsH}g3+^VQOKHru>$JL`tu?(l4*ojenL zGUS>!4K0-_@T_&Wm8D7io7S_vTI$!eBF86$HrVo`4r*q79MbZO^sMIt;Yqx1X5%a` Xv2NzI{A!x`jE)oK^2o9WcESDuw>h>I literal 0 HcmV?d00001 diff --git a/django_filters/locale/es_AR/LC_MESSAGES/django.po b/django_filters/locale/es_AR/LC_MESSAGES/django.po new file mode 100644 index 0000000..f40b2af --- /dev/null +++ b/django_filters/locale/es_AR/LC_MESSAGES/django.po @@ -0,0 +1,201 @@ +# Django Filter translation. +# Copyright (C) 2013 +# This file is distributed under the same license as the django_filter package. +# Gonzalo Bustos, 2015. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2015-10-11 20:53-0300\n" +"Last-Translator: Gonzalo Bustos\n" +"Language-Team: Spanish (Argentina)\n" +"Language: es_AR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Poedit 1.6.10\n" + +#: conf.py:16 +#, fuzzy +#| msgid "Any date" +msgid "date" +msgstr "Cualquier fecha" + +#: conf.py:17 +#, fuzzy +#| msgid "This year" +msgid "year" +msgstr "Este año" + +#: conf.py:18 +#, fuzzy +#| msgid "This month" +msgid "month" +msgstr "Este mes" + +#: conf.py:19 +#, fuzzy +#| msgid "Today" +msgid "day" +msgstr "Hoy" + +#: conf.py:20 +msgid "week day" +msgstr "" + +#: conf.py:21 +msgid "hour" +msgstr "" + +#: conf.py:22 +msgid "minute" +msgstr "" + +#: conf.py:23 +msgid "second" +msgstr "" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "" + +#: conf.py:29 +msgid "is in" +msgstr "" + +#: conf.py:30 +msgid "is greater than" +msgstr "" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "" + +#: conf.py:32 +msgid "is less than" +msgstr "" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "" + +#: conf.py:38 +msgid "is in range" +msgstr "" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "" + +#: conf.py:44 +msgid "is contained by" +msgstr "" + +#: conf.py:45 +msgid "overlaps" +msgstr "" + +#: conf.py:46 +msgid "has key" +msgstr "" + +#: conf.py:47 +msgid "has keys" +msgstr "" + +#: conf.py:48 +msgid "has any keys" +msgstr "" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "" + +#: filters.py:437 +msgid "Today" +msgstr "Hoy" + +#: filters.py:438 +msgid "Yesterday" +msgstr "" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Últimos 7 días" + +#: filters.py:440 +msgid "This month" +msgstr "Este mes" + +#: filters.py:441 +msgid "This year" +msgstr "Este año" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "" + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "" + +#: filters.py:737 +msgid "Ordering" +msgstr "" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "" + +#: utils.py:308 +msgid "exclude" +msgstr "" + +#: widgets.py:58 +msgid "All" +msgstr "Todos" + +#: widgets.py:162 +msgid "Unknown" +msgstr "" + +#: widgets.py:162 +msgid "Yes" +msgstr "" + +#: widgets.py:162 +msgid "No" +msgstr "" + +#~ msgid "This is an exclusion filter" +#~ msgstr "Este es un filtro de exclusión" diff --git a/django_filters/locale/fa/LC_MESSAGES/django.mo b/django_filters/locale/fa/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..18cb472483ee1be42758d6ba6752a96dd47b3efc GIT binary patch literal 2624 zcmZ{jPiz!b9LJx6B8!TE{{?xX2nDx_F%h?btnC&Xy4|LKFy+K__pu#2JG0Epwp|lU zXxeT~dQqb$-ZaLRTDxvb0`)-RQN?)h@}`^M$pa^iC%yUo&Q4n);bq_Z%=`V``~7`; zbLZwy1jb>^-I)G8LbQN4?!|&}ZIck&!4(ic@gtUpz+XV#se?SaWwQ_ufH80zxC`71 z?gbwK-vsXmyTKUv4!9K@1n&baa0}>y^z&Y%e;=gXX%Ij0Ar|UC1$qB-koUd<9|RYo z{R+r?KY;j&pRh2GUnBkwK7;+AApLK{!nk*Uw6h0%530K`w6!$Lpj zBe@fC1f;!-k^Tb^uEa-R5;gt|WIO?k(cUdAPl11dU0@7ODIWlLfakzRK^JTVE8t7u z&mimh56Jj7AsFs=MBEKBp93K6y%xz^K>S2|w9kOlp9Ljofb82i$Uc4yvL4GI-^mRS zKXD7owiG$!BovzQ!= z=`qZGn9S=5OxB6H9>U~cd>o7qZ3**g0uNv!jc~A+hcVfkhcWpUIamvh{SAb*jXuS} z=!5S_?Dyosobs~D&Y5<;NhB>xw42Jx$@8Y=E7ue0lI5F4OUV(#Dk)DEjItb5(o;pl zHGGwmgJqd@3I)S!7F~|WxH;v*l;}1*U%oDLM%fcRhMiaPLP@!0sm6*b>wD54bt03^ zqE}gvNkdwWGh8Y{P#P?lzUUh=;n1=Dp~h!f8LsGaU{mzl!?rVOivi_vB2-GVIBS@; zCvpf4OIaW>PmY?fpvJORDW}Ac;Yq_T%VCAcxWUI7A#h5rfY-=Um>>6fSHYw!{UO7? zb1xlNstYB`u0xPM%81 zGpU~5j!ajqM-?5{kEgx7nTx+w%6suXCn00qnRt&HF?lE6hRhRkAeHQir!(=kqm7f!MK(T< zAGGBOd8DZ&7XCkiDZLa-2NU&~CJ|JE$)F;FOZAyxLeJ}3P|>sX85s$x0_w@t%fXb? zvwB(2%hf4duj2HSglb$@A+Je2r)TBrWjz~A;sc^3Ny}0%@PO1;;1AcDg%bjHq9ga6XNTt5yA-zM|(D)};PcS0Swi6`04z*Sd!2D7(#lE%XW(^ZHsN zpfE0atk0}omcc|Y4d^d}>u|GicoB!^Xn6`@F+3#0kb(((MoD5vC< z+_)|aJqIs1iQ+_RWPxk6HBZBkFN!tQ95M>7(+SS7mQ0Jjt6?!|ts?dJv?XzQNuUz5 z!8BV_fe0a^fAmEy8ndBaQ{7bo17VNCTde;It|OlX785wYiJ3cMr4pc zIR95L38WAfh#}$xjRzHi7GVerkF57ou%D|_crOjSt^fc4 literal 0 HcmV?d00001 diff --git a/django_filters/locale/fa/LC_MESSAGES/django.po b/django_filters/locale/fa/LC_MESSAGES/django.po new file mode 100644 index 0000000..4092d30 --- /dev/null +++ b/django_filters/locale/fa/LC_MESSAGES/django.po @@ -0,0 +1,190 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: conf.py:16 +msgid "date" +msgstr "تاریخ" + +#: conf.py:17 +msgid "year" +msgstr "سال" + +#: conf.py:18 +msgid "month" +msgstr "ماه" + +#: conf.py:19 +msgid "day" +msgstr "روز" + +#: conf.py:20 +msgid "week day" +msgstr "روز هفته" + +#: conf.py:21 +msgid "hour" +msgstr "ساعت" + +#: conf.py:22 +msgid "minute" +msgstr "دقیقه" + +#: conf.py:23 +msgid "second" +msgstr "ثانیه" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "شامل" + +#: conf.py:29 +msgid "is in" +msgstr "هست در" + +#: conf.py:30 +msgid "is greater than" +msgstr "بزرگتر است از" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "بزرگتر یا مساوی است" + +#: conf.py:32 +msgid "is less than" +msgstr "کوچکتر است از" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "کوچکتر یا مساوی است" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "شروع می شود با" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "به پایان می رسد با" + +#: conf.py:38 +msgid "is in range" +msgstr "در محدوده" + +#: conf.py:39 +msgid "is null" +msgstr "خالی است" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "با ریجکس منطبق است" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "جستجو" + +#: conf.py:44 +msgid "is contained by" +msgstr "وجود دارد در" + +#: conf.py:45 +msgid "overlaps" +msgstr "تداخل دارد" + +#: conf.py:46 +msgid "has key" +msgstr "حاوی کلید است" + +#: conf.py:47 +msgid "has keys" +msgstr "حاوی کلیدها است" + +#: conf.py:48 +msgid "has any keys" +msgstr "حاوی هر کلیدی است" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "یک لوک آپ را انتخاب کنید." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "محدوده کوئری دو مقدار را انتظار دارد." + +#: filters.py:437 +msgid "Today" +msgstr "امروز" + +#: filters.py:438 +msgid "Yesterday" +msgstr "دیروز" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "۷ روز گذشته" + +#: filters.py:440 +msgid "This month" +msgstr "این ماه" + +#: filters.py:441 +msgid "This year" +msgstr "امسال" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "ممکن است چندین مقدار با کاما از هم جدا شوند." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (نزولی)" + +#: filters.py:737 +msgid "Ordering" +msgstr "مرتب سازی" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "ارسال" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "فیلترهای فیلد" + +#: utils.py:308 +msgid "exclude" +msgstr "به غیر از" + +#: widgets.py:58 +msgid "All" +msgstr "همه" + +#: widgets.py:162 +msgid "Unknown" +msgstr "ناشناس" + +#: widgets.py:162 +msgid "Yes" +msgstr "بله" + +#: widgets.py:162 +msgid "No" +msgstr "خیر" diff --git a/django_filters/locale/fi/LC_MESSAGES/django.po b/django_filters/locale/fi/LC_MESSAGES/django.po new file mode 100644 index 0000000..9309fe4 --- /dev/null +++ b/django_filters/locale/fi/LC_MESSAGES/django.po @@ -0,0 +1,191 @@ +# Django Filter translation. +# Copyright (C) 2013 +# This file is distributed under the same license as the django_filter package. +# Carlos Goce, 2017. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 17:45+0200\n" +"PO-Revision-Date: 2023-02-12 14:36+0000\n" +"Last-Translator: Janne Tervo \n" +"Language-Team: Finnish \n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.16-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "päivämäärä" + +#: conf.py:17 +msgid "year" +msgstr "vuosi" + +#: conf.py:18 +msgid "month" +msgstr "kuukausi" + +#: conf.py:19 +msgid "day" +msgstr "päivä" + +#: conf.py:20 +msgid "week day" +msgstr "viikonpäivä" + +#: conf.py:21 +msgid "hour" +msgstr "tunti" + +#: conf.py:22 +msgid "minute" +msgstr "minuutti" + +#: conf.py:23 +msgid "second" +msgstr "sekunti" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "sisältää" + +#: conf.py:29 +msgid "is in" +msgstr "löytyy" + +#: conf.py:30 +msgid "is greater than" +msgstr "suurempi kuin" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "suurempi tai yhtäsuuri kuin" + +#: conf.py:32 +msgid "is less than" +msgstr "pienempi kuin" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "pienempi tai yhtäsuuri kuin" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "alkaa" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "päättyy" + +#: conf.py:38 +msgid "is in range" +msgstr "on välillä" + +#: conf.py:39 +msgid "is null" +msgstr "on null" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "täsmää säännölliseen lausekkeeseen" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "hae" + +#: conf.py:44 +msgid "is contained by" +msgstr "sisältyy kokonaan" + +#: conf.py:45 +msgid "overlaps" +msgstr "on päällekkäinen" + +#: conf.py:46 +msgid "has key" +msgstr "sisältää avaimen" + +#: conf.py:47 +msgid "has keys" +msgstr "sisältää avaimet" + +#: conf.py:48 +msgid "has any keys" +msgstr "sisältää minkä tahansa avaimista" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Hakuehto vaaditaan." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Välin hakuun tarvitaan kaksi arvoa." + +#: filters.py:437 +msgid "Today" +msgstr "Tänään" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Eilen" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Edelliset 7 päivää" + +#: filters.py:440 +msgid "This month" +msgstr "Tässä kuussa" + +#: filters.py:441 +msgid "This year" +msgstr "Tänä vuonna" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Voit syöttää useita arvoja pilkulla erotettuna." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (laskeva)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Järjestä" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Lähetä" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Kenttävalinnat" + +#: utils.py:312 +msgid "exclude" +msgstr "poissulje" + +#: widgets.py:58 +msgid "All" +msgstr "Kaikki" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Tuntematon" + +#: widgets.py:162 +msgid "Yes" +msgstr "Kyllä" + +#: widgets.py:162 +msgid "No" +msgstr "Ei" diff --git a/django_filters/locale/fr/LC_MESSAGES/django.mo b/django_filters/locale/fr/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..2ae9948f350604fd51707afbea1f098c4a95a297 GIT binary patch literal 2344 zcmZ9MPi&M$6u<{X(M3_f|B4JMLLpym7mZCT2ttuYDh(8oi*dR;-5vVve9O%DwOta4 z2M>Cb#6R)G!GlFlp5SQKiw2_?4@QF~#>A5xJQy#=-`o9K8YVmQ`{vJk^WK~H_S&Yk zA1K;x`eXEbjZ$Oq>Mabk%eN|Z54-~Tsc#tWhTlPv`5DU5b!(Nn16JUAxEXGRTj9O% zMR+@$f)#iQ-U(;mZ7_xFV1RPZxpMzJ6us|4e(HS&+5ZrV{3lT4K81I|FUt89C~{vx ze(GBW@#FiFzrshEUx#x4dIqt3BNRPb;6rd16#WOG`27kLKTbn_>P-f@XSQ6=O3p*k z_g1<89^@)@0Ujd8AHj{xe?gh7{{`%gN@D2DNd>ispA2Uc? zFG8{Zb13&;hWymm45IHUl>2^wV)u{b{94K1;Re?KgyQEvP~!F0XzvYkX97L|PeGCMP|lq%_uqkH_XUVbbqPKVzl3t%Pf+ap4a)oeQSv&J^Z!EeZw;Gb z#|9{J+aO`>`6Tn@Cc3wj6Uj%3fxN5ay2vj#vGFOoE*GAJ;?E;=$?wPM(l*oYr$0fL z_Y+^le~I-jy0nM;==m=;%exHFchE7j*Y0E7O&4Dz-ja*bA_BKO{bC zd(=DYHrA}KJKq>k2hvm>b~df+S(oNEL^WBYxof9Z&zrQcQMXJ-&sZI8+XR!_x}NFi zTGncrIH+FD)Ui;v0aa?s#9TkG>!uUcapN0SpDk?YXuH_9wLI#4AuCl5suMP4O>N z*<8_Pp_pm8TunC}7iK$25kH!m+3q z92)FmEiLL+HBHpUcl4aaGMVtPOct^tC~hq^_5720BUn@hoi~lYd9Jgd?b*VlI?rU! z^-egigZM2gsf~DCimpsQHr0GCY(FSM~67qt%h!L)D?7%2D1mnZ~o2nmh}m`oN-1^$}BGhR^j2 zK67EloiicW{f(A!=^)v$4>8{;Ov5JA*0i{8c|NLVLuGPea{Pvc!-GSWgFK}5T-0e} zNp2VOXWA(*JEm(*6Qa%co}50MjNCXU2F==#jQd(9sXVGjW?WvGN{e99Raa8+u zZyNVj$8`U5?@q7x>EVH~%InF?)>~3qe45H^-Q{}E;Iox}iFB80A#*X};s6;~M5-js z1MgI~Vp6NEjxwP}Y!S%WvS`@O+&qrx?j=s^*j=J*x=S2|$RgrGqaY=udc2wrPEj;A zc*le3Gh|~_M~$A%3bG>4ttg~Y=83YdF5jn4beE)pcspFsg)a+9jr;kmV}m+qDI*t? zn&VTn81Jz{9Vq06`i^Gd)C7_9zEH>bKEmz2VshBtFD5xi#_<+`q_kqc8kdsFmElGV z!S)`oj zYQif**oZFYXIF`?nk|dkWm)PBlSt6mrhZt}=??yum`nC+-iH@)-Oo_EQhyG&ns(mE iGpJx0sX$wnphaD)Wqqw5773N)1@1>n33#i@c>fQEl`N|O literal 0 HcmV?d00001 diff --git a/django_filters/locale/fr/LC_MESSAGES/django.po b/django_filters/locale/fr/LC_MESSAGES/django.po new file mode 100644 index 0000000..2d4da24 --- /dev/null +++ b/django_filters/locale/fr/LC_MESSAGES/django.po @@ -0,0 +1,194 @@ +# Django Filter translation. +# Copyright (C) 2013 +# This file is distributed under the same license as the django_filter package. +# Axel Haustant , 2013. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2024-01-18 14:00+0000\n" +"Last-Translator: Nils Van Zuijlen \n" +"Language-Team: French \n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.4-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "date" + +#: conf.py:17 +msgid "year" +msgstr "année" + +#: conf.py:18 +msgid "month" +msgstr "mois" + +#: conf.py:19 +msgid "day" +msgstr "jour" + +#: conf.py:20 +msgid "week day" +msgstr "jour de la semaine" + +#: conf.py:21 +msgid "hour" +msgstr "heure" + +#: conf.py:22 +msgid "minute" +msgstr "minute" + +#: conf.py:23 +msgid "second" +msgstr "seconde" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "contient" + +#: conf.py:29 +msgid "is in" +msgstr "est inclus dans" + +#: conf.py:30 +msgid "is greater than" +msgstr "supérieur à" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "supérieur ou égal à" + +#: conf.py:32 +msgid "is less than" +msgstr "inférieur à" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "inférieur ou égale à" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "commence par" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "se termine par" + +#: conf.py:38 +msgid "is in range" +msgstr "entre" + +#: conf.py:39 +msgid "is null" +msgstr "est nul" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "correspond à l'expression régulière" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "recherche" + +#: conf.py:44 +msgid "is contained by" +msgstr "est contenu dans" + +#: conf.py:45 +msgid "overlaps" +msgstr "chevauche" + +#: conf.py:46 +msgid "has key" +msgstr "contient la clé" + +#: conf.py:47 +msgid "has keys" +msgstr "contient les clés" + +#: conf.py:48 +msgid "has any keys" +msgstr "a une des clés" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Sélectionner un opérateur." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "La fourchette doit avoir 2 valeurs." + +#: filters.py:437 +msgid "Today" +msgstr "Aujourd'hui" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Hier" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "7 derniers jours" + +#: filters.py:440 +msgid "This month" +msgstr "Ce mois-ci" + +#: filters.py:441 +msgid "This year" +msgstr "Cette année" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Les valeurs multiples doivent être séparées par des virgules." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (décroissant)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Tri" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Envoyer" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtres de champ" + +#: utils.py:308 +msgid "exclude" +msgstr "Exclut" + +#: widgets.py:58 +msgid "All" +msgstr "Tous" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Inconnu" + +#: widgets.py:162 +msgid "Yes" +msgstr "Oui" + +#: widgets.py:162 +msgid "No" +msgstr "Non" + +#~ msgid "This is an exclusion filter" +#~ msgstr "Ceci est un filtre d'exclusion" diff --git a/django_filters/locale/it/LC_MESSAGES/django.mo b/django_filters/locale/it/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..f53c4eaa17f3609e45b985b69968e1ea3c82b7ea GIT binary patch literal 2268 zcmZ9MO=w(I6vt0(>&IBDMys`c-Kw>T;iZ{?HcklI)}%xm8mlbLJYyZ80p z_a+$^3T{>0)P)Nd3W7mgsEAZ72nAiZ5`^x=wL5X;LhygyylJ$Tx$k#B&pn^>+sK{| z2<0j+!EF#fx`@w>;3e=D@JDbQ{1vRO>>2Fu25-jtKJY>C zAb34E4K~21z?;Bl!M$J`ya9X}geY38_t!yrF9-3XK0dPlCMfsc2Ibzn;6Cs|J^vV# zd)pv>^c6m0$G0_q0`JBA3MlXY1&Y3ZgCb`y77v0Wpx8MMivCZ6_|en&i2V6_{cO#1 zpvZZ(-Zvmbk_S)1x0~Q?n12Uh7}C$+e()Di)_(^T_$Mg-9D#8n?*J(J9|k2>O;GN? zQtz+Tw4l8AMm>KE6o0)_ufGq9-WTfmMV=0uiSr?J@w?=Pv^&rbR3oC> z!Mo8VPNM4=x-{|A1L$He)S~;*N6{Zemt2=7zLB_zEfR0BLE7N~Dxb(uY#g?u^+5bV zM}itnIK*rdV>@GXB2DRp?W;r=O!J1*M6H{&U>|6)Obe5zta>^vIjBtc)f%h7x%N1n zsI|U|U6$!ELC-rn>l5~nNlQ8u>Nq6!11)RYVRgP_-&eeqb6f;fY`R+H1g(^7nJK8< zHIVOY(H#u?tUa|IM9`|;ux``ROB|#_Gg*ysRvR0r(py$wP*9r&5_l_4%Y><`gVHc< zgQ18_Fc=aGuJnXgYe|(kGVgeXab6W&ZLggx=M|qXb*c&{d!{;Jtny-}tfU-ZV14!K z-Rtma zw2(yS5HjOzOEs1`cfN=gL&qf1$+8oow!`w$*=U)2Mh->Kz{HlCnrt4ACY#aJ6BxE0 zpBkTRPEIz?Abe397KKz7&bQPl?Nb-jX%{m#ZKu>7j@qoVmRiZRHKD6U=R&S8f2qf= z9%v~Jug$GA78e%hc64h_Og2s-bZqfNKZgzlZxzS#6tSF9aaa4m#q4T(KAPS+C#tNo zkLGObBxze}dd(D#7o*c`8JQ?LE;&w2p_&uZ6U}C0DJ{KDqj~4E&{8(9reSt!Mh%9u zqgEZBRn4)PMqLoGuWF*;F>04ZVdw=!IT#&`RE9=nq=mXbKe*KoorDXY4Jcv`SM zqoELz->HlP569YClwGG|Xa#xVLTpOBv~u|iT0kXMHDcf*sS!=pyN>V@QckO!J;7uY z%FaP(G&CAo=pJ7cp;C?LT(iW3B}2~Z>LeqTofJi;p_KEm!t9KlDv>()JHcWOcf&0# zhb^b+(H$2^MGUVFM*qDSJ7Z%5|G;2Tii3!foMtH~muin\n" +"Language-Team: Italian \n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.18-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "data" + +#: conf.py:17 +msgid "year" +msgstr "anno" + +#: conf.py:18 +msgid "month" +msgstr "mese" + +#: conf.py:19 +msgid "day" +msgstr "giorno" + +#: conf.py:20 +msgid "week day" +msgstr "giorno della settimana" + +#: conf.py:21 +msgid "hour" +msgstr "ora" + +#: conf.py:22 +msgid "minute" +msgstr "minuto" + +#: conf.py:23 +msgid "second" +msgstr "secondo" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "contiene" + +#: conf.py:29 +msgid "is in" +msgstr "presente in" + +#: conf.py:30 +msgid "is greater than" +msgstr "maggiore di" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "maggiore o uguale di" + +#: conf.py:32 +msgid "is less than" +msgstr "minore di" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "minore o uguale di" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "comincia per" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "termina per" + +#: conf.py:38 +msgid "is in range" +msgstr "nell'intervallo" + +#: conf.py:39 +msgid "is null" +msgstr "nullo" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "coincide con la espressione regolare" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "cerca" + +#: conf.py:44 +msgid "is contained by" +msgstr "contenuto in" + +#: conf.py:45 +msgid "overlaps" +msgstr "sovrapposto" + +#: conf.py:46 +msgid "has key" +msgstr "contiene la chiave" + +#: conf.py:47 +msgid "has keys" +msgstr "contiene le chiavi" + +#: conf.py:48 +msgid "has any keys" +msgstr "contiene qualsiasi chiave" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "La query di intervallo richiede due valori." + +#: filters.py:437 +msgid "Today" +msgstr "Oggi" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Ieri" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Ultimi 7 giorni" + +#: filters.py:440 +msgid "This month" +msgstr "Questo mese" + +#: filters.py:441 +msgid "This year" +msgstr "Questo anno" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Più valori separati da virgole." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (decrescente)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Ordinamento" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Invia" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtri del campo" + +#: utils.py:308 +msgid "exclude" +msgstr "escludi" + +#: widgets.py:58 +msgid "All" +msgstr "Tutti" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Sconosciuto" + +#: widgets.py:162 +msgid "Yes" +msgstr "Sì" + +#: widgets.py:162 +msgid "No" +msgstr "No" + +#~ msgid "Any date" +#~ msgstr "Qualsiasi data" diff --git a/django_filters/locale/nl/LC_MESSAGES/django.mo b/django_filters/locale/nl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..dcfae01a5231e84fc2fa401491253f7abb313d49 GIT binary patch literal 2277 zcmZ9MPi$009LGll(FOkiDk>s_iWKUr;svs$%0mB8XuC~YYA~8OyYIJer~7thc{8uu zZKCn0M@_)Q#CY*UyciEkylA2^8i}5aiAFhiG%@j_N58+fvlRQXzxmAH-@lpP{wOc%PrQwW*ROzl{ymV-eF*LZKMLb( zAfNjZ#7}&OhU54l@ON+@#(#lqe+L@&dl$%h_Ja?BM?uzq2IRQUgB-_25I^xM8n)92 z^EPl5WPPuN^|wHn67PUB$nm=%>-z)B&=r4!Z1-RAIJgZ)InFVV^;f`M;5qOK@MZ7; z@Qtv31?0Sb5XM(Q{KO|={5i#t1G3#81AhY9-mf70eFJ2De+K>oa=y2~8J^z> z^8URb-|s$<<9Qn7yp}=E({h-9C9oCNdmvPb%OJ=7KFIs8g6!AFAb#RgG@Q3DK;Hi~ z$o8*?@y}uX28gs4XIRhRdkUTXVZiT^edc@Rx4s)P_}J!?5E&*o#~jZi5YF3U5dQW+ zIPZ@`_&)YRIDXFAQ3!tz_ffnz_L==X0yzxf9P)QRWEjG+-vi;C@prHfaVYS?K*mt$ zb3Vi&Cx>EkbuzIw$q`XWQ!%M2jb%fpo-!w9^VI83N^(`DIXT%@Jy|2^sG~CFDVDXK ztlM^5xe+mEMKy~lgDNqvoR`OCta?r?D3g%9lvCD|wAP`zchYxlP&pzNDaD*rGPSmq zcQBFH+S-eyriMXle6!!}k;=r9g-&t7w2bW4f#GCkQMc*X;C2E>HTGXbkXQxPAJlZ>D;lfJ3U=CQPyq)WLXRRCSzi$V0sez{^-TuQDXG z2(nAm;+%^jRr8r$L1LrnI9kSCYHP}JzH;V#Wokk$Pb@4>SLaF#)Ulb5W?iD==yaaA zXvvmkX}%gQ(5mJ$(KsS6%Zn40g=n@KjaTH^YI$~g_@(OHL}>=s94#SGmnv_wvRp*l zmS-uECmnZB6>Uv98i{qHy-J_QA(P}Pp=gOzyDVoab5j@Cr;{@?r&2v)vt(lre3_k| zo!AKA*vPY`Gq`6mFx>0FGf!*&nNEs}AC>i{${hKz3rmyHiH&{iV1u$~!qhFl^s+or z)4nvH=9x;PN%-l?(sYWU8+&e4_Pb+4MjjlK$BvAaic(RH)OPTsibBE5TmE0A5FR0A zB)dwXV`M8g21rm}P0~EmwZ%eg@nTwBG>5rrh{Uo@6J8UQMnZ*+qIME8;xtt1R;V7l zfUc@HJ<5k}8X6Q3>`Q``K^0A-s0kj3aat!7uEJv(*Iur`Ke3FFQi-UV8nqCTIH$yv z=0d`O8m%hNMU=PECW16nC0@44i(Gq`qQSN%QNxEq8gy@+%u!1mvd2FL6iSY}Up$s; zDIS#4U?gn=*-G_FOTt;P4qs7AeLw~0fsdmokmteijnSs#*tt, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-08-21 12:25+0000\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Storm Heg \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +#: conf.py:16 +msgid "date" +msgstr "datum" + +#: conf.py:17 +msgid "year" +msgstr "jaar" + +#: conf.py:18 +msgid "month" +msgstr "maand" + +#: conf.py:19 +msgid "day" +msgstr "dag" + +#: conf.py:20 +msgid "week day" +msgstr "weekdag" + +#: conf.py:21 +msgid "hour" +msgstr "uur" + +#: conf.py:22 +msgid "minute" +msgstr "minuur" + +#: conf.py:23 +msgid "second" +msgstr "seconde" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "bevat" + +#: conf.py:29 +msgid "is in" +msgstr "zit in" + +#: conf.py:30 +msgid "is greater than" +msgstr "is groter dan" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "is groter dan of gelijk aan" + +#: conf.py:32 +msgid "is less than" +msgstr "is minder dan" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "is minder dan of gelijk aan" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "begint met" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "eindigt met" + +#: conf.py:38 +msgid "is in range" +msgstr "zit in bereik" + +#: conf.py:39 +msgid "is null" +msgstr "is null" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "matcht regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "zoek" + +#: conf.py:44 +msgid "is contained by" +msgstr "wordt bevat door" + +#: conf.py:45 +msgid "overlaps" +msgstr "overlapt" + +#: conf.py:46 +msgid "has key" +msgstr "heeft key" + +#: conf.py:47 +msgid "has keys" +msgstr "heeft keys" + +#: conf.py:48 +msgid "has any keys" +msgstr "heeft keys" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Selecteer een lookup." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Bereik query verwacht twee waarden." + +#: filters.py:437 +msgid "Today" +msgstr "Vandaag" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Gisteren" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Afgelopen 7 dagen" + +#: filters.py:440 +msgid "This month" +msgstr "Deze maand" + +#: filters.py:441 +msgid "This year" +msgstr "Dit jaar" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Meerdere waarden kunnen gescheiden worden door komma's." + +#: filters.py:721 tests/test_filters.py:1670 +#, python-format +msgid "%s (descending)" +msgstr "%s (aflopend)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Volgorde" + +#: rest_framework/filterset.py:33 +#: templates/rest_framework/form.html:5 +msgid "Submit" +msgstr "Indienen" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Veld filters" + +#: utils.py:323 +msgid "exclude" +msgstr "uitsluiten" + +#: widgets.py:58 +msgid "All" +msgstr "Alles" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Onbekend" + +#: widgets.py:162 +msgid "Yes" +msgstr "Ja" + +#: widgets.py:162 +msgid "No" +msgstr "Nee" diff --git a/django_filters/locale/pl/LC_MESSAGES/django.mo b/django_filters/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..fdbf09d482aaf689692fd17d17becd69f598c4c2 GIT binary patch literal 1859 zcmb7@&u<$=6vqb$zYG-GQhrwGL6s^|wPx)kN^#3X-shmh(k5mo!VosXWW@} zw>G^XTJ^>S^?=#~5`O?lTo5Wkf|>(IE(i$_;=&0bByMov`!?Hz_QuHL&%EDnW_Etw zGjT;=>@Vg&;3Vdcci<1Bf2R-+gJ;3Jz<0p=z)RpE@I4Se@p+;D0(=1SH(&|;4!j@y z3A`Kp4dgt(7y3Uz&i8jAPrx_>q&aw+P+~u7YqC zuY&BqQRv?)7=gT>ZXv&2$nSz&_kD0Lcn#$IpMZ~pUl#W73;Qo1LH`$spV)`u%>5we zKTvQ6`qIH3)8>#O+v`bR7ALG&cd>HFA{x@CG>;rZFPd$QKx@+W)^ez%6HN=7cvE?v zsd6ku@R8bhfmS?a8UbxPa020lDKE%!%PEw1l(wb0T_)>DogK)8Qp+}-duT&WnwDZs zqP*V@-4&Y}~W5Z6h)Opd759-LI?GzSJN*jtUNVP!4| z=Y#4Tg_T-${!my6!_sk_Y|zA3d?HipYP1~79IQloxyx^cX;wz_t7XJ?giSb7=Pr3{)G_R(#s&Zp1!6WredMQ!Q4 zO6#YZ$AZH+uIFoH`nl-qvkR!qmim;b*DG{{ zLaNb}nXH6M^(q}aNW5IE&rb6?*N2OhDqXmc8^WauEJvtvKd=(9=Vx3Z@JXfAAq9Wj!bM$4jW#}}i~ zkl_CT87W#8HNnE3>%aOi6MdTv$JbS7dqK%ylib&zW=7rOOxbNBjbzuMAB9k(iyT{v z|K{jRKj, YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django_filters 0.0.1\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2023-04-10 20:47+0000\n" +"Last-Translator: Quadric \n" +"Language-Team: Polish \n" +"Language: pl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n" +"%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n" +"%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" +"X-Generator: Weblate 4.17-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "data" + +#: conf.py:17 +msgid "year" +msgstr "rok" + +#: conf.py:18 +msgid "month" +msgstr "miesiąc" + +#: conf.py:19 +msgid "day" +msgstr "dzień" + +#: conf.py:20 +msgid "week day" +msgstr "dzień tygodnia" + +#: conf.py:21 +msgid "hour" +msgstr "godzina" + +#: conf.py:22 +msgid "minute" +msgstr "minuta" + +#: conf.py:23 +msgid "second" +msgstr "sekunda" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "zawiera" + +#: conf.py:29 +msgid "is in" +msgstr "zawiera się w" + +#: conf.py:30 +msgid "is greater than" +msgstr "powyżej" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "powyżej lub równe" + +#: conf.py:32 +msgid "is less than" +msgstr "poniżej" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "poniżej lub równe" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "zaczyna się od" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "kończy się na" + +#: conf.py:38 +msgid "is in range" +msgstr "zawiera się w zakresie" + +#: conf.py:39 +msgid "is null" +msgstr "jest wartością null" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "pasuje do wyrażenia regularnego" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "szukaj" + +#: conf.py:44 +msgid "is contained by" +msgstr "zawiera się w" + +#: conf.py:45 +msgid "overlaps" +msgstr "nakłada się" + +#: conf.py:46 +msgid "has key" +msgstr "posiada klucz" + +#: conf.py:47 +msgid "has keys" +msgstr "posiada klucze" + +#: conf.py:48 +msgid "has any keys" +msgstr "posiada jakiekolwiek klucze" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Wybierz wyszukiwanie." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Zapytanie o zakres oczekuje dwóch wartości." + +#: filters.py:437 +msgid "Today" +msgstr "Dziś" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Wczoraj" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Ostatnie 7 dni" + +#: filters.py:440 +msgid "This month" +msgstr "Ten miesiąc" + +#: filters.py:441 +msgid "This year" +msgstr "Ten rok" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Wiele wartości można rozdzielić przecinkami." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (malejąco)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Sortowanie" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Wyślij" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtry pola" + +#: utils.py:308 +msgid "exclude" +msgstr "wyklucz" + +#: widgets.py:58 +msgid "All" +msgstr "Wszystko" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Nieznane" + +#: widgets.py:162 +msgid "Yes" +msgstr "Tak" + +#: widgets.py:162 +msgid "No" +msgstr "Nie" + +#~ msgid "Any date" +#~ msgstr "Dowolna data" + +#~ msgid "This is an exclusion filter" +#~ msgstr "Jest to filtr wykluczający" diff --git a/django_filters/locale/pt_BR/LC_MESSAGES/django.mo b/django_filters/locale/pt_BR/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e9cc1a8882e9192392bccf953d1f632118ec211f GIT binary patch literal 2263 zcmZ9MNo*WN6owxpVHv`bu!SuYiyu)tHUwd8?1=>kglf9WGex?qI#tzU z&jleQZk$ly033)w0!PXLqzDDU0gVU;jvxUS&WI}~xWNCq+cBZk)nC{4wtBCB+r9l= zLVF1PPW1FLqG|B!%ke_{Y#Y(_;0B0?&f|3z_zie1cmdoG{sfjswpZ)hz-utS6TBPT z16~16fer8p@M`cGa0l1{uLNHLA&R>7`YOo!au5#<@#6K@K|cQ`$miY$cY>$t@oA9H zZGd>_3%uBmFKd1e-huJYAnX4VWPAStSfDlcegDmen z$Z`4(WP5)E5zg`q@7ru+n;#(O9q;9P<#|dW9UFiGJA3*0^=XMi1*BHlwTBl5#0+FwLw*%!;nS1i^KkfstE+HSJL)=Q|)|5KIp`|iJ zi_X4=m`2BvXa!fMt!azKlFF?M(Y){JBsx;`eAKa+UR;Ql)Ijs5=qOxli^+-Bfv7bZ zwOV3wvORGinwXrJXgrJSi#qVgr!rXA7KaTk)>|W%V_O6Z?P6J{1BsocSIC}QCbpcgZ86o=q47fWlrjog$o4H-mFOT^&8cSVk;Y&md6}X>ityM2T2txuq4ETAUEs=&Q0k zu$J3IWvB~R*G5v#IWZWWb-f}j>tpnBRUt+~#prz;&9DnqqNOK<#iQ6HB)KY=kR6o` z7DNn`10\n" +"Language-Team: Portuguese (Brazil) \n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 5.0-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "data" + +#: conf.py:17 +msgid "year" +msgstr "ano" + +#: conf.py:18 +msgid "month" +msgstr "mês" + +#: conf.py:19 +msgid "day" +msgstr "dia" + +#: conf.py:20 +msgid "week day" +msgstr "dia da semana" + +#: conf.py:21 +msgid "hour" +msgstr "hora" + +#: conf.py:22 +msgid "minute" +msgstr "minuto" + +#: conf.py:23 +msgid "second" +msgstr "segundo" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "contém" + +#: conf.py:29 +msgid "is in" +msgstr "presente em" + +#: conf.py:30 +msgid "is greater than" +msgstr "é maior que" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "é maior ou igual que" + +#: conf.py:32 +msgid "is less than" +msgstr "é menor que" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "é menor ou igual que" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "começa com" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "termina com" + +#: conf.py:38 +msgid "is in range" +msgstr "está no range" + +#: conf.py:39 +msgid "is null" +msgstr "é nulo" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "coincide com a expressão regular" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "buscar" + +#: conf.py:44 +msgid "is contained by" +msgstr "está contido por" + +#: conf.py:45 +msgid "overlaps" +msgstr "sobrepõe" + +#: conf.py:46 +msgid "has key" +msgstr "contém a chave" + +#: conf.py:47 +msgid "has keys" +msgstr "contém as chaves" + +#: conf.py:48 +msgid "has any keys" +msgstr "contém uma das chaves" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Selecione uma pesquisa." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Consulta por range requer dois valores." + +#: filters.py:437 +msgid "Today" +msgstr "Hoje" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Ontem" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Últimos 7 dias" + +#: filters.py:440 +msgid "This month" +msgstr "Este mês" + +#: filters.py:441 +msgid "This year" +msgstr "Este ano" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Valores múltiplos podem ser separados por vírgulas." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (decrescente)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Ordenado" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Enviar" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtros de campo" + +#: utils.py:308 +msgid "exclude" +msgstr "excluir" + +#: widgets.py:58 +msgid "All" +msgstr "Tudo" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Desconhecido" + +#: widgets.py:162 +msgid "Yes" +msgstr "Sim" + +#: widgets.py:162 +msgid "No" +msgstr "Não" + +#~ msgid "Any date" +#~ msgstr "Qualquer data" diff --git a/django_filters/locale/ro/LC_MESSAGES/django.po b/django_filters/locale/ro/LC_MESSAGES/django.po new file mode 100644 index 0000000..a622b23 --- /dev/null +++ b/django_filters/locale/ro/LC_MESSAGES/django.po @@ -0,0 +1,192 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 14:47+0000\n" +"PO-Revision-Date: 2023-02-10 16:28+0000\n" +"Last-Translator: Dan Braghis \n" +"Language-Team: Romanian \n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" +"X-Generator: Weblate 4.16-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "dată" + +#: conf.py:17 +msgid "year" +msgstr "an" + +#: conf.py:18 +msgid "month" +msgstr "lună" + +#: conf.py:19 +msgid "day" +msgstr "zi" + +#: conf.py:20 +msgid "week day" +msgstr "zi a săptămânii" + +#: conf.py:21 +msgid "hour" +msgstr "oră" + +#: conf.py:22 +msgid "minute" +msgstr "minută" + +#: conf.py:23 +msgid "second" +msgstr "secundă" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "conține" + +#: conf.py:29 +msgid "is in" +msgstr "este în" + +#: conf.py:30 +msgid "is greater than" +msgstr "este mai mare decât" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "este mai mare sau egal cu" + +#: conf.py:32 +msgid "is less than" +msgstr "este mai mic decât" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "este mai mic sau egal cu" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "începe cu" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "se termină cu" + +#: conf.py:38 +msgid "is in range" +msgstr "este în intervalul" + +#: conf.py:39 +msgid "is null" +msgstr "este nul" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "se potrivește cu expresia regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "căutare" + +#: conf.py:44 +msgid "is contained by" +msgstr "cuprins de" + +#: conf.py:45 +msgid "overlaps" +msgstr "se suprapune" + +#: conf.py:46 +msgid "has key" +msgstr "are cheia" + +#: conf.py:47 +msgid "has keys" +msgstr "are cheile" + +#: conf.py:48 +msgid "has any keys" +msgstr "are orice cheie" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Selectați o căutare." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Interogarea de interval așteaptă două valori." + +#: filters.py:437 +msgid "Today" +msgstr "Astăzi" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Ieri" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Ultimele 7 zile" + +#: filters.py:440 +msgid "This month" +msgstr "Luna aceasta" + +#: filters.py:441 +msgid "This year" +msgstr "Anul acesta" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Valorile multiple pot fi separate prin virgule." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (descescător)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Rânduire" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Trimite" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtre de câmp" + +#: utils.py:312 +msgid "exclude" +msgstr "exclude" + +#: widgets.py:58 +msgid "All" +msgstr "Toate" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Necunoscut" + +#: widgets.py:162 +msgid "Yes" +msgstr "Da" + +#: widgets.py:162 +msgid "No" +msgstr "Nu" diff --git a/django_filters/locale/ru/LC_MESSAGES/django.mo b/django_filters/locale/ru/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..a4ff1ce33683d241306b1e34e110f16adc96604c GIT binary patch literal 2796 zcmZvcTWl0n7{?C+Dl6W=3*HYZ*g|&QEfv~rw}3(k#!7>QsL{mf?&sl<1B2`#}0Dfw)BlFYX@)sXq)-Zxmb$o{!cS zK0721DWSmkny*IxWz8KXumU(ABcDu zq@A~;eG`O9;ex-Swu9iKSa&06+Up0`b02&XJO#c5ejV-K1}FDmy#{;&+yL$aw}b1z z;~?Wa3qAmT3-bH|ct7|fNdJF=tot?aKJYIPw^)H9k};5Rtp~ZE042B+WPI;{4}w0( zxIY9R2G2(O7eU592XYR619|?BX#byRe+`1z19=0;Iu}94^)6oY|6a8I5@a6Vfy`?f zq`jX&`o9LEoZ$?hR7=;UrLX$jaaLF#&Nl0{c+ti)cw{7a8f2dt1LNmx@M7-t%Zv47 z&a4l6+=z$QBY2oQ=Zm#upBnIN#)B}!i#cq;!#g-zaulme_4qWX|xF=rom;lYOS;E7ucUWy?29mXZU8RaTxX8Wq{Aq^C-T zi_gnh^M3-!;6GF;K)z=Swt_uI~(E#6QbA4EoJ7H199_Cy#rB}mAVgC;Df zp{!NTDN!&yX&|+Jg+RE#$08wc%C3Od$WoXN*LhbVIam4x!@hYf9apNOWy6xb!#y)R zVcODVnv__|LxPd&(qfrj(eSecl+#stH6)6rT}I{WxjO^OwTzM{JmjA(0EjLpJl}9p zw=lUurTSS~5tgXib&jB>@%_2@VYJM2?6k}sK`>6d-o@BKRdQTE-sR=ZT>Qmy-i!A* zX&LK25I?8}OlrjUAm6lXN~X5QldbWlR+&nrn|EwYZc8R(ub`Ll9;D}4hVQs(*=6<@ z4ATOA*Xc8CXF#?Wi@TJivI)1`0R=l>Hu5Uoql_XPEw0njEyud{ckR6%XeyD6y@Wn0 z8!jp(#NewT|M`-I#&fjqkOy4ktJ*TY61D)@_wt!-{u0 zZqZ9iyA&?HOmmy8e`Xr&O{ruilaiY^OMWIdW>P7+Qzj*jW8INyTHI>SH1jjmNVcb% z^TKuY*2X0{?842W&-M%~?37I~u&uEz_IiAuvK4+y zENr)e~>shHU!^31SBJ>5s6E2Y5SeQ#aMY^8T^Fp6zdC##>bR$qk zXod?!7$EPZ9n33u-Tg+oo zcB`$hZs-WgQ7;C*Fyibk>WUsql!1;$k_*iOC)I

CKnHCBI*+&{sTn`(N_Qf literal 0 HcmV?d00001 diff --git a/django_filters/locale/ru/LC_MESSAGES/django.po b/django_filters/locale/ru/LC_MESSAGES/django.po new file mode 100644 index 0000000..5a61595 --- /dev/null +++ b/django_filters/locale/ru/LC_MESSAGES/django.po @@ -0,0 +1,195 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: django-filter\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2016-09-29 11:47+0300\n" +"Last-Translator: Mikhail Mitrofanov \n" +"Language-Team: \n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" +"X-Generator: Poedit 1.8.9\n" + +#: conf.py:16 +msgid "date" +msgstr "дата" + +#: conf.py:17 +msgid "year" +msgstr "год" + +#: conf.py:18 +msgid "month" +msgstr "месяц" + +#: conf.py:19 +msgid "day" +msgstr "день" + +#: conf.py:20 +msgid "week day" +msgstr "день недели" + +#: conf.py:21 +msgid "hour" +msgstr "час" + +#: conf.py:22 +msgid "minute" +msgstr "минута" + +#: conf.py:23 +msgid "second" +msgstr "секунда" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "содержит" + +#: conf.py:29 +msgid "is in" +msgstr "в" + +#: conf.py:30 +msgid "is greater than" +msgstr "больше чем" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "больше или равно" + +#: conf.py:32 +msgid "is less than" +msgstr "меньше чем" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "меньше или равно" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "начинается" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "заканчивается" + +#: conf.py:38 +msgid "is in range" +msgstr "в диапазоне" + +#: conf.py:39 +msgid "is null" +msgstr "" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "соответствует регулярному выражению" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "поиск" + +#: conf.py:44 +msgid "is contained by" +msgstr "содержится в" + +#: conf.py:45 +msgid "overlaps" +msgstr "перекрывается" + +#: conf.py:46 +msgid "has key" +msgstr "имеет ключ" + +#: conf.py:47 +msgid "has keys" +msgstr "имеет ключи" + +#: conf.py:48 +msgid "has any keys" +msgstr "имеет любые ключи" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Запрос диапазона ожидает два значения." + +#: filters.py:437 +msgid "Today" +msgstr "Сегодня" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Вчера" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Прошедшие 7 дней" + +#: filters.py:440 +msgid "This month" +msgstr "За этот месяц" + +#: filters.py:441 +msgid "This year" +msgstr "В этом году" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Несколько значений могут быть разделены запятыми." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (по убыванию)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Порядок" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Отправить" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Фильтры по полям" + +#: utils.py:308 +msgid "exclude" +msgstr "исключая" + +#: widgets.py:58 +msgid "All" +msgstr "Все" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Не задано" + +#: widgets.py:162 +msgid "Yes" +msgstr "Да" + +#: widgets.py:162 +msgid "No" +msgstr "Нет" + +#~ msgid "Any date" +#~ msgstr "Любая дата" diff --git a/django_filters/locale/sk/LC_MESSAGES/django.mo b/django_filters/locale/sk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..d9c67d890166eae569fc062218eba2517b4d85db GIT binary patch literal 2394 zcmZXTOKco97{^T?JeKkbuTmcU3N&pR%{H61kZzi`p-rknUZk6dR^s5@ad#&(Yj5qD zO|}OldMXmRfy6b3N<^X(LX{8^$z^tn5aNaeC(cM55eIJkzs)42#TxtP&;IL7N(L+KEgWvDKfcE81A)W$PL44vn43C2A;1l3oupj&d>>k;*xxW*99P4|) z{or2kVQ>h{foH(Sz<0sjUX^EW^~_bIps{4A4K zKt8t$;uGIs;5@#~_yhPd3tzXCbWuR+#Z178Jy&es0~ z`P|=`yaPe8zdazw_e>`513CWv*?Mm#AI1XQLL;JlSvc@jYv^bMu~D%mn|wQa;hOM zw0$bKsAB4M>GERAh-vF93!7p_x|rUE#g-GZQdbpSOO$PqT570D>?mF|naRAkl$7g1 zEK0Qi_Kl8fo70w(R+J1(h&df94!X0pq468;ww>; zjwDhG6#`)alPzMwBv!y{W~rMF%T=q8oTa!X^@B1QOX^x8BZ>|01zn9mljSsdB~lIv zW=FS$`_9#6T&ba)R#nxKs0TVh~6$ z#+n7x)Vt_=^SH9W=pxOGo_lZf!Whku&0e}VJ(ZhP4P#?((p3ZBdnc(nuVjjpo0;}z zRWsl--g#tPq``s0kT-D58$3aUlf}YN|G>bBq1*&+(<>oC7s=SzB9#w~*&w8nieR|u z!WNyvy@zKTR#uT)P{E*F9)HH^LpZIgiL5HGq-4EF6QffX<~X=h6BB2nAa88-^tKLy zn!GqUb}y4cejs-a7p*iRXf+UGtd`=VjR-eCOqH6nPQ@d0rEzcQo*qYfRatLLR}BB+ zMH(sxac(9`tc<*IW9zO+y3rNg$njy?oQ@pUbdU-(GC~8?+e?~f1v&!>>JMz49-+Za zrBfqx97=_4r2~Ba3=J0PSl@8&gYC*G-C%(A4V>u zYZcQc<~u7Y4qIY0OxHux-e~f*rz>$%$19CutEhohDdq!NQPxn+_&U84Q$4-Y*-&_z zom*slAD5)l^-7J}%Yn3^tOt0jff84YmA=xL%@`LcoMk0ETAkh&v*x;!H8SmG8Kx^u zNq$px9hkV4$AP$M{h)J8lyEVI>dGO8Ot2;t=QW<{l)A3dmAVq?$J&Vb_Oh~4m@@1p z3rb{}_^NYLghscQ)7#{PR@(~obcNu2bu0C-y^*fLh~SM(`0pIAoo`!;1w}9t$Qqti zy3S%#wwF6AaG+IZ#e*x}TLudd1 literal 0 HcmV?d00001 diff --git a/django_filters/locale/sk/LC_MESSAGES/django.po b/django_filters/locale/sk/LC_MESSAGES/django.po new file mode 100644 index 0000000..385b3d3 --- /dev/null +++ b/django_filters/locale/sk/LC_MESSAGES/django.po @@ -0,0 +1,196 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2023-07-21 19:07+0000\n" +"Last-Translator: Milan Šalka \n" +"Language-Team: Slovak \n" +"Language: sk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n " +">= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n" +"X-Generator: Weblate 5.0-dev\n" +"X-Translated-Using: django-rosetta 0.8.1\n" + +#: conf.py:16 +msgid "date" +msgstr "dátum" + +#: conf.py:17 +msgid "year" +msgstr "rok" + +#: conf.py:18 +msgid "month" +msgstr "mesiac" + +#: conf.py:19 +msgid "day" +msgstr "deň" + +#: conf.py:20 +msgid "week day" +msgstr "deň týždňa" + +#: conf.py:21 +msgid "hour" +msgstr "hodina" + +#: conf.py:22 +msgid "minute" +msgstr "minúta" + +#: conf.py:23 +msgid "second" +msgstr "sekunda" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "obsahuje" + +#: conf.py:29 +msgid "is in" +msgstr "je v" + +#: conf.py:30 +msgid "is greater than" +msgstr "je vačší než" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "je vačší alebo rovný ako" + +#: conf.py:32 +msgid "is less than" +msgstr "je menší než" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "je menší alebo rovný ako" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "začína s" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "končí s" + +#: conf.py:38 +msgid "is in range" +msgstr "je v rozsahu" + +#: conf.py:39 +msgid "is null" +msgstr "je nulová" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "spĺňa regex" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "hľadať" + +#: conf.py:44 +msgid "is contained by" +msgstr "je obsiahnutý" + +#: conf.py:45 +msgid "overlaps" +msgstr "presahuje" + +#: conf.py:46 +msgid "has key" +msgstr "má kľúč" + +#: conf.py:47 +msgid "has keys" +msgstr "má kľúče" + +#: conf.py:48 +msgid "has any keys" +msgstr "má akékoľvek kľúče" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Vyberte vyhľadávanie." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Rozsah očakáva dve hodnoty." + +#: filters.py:437 +msgid "Today" +msgstr "Dnes" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Včera" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Posledných 7 dní" + +#: filters.py:440 +msgid "This month" +msgstr "Tento mesiac" + +#: filters.py:441 +msgid "This year" +msgstr "Tento rok" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Viacero hodnôt môže byť oddelených čiarkami." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (klesajúco)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Zoradenie" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Potvrdiť" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Filtre poľa" + +#: utils.py:308 +msgid "exclude" +msgstr "neobsahuje" + +#: widgets.py:58 +msgid "All" +msgstr "Všetky" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Neznáme" + +#: widgets.py:162 +msgid "Yes" +msgstr "Áno" + +#: widgets.py:162 +msgid "No" +msgstr "Nie" + +#~ msgid "Any date" +#~ msgstr "Akýkoľvek dátum" diff --git a/django_filters/locale/uk/LC_MESSAGES/django.mo b/django_filters/locale/uk/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..e16148d1482d99cf113a777287419c466d074758 GIT binary patch literal 2912 zcmZ{kUu+yl9mfaK@aHJBgaR!EIxS6z8}0SZHPpW3(uR^$MRjAP*Ope|VSP8b+j?*J zy1N(WqylN8rhTw#Q3WGapsEE4`gU>c#BpNht-Q`k2p%f&g2Y34hXW%3(!AIcd;g8^M*nppfFF>T!Z1Mdhl=FI!pBnIx?>~d$ ze-?`00=yMoDAw;l@p}*QQ_DOgkIM!B2=8Y77bxfd6H2`Qfuge;t+Poe0Xhobv7yce!O zsoS5S==~i^ef|x<3U?#=6?iwiA3g}>9yFkQe-4UY7v2Yd4kzKeP~!Lyirz<1>hdqh zPu)Qg<@-HQ@+w0)=O~nXo`+mjcL${ZTVwCm3zT~&cSZ6N?LEw`AsXLd>cSwgNuR&L zl=$Ut$dEH74;hk&^g!y%@oJ1I<1VK3PU<8z{T6dSb01T3ks&pGfGN33UUDa7NR4Gk z?PN%cGHKI9tsrWTsUu;ijzk09@-w531tx6ilR=o7BvsS>FbjI2 z(Wm^dZ&Ka$2YS}%)b#v>-7P&k(9O8p_0zI?DptpnmPyc5Gk%)shfy4)>VzM)jees9a*;%Lvo4EI(~HX zTE~etFZKOUXR&+>+>Rj9iKHo((4-_-xZYTN%&+Tb%?{;EOxv7R-5}~y`BCoiDU*bL zFI6e|H#>mnS}M)_gu1!p=8c(?(kfS?nIwLZntD&Pyk}`y5JxrLdXZpaZ`8%o3Db*{ z%$rWzLCgC=znyxGxTZ@p$GsEgR3IMS56QQt$1BzEdzC3~d`efVwTXuhR355SN>9>D zuR(fg=x1?K(?|Pl6Zv{NnCtk1Fqn%^`TCG?#&S34_`%5bXuHd6nd@;Fji}xC+s11c zzgyD{b2@97ZjThReqwHXuIc_ zCaXWwIOa`m?~`Cpn#4OAHDkHsH9a{SWTly~pZKA7EKa&#hG6v*f`tnqRK#IxdAR<)kLgd1?f8mbo%n9V&w2IggdUR<#%ubav4f=_dykvQ z@E0uYoQX{<$aJ+lS)MAne-8G#-PHLjU}#tDFn=R|Enl)%#+3an)>UPHk)N|G`GS`( z+I2hBZqr#iRQ7l5yP7ZLXY(_5O*&pJxuAzL6vzPc+ zgmnXzWo3Vb?{&MDpT&kn7DLY1l+79m$#tFcFNn{wq_-ndHZ5}Mo9tP!*9mXP7PRb| z6V~~8;<-XL`BMH0NuSRb*o`?~kgz#HQewHJ>^si(K6V$I%S8@zMW;BM%D&5jRNkaa zsTm_uv|Ei%w+o<@md*j+jKUVGg?w&02PT5_XTwA5Rm-BNff7Mm*s@$mU zB#Z7|x2sNLo#z_+5Zx|1XXURWzOLjiNA490G)+kqG{On)bSV0$\n" +"Language-Team: Ukrainian \n" +"Language: uk\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 " +"? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > " +"14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % " +"100 >=11 && n % 100 <=14 )) ? 2: 3);\n" +"X-Generator: Weblate 5.4-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "дата" + +#: conf.py:17 +msgid "year" +msgstr "рік" + +#: conf.py:18 +msgid "month" +msgstr "місяць" + +#: conf.py:19 +msgid "day" +msgstr "день" + +#: conf.py:20 +msgid "week day" +msgstr "день тижня" + +#: conf.py:21 +msgid "hour" +msgstr "година" + +#: conf.py:22 +msgid "minute" +msgstr "хвилина" + +#: conf.py:23 +msgid "second" +msgstr "секунда" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "містить" + +#: conf.py:29 +msgid "is in" +msgstr "в" + +#: conf.py:30 +msgid "is greater than" +msgstr "більше ніж" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "більше або дорівнює" + +#: conf.py:32 +msgid "is less than" +msgstr "менше ніж" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "менше або дорівнює" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "починається" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "закінчується" + +#: conf.py:38 +msgid "is in range" +msgstr "в діапазоні" + +#: conf.py:39 +msgid "is null" +msgstr "є порожнім" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "відповідає регулярному виразу" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "пошук" + +#: conf.py:44 +msgid "is contained by" +msgstr "міститься в" + +#: conf.py:45 +msgid "overlaps" +msgstr "перекривається" + +#: conf.py:46 +msgid "has key" +msgstr "має ключ" + +#: conf.py:47 +msgid "has keys" +msgstr "має ключі" + +#: conf.py:48 +msgid "has any keys" +msgstr "має будь-які ключі" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "Оберіть оператор запиту." + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "Запит діапазону очікує два значення." + +#: filters.py:437 +msgid "Today" +msgstr "Сьогодні" + +#: filters.py:438 +msgid "Yesterday" +msgstr "Вчора" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "Минулі 7 днів" + +#: filters.py:440 +msgid "This month" +msgstr "За цей місяць" + +#: filters.py:441 +msgid "This year" +msgstr "В цьому році" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "Кілька значень можуть бути розділені комами." + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s (по спадаючій)" + +#: filters.py:737 +msgid "Ordering" +msgstr "Порядок" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "Відправити" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "Фільтри по полях" + +#: utils.py:308 +msgid "exclude" +msgstr "виключаючи" + +#: widgets.py:58 +msgid "All" +msgstr "Усе" + +#: widgets.py:162 +msgid "Unknown" +msgstr "Не задано" + +#: widgets.py:162 +msgid "Yes" +msgstr "Так" + +#: widgets.py:162 +msgid "No" +msgstr "Немає" + +#~ msgid "Any date" +#~ msgstr "Будь-яка дата" diff --git a/django_filters/locale/zh_CN/LC_MESSAGES/django.mo b/django_filters/locale/zh_CN/LC_MESSAGES/django.mo new file mode 100644 index 0000000000000000000000000000000000000000..7047a5e13f617e0e3d107d6bc323a579c2c4a5b5 GIT binary patch literal 852 zcmYk3&1(}u7{*7fU#nCUdeXxv2#QSID79hJ)}}QnrAZrVTF~2=OgF2W*)Y2)33w3^ zt784YQj0xW2qN?%f~Mj>B0`}X+f%)H^_gU)4*TwJ=AHNBd6}Q5x|Rsmao8Eyeb`CZ z513wbA0a2ev)}M@*eWYE#af2-sO~cR}=y^USzXE>2!X4w?xA@3*_L zu(R?!{Q6>d;|U2LHFh30$X2tt^=+xO{5f1`lI`!0Tg~_3N`tf(Un5RC!o?;YvbDTM jTB{$zm+QaYG`82*{)=4w*jimcou}cKPa5sew+)TI)jR3- literal 0 HcmV?d00001 diff --git a/django_filters/locale/zh_CN/LC_MESSAGES/django.po b/django_filters/locale/zh_CN/LC_MESSAGES/django.po new file mode 100644 index 0000000..9fb5ce9 --- /dev/null +++ b/django_filters/locale/zh_CN/LC_MESSAGES/django.po @@ -0,0 +1,194 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# Kane Blueriver , 2016. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-02-10 11:07+0000\n" +"PO-Revision-Date: 2023-05-07 03:57+0000\n" +"Last-Translator: Lattefang <370358679@qq.com>\n" +"Language-Team: Chinese (Simplified) \n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.18-dev\n" + +#: conf.py:16 +msgid "date" +msgstr "日期" + +#: conf.py:17 +msgid "year" +msgstr "年" + +#: conf.py:18 +msgid "month" +msgstr "月" + +#: conf.py:19 +msgid "day" +msgstr "日" + +#: conf.py:20 +msgid "week day" +msgstr "工作日" + +#: conf.py:21 +msgid "hour" +msgstr "小时" + +#: conf.py:22 +msgid "minute" +msgstr "分钟" + +#: conf.py:23 +msgid "second" +msgstr "秒" + +#: conf.py:27 conf.py:28 +msgid "contains" +msgstr "包含" + +#: conf.py:29 +msgid "is in" +msgstr "在" + +#: conf.py:30 +msgid "is greater than" +msgstr "大于" + +#: conf.py:31 +msgid "is greater than or equal to" +msgstr "大于等于" + +#: conf.py:32 +msgid "is less than" +msgstr "小于" + +#: conf.py:33 +msgid "is less than or equal to" +msgstr "小于等于" + +#: conf.py:34 conf.py:35 +msgid "starts with" +msgstr "以……开始" + +#: conf.py:36 conf.py:37 +msgid "ends with" +msgstr "以……结尾" + +#: conf.py:38 +msgid "is in range" +msgstr "在范围内" + +#: conf.py:39 +msgid "is null" +msgstr "为空" + +#: conf.py:40 conf.py:41 +msgid "matches regex" +msgstr "匹配正则表达式" + +#: conf.py:42 conf.py:49 +msgid "search" +msgstr "搜索" + +#: conf.py:44 +msgid "is contained by" +msgstr "包含在" + +#: conf.py:45 +msgid "overlaps" +msgstr "重叠" + +#: conf.py:46 +msgid "has key" +msgstr "单值" + +#: conf.py:47 +msgid "has keys" +msgstr "多值" + +#: conf.py:48 +msgid "has any keys" +msgstr "任何值" + +#: fields.py:94 +msgid "Select a lookup." +msgstr "选择查找。" + +#: fields.py:198 +msgid "Range query expects two values." +msgstr "范围查询需要两个值。" + +#: filters.py:437 +msgid "Today" +msgstr "今日" + +#: filters.py:438 +msgid "Yesterday" +msgstr "昨日" + +#: filters.py:439 +msgid "Past 7 days" +msgstr "过去 7 日" + +#: filters.py:440 +msgid "This month" +msgstr "本月" + +#: filters.py:441 +msgid "This year" +msgstr "今年" + +#: filters.py:543 +msgid "Multiple values may be separated by commas." +msgstr "多个值可以用逗号分隔。" + +#: filters.py:721 +#, python-format +msgid "%s (descending)" +msgstr "%s(降序)" + +#: filters.py:737 +msgid "Ordering" +msgstr "排序" + +#: rest_framework/filterset.py:33 +#: templates/django_filters/rest_framework/form.html:5 +msgid "Submit" +msgstr "提交" + +#: templates/django_filters/rest_framework/crispy_form.html:4 +#: templates/django_filters/rest_framework/form.html:2 +msgid "Field filters" +msgstr "字段过滤器" + +#: utils.py:308 +msgid "exclude" +msgstr "排除" + +#: widgets.py:58 +msgid "All" +msgstr "全部" + +#: widgets.py:162 +msgid "Unknown" +msgstr "未知" + +#: widgets.py:162 +msgid "Yes" +msgstr "是" + +#: widgets.py:162 +msgid "No" +msgstr "否" + +#~ msgid "This is an exclusion filter" +#~ msgstr "未启用该过滤器" diff --git a/django_filters/rest_framework/__init__.py b/django_filters/rest_framework/__init__.py new file mode 100644 index 0000000..4ffc408 --- /dev/null +++ b/django_filters/rest_framework/__init__.py @@ -0,0 +1,4 @@ +# flake8: noqa +from .backends import DjangoFilterBackend +from .filters import * +from .filterset import FilterSet diff --git a/django_filters/rest_framework/__pycache__/__init__.cpython-312.pyc b/django_filters/rest_framework/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..98d0ec46cf7813d5c2fc4fc017dc4ba3b7bcf482 GIT binary patch literal 314 zcmX@j%ge<81pfK~X@x-gF^B^LOi;#WH6UX;LkdF*V-78WT<4(WPQm9RIJH(OV}kVF)uyeEirLaY7lXB}J@2iIohWfh5DPX#I@*+*JM2;?yGjlGNf7{j$`& zGX0#)B>jTQl8pR3V?9G7{o>4$RNVrgxryni#ri2=r^G|e(=P(*icc#_%uOxNFUr=B zkI&4@EQycTE2#X%VUwGmQks)$SHuIf3*?nzJ|OXdnURt4DTC%62C;h#3PqqG0{~d< BSLFZz literal 0 HcmV?d00001 diff --git a/django_filters/rest_framework/__pycache__/backends.cpython-312.pyc b/django_filters/rest_framework/__pycache__/backends.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..13efcfa2850b6478b05385ac51b493105bc288da GIT binary patch literal 7407 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 af0M2MLpuJGNcV+TS*Cpja%aXm$o~Vz@{b?@ literal 0 HcmV?d00001 diff --git a/django_filters/rest_framework/__pycache__/filters.cpython-312.pyc b/django_filters/rest_framework/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9eb37bff25ce78fd6b3978e3ae05fdbe716fe37 GIT binary patch literal 883 zcmY*Xy=xRf6o0e3cQ-k5k!Vl@BEc`*fEkR9g@{;~${4T^wi(vjxyvSVx97}W&XX%r z1WXD)8c9lvG!pzvYzzvKg@9n1bb(V0seH4$m&6DAoA>s8{N8&rUn-R{pgdu7wYvo1 zmoWxX$d&#)D(etHKqNGXM+gK~U`z7ZN;OAX4coH`2(my2$tS1hSTF-YVFiLBMx=Zv zUZZWDeUnZ%!!hfySj-+UGZbrDyyybMj4k^W_b*VwQC zj|AXZt572WS)rc23NMN0JO$S}F7zlRsp9O%V&*=BUw;na16hZjwQ$;>2L>b_P{LNO z5r_v{gEhMcZ-xPSB*Y4vMWu%PcDTa<1n2buE1Z*E=(Q( zf;ud*4%JGRD_OTUW_nS4L9Gv;oOxqkqSwA4TOEz-6C literal 0 HcmV?d00001 diff --git a/django_filters/rest_framework/__pycache__/filterset.cpython-312.pyc b/django_filters/rest_framework/__pycache__/filterset.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69e75e6b8ae09c035a44f143ab51d6f5fea7b3a6 GIT binary patch literal 1907 zcmZ`4O>YxNbY^$GUdJDCh@pT(zDPi>8e6mqMJ=iVN=#8hQjt`u7Nph2I}SFpUUy~; zIC2mNq#B7_-yRb`Edf_j~i+o40=? zlRbc+`NHSr9~1!o5=3}n0kWBa0Ne%^upkCD)FBkOge6_J-wBai9o|X%xD`Xm z3goiU|CA*>+1UTdDsmWAWOfQzJ=cL1=lLD_x5Yi#=jr{;L@xPU5IN{-7DDxsQ*Uxy zwH*s#%CW>UVhmkj1~ylOBv!6qh6qLMx#ZiaCC9Ft?76sfPI8kc9S0+`R`m4TzSGp1 zHW^y1*eGBnd>2Luo0OJB^za0Efz9_g=WE_C1axQtT|%<1phz2(p#`sN_X2%gZG$UN zk1mL~G2ir7Y;dV34x!=RvfCa_?+=#ZoH+*1LA&Z2}sv2V3-!L30Tab?o zACpyyj{~%1tlH64+16GS2v~n;(Sp@Xh;M(Z?`-2C7J3d_CxMn?DQsUTw<4j$Qh$$z zZCi#bTwyiBwWZL*s%mL1)kubxTqd_7-vZ7{g}j#9f=2Ha1$o(Gb0p|uPthUvrwG>( z;l)&E&8E{}uDZ}zvMbC5WEZzvi7&C*goVmx12ZuTB})A+y7H-+#a!Br&<1zlDrN4B zXxzk&Rk#YN(0bGD_rHb^()RY+0?>DEp3Prd~MAf|@JN)(ex`r5Br-o{bk`XUg!@rGTP?7tvf3Ceb zU%24dsL-H@6d0nca0%5e6>w##P;c_!wGZ+~-Y?J!LlbqgbkST!v|v@u+OlK#lTHhS zTN!0y+UT-FE*1hdV)=U0%Wx&NHNAOptGzrt6ByZgfBg9V#KZK|3t2jz zdI_YFR3~xZr3&^8e|NrJTpu~qEZq8??~QSBK*k%cW*#9SOwEOBW8_alU1A= z5xam43Z2y3T_j>R5b@0Y(T)afB;xl&;sU(OfvYy^7TS{xG l^Y_0`, `_1`, etc... + from django_filters import RemovedInDjangoFilter25Warning + warnings.warn( + "Built-in schema generation is deprecated. Use drf-spectacular.", + category=RemovedInDjangoFilter25Warning, + ) + assert ( + compat.coreapi is not None + ), "coreapi must be installed to use `get_schema_fields()`" + assert ( + compat.coreschema is not None + ), "coreschema must be installed to use `get_schema_fields()`" + + try: + queryset = view.get_queryset() + except Exception: + queryset = None + warnings.warn( + "{} is not compatible with schema generation".format(view.__class__) + ) + + filterset_class = self.get_filterset_class(view, queryset) + + return ( + [] + if not filterset_class + else [ + compat.coreapi.Field( + name=field_name, + required=field.extra["required"], + location="query", + schema=self.get_coreschema_field(field), + ) + for field_name, field in filterset_class.base_filters.items() + ] + ) + + def get_schema_operation_parameters(self, view): + from django_filters import RemovedInDjangoFilter25Warning + warnings.warn( + "Built-in schema generation is deprecated. Use drf-spectacular.", + category=RemovedInDjangoFilter25Warning, + ) + try: + queryset = view.get_queryset() + except Exception: + queryset = None + warnings.warn( + "{} is not compatible with schema generation".format(view.__class__) + ) + + filterset_class = self.get_filterset_class(view, queryset) + + if not filterset_class: + return [] + + parameters = [] + for field_name, field in filterset_class.base_filters.items(): + parameter = { + "name": field_name, + "required": field.extra["required"], + "in": "query", + "description": field.label if field.label is not None else field_name, + "schema": { + "type": "string", + }, + } + if field.extra and "choices" in field.extra: + parameter["schema"]["enum"] = [c[0] for c in field.extra["choices"]] + parameters.append(parameter) + return parameters diff --git a/django_filters/rest_framework/filters.py b/django_filters/rest_framework/filters.py new file mode 100644 index 0000000..e2c8f10 --- /dev/null +++ b/django_filters/rest_framework/filters.py @@ -0,0 +1,13 @@ +from django_filters import filters + +from ..filters import * # noqa +from ..widgets import BooleanWidget + +__all__ = filters.__all__ + + +class BooleanFilter(filters.BooleanFilter): + def __init__(self, *args, **kwargs): + kwargs.setdefault("widget", BooleanWidget) + + super().__init__(*args, **kwargs) diff --git a/django_filters/rest_framework/filterset.py b/django_filters/rest_framework/filterset.py new file mode 100644 index 0000000..c27f77b --- /dev/null +++ b/django_filters/rest_framework/filterset.py @@ -0,0 +1,41 @@ +from copy import deepcopy + +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from django_filters import filterset + +from .. import compat +from .filters import BooleanFilter, IsoDateTimeFilter + +FILTER_FOR_DBFIELD_DEFAULTS = deepcopy(filterset.FILTER_FOR_DBFIELD_DEFAULTS) +FILTER_FOR_DBFIELD_DEFAULTS.update( + { + models.DateTimeField: {"filter_class": IsoDateTimeFilter}, + models.BooleanField: {"filter_class": BooleanFilter}, + models.NullBooleanField: {"filter_class": BooleanFilter}, + } +) + + +class FilterSet(filterset.FilterSet): + FILTER_DEFAULTS = FILTER_FOR_DBFIELD_DEFAULTS + + @property + def form(self): + form = super().form + + if compat.is_crispy(): + from crispy_forms.helper import FormHelper + from crispy_forms.layout import Layout, Submit + + layout_components = list(form.fields.keys()) + [ + Submit("", _("Submit"), css_class="btn-default"), + ] + helper = FormHelper() + helper.form_method = "GET" + helper.layout = Layout(*layout_components) + + form.helper = helper + + return form diff --git a/django_filters/templates/django_filters/rest_framework/crispy_form.html b/django_filters/templates/django_filters/rest_framework/crispy_form.html new file mode 100644 index 0000000..171767c --- /dev/null +++ b/django_filters/templates/django_filters/rest_framework/crispy_form.html @@ -0,0 +1,5 @@ +{% load crispy_forms_tags %} +{% load i18n %} + +

{% trans "Field filters" %}

+{% crispy filter.form %} diff --git a/django_filters/templates/django_filters/rest_framework/form.html b/django_filters/templates/django_filters/rest_framework/form.html new file mode 100644 index 0000000..b116e35 --- /dev/null +++ b/django_filters/templates/django_filters/rest_framework/form.html @@ -0,0 +1,6 @@ +{% load i18n %} +

{% trans "Field filters" %}

+
+ {{ filter.form.as_p }} + +
diff --git a/django_filters/templates/django_filters/widgets/multiwidget.html b/django_filters/templates/django_filters/widgets/multiwidget.html new file mode 100644 index 0000000..089ddb2 --- /dev/null +++ b/django_filters/templates/django_filters/widgets/multiwidget.html @@ -0,0 +1 @@ +{% for widget in widget.subwidgets %}{% include widget.template_name %}{% if forloop.first %}-{% endif %}{% endfor %} diff --git a/django_filters/utils.py b/django_filters/utils.py new file mode 100644 index 0000000..9b3f872 --- /dev/null +++ b/django_filters/utils.py @@ -0,0 +1,350 @@ +import datetime +import warnings +from collections import OrderedDict + +import django +from django.conf import settings +from django.core.exceptions import FieldDoesNotExist, FieldError +from django.db import models +from django.db.models.constants import LOOKUP_SEP +from django.db.models.expressions import Expression +from django.db.models.fields.related import ForeignObjectRel, RelatedField +from django.utils import timezone +from django.utils.encoding import force_str +from django.utils.text import capfirst +from django.utils.translation import gettext as _ + +from .exceptions import FieldLookupError + + +def deprecate(msg, level_modifier=0): + warnings.warn(msg, MigrationNotice, stacklevel=3 + level_modifier) + + +class MigrationNotice(DeprecationWarning): + url = "https://django-filter.readthedocs.io/en/main/guide/migration.html" + + def __init__(self, message): + super().__init__("%s See: %s" % (message, self.url)) + + +class RenameAttributesBase(type): + """ + Handles the deprecation paths when renaming an attribute. + + It does the following: + - Defines accessors that redirect to the renamed attributes. + - Complain whenever an old attribute is accessed. + + This is conceptually based on `django.utils.deprecation.RenameMethodsBase`. + """ + + renamed_attributes = () + + def __new__(metacls, name, bases, attrs): + # remove old attributes before creating class + old_names = [r[0] for r in metacls.renamed_attributes] + old_names = [name for name in old_names if name in attrs] + old_attrs = {name: attrs.pop(name) for name in old_names} + + # get a handle to any accessors defined on the class + cls_getattr = attrs.pop("__getattr__", None) + cls_setattr = attrs.pop("__setattr__", None) + + new_class = super().__new__(metacls, name, bases, attrs) + + def __getattr__(self, name): + name = type(self).get_name(name) + if cls_getattr is not None: + return cls_getattr(self, name) + elif hasattr(super(new_class, self), "__getattr__"): + return super(new_class, self).__getattr__(name) + return self.__getattribute__(name) + + def __setattr__(self, name, value): + name = type(self).get_name(name) + if cls_setattr is not None: + return cls_setattr(self, name, value) + return super(new_class, self).__setattr__(name, value) + + new_class.__getattr__ = __getattr__ + new_class.__setattr__ = __setattr__ + + # set renamed attributes + for name, value in old_attrs.items(): + setattr(new_class, name, value) + + return new_class + + def get_name(metacls, name): + """ + Get the real attribute name. If the attribute has been renamed, + the new name will be returned and a deprecation warning issued. + """ + for renamed_attribute in metacls.renamed_attributes: + old_name, new_name, deprecation_warning = renamed_attribute + + if old_name == name: + warnings.warn( + "`%s.%s` attribute should be renamed `%s`." + % (metacls.__name__, old_name, new_name), + deprecation_warning, + 3, + ) + return new_name + + return name + + def __getattr__(metacls, name): + return super().__getattribute__(metacls.get_name(name)) + + def __setattr__(metacls, name, value): + return super().__setattr__(metacls.get_name(name), value) + + +def try_dbfield(fn, field_class): + """ + Try ``fn`` with the DB ``field_class`` by walking its + MRO until a result is found. + + ex:: + _try_dbfield(field_dict.get, models.CharField) + + """ + # walk the mro, as field_class could be a derived model field. + for cls in field_class.mro(): + # skip if cls is models.Field + if cls is models.Field: + continue + + data = fn(cls) + if data: + return data + + +def get_all_model_fields(model): + opts = model._meta + + return [ + f.name + for f in sorted(opts.fields + opts.many_to_many) + if not isinstance(f, models.AutoField) + and not (getattr(f.remote_field, "parent_link", False)) + ] + + +def get_model_field(model, field_name): + """ + Get a ``model`` field, traversing relationships + in the ``field_name``. + + ex:: + + f = get_model_field(Book, 'author__first_name') + + """ + fields = get_field_parts(model, field_name) + return fields[-1] if fields else None + + +def get_field_parts(model, field_name): + """ + Get the field parts that represent the traversable relationships from the + base ``model`` to the final field, described by ``field_name``. + + ex:: + + >>> parts = get_field_parts(Book, 'author__first_name') + >>> [p.verbose_name for p in parts] + ['author', 'first name'] + + """ + parts = field_name.split(LOOKUP_SEP) + opts = model._meta + fields = [] + + # walk relationships + for name in parts: + try: + field = opts.get_field(name) + except FieldDoesNotExist: + return None + + fields.append(field) + try: + if isinstance(field, RelatedField): + opts = field.remote_field.model._meta + elif isinstance(field, ForeignObjectRel): + opts = field.related_model._meta + except AttributeError: + # Lazy relationships are not resolved until registry is populated. + raise RuntimeError( + "Unable to resolve relationship `%s` for `%s`. Django is most " + "likely not initialized, and its apps registry not populated. " + "Ensure Django has finished setup before loading `FilterSet`s." + % (field_name, model._meta.label) + ) + + return fields + + +def resolve_field(model_field, lookup_expr): + """ + Resolves a ``lookup_expr`` into its final output field, given + the initial ``model_field``. The lookup expression should only contain + transforms and lookups, not intermediary model field parts. + + Note: + This method is based on django.db.models.sql.query.Query.build_lookup + + For more info on the lookup API: + https://docs.djangoproject.com/en/stable/ref/models/lookups/ + + """ + query = model_field.model._default_manager.all().query + lhs = Expression(model_field) + lookups = lookup_expr.split(LOOKUP_SEP) + + assert len(lookups) > 0 + + try: + while lookups: + name = lookups[0] + args = (lhs, name) + # If there is just one part left, try first get_lookup() so + # that if the lhs supports both transform and lookup for the + # name, then lookup will be picked. + if len(lookups) == 1: + final_lookup = lhs.get_lookup(name) + if not final_lookup: + # We didn't find a lookup. We are going to interpret + # the name as transform, and do an Exact lookup against + # it. + lhs = query.try_transform(*args) + final_lookup = lhs.get_lookup("exact") + return lhs.output_field, final_lookup.lookup_name + lhs = query.try_transform(*args) + lookups = lookups[1:] + except FieldError as e: + raise FieldLookupError(model_field, lookup_expr) from e + + +def handle_timezone(value, is_dst=None): + if settings.USE_TZ and timezone.is_naive(value): + # On pre-5.x versions, the default is to use zoneinfo, but pytz + # is still available under USE_DEPRECATED_PYTZ, and is_dst is + # meaningful there. Under those versions we should only use is_dst + # if USE_DEPRECATED_PYTZ is present and True; otherwise, we will cause + # deprecation warnings, and we should not. See #1580. + # + # This can be removed once 4.2 is no longer supported upstream. + if django.VERSION < (5, 0) and settings.USE_DEPRECATED_PYTZ: + return timezone.make_aware(value, timezone.get_current_timezone(), is_dst) + return timezone.make_aware(value, timezone.get_current_timezone()) + elif not settings.USE_TZ and timezone.is_aware(value): + return timezone.make_naive(value, datetime.timezone.utc) + return value + + +def verbose_field_name(model, field_name): + """ + Get the verbose name for a given ``field_name``. The ``field_name`` + will be traversed across relationships. Returns '[invalid name]' for + any field name that cannot be traversed. + + ex:: + + >>> verbose_field_name(Article, 'author__name') + 'author name' + + """ + if field_name is None: + return "[invalid name]" + + parts = get_field_parts(model, field_name) + if not parts: + return "[invalid name]" + + names = [] + for part in parts: + if isinstance(part, ForeignObjectRel): + if part.related_name: + names.append(part.related_name.replace("_", " ")) + else: + return "[invalid name]" + else: + names.append(force_str(part.verbose_name)) + + return " ".join(names) + + +def verbose_lookup_expr(lookup_expr): + """ + Get a verbose, more humanized expression for a given ``lookup_expr``. + Each part in the expression is looked up in the ``FILTERS_VERBOSE_LOOKUPS`` + dictionary. Missing keys will simply default to itself. + + ex:: + + >>> verbose_lookup_expr('year__lt') + 'year is less than' + + # with `FILTERS_VERBOSE_LOOKUPS = {}` + >>> verbose_lookup_expr('year__lt') + 'year lt' + + """ + from .conf import settings as app_settings + + VERBOSE_LOOKUPS = app_settings.VERBOSE_LOOKUPS or {} + lookups = [ + force_str(VERBOSE_LOOKUPS.get(lookup, _(lookup))) + for lookup in lookup_expr.split(LOOKUP_SEP) + ] + + return " ".join(lookups) + + +def label_for_filter(model, field_name, lookup_expr, exclude=False): + """ + Create a generic label suitable for a filter. + + ex:: + + >>> label_for_filter(Article, 'author__name', 'in') + 'auther name is in' + + """ + name = verbose_field_name(model, field_name) + verbose_expression = [_("exclude"), name] if exclude else [name] + + # iterable lookups indicate a LookupTypeField, which should not be verbose + if isinstance(lookup_expr, str): + verbose_expression += [verbose_lookup_expr(lookup_expr)] + + verbose_expression = [force_str(part) for part in verbose_expression if part] + verbose_expression = capfirst(" ".join(verbose_expression)) + + return verbose_expression + + +def translate_validation(error_dict): + """ + Translate a Django ErrorDict into its DRF ValidationError. + """ + # it's necessary to lazily import the exception, as it can otherwise create + # an import loop when importing django_filters inside the project settings. + from rest_framework.exceptions import ErrorDetail, ValidationError + + exc = OrderedDict( + ( + key, + [ + ErrorDetail(e.message % (e.params or ()), code=e.code) + for e in error_list + ], + ) + for key, error_list in error_dict.as_data().items() + ) + + return ValidationError(exc) diff --git a/django_filters/views.py b/django_filters/views.py new file mode 100644 index 0000000..c24f9ab --- /dev/null +++ b/django_filters/views.py @@ -0,0 +1,129 @@ +from django.core.exceptions import ImproperlyConfigured +from django.views.generic import View +from django.views.generic.list import ( + MultipleObjectMixin, + MultipleObjectTemplateResponseMixin, +) + +from .constants import ALL_FIELDS +from .filterset import filterset_factory + + +class FilterMixin: + """ + A mixin that provides a way to show and handle a FilterSet in a request. + """ + + filterset_class = None + filterset_fields = ALL_FIELDS + strict = True + + def get_filterset_class(self): + """ + Returns the filterset class to use in this view + """ + if self.filterset_class: + return self.filterset_class + elif self.model: + return filterset_factory(model=self.model, fields=self.filterset_fields) + else: + msg = "'%s' must define 'filterset_class' or 'model'" + raise ImproperlyConfigured(msg % self.__class__.__name__) + + def get_filterset(self, filterset_class): + """ + Returns an instance of the filterset to be used in this view. + """ + kwargs = self.get_filterset_kwargs(filterset_class) + return filterset_class(**kwargs) + + def get_filterset_kwargs(self, filterset_class): + """ + Returns the keyword arguments for instantiating the filterset. + """ + kwargs = { + "data": self.request.GET or None, + "request": self.request, + } + try: + kwargs.update( + { + "queryset": self.get_queryset(), + } + ) + except ImproperlyConfigured: + # ignore the error here if the filterset has a model defined + # to acquire a queryset from + if filterset_class._meta.model is None: + msg = ( + "'%s' does not define a 'model' and the view '%s' does " + "not return a valid queryset from 'get_queryset'. You " + "must fix one of them." + ) + args = (filterset_class.__name__, self.__class__.__name__) + raise ImproperlyConfigured(msg % args) + return kwargs + + def get_strict(self): + return self.strict + + +class BaseFilterView(FilterMixin, MultipleObjectMixin, View): + def get(self, request, *args, **kwargs): + filterset_class = self.get_filterset_class() + self.filterset = self.get_filterset(filterset_class) + + if ( + not self.filterset.is_bound + or self.filterset.is_valid() + or not self.get_strict() + ): + self.object_list = self.filterset.qs + else: + self.object_list = self.filterset.queryset.none() + + context = self.get_context_data( + filter=self.filterset, object_list=self.object_list + ) + return self.render_to_response(context) + + +class FilterView(MultipleObjectTemplateResponseMixin, BaseFilterView): + """ + Render some list of objects with filter, set by `self.model` or + `self.queryset`. + `self.queryset` can actually be any iterable of items, not just a queryset. + """ + + template_name_suffix = "_filter" + + +def object_filter( + request, + model=None, + queryset=None, + template_name=None, + extra_context=None, + context_processors=None, + filter_class=None, +): + class ECFilterView(FilterView): + """Handle the extra_context from the functional object_filter view""" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + extra_context = self.kwargs.get("extra_context") or {} + for k, v in extra_context.items(): + if callable(v): + v = v() + context[k] = v + return context + + kwargs = dict( + model=model, + queryset=queryset, + template_name=template_name, + filterset_class=filter_class, + ) + view = ECFilterView.as_view(**kwargs) + return view(request, extra_context=extra_context) diff --git a/django_filters/widgets.py b/django_filters/widgets.py new file mode 100644 index 0000000..f5c99b1 --- /dev/null +++ b/django_filters/widgets.py @@ -0,0 +1,270 @@ +from collections.abc import Iterable +from copy import deepcopy +from itertools import chain +from re import search, sub + +from django import forms +from django.db.models.fields import BLANK_CHOICE_DASH +from django.forms.utils import flatatt +from django.utils.datastructures import MultiValueDict +from django.utils.encoding import force_str +from django.utils.http import urlencode +from django.utils.safestring import mark_safe +from django.utils.translation import gettext as _ + + +class LinkWidget(forms.Widget): + def __init__(self, attrs=None, choices=()): + super().__init__(attrs) + + self.choices = choices + + def value_from_datadict(self, data, files, name): + value = super().value_from_datadict(data, files, name) + self.data = data + return value + + def render(self, name, value, attrs=None, choices=(), renderer=None): + if not hasattr(self, "data"): + self.data = {} + if value is None: + value = "" + final_attrs = self.build_attrs(self.attrs, extra_attrs=attrs) + output = ["" % flatatt(final_attrs)] + options = self.render_options(choices, [value], name) + if options: + output.append(options) + output.append("") + return mark_safe("\n".join(output)) + + def render_options(self, choices, selected_choices, name): + selected_choices = set(force_str(v) for v in selected_choices) + output = [] + for option_value, option_label in chain(self.choices, choices): + if isinstance(option_label, (list, tuple)): + for option in option_label: + output.append(self.render_option(name, selected_choices, *option)) + else: + output.append( + self.render_option( + name, selected_choices, option_value, option_label + ) + ) + return "\n".join(output) + + def render_option(self, name, selected_choices, option_value, option_label): + option_value = force_str(option_value) + if option_label == BLANK_CHOICE_DASH[0][1]: + option_label = _("All") + data = self.data.copy() + data[name] = option_value + selected = data == self.data or option_value in selected_choices + try: + url = data.urlencode() + except AttributeError: + url = urlencode(data) + return self.option_string() % { + "attrs": selected and ' class="selected"' or "", + "query_string": url, + "label": force_str(option_label), + } + + def option_string(self): + return '
  • %(label)s
  • ' + + +class SuffixedMultiWidget(forms.MultiWidget): + """ + A MultiWidget that allows users to provide custom suffixes instead of indexes. + + - Suffixes must be unique. + - There must be the same number of suffixes as fields. + """ + + suffixes = [] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + assert len(self.widgets) == len(self.suffixes) + assert len(self.suffixes) == len(set(self.suffixes)) + + def suffixed(self, name, suffix): + return "_".join([name, suffix]) if suffix else name + + def get_context(self, name, value, attrs): + context = super().get_context(name, value, attrs) + for subcontext, suffix in zip(context["widget"]["subwidgets"], self.suffixes): + subcontext["name"] = self.suffixed(name, suffix) + + return context + + def value_from_datadict(self, data, files, name): + return [ + widget.value_from_datadict(data, files, self.suffixed(name, suffix)) + for widget, suffix in zip(self.widgets, self.suffixes) + ] + + def value_omitted_from_data(self, data, files, name): + return all( + widget.value_omitted_from_data(data, files, self.suffixed(name, suffix)) + for widget, suffix in zip(self.widgets, self.suffixes) + ) + + def replace_name(self, output, index): + result = search(r'name="(?P.*)_%d"' % index, output) + name = result.group("name") + name = self.suffixed(name, self.suffixes[index]) + name = 'name="%s"' % name + + return sub(r'name=".*_%d"' % index, name, output) + + def decompress(self, value): + if value is None: + return [None, None] + return value + + +class RangeWidget(SuffixedMultiWidget): + template_name = "django_filters/widgets/multiwidget.html" + suffixes = ["min", "max"] + + def __init__(self, attrs=None): + widgets = (forms.TextInput, forms.TextInput) + super().__init__(widgets, attrs) + + def decompress(self, value): + if value: + return [value.start, value.stop] + return [None, None] + + +class DateRangeWidget(RangeWidget): + suffixes = ["after", "before"] + + +class LookupChoiceWidget(SuffixedMultiWidget): + suffixes = [None, "lookup"] + + def decompress(self, value): + if value is None: + return [None, None] + return value + + +class BooleanWidget(forms.Select): + """Convert true/false values into the internal Python True/False. + This can be used for AJAX queries that pass true/false from JavaScript's + internal types through. + """ + + def __init__(self, attrs=None): + choices = (("", _("Unknown")), ("true", _("Yes")), ("false", _("No"))) + super().__init__(attrs, choices) + + def render(self, name, value, attrs=None, renderer=None): + try: + value = {True: "true", False: "false", "1": "true", "0": "false"}[value] + except KeyError: + value = "" + return super().render(name, value, attrs, renderer=renderer) + + def value_from_datadict(self, data, files, name): + value = data.get(name, None) + if isinstance(value, str): + value = value.lower() + + return { + "1": True, + "0": False, + "true": True, + "false": False, + True: True, + False: False, + }.get(value, None) + + +class BaseCSVWidget(forms.Widget): + # Surrogate widget for rendering multiple values + surrogate = forms.TextInput + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + if isinstance(self.surrogate, type): + self.surrogate = self.surrogate() + else: + self.surrogate = deepcopy(self.surrogate) + + def _isiterable(self, value): + return isinstance(value, Iterable) and not isinstance(value, str) + + def value_from_datadict(self, data, files, name): + value = super().value_from_datadict(data, files, name) + + if value is not None: + if value == "": # empty value should parse as an empty list + return [] + if isinstance(value, list): + # since django.forms.widgets.SelectMultiple tries to use getlist + # if available, we should return value if it's already an array + return value + return value.split(",") + return None + + def render(self, name, value, attrs=None, renderer=None): + if not self._isiterable(value): + value = [value] + + if len(value) <= 1: + # delegate to main widget (Select, etc...) if not multiple values + value = value[0] if value else "" + return super().render(name, value, attrs, renderer=renderer) + + # if we have multiple values, we need to force render as a text input + # (otherwise, the additional values are lost) + value = [force_str(self.surrogate.format_value(v)) for v in value] + value = ",".join(list(value)) + + return self.surrogate.render(name, value, attrs, renderer=renderer) + + +class CSVWidget(BaseCSVWidget, forms.TextInput): + def __init__(self, *args, attrs=None, **kwargs): + super().__init__(*args, attrs, **kwargs) + + if attrs is not None: + self.surrogate.attrs.update(attrs) + + +class QueryArrayWidget(BaseCSVWidget, forms.TextInput): + """ + Enables request query array notation that might be consumed by MultipleChoiceFilter + + 1. Values can be provided as csv string: ?foo=bar,baz + 2. Values can be provided as query array: ?foo[]=bar&foo[]=baz + 3. Values can be provided as query array: ?foo=bar&foo=baz + + Note: Duplicate and empty values are skipped from results + """ + + def value_from_datadict(self, data, files, name): + if not isinstance(data, MultiValueDict): + data = data.copy() + for key, value in data.items(): + # treat value as csv string: ?foo=1,2 + if isinstance(value, str): + data[key] = [x.strip() for x in value.rstrip(",").split(",") if x] + data = MultiValueDict(data) + + values_list = data.getlist(name, data.getlist("%s[]" % name)) or [] + + # apparently its an array, so no need to process it's values as csv + # ?foo=1&foo=2 -> data.getlist(foo) -> foo = [1, 2] + # ?foo[]=1&foo[]=2 -> data.getlist(foo[]) -> foo = [1, 2] + if len(values_list) > 0: + ret = [x for x in values_list if x] + else: + ret = [] + + return list(set(ret))