mirror of
https://github.com/SectorLabs/django-localized-fields.git
synced 2025-04-24 19:32:53 +03:00
Add sphinx based docs
This commit is contained in:
parent
7bf0311306
commit
cdf1831d35
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build/
|
20
docs/Makefile
Normal file
20
docs/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
35
docs/make.bat
Normal file
35
docs/make.bat
Normal file
@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
BIN
docs/source/_static/django_admin_widget.png
Normal file
BIN
docs/source/_static/django_admin_widget.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 57 KiB |
10
docs/source/conf.py
Normal file
10
docs/source/conf.py
Normal file
@ -0,0 +1,10 @@
|
||||
import sphinx_rtd_theme
|
||||
|
||||
project = 'django-localized-fields'
|
||||
copyright = '2019, Sector Labs'
|
||||
author = 'Sector Labs'
|
||||
extensions = ["sphinx_rtd_theme"]
|
||||
templates_path = ['_templates']
|
||||
exclude_patterns = []
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_static_path = ['_static']
|
100
docs/source/constraints.rst
Normal file
100
docs/source/constraints.rst
Normal file
@ -0,0 +1,100 @@
|
||||
.. _unique_together: https://docs.djangoproject.com/en/2.2/ref/models/options/#unique-together
|
||||
|
||||
Constraints
|
||||
===========
|
||||
|
||||
All constraints are enforced by PostgreSQL. Constraints can be applied to all fields documented in :ref:`Fields <fields>`.
|
||||
|
||||
.. warning::
|
||||
|
||||
Don't forget to run ``python manage.py makemigrations`` after modifying constraints.
|
||||
|
||||
Required/optional
|
||||
-----------------
|
||||
|
||||
|
||||
* Default language required and all other languages optional:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField()
|
||||
|
||||
|
||||
* All languages are optional and the field itself can be ``None``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(blank=True, null=True, required=False)
|
||||
|
||||
* All languages are optional but the field itself cannot be ``None``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(blank=False, null=False, required=False)
|
||||
|
||||
|
||||
* Make specific languages required:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(blank=False, null=False, required=['en', 'ro'])
|
||||
|
||||
|
||||
* Make all languages required:
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(blank=False, null=False, required=True)
|
||||
|
||||
|
||||
Uniqueness
|
||||
----------
|
||||
|
||||
.. note::
|
||||
|
||||
Uniqueness is enforced by PostgreSQL by creating unique indexes on hstore keys. Keep this is mind when setting up unique constraints. If you already have a unique constraint in place, you do not have to add an additional index as uniqueness is enforced by creating an index.
|
||||
|
||||
|
||||
* Enforce uniqueness for one or more languages:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(uniqueness=['en', 'ro'])
|
||||
|
||||
|
||||
* Enforce uniqueness for all languages:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.util import get_language_codes
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(uniqueness=get_language_codes())
|
||||
|
||||
|
||||
* Enforce uniqueness for one or more languages together:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(uniqueness=[('en', 'ro')])
|
||||
|
||||
This is similar to Django's `unique_together`_.
|
||||
|
||||
|
||||
* Enforce uniqueness for all languages together:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.util import get_language_codes
|
||||
|
||||
class MyModel(models.Model):
|
||||
title = LocalizedField(uniqueness=[(*get_language_codes())])
|
19
docs/source/django_admin.rst
Normal file
19
docs/source/django_admin.rst
Normal file
@ -0,0 +1,19 @@
|
||||
Django Admin
|
||||
------------
|
||||
|
||||
To display ``LocalizedFields`` as a tab bar in Django Admin; inherit your admin model class from ``LocalizedFieldsAdminMixin``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.contrib import admin
|
||||
from myapp.models import MyLocalizedModel
|
||||
|
||||
from localized_fields.admin import LocalizedFieldsAdminMixin
|
||||
|
||||
class MyLocalizedModelAdmin(LocalizedFieldsAdminMixin, admin.ModelAdmin):
|
||||
"""Any admin options you need go here"""
|
||||
|
||||
admin.site.register(MyLocalizedModel, MyLocalizedModelAdmin)
|
||||
|
||||
|
||||
.. image:: _static/django_admin_widget.png
|
99
docs/source/fields.rst
Normal file
99
docs/source/fields.rst
Normal file
@ -0,0 +1,99 @@
|
||||
.. _django.db.models.CharField: https://docs.djangoproject.com/en/2.2/ref/models/fields/#charfield
|
||||
.. _django.db.models.TextField: https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.TextField
|
||||
.. _django.db.models.IntegerField: https://docs.djangoproject.com/en/2.2/ref/models/fields/#integerfield
|
||||
.. _django.db.models.FileField: https://docs.djangoproject.com/en/2.2/ref/models/fields/#filefield
|
||||
|
||||
.. _fields:
|
||||
|
||||
Localized fields
|
||||
================
|
||||
|
||||
LocalizedField
|
||||
--------------
|
||||
|
||||
Base localized fields. Stores content as strings of arbitrary lengths.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
LocalizedCharField
|
||||
------------------
|
||||
|
||||
Localized version of `django.db.models.CharField`_.
|
||||
|
||||
Use this for single-line text content. Uses ``<input type="text" />`` when rendered as a widget.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.fields import LocalizedCharField
|
||||
|
||||
Follows the same convention as `django.db.models.CharField`_ to store empty strings for "no data" and not NULL.
|
||||
|
||||
|
||||
LocalizedTextField
|
||||
------------------
|
||||
|
||||
Localized version of `django.db.models.TextField`_.
|
||||
|
||||
Use this for multi-line text content.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.fields import LocalizedTextField
|
||||
|
||||
Follows the same convention as `django.db.models.TextField`_ to store empty strings for "no data" and not NULL.
|
||||
|
||||
|
||||
LocalizedFileField
|
||||
------------------
|
||||
|
||||
Localized version of `django.db.models.FileField`_.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.fields import LocalizedFileField
|
||||
|
||||
def my_directory_path(instance, filename, lang):
|
||||
# file will be uploaded to MEDIA_ROOT/<lang>/<id>_<filename>
|
||||
return '{0}/{0}_{1}'.format(lang, instance.id, filename)
|
||||
|
||||
class MyModel(models.Model):
|
||||
file1 = LocalizedFileField(upload_to='uploads/{lang}/')
|
||||
file2 = LocalizedFileField(upload_to=my_directory_path)
|
||||
|
||||
|
||||
The ``upload_to`` supports the ``{lang}}`` placeholder for string formatting or as function argument (in case if upload_to is a callable).
|
||||
|
||||
In a template, you can access the files for different languages:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
{# For current active language: #}
|
||||
|
||||
{{ model.file.url }} {# output file url #}
|
||||
{{ model.file.name }} {# output file name #}
|
||||
|
||||
{# Or get it in a specific language: #}
|
||||
|
||||
{{ model.file.ro.url }} {# output file url for romanian language #}
|
||||
{{ model.file.ro.name }} {# output file name for romanian language #}
|
||||
|
||||
To get the file instance for the current language:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
model.file.localized()
|
||||
|
||||
|
||||
LocalizedIntegerField
|
||||
---------------------
|
||||
|
||||
Localized version of `django.db.models.IntegerField`_.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.fields import LocalizedIntegerField
|
||||
|
||||
Although the underlying PostgreSQL data type for ``LocalizedField`` is hstore (which only stores strings). ``LocalizedIntegerField`` takes care of making sure that input values are integers and casts the values back to integers when querying them.
|
44
docs/source/filtering.rst
Normal file
44
docs/source/filtering.rst
Normal file
@ -0,0 +1,44 @@
|
||||
Filtering localized content
|
||||
===========================
|
||||
|
||||
.. note::
|
||||
|
||||
All examples below assume a model declared like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.models import LocalizedModel
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
class MyModel(LocalizedModel):
|
||||
title = LocalizedField()
|
||||
|
||||
|
||||
Active language
|
||||
----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils import translation
|
||||
|
||||
# filter in english
|
||||
translation.activate("en")
|
||||
MyModel.objects.filter(title="test")
|
||||
|
||||
# filter in dutch
|
||||
translation.activate("nl")
|
||||
MyModel.objects.filter(title="test")
|
||||
|
||||
|
||||
Specific language
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
MyModel.objects.filter(title__en="test")
|
||||
MyModel.objects.filter(title__nl="test")
|
||||
|
||||
# do it dynamically, where the language code is a var
|
||||
lang_code = "nl"
|
||||
MyModel.objects.filter(**{"title_%s" % lang_code: "test"})
|
22
docs/source/index.rst
Normal file
22
docs/source/index.rst
Normal file
@ -0,0 +1,22 @@
|
||||
Welcome
|
||||
=======
|
||||
|
||||
``django-localized-fields`` is a Django library that provides fields to store localized content (content in various languages) in a PostgreSQL database. It does this by utilizing the PostgreSQL ``hstore`` type, which is available in Django as ``HStoreField`` since Django 1.10.
|
||||
|
||||
This package requires Python 3.7 or newer, Django 2.0 or newer and PostgreSQL 10 or newer.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Overview
|
||||
|
||||
installation
|
||||
quick_start
|
||||
constraints
|
||||
fields
|
||||
saving
|
||||
querying
|
||||
filtering
|
||||
localized_value
|
||||
django_admin
|
||||
settings
|
||||
releases
|
73
docs/source/installation.rst
Normal file
73
docs/source/installation.rst
Normal file
@ -0,0 +1,73 @@
|
||||
.. _installation:
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
1. Install the package from PyPi:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install django-localized-fields
|
||||
|
||||
2. Add ``django.contrib.postgres``, ``psqlextra`` and ``localized_fields`` to your ``INSTALLED_APPS``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
"django.contrib.postgres",
|
||||
"psqlextra",
|
||||
"localized_fields",
|
||||
]
|
||||
|
||||
|
||||
3. Set the database engine to ``psqlextra.backend``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
...
|
||||
"ENGINE": "psqlextra.backend",
|
||||
],
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
Already using a custom back-end? Set ``POSTGRES_EXTRA_DB_BACKEND_BASE`` to your custom back-end. See django-postgres-extra's documentation for more details: `Using a custom database back-end <https://django-postgres-extra.readthedocs.io/db-engine/#using-a-custom-database-back-end>`_.
|
||||
|
||||
4. Set ``LANGUAGES`` and ``LANGUAGE_CODE``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
LANGUAGE_CODE = "en" # default language
|
||||
LANGUAGES = (
|
||||
("en", "English"), # default language
|
||||
("ar", "Arabic"),
|
||||
("ro", "Romanian"),
|
||||
)
|
||||
|
||||
|
||||
.. warning::
|
||||
|
||||
Make sure that the language specified in ``LANGUAGE_CODE`` is the first language in the ``LANGUAGES`` list. Django and many third party packages assume that the default language is the first one in the list.
|
||||
|
||||
5. Apply migrations to enable the HStore extension:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ python manage.py migrate
|
||||
|
||||
.. note::
|
||||
|
||||
Migrations might fail to be applied if the PostgreSQL user applying the migration is not a super user. Enabling/creating extensions requires superuser permission. Not a superuser? Ask your database administrator to create the ``hstore`` extension on your PostgreSQL server manually using the following statement:
|
||||
|
||||
.. code-block:: sql
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS hstore;
|
||||
|
||||
Then, fake apply the migration to tell Django that the migration was applied already:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
python manage.py migrate localized_fields --fake
|
79
docs/source/localized_value.rst
Normal file
79
docs/source/localized_value.rst
Normal file
@ -0,0 +1,79 @@
|
||||
Working with localized values
|
||||
=============================
|
||||
|
||||
.. note::
|
||||
|
||||
All examples below assume a model declared like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.models import LocalizedModel
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
class MyModel(LocalizedModel):
|
||||
title = LocalizedField()
|
||||
|
||||
Localized content is represented by ``localized_fields.value.LocalizedValue``. Which is essentially a dictionary where the key is the language and the value the content in the respective language.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.value import LocalizedValue
|
||||
|
||||
obj = MyModel.objects.first()
|
||||
assert isistance(obj.title, LocalizedValue) # True
|
||||
|
||||
|
||||
With fallback
|
||||
-------------
|
||||
|
||||
.. seealso::
|
||||
|
||||
Configure :ref:`LOCALIZED_FIELDS_FALLBACKS <LOCALIZED_FIELDS_FALLBACKS>` to control the fallback behaviour.
|
||||
|
||||
|
||||
Active language
|
||||
***************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# gets content in Arabic, falls back to next language
|
||||
# if not availble
|
||||
translation.activate('ar')
|
||||
obj.title.translate()
|
||||
|
||||
# alternative: cast to string
|
||||
title_ar = str(obj.title)
|
||||
|
||||
|
||||
Specific language
|
||||
*****************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# gets content in Arabic, falls back to next language
|
||||
# if not availble
|
||||
obj.title.translate('ar')
|
||||
|
||||
|
||||
Without fallback
|
||||
----------------
|
||||
|
||||
Specific language
|
||||
*****************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# gets content in Dutch, None if not available
|
||||
# no fallback to secondary languages here!
|
||||
obj.title.nl
|
||||
|
||||
|
||||
Specific language dynamically
|
||||
*****************************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
# gets content in Dutch, None if not available
|
||||
# no fallback to secondary languages here!
|
||||
obj.title.get('nl')
|
59
docs/source/querying.rst
Normal file
59
docs/source/querying.rst
Normal file
@ -0,0 +1,59 @@
|
||||
Querying localized content
|
||||
==========================
|
||||
|
||||
.. note::
|
||||
|
||||
All examples below assume a model declared like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.models import LocalizedModel
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
class MyModel(LocalizedModel):
|
||||
title = LocalizedField()
|
||||
|
||||
|
||||
Active language
|
||||
---------------
|
||||
|
||||
Only need a value in a specific language? Use the ``LocalizedRef`` expression to query a value in the currently active language:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.expressions import LocalizedRef
|
||||
|
||||
MyModel.objects.create(title=dict(en="Hello", nl="Hallo"))
|
||||
|
||||
translation.activate("nl")
|
||||
english_title = (
|
||||
MyModel
|
||||
.objects
|
||||
.annotate(title=LocalizedRef("title"))
|
||||
.values_list("title", flat=True)
|
||||
.first()
|
||||
)
|
||||
|
||||
print(english_title) # prints "Hallo"
|
||||
|
||||
|
||||
Specific language
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.expressions import LocalizedRef
|
||||
|
||||
result = (
|
||||
MyModel
|
||||
.objects
|
||||
.values(
|
||||
'title__en',
|
||||
'title__nl',
|
||||
)
|
||||
.first()
|
||||
)
|
||||
|
||||
print(result['title__en'])
|
||||
print(result['title__nl'])
|
140
docs/source/quick_start.rst
Normal file
140
docs/source/quick_start.rst
Normal file
@ -0,0 +1,140 @@
|
||||
.. _django.utils.translation.override: https://docs.djangoproject.com/en/2.2/ref/utils/#django.utils.translation.override
|
||||
.. _django.db.models.TextField: https://docs.djangoproject.com/en/2.2/ref/models/fields/#django.db.models.TextField
|
||||
.. _LANGUAGES: https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-LANGUAGE_CODE
|
||||
.. _LANGUAGE_CODE: https://docs.djangoproject.com/en/2.2/ref/settings/#languages
|
||||
|
||||
Quick start
|
||||
===========
|
||||
|
||||
.. warning::
|
||||
|
||||
This assumes you have followed the :ref:`Installation guide <installation>`.
|
||||
|
||||
``django-localized-fields`` provides various model field types to store content in multiple languages. The most basic of them all is ``LocalizedField`` which stores text of arbitrary length (like `django.db.models.TextField`_).
|
||||
|
||||
Declaring a model
|
||||
-----------------
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.models import LocalizedModel
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
class MyModel(LocalizedModel):
|
||||
title = LocalizedField()
|
||||
|
||||
|
||||
This creates a model with one localized field. Inside the ``LocalizedField``, strings can be stored in multiple languages. There are more fields like this for different data types (integers, images etc). ``LocalizedField`` is the most basic of them all.
|
||||
|
||||
Saving localized content
|
||||
------------------------
|
||||
|
||||
You can now save text in ``MyModel.title`` in all languages you defined in the `LANGUAGES`_ setting. A short example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
newobj = MyModel()
|
||||
newobj.title.en = "Hello"
|
||||
newobj.title.ar = "مرحبا"
|
||||
newobj.title.nl = "Hallo"
|
||||
newobj.save()
|
||||
|
||||
There are various other ways of saving localized content. For example, all fields can be set at once by assigning a ``dict``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
newobj = MyModel()
|
||||
newobj.title = dict(en="Hello", ar="مرحبا", nl="Hallo")
|
||||
newobj.save()
|
||||
|
||||
This also works when using the ``create`` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
newobj = MyModel.objects.create(title=dict(en="Hello", ar="مرحبا", nl="Hallo"))
|
||||
|
||||
Need to set the content dynamically? Use the ``set`` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
newobj = MyModel()
|
||||
newobj.title.set("en", "Hello")
|
||||
|
||||
.. note::
|
||||
|
||||
Localized field values (``localized_fields.value.LocalizedValue``) act like dictionaries. In fact, ``LocalizedValue`` extends ``dict``. Anything that works on a ``dict`` works on ``LocalizedValue``.
|
||||
|
||||
Retrieving localized content
|
||||
----------------------------
|
||||
|
||||
When querying, the currently active language is taken into account. If there is no active language set, the default language is returned (set by the `LANGUAGE_CODE`_ setting).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils import translation
|
||||
|
||||
obj = MyModel.objects.first()
|
||||
|
||||
print(obj.title) # prints "Hello"
|
||||
|
||||
translation.activate("ar")
|
||||
print(obj.title) # prints "مرحبا"
|
||||
str(obj.title) # same as printing, forces translation to active language
|
||||
|
||||
translation.activate("nl")
|
||||
print(obj.title) # prints "Hallo"
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Use `django.utils.translation.override`_ to change the language for just a block of code rather than setting the language globally:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.utils import translation
|
||||
|
||||
with translation.override("nl"):
|
||||
print(obj.title) # prints "Hallo"
|
||||
|
||||
|
||||
Fallback
|
||||
********
|
||||
|
||||
If there is no content for the currently active language, a fallback kicks in where the content will be returned in the next language. The fallback order is controlled by the order set in the `LANGUAGES`_ setting.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel.objects.create(dict(en="Hallo", ar="مرحبا"))
|
||||
|
||||
translation.activate("nl")
|
||||
print(obj.title) # prints "مرحبا" because there"s no content in NL
|
||||
|
||||
.. seealso::
|
||||
|
||||
Use the :ref:`LOCALIZED_FIELDS_FALLBACKS <LOCALIZED_FIELDS_FALLBACKS>` setting to control the fallback behaviour.
|
||||
|
||||
|
||||
Cast to str
|
||||
***********
|
||||
|
||||
Want to get the value in the currently active language without casting to ``str``? (For null-able fields for example). Use the ``.translate()`` function:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel.objects.create(dict(en="Hallo", ar="مرحبا"))
|
||||
|
||||
str(obj.title) == obj.title.translate() # True
|
||||
|
||||
.. note::
|
||||
|
||||
``str(..)`` is guarenteed to return a string. If the value is ``None``, ``str(..)`` returns an empty string. ``translate()`` would return ``None``. This is because Python forces the ``__str__`` function to return a string.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel.objects.create(dict(en="Hallo"))
|
||||
|
||||
translation.activate('nl')
|
||||
|
||||
str(obj.title) # ""
|
||||
obj.title.translate() # None
|
17
docs/source/releases.rst
Normal file
17
docs/source/releases.rst
Normal file
@ -0,0 +1,17 @@
|
||||
Releases
|
||||
========
|
||||
|
||||
v6.0
|
||||
----
|
||||
|
||||
Breaking changes
|
||||
****************
|
||||
|
||||
* Removes support for Python 3.6 and earlier.
|
||||
* Removes support for PostgreSQL 9.6 and earlier.
|
||||
* Sets ``LOCALIZED_FIELDS_EXPERIMENTAL`` to ``True`` by default.
|
||||
|
||||
Bug fixes
|
||||
*********
|
||||
|
||||
* Fixes a bug where ``LocalizedIntegerField`` could not be used in ``order_by``.
|
82
docs/source/saving.rst
Normal file
82
docs/source/saving.rst
Normal file
@ -0,0 +1,82 @@
|
||||
Saving localized content
|
||||
========================
|
||||
|
||||
.. note::
|
||||
|
||||
All examples below assume a model declared like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from localized_fields.models import LocalizedModel
|
||||
from localized_fields.fields import LocalizedField
|
||||
|
||||
|
||||
class MyModel(LocalizedModel):
|
||||
title = LocalizedField()
|
||||
|
||||
|
||||
Individual assignment
|
||||
*********************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel()
|
||||
obj.title.en = 'Hello'
|
||||
obj.title.nl = 'Hallo'
|
||||
obj.save()
|
||||
|
||||
|
||||
Individual dynamic assignment
|
||||
*****************************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel()
|
||||
obj.title.set('en', 'Hello')
|
||||
obj.title.set('nl', 'Hallo')
|
||||
obj.save()
|
||||
|
||||
|
||||
Multiple assignment
|
||||
*******************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel()
|
||||
obj.title = dict(en='Hello', nl='Hallo')
|
||||
obj.save()
|
||||
|
||||
obj = MyModel(title=dict(en='Hello', nl='Hallo'))
|
||||
obj.save()
|
||||
|
||||
obj = MyModel.objects.create(title=dict(en='Hello', nl='Hallo'))
|
||||
|
||||
|
||||
Default language assignment
|
||||
***************************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel()
|
||||
obj.title = 'Hello' # assumes value is in default language
|
||||
obj.save()
|
||||
|
||||
obj = MyModel(title='Hello') # assumes value is in default language
|
||||
obj.save()
|
||||
|
||||
obj = MyModel.objects.create(title='title') # assumes value is in default language
|
||||
|
||||
|
||||
Array assignment
|
||||
****************
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
obj = MyModel()
|
||||
obj.title = ['Hello', 'Hallo'] # order according to LANGUAGES
|
||||
obj.save()
|
||||
|
||||
obj = MyModel(title=['Hello', 'Hallo']) # order according to LANGUAGES
|
||||
obj.save()
|
||||
|
||||
obj = MyModel.objects.create(title=['Hello', 'Hallo']) # order according to LANGUAGES
|
39
docs/source/settings.rst
Normal file
39
docs/source/settings.rst
Normal file
@ -0,0 +1,39 @@
|
||||
.. _LANGUAGES: https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-LANGUAGE_CODE
|
||||
.. _LANGUAGE_CODE: https://docs.djangoproject.com/en/2.2/ref/settings/#languages
|
||||
|
||||
Settings
|
||||
========
|
||||
|
||||
.. LOCALIZED_FIELDS_EXPERIMENTAL:
|
||||
|
||||
* ``LOCALIZED_FIELDS_EXPERIMENTAL``
|
||||
|
||||
.. note::
|
||||
|
||||
Disabled in v5.x and earlier. Enabled by default since v6.0.
|
||||
|
||||
When enabled:
|
||||
|
||||
* ``LocalizedField`` will return ``None`` instead of an empty ``LocalizedValue`` if there is no database value.
|
||||
* ``LocalizedField`` lookups will by the currently active language instead of an exact match by dict.
|
||||
|
||||
|
||||
.. _LOCALIZED_FIELDS_FALLBACKS:
|
||||
|
||||
* ``LOCALIZED_FIELDS_FALLBACKS``
|
||||
|
||||
List of language codes which define the order in which fallbacks should happen. If a value is not available in a specific language, we'll try to pick the value in the next language in the list.
|
||||
|
||||
.. warning::
|
||||
|
||||
If this setting is not configured, the default behaviour is to fall back to the value in the **default language**. It is recommended to configure this setting to get predictible fallback behaviour that suits your use case.
|
||||
|
||||
Use the same language codes as you used for configuring the `LANGUAGES`_ and `LANGUAGE_CODE`_ setting.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
LOCALIZED_FIELDS_FALLBACKS = {
|
||||
"en": ["nl", "ar"], # if trying to get EN, but not available, try NL and then AR
|
||||
"nl": ["en", "ar"], # if trying to get NL, but not available, try EN and then AR
|
||||
"ar": ["en", "nl"], # if trying to get AR, but not available, try EN and then NL
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user