django-parler


Namedjango-parler JSON
Version 2.3 PyPI version JSON
download
home_pagehttps://github.com/edoburu/django-parler
SummarySimple Django model translations without nasty hacks, featuring nice admin integration.
upload_time2021-11-18 09:32:28
maintainer
docs_urlNone
authorDiederik van der Boor
requires_python
licenseApache 2.0
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage
            .. image:: https://github.com/django-parler/django-parler/actions/workflows/tests.yaml/badge.svg
    :target: https://github.com/django-parler/django-parler/actions/workflows/tests.yaml
.. image:: https://readthedocs.org/projects/django-parler/badge/?version=stable
    :target: https://django-parler.readthedocs.io/en/stable/
.. image:: https://img.shields.io/pypi/v/django-parler.svg
    :target: https://pypi.python.org/pypi/django-parler/
.. image:: https://img.shields.io/pypi/l/django-parler.svg
    :target: https://pypi.python.org/pypi/django-parler/
.. image:: https://img.shields.io/codecov/c/github/django-parler/django-parler/master.svg
    :target: https://codecov.io/github/django-parler/django-parler?branch=master


django-parler
=============

Simple Django model translations without nasty hacks.

Features:

* Nice admin integration.
* Access translated attributes like regular attributes.
* Automatic fallback to the default language.
* Separate table for translated fields, compatible with django-hvad_.
* Plays nice with others, compatible with django-polymorphic_, django-mptt_ and such:

  * No ORM query hacks.
  * Easy to combine with custom Manager or QuerySet classes.
  * Easy to construct the translations model manually when needed.

See the documentation_ for more details.


A brief overview
================

Installing django-parler
------------------------

The package can be installed using:

.. code-block:: bash

    pip install django-parler

Add the following settings:

.. code-block:: python

    INSTALLED_APPS += (
        'parler',
    )

Optionally, the admin tabs can be configured too:

.. code-block:: python

    PARLER_LANGUAGES = {
        None: (
            {'code': 'en',},
            {'code': 'en-us',},
            {'code': 'it',},
            {'code': 'nl',},
        ),
        'default': {
            'fallback': 'en',             # defaults to PARLER_DEFAULT_LANGUAGE_CODE
            'hide_untranslated': False,   # the default; let .active_translations() return fallbacks too.
        }
    }

Replace ``None`` with the ``SITE_ID`` when you run a multi-site project with the sites framework.
Each ``SITE_ID`` can be added as additional entry in the dictionary.

Make sure your project is configured for multiple languages.
It might be useful to limit the ``LANGUAGES`` setting. For example:

.. code-block:: python

    from django.utils.translation import gettext_lazy as _

    LANGUAGE_CODE = 'en'

    LANGUAGES = (
        ('en', _("English")),
        ('en-us', _("US English")),
        ('it', _('Italian')),
        ('nl', _('Dutch')),
        ('fr', _('French')),
        ('es', _('Spanish')),
    )

By default, the fallback language is the same as ``LANGUAGE_CODE``.
The fallback language can be changed in the settings:

.. code-block:: python

    PARLER_DEFAULT_LANGUAGE_CODE = 'en'


Creating models
---------------

Using the ``TranslatedFields`` wrapper, model fields can be marked as translatable:

.. code-block:: python

    from django.db import models
    from parler.models import TranslatableModel, TranslatedFields

    class MyModel(TranslatableModel):
        translations = TranslatedFields(
            title = models.CharField(_("Title"), max_length=200)
        )

        def __unicode__(self):
            return self.title

Accessing fields
----------------

Translatable fields can be used like regular fields:

.. code-block:: python

    >>> object = MyModel.objects.all()[0]
    >>> object.get_current_language()
    'en'
    >>> object.title
    u'cheese omelet'

    >>> object.set_current_language('fr')       # Only switches
    >>> object.title = "omelette du fromage"    # Translation is created on demand.
    >>> object.save()

Internally, django-parler stores the translated fields in a separate model, with one row per language.

Filtering translations
----------------------

To query translated fields, use the ``.translated()`` method:

.. code-block:: python

    MyObject.objects.translated(title='cheese omelet')

To access objects in both the current and possibly the fallback language, use:

.. code-block:: python

    MyObject.objects.active_translations(title='cheese omelet')

This returns objects in the languages which are considered "active", which are:

* The current language
* The fallback language when ``hide_untranslated=False`` in the ``PARLER_LANGUAGES`` setting.


Changing the language
---------------------

The queryset can be instructed to return objects in a specific language:

.. code-block:: python

    >>> objects = MyModel.objects.language('fr').all()
    >>> objects[0].title
    u'omelette du fromage'

This only sets the language of the object.
By default, the current Django language is used.

Use ``object.get_current_language()`` and ``object.set_current_language()``
to change the language on individual objects.
There is a context manager to do this temporary:

.. code-block:: python

    from parler.utils.context import switch_language

    with switch_language(model, 'fr'):
        print model.title

And a function to query just a specific field:

.. code-block:: python

    model.safe_translation_getter('title', language_code='fr')


Advanced Features
-----------------

This package also includes:

* Creating the ``TranslatedFieldsModel`` manually!
* Form classes for inline support.
* View classes for switching languages, creating/updating translatable objects.
* Template tags for language switching-buttons.
* ORM methods to handle the translated fields.
* Admin inlines support.

See the documentation_ for more details.


Special notes
=============

* Using ``ModelAdmin.prepopulated_fields`` doesn't work, but you can use ``get_prepopulated_fields()`` as workaround.
* Due to `ORM restrictions <https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships>`_
  queries for translated fields should be performed in a single ``.translated(..)`` or ``.active_translations(..)`` call.
* The ``.active_translations(..)`` method typically needs to ``.distinct()`` call to avoid duplicate results of the same object.


TODO
====

* The list code currently performs one query per object. This needs to be reduced.
* Preferably, the ``TranslatedField`` proxy on the model should behave like a ``RelatedField``,
  if that would nicely with the ORM too.

Please contribute your improvements or work on these area's!


Contributing
============

This module is designed to be generic. In case there is anything you didn't like about it,
or think it's not flexible enough, please let us know. We'd love to improve it!

If you have any other valuable contribution, suggestion or idea,
please let us know as well because we will look into it.
Pull requests are welcome too. :-)


.. _django-hvad: https://github.com/kristianoellegaard/django-hvad
.. _django-mptt: https://github.com/django-mptt/django-mptt
.. _django-fluent-pages: https://github.com/edoburu/django-fluent-pages
.. _django-polymorphic: https://github.com/django-polymorphic/django-polymorphic
.. _documentation: https://django-parler.readthedocs.io/



            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/edoburu/django-parler",
    "name": "django-parler",
    "maintainer": "",
    "docs_url": null,
    "requires_python": "",
    "maintainer_email": "",
    "keywords": "",
    "author": "Diederik van der Boor",
    "author_email": "opensource@edoburu.nl",
    "download_url": "https://files.pythonhosted.org/packages/8c/2b/2423d31620efe8ab0d0390e60afab4f9cc2e62d4bf39fe0e05df0eef1b93/django-parler-2.3.tar.gz",
    "platform": "",
    "description": ".. image:: https://github.com/django-parler/django-parler/actions/workflows/tests.yaml/badge.svg\n    :target: https://github.com/django-parler/django-parler/actions/workflows/tests.yaml\n.. image:: https://readthedocs.org/projects/django-parler/badge/?version=stable\n    :target: https://django-parler.readthedocs.io/en/stable/\n.. image:: https://img.shields.io/pypi/v/django-parler.svg\n    :target: https://pypi.python.org/pypi/django-parler/\n.. image:: https://img.shields.io/pypi/l/django-parler.svg\n    :target: https://pypi.python.org/pypi/django-parler/\n.. image:: https://img.shields.io/codecov/c/github/django-parler/django-parler/master.svg\n    :target: https://codecov.io/github/django-parler/django-parler?branch=master\n\n\ndjango-parler\n=============\n\nSimple Django model translations without nasty hacks.\n\nFeatures:\n\n* Nice admin integration.\n* Access translated attributes like regular attributes.\n* Automatic fallback to the default language.\n* Separate table for translated fields, compatible with django-hvad_.\n* Plays nice with others, compatible with django-polymorphic_, django-mptt_ and such:\n\n  * No ORM query hacks.\n  * Easy to combine with custom Manager or QuerySet classes.\n  * Easy to construct the translations model manually when needed.\n\nSee the documentation_ for more details.\n\n\nA brief overview\n================\n\nInstalling django-parler\n------------------------\n\nThe package can be installed using:\n\n.. code-block:: bash\n\n    pip install django-parler\n\nAdd the following settings:\n\n.. code-block:: python\n\n    INSTALLED_APPS += (\n        'parler',\n    )\n\nOptionally, the admin tabs can be configured too:\n\n.. code-block:: python\n\n    PARLER_LANGUAGES = {\n        None: (\n            {'code': 'en',},\n            {'code': 'en-us',},\n            {'code': 'it',},\n            {'code': 'nl',},\n        ),\n        'default': {\n            'fallback': 'en',             # defaults to PARLER_DEFAULT_LANGUAGE_CODE\n            'hide_untranslated': False,   # the default; let .active_translations() return fallbacks too.\n        }\n    }\n\nReplace ``None`` with the ``SITE_ID`` when you run a multi-site project with the sites framework.\nEach ``SITE_ID`` can be added as additional entry in the dictionary.\n\nMake sure your project is configured for multiple languages.\nIt might be useful to limit the ``LANGUAGES`` setting. For example:\n\n.. code-block:: python\n\n    from django.utils.translation import gettext_lazy as _\n\n    LANGUAGE_CODE = 'en'\n\n    LANGUAGES = (\n        ('en', _(\"English\")),\n        ('en-us', _(\"US English\")),\n        ('it', _('Italian')),\n        ('nl', _('Dutch')),\n        ('fr', _('French')),\n        ('es', _('Spanish')),\n    )\n\nBy default, the fallback language is the same as ``LANGUAGE_CODE``.\nThe fallback language can be changed in the settings:\n\n.. code-block:: python\n\n    PARLER_DEFAULT_LANGUAGE_CODE = 'en'\n\n\nCreating models\n---------------\n\nUsing the ``TranslatedFields`` wrapper, model fields can be marked as translatable:\n\n.. code-block:: python\n\n    from django.db import models\n    from parler.models import TranslatableModel, TranslatedFields\n\n    class MyModel(TranslatableModel):\n        translations = TranslatedFields(\n            title = models.CharField(_(\"Title\"), max_length=200)\n        )\n\n        def __unicode__(self):\n            return self.title\n\nAccessing fields\n----------------\n\nTranslatable fields can be used like regular fields:\n\n.. code-block:: python\n\n    >>> object = MyModel.objects.all()[0]\n    >>> object.get_current_language()\n    'en'\n    >>> object.title\n    u'cheese omelet'\n\n    >>> object.set_current_language('fr')       # Only switches\n    >>> object.title = \"omelette du fromage\"    # Translation is created on demand.\n    >>> object.save()\n\nInternally, django-parler stores the translated fields in a separate model, with one row per language.\n\nFiltering translations\n----------------------\n\nTo query translated fields, use the ``.translated()`` method:\n\n.. code-block:: python\n\n    MyObject.objects.translated(title='cheese omelet')\n\nTo access objects in both the current and possibly the fallback language, use:\n\n.. code-block:: python\n\n    MyObject.objects.active_translations(title='cheese omelet')\n\nThis returns objects in the languages which are considered \"active\", which are:\n\n* The current language\n* The fallback language when ``hide_untranslated=False`` in the ``PARLER_LANGUAGES`` setting.\n\n\nChanging the language\n---------------------\n\nThe queryset can be instructed to return objects in a specific language:\n\n.. code-block:: python\n\n    >>> objects = MyModel.objects.language('fr').all()\n    >>> objects[0].title\n    u'omelette du fromage'\n\nThis only sets the language of the object.\nBy default, the current Django language is used.\n\nUse ``object.get_current_language()`` and ``object.set_current_language()``\nto change the language on individual objects.\nThere is a context manager to do this temporary:\n\n.. code-block:: python\n\n    from parler.utils.context import switch_language\n\n    with switch_language(model, 'fr'):\n        print model.title\n\nAnd a function to query just a specific field:\n\n.. code-block:: python\n\n    model.safe_translation_getter('title', language_code='fr')\n\n\nAdvanced Features\n-----------------\n\nThis package also includes:\n\n* Creating the ``TranslatedFieldsModel`` manually!\n* Form classes for inline support.\n* View classes for switching languages, creating/updating translatable objects.\n* Template tags for language switching-buttons.\n* ORM methods to handle the translated fields.\n* Admin inlines support.\n\nSee the documentation_ for more details.\n\n\nSpecial notes\n=============\n\n* Using ``ModelAdmin.prepopulated_fields`` doesn't work, but you can use ``get_prepopulated_fields()`` as workaround.\n* Due to `ORM restrictions <https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships>`_\n  queries for translated fields should be performed in a single ``.translated(..)`` or ``.active_translations(..)`` call.\n* The ``.active_translations(..)`` method typically needs to ``.distinct()`` call to avoid duplicate results of the same object.\n\n\nTODO\n====\n\n* The list code currently performs one query per object. This needs to be reduced.\n* Preferably, the ``TranslatedField`` proxy on the model should behave like a ``RelatedField``,\n  if that would nicely with the ORM too.\n\nPlease contribute your improvements or work on these area's!\n\n\nContributing\n============\n\nThis module is designed to be generic. In case there is anything you didn't like about it,\nor think it's not flexible enough, please let us know. We'd love to improve it!\n\nIf you have any other valuable contribution, suggestion or idea,\nplease let us know as well because we will look into it.\nPull requests are welcome too. :-)\n\n\n.. _django-hvad: https://github.com/kristianoellegaard/django-hvad\n.. _django-mptt: https://github.com/django-mptt/django-mptt\n.. _django-fluent-pages: https://github.com/edoburu/django-fluent-pages\n.. _django-polymorphic: https://github.com/django-polymorphic/django-polymorphic\n.. _documentation: https://django-parler.readthedocs.io/\n\n\n",
    "bugtrack_url": null,
    "license": "Apache 2.0",
    "summary": "Simple Django model translations without nasty hacks, featuring nice admin integration.",
    "version": "2.3",
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "md5": "947362e6859184f51aaf164e7c950302",
                "sha256": "8f6c8061e4b5690f1ee2d8e5760940ef06bf78a5bfa033d11178377559c749cf"
            },
            "downloads": -1,
            "filename": "django_parler-2.3-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "947362e6859184f51aaf164e7c950302",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 83288,
            "upload_time": "2021-11-18T09:32:27",
            "upload_time_iso_8601": "2021-11-18T09:32:27.193523Z",
            "url": "https://files.pythonhosted.org/packages/47/38/11f1a7e3d56f3a6b74cf99e307f2554b741cadebc9b1c45b05e2ec1f35a2/django_parler-2.3-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "md5": "e8aa8477d698cfffa1b458476153fd41",
                "sha256": "2c8f5012ceb5e49af93b16ea3fe4d0c83d70b91b2d0f470c05d7d742b6f3083d"
            },
            "downloads": -1,
            "filename": "django-parler-2.3.tar.gz",
            "has_sig": false,
            "md5_digest": "e8aa8477d698cfffa1b458476153fd41",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 69167,
            "upload_time": "2021-11-18T09:32:28",
            "upload_time_iso_8601": "2021-11-18T09:32:28.959971Z",
            "url": "https://files.pythonhosted.org/packages/8c/2b/2423d31620efe8ab0d0390e60afab4f9cc2e62d4bf39fe0e05df0eef1b93/django-parler-2.3.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2021-11-18 09:32:28",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "github_user": "edoburu",
    "github_project": "django-parler",
    "travis_ci": false,
    "coveralls": true,
    "github_actions": true,
    "tox": true,
    "lcname": "django-parler"
}
        
Elapsed time: 0.04151s