# djangocms-xliff
[](https://github.com/energie360/djangocms-xliff/actions/workflows/tests.yaml)
[](https://pypi.org/project/djangocms-xliff)
XLIFF (XML Localization Interchange File Format) is an XML-based format created
to standardize the way localizable data are passed between and among tools during a localization process.
With djangocms-xliff it is possible to export all text objects from a page into an XLIFF-compatible file and re-import
the file at the end of the translation process.
## Migration to django-cms 5
If you are using djangocms-xliff with django-cms version 3 or lower use the v1 release of this package:
```shell
pip install djangocms-xliff==1.*.*
```
*We are not planning to support this package for django-cms version 3 or lower*
Please upgrade to a v2 release if you are using django-cms version 5 or higher
## Installation
Before the installation you need to make sure, that your
localization / internalization are set up properly
for [Django](https://docs.djangoproject.com/en/dev/topics/i18n/translation/)
and [Django-CMS](https://docs.django-cms.org/en/latest/topics/i18n.html)
### Setup
djangocms-xliff is available on [PyPI](https://pypi.org/project/djangocms-xliff/):
```shell
$ pip install djangocms-xliff
```
Add `djangocms_xliff` to your `INSTALLED_APPS`.
```python
INSTALLED_APPS = (
...,
"djangocms_xliff"
)
```
Add the views for `djangocms_xliff` to your `urls.py`
```python
urlpatterns = [
path("xliff/", include("djangocms_xliff.urls"))
]
```
## Documentation
To make the process fail-safe there are some Django CMS related restrictions:
* You can only import the file to the same page and language that you exported from before.
* It is not possible to export a file for one language and import it to another language.
* It is not possible to add fields during the translation process. (Missing fields will be ignored.)
This is because the reference for an entity is the unique ID of the Django CMS plugin, and each plugin has its own
unique ID for each page and language.
Therefore, you need to follow these steps to work with djangocms-xliff.
### Step-by-step
If the page does not exist yet in the target language, create it and copy the plugins from the page with the source
plugins.
Go to the page in the target language.
Export the XLIFF file at Language > Export as XLIFF…

This will generate an XLIFF file in the following format:
```xml
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" version="1.2">
<file original="verbund/meilen/projekt" datatype="plaintext" source-language="fr" target-language="en">
<tool tool-id="96" tool-name="djangocms_xliff" tool-company-name="Energie 360°"/>
<body>
<trans-unit id="5872__title" resname="5872__title" maxwidth="60" size-unit="char"
extype="django.db.models.fields.CharField">
<source><![CDATA[The project in short]]></source>
<target><![CDATA[]]></target>
<note>CarouselTripleBlockWrapperPlugin</note>
<note>Carousel Triple Block</note>
<note>Titel</note>
<note>Max characters: 60</note>
</trans-unit>
<trans-unit id="5874__title" resname="5874__title" maxwidth="35" size-unit="char"
extype="django.db.models.fields.CharField">
<source><![CDATA[Practical Solution]]></source>
<target><![CDATA[]]></target>
<note>CarouselTripleBlockSlidePlugin</note>
<note>Slide</note>
<note>Titel</note>
<note>Max characters: 35</note>
</trans-unit>
</body>
</file>
</xliff>
```
Edit the file in the XLIFF editor of your choice.
Import the XLIFF to the same page in the same language you exported from with Languages > Import from XLIFF

You will get a preview of the import that needs to be confirmed.

The translations are now imported, and you can publish the page.
## Settings
By default, djangocms-xliff searches for the following django model fields: `CharField, SlugField, TextField, URLField`
in your
plugins.
The texts from these fields will be used for the XLIFF import and export.
If you want to add additional or 3rd party app fields, you can define the following settings in your `settings.py`,
to integrate them into the XLIFF package:
```python
# A list of fields, that will be searched for while exporting.
DJANGOCMS_XLIFF_FIELDS = (
"djangocms_text_ckeditor.fields.HTMLField",
)
```
```python
# List of tuples with field and custom function for the export
DJANGOCMS_XLIFF_FIELD_EXTRACTORS = (
("third_party.models.LinkField", "your_module.xliff.link_field_extractor"),
)
# The signature of the extractor function must be the following:
# The source parameter is the same as getattr(instance, field.name)
def link_field_extractor(instance: CMSPlugin, field: LinkField, source: Any) -> List[djangocms_xliff.types.Unit]:
# example:
from djangocms_xliff.utils import get_type_with_path
text = source.find_text()
return [
Unit(
plugin_id=str(instance.pk),
plugin_type=instance.plugin_type,
plugin_name=instance.get_plugin_name(),
field_name=field.name,
field_type=get_type_with_path(field),
field_verbose_name=field.verbose_name,
source=text,
max_length=field.max_length,
)
]
```
```python
# List of tuples with field and custom function for the import
DJANGOCMS_XLIFF_FIELD_IMPORTERS = (
("third_party.models.LinkField", "your_module.xliff.link_field_importer"),
)
# The signature of the importer function must be the following:
def link_field_importer(instance: CMSPlugin, unit: djangocms_xliff.types.Unit) -> CMSPlugin:
# example:
field = getattr(instance, unit.field_name)
field.body = unit.target
return instance
```
```python
# List of custom validators for fields that need to be ignored or included in the export
DJANGOCMS_XLIFF_VALIDATORS = ("your_module.xliff.is_not_background",)
# The signature of the validator function must be the following:
def is_not_background(field: django.db.models.Field, instance: CMSPlugin) -> bool:
# example:
return field.name != "background"
```
## Placeholders Outside the CMS
This package does not handle translatability at database level. There are various packages for that. We recommend the
use of `django-modeltranslation`. Because this way import and export of XLIFF works out-of-the-box.
You can import / export any django model with this package. In your admin.py add the following code:
```python
from django.contrib import admin
from djangocms_xliff.admin import XliffImportExportMixin
from magazine.models import Article
@admin.register(Article)
class ArticleAdmin(XliffImportExportMixin, admin.ModelAdmin):
pass
```
You can customize the fields that are exported with the following configuration:
```python
# By default djangocms_xliff.settings.METADATA_FIELDS fields get exported. You can include and exclude fields like this:
DJANGOCMS_XLIFF_MODEL_METADATA_FIELDS = {
'magazine.models.Article': {
"include": {
"lead": _("Lead"),
},
'exclude': ["slug", "og_title", "og_description"]
}
}
```
If you have a custom alias content in your app, you need to set the following setting variable:
```python
DJANGOCMS_XLIFF_MODEL_FOR_ALIAS_CONTENT = "your_module.xliff.get_model_for_alias_content"
# The signature of the path function must be the following:
def get_model_for_alias_content(alias):
if hasattr(alias, "magazine_article"):
return alias.magazine_article
return None
```
You need to make sure that the your model has a `get_absolute_url(language: str)` method for everything to work.
## Contribute
Issues and pull requests are welcomed.
You can find a documentation on how to set up your project
in [here](docs/contribute.md)
Raw data
{
"_id": null,
"home_page": null,
"name": "djangocms-xliff",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.13",
"maintainer_email": "Energie 360 <onlineservice@energie360.ch>",
"keywords": "django, django-cms, export, import, xliff",
"author": null,
"author_email": "Energie 360 <onlineservice@energie360.ch>",
"download_url": "https://files.pythonhosted.org/packages/2f/b6/a5ab08c156850cb4f9bc47205214d0a5cd806ebb5308c5c2d48d95860969/djangocms_xliff-2.0.3.tar.gz",
"platform": null,
"description": "# djangocms-xliff\n\n[](https://github.com/energie360/djangocms-xliff/actions/workflows/tests.yaml)\n[](https://pypi.org/project/djangocms-xliff)\n\n\nXLIFF (XML Localization Interchange File Format) is an XML-based format created\nto standardize the way localizable data are passed between and among tools during a localization process.\n\nWith djangocms-xliff it is possible to export all text objects from a page into an XLIFF-compatible file and re-import\nthe file at the end of the translation process.\n\n## Migration to django-cms 5\n\nIf you are using djangocms-xliff with django-cms version 3 or lower use the v1 release of this package:\n```shell\npip install djangocms-xliff==1.*.*\n```\n\n*We are not planning to support this package for django-cms version 3 or lower*\n\nPlease upgrade to a v2 release if you are using django-cms version 5 or higher\n\n## Installation\n\nBefore the installation you need to make sure, that your\nlocalization / internalization are set up properly\nfor [Django](https://docs.djangoproject.com/en/dev/topics/i18n/translation/)\nand [Django-CMS](https://docs.django-cms.org/en/latest/topics/i18n.html)\n\n### Setup\n\ndjangocms-xliff is available on [PyPI](https://pypi.org/project/djangocms-xliff/):\n\n```shell\n$ pip install djangocms-xliff\n```\n\nAdd `djangocms_xliff` to your `INSTALLED_APPS`.\n\n```python\nINSTALLED_APPS = (\n ...,\n \"djangocms_xliff\"\n)\n```\n\nAdd the views for `djangocms_xliff` to your `urls.py`\n\n```python\nurlpatterns = [\n path(\"xliff/\", include(\"djangocms_xliff.urls\"))\n]\n```\n\n## Documentation\n\nTo make the process fail-safe there are some Django CMS related restrictions:\n\n* You can only import the file to the same page and language that you exported from before.\n* It is not possible to export a file for one language and import it to another language.\n* It is not possible to add fields during the translation process. (Missing fields will be ignored.)\n\nThis is because the reference for an entity is the unique ID of the Django CMS plugin, and each plugin has its own\nunique ID for each page and language.\n\nTherefore, you need to follow these steps to work with djangocms-xliff.\n\n### Step-by-step\n\nIf the page does not exist yet in the target language, create it and copy the plugins from the page with the source\nplugins.\n\nGo to the page in the target language.\n\nExport the XLIFF file at Language > Export as XLIFF\u2026\n\n\n\nThis will generate an XLIFF file in the following format:\n\n```xml\n<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<xliff xmlns=\"urn:oasis:names:tc:xliff:document:1.2\" version=\"1.2\">\n <file original=\"verbund/meilen/projekt\" datatype=\"plaintext\" source-language=\"fr\" target-language=\"en\">\n <tool tool-id=\"96\" tool-name=\"djangocms_xliff\" tool-company-name=\"Energie 360\u00b0\"/>\n <body>\n <trans-unit id=\"5872__title\" resname=\"5872__title\" maxwidth=\"60\" size-unit=\"char\"\n extype=\"django.db.models.fields.CharField\">\n <source><![CDATA[The project in short]]></source>\n <target><![CDATA[]]></target>\n <note>CarouselTripleBlockWrapperPlugin</note>\n <note>Carousel Triple Block</note>\n <note>Titel</note>\n <note>Max characters: 60</note>\n </trans-unit>\n <trans-unit id=\"5874__title\" resname=\"5874__title\" maxwidth=\"35\" size-unit=\"char\"\n extype=\"django.db.models.fields.CharField\">\n <source><![CDATA[Practical Solution]]></source>\n <target><![CDATA[]]></target>\n <note>CarouselTripleBlockSlidePlugin</note>\n <note>Slide</note>\n <note>Titel</note>\n <note>Max characters: 35</note>\n </trans-unit>\n </body>\n </file>\n</xliff>\n```\n\nEdit the file in the XLIFF editor of your choice.\n\nImport the XLIFF to the same page in the same language you exported from with Languages > Import from XLIFF\n\n\n\nYou will get a preview of the import that needs to be confirmed.\n\n\n\nThe translations are now imported, and you can publish the page.\n\n## Settings\n\nBy default, djangocms-xliff searches for the following django model fields: `CharField, SlugField, TextField, URLField`\nin your\nplugins.\nThe texts from these fields will be used for the XLIFF import and export.\n\nIf you want to add additional or 3rd party app fields, you can define the following settings in your `settings.py`,\nto integrate them into the XLIFF package:\n\n```python\n# A list of fields, that will be searched for while exporting.\nDJANGOCMS_XLIFF_FIELDS = (\n \"djangocms_text_ckeditor.fields.HTMLField\",\n)\n```\n\n```python\n# List of tuples with field and custom function for the export\nDJANGOCMS_XLIFF_FIELD_EXTRACTORS = (\n (\"third_party.models.LinkField\", \"your_module.xliff.link_field_extractor\"),\n)\n\n\n# The signature of the extractor function must be the following:\n# The source parameter is the same as getattr(instance, field.name)\ndef link_field_extractor(instance: CMSPlugin, field: LinkField, source: Any) -> List[djangocms_xliff.types.Unit]:\n # example:\n from djangocms_xliff.utils import get_type_with_path\n\n text = source.find_text()\n return [\n Unit(\n plugin_id=str(instance.pk),\n plugin_type=instance.plugin_type,\n plugin_name=instance.get_plugin_name(),\n field_name=field.name,\n field_type=get_type_with_path(field),\n field_verbose_name=field.verbose_name,\n source=text,\n max_length=field.max_length,\n )\n ]\n```\n\n```python\n# List of tuples with field and custom function for the import\nDJANGOCMS_XLIFF_FIELD_IMPORTERS = (\n (\"third_party.models.LinkField\", \"your_module.xliff.link_field_importer\"),\n)\n\n\n# The signature of the importer function must be the following:\ndef link_field_importer(instance: CMSPlugin, unit: djangocms_xliff.types.Unit) -> CMSPlugin:\n # example:\n field = getattr(instance, unit.field_name)\n field.body = unit.target\n return instance\n```\n\n```python\n# List of custom validators for fields that need to be ignored or included in the export\nDJANGOCMS_XLIFF_VALIDATORS = (\"your_module.xliff.is_not_background\",)\n\n\n# The signature of the validator function must be the following:\ndef is_not_background(field: django.db.models.Field, instance: CMSPlugin) -> bool:\n # example:\n return field.name != \"background\"\n```\n\n## Placeholders Outside the CMS\n\nThis package does not handle translatability at database level. There are various packages for that. We recommend the\nuse of `django-modeltranslation`. Because this way import and export of XLIFF works out-of-the-box.\n\nYou can import / export any django model with this package. In your admin.py add the following code:\n\n```python\nfrom django.contrib import admin\nfrom djangocms_xliff.admin import XliffImportExportMixin\n\nfrom magazine.models import Article\n\n\n@admin.register(Article)\nclass ArticleAdmin(XliffImportExportMixin, admin.ModelAdmin):\n pass\n```\n\nYou can customize the fields that are exported with the following configuration:\n\n```python\n# By default djangocms_xliff.settings.METADATA_FIELDS fields get exported. You can include and exclude fields like this:\nDJANGOCMS_XLIFF_MODEL_METADATA_FIELDS = {\n 'magazine.models.Article': {\n \"include\": {\n \"lead\": _(\"Lead\"),\n },\n 'exclude': [\"slug\", \"og_title\", \"og_description\"]\n }\n}\n```\n\nIf you have a custom alias content in your app, you need to set the following setting variable:\n\n```python\nDJANGOCMS_XLIFF_MODEL_FOR_ALIAS_CONTENT = \"your_module.xliff.get_model_for_alias_content\"\n\n\n# The signature of the path function must be the following:\ndef get_model_for_alias_content(alias):\n if hasattr(alias, \"magazine_article\"):\n return alias.magazine_article\n return None\n```\n\nYou need to make sure that the your model has a `get_absolute_url(language: str)` method for everything to work.\n\n## Contribute\n\nIssues and pull requests are welcomed.\n\nYou can find a documentation on how to set up your project\nin [here](docs/contribute.md)\n",
"bugtrack_url": null,
"license": null,
"summary": "XLIFF Import and Export for the Django CMS",
"version": "2.0.3",
"project_urls": {
"Homepage": "https://energie360.ch",
"Repository": "https://github.com/energie360/djangocms-xliff"
},
"split_keywords": [
"django",
" django-cms",
" export",
" import",
" xliff"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8b4aa0f790aa46015b21e2a58d8e114493ba8dcf619edb75102142fa851e8c41",
"md5": "87c51762120edb46d3f70899216c5da2",
"sha256": "4ad7262ddbed2750da98d1c4975a20642cb99c00b5e46ea78c4eaf6644bf79ac"
},
"downloads": -1,
"filename": "djangocms_xliff-2.0.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "87c51762120edb46d3f70899216c5da2",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.13",
"size": 40500,
"upload_time": "2025-10-09T14:38:46",
"upload_time_iso_8601": "2025-10-09T14:38:46.687297Z",
"url": "https://files.pythonhosted.org/packages/8b/4a/a0f790aa46015b21e2a58d8e114493ba8dcf619edb75102142fa851e8c41/djangocms_xliff-2.0.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "2fb6a5ab08c156850cb4f9bc47205214d0a5cd806ebb5308c5c2d48d95860969",
"md5": "18f4f43429829989fa660ff75742c57c",
"sha256": "1975b8f56a5ed02dbcee93bc8021799f860900d195fc1b3672017ab85549c069"
},
"downloads": -1,
"filename": "djangocms_xliff-2.0.3.tar.gz",
"has_sig": false,
"md5_digest": "18f4f43429829989fa660ff75742c57c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.13",
"size": 26432,
"upload_time": "2025-10-09T14:38:47",
"upload_time_iso_8601": "2025-10-09T14:38:47.921776Z",
"url": "https://files.pythonhosted.org/packages/2f/b6/a5ab08c156850cb4f9bc47205214d0a5cd806ebb5308c5c2d48d95860969/djangocms_xliff-2.0.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-09 14:38:47",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "energie360",
"github_project": "djangocms-xliff",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"tox": true,
"lcname": "djangocms-xliff"
}