Compare commits

..

No commits in common. "master" and "v0.8.1" have entirely different histories.

33 changed files with 308 additions and 1177 deletions

9
.gitignore vendored
View file

@ -35,15 +35,6 @@ _build
# GitEye / Eclipse project file
/.project
# PyCharm
/.idea
# vim
*~
*.swp
# vscode
.vscode
# pyenv
.python-version

View file

@ -1,54 +1,47 @@
language: python
python:
- "3.8"
- "3.6"
env:
- WAGTAIL="wagtail>=2.7,<2.8" DB=sqlite
- WAGTAIL="wagtail>=2.0,<2.1" DB=sqlite
matrix:
include:
# Latest Wagtail version
- env: WAGTAIL="wagtail>=2.7,<2.8" DB=postgres
- env: WAGTAIL="wagtail>=2.7,<2.8" DB=mysql
- python: "3.8"
- python: "3.7"
- python: "3.6"
- env: WAGTAIL="wagtail>=2.0,<2.1" DB=sqlite
- env: WAGTAIL="wagtail>=2.0,<2.1" DB=postgres
- env: WAGTAIL="wagtail>=2.0,<2.1" DB=mysql
- python: "3.5"
- python: "3.4"
# Past Wagtail versions
- python: "3.7"
env: WAGTAIL="wagtail>=2.6,<2.7"
- python: "3.7"
env: WAGTAIL="wagtail>=2.5,<2.6"
- python: "3.4" # Wagtail 2.5 was the last to support python 3.4
env: WAGTAIL="wagtail>=2.5,<2.6"
- python: "3.7"
env: WAGTAIL="wagtail>=2.4,<2.5"
- python: "3.7"
env: WAGTAIL="wagtail>=2.3,<2.4"
- python: "3.7"
env: WAGTAIL="wagtail>=2.2,<2.3"
- python: "3.7"
env: WAGTAIL="wagtail>=2.1,<2.2"
- python: "3.7"
env: WAGTAIL="wagtail>=2.0,<2.1"
- python: "3.6"
env: WAGTAIL="wagtail>=1.13,<1.14"
- python: "2.7" # Wagtail 1.13 was the latest tested against 2.7
env: WAGTAIL="wagtail>=1.13,<1.14"
- python: "3.7"
env: WAGTAIL="wagtail>=1.13,<1.14"
- python: "2.7"
- python: "3.6"
env: WAGTAIL="wagtail>=1.12,<1.13"
- python: "3.7"
env: WAGTAIL="wagtail>=1.12,<1.13"
services:
- mysql
- postgresql
addons:
postgresql: "9.4"
- python: "3.6"
env: WAGTAIL="wagtail>=1.11,<1.12"
- python: "3.6"
env: WAGTAIL="wagtail>=1.10,<1.11"
- python: "3.5"
env: WAGTAIL="wagtail>=1.9,<1.10"
- python: "3.3" # Wagtail 1.9 was the latest tested against 3.3
env: WAGTAIL="wagtail>=1.9,<1.10"
- python: "3.5"
env: WAGTAIL="wagtail>=1.8,<1.9"
- python: "3.5"
env: WAGTAIL="wagtail>=1.6,<1.7"
- python: "3.5"
env: WAGTAIL="wagtail>=1.5,<1.6"
- python: "3.5"
env: WAGTAIL="wagtail>=1.4,<1.5"
before_script:
- mysql -e 'create database wagtail_modeltranslation;'
- psql -c 'create database wagtail_modeltranslation;' -U postgres
install:
- pip install --upgrade -q pip setuptools
- if [[ $DB == mysql ]] && [[ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]]; then pip install -q mysql-python; elif [[ $DB == mysql ]] && [[ ${TRAVIS_PYTHON_VERSION:0:1} == "3" ]]; then pip install -q mysqlclient; fi
- if [[ $DB == postgres ]]; then pip install -q 'psycopg2-binary'; fi
- if [[ $DB == postgres ]]; then pip install -q psycopg2; fi
- if [[ $TRAVIS_PYTHON_VERSION == '3.3' ]]; then pip install 'Django>=1.8,<1.9'; fi
- pip install $WAGTAIL
- pip install -e .
script:

View file

@ -22,7 +22,6 @@ Contributors
* Raphael Grill
* Tom Dyson
* Tim Tan
* Benedikt Willi
.. _Django-modeltranslation: https://github.com/deschler/django-modeltranslation

View file

@ -1,11 +1,3 @@
v0.6.0rc2:
- added RichTextFieldPanel to the default list of patched panels
- added settings to allow the patching of custom panels
- slug auto-population is now made the same way as wagtail (no changes in live pages)
- Fixed: When adding a page link in a translated RichTextField the link was always to the default language version of that page
- Fixed: Copy content of streamfield fails with 414 Request-URI Too Long
- Fixed: Panel patching failed with the error "AttributeError: 'list' object has no attribute 'children'"
v0.6.0rc1:
- django-modeltranslation is now a dependency.
- added compatibility with Python 3 (3.3, 3.4, 3.5).

View file

@ -3,6 +3,5 @@ recursive-include docs *.rst conf.py Makefile make.bat
recursive-include wagtail_modeltranslation/static *
recursive-include wagtail_modeltranslation/management *
recursive-include wagtail_modeltranslation/templatetags *
recursive-include wagtail_modeltranslation/templates *
global-exclude *.pyc
global-exclude *.DS_Store

View file

@ -1,43 +0,0 @@
.PHONY: clean-pyc clean-build help test
.DEFAULT_GOAL := help
help: ## print this help screen
@perl -nle'print $& if m{^[a-zA-Z0-9_-]+:.*?## .*$$}' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-25s\033[0m %s\n", $$1, $$2}'
clean: clean-build clean-pyc
@echo "all clean now .."
clean-build: ## remove build artifacts
@rm -fr build/
@rm -fr dist/
@rm -fr htmlcov/
@rm -fr *.egg-info
@rm -rf .coverage
clean-pyc: ## remove Python file artifacts
@find . -name '*.pyc' -exec rm -f {} +
@find . -name '*.pyo' -exec rm -f {} +
@find . -name '*.orig' -exec rm -f {} +
@find . -name '*~' -exec rm -f {} +
release: clean ## package and upload a release (working dir must be clean)
@while true; do \
CURRENT=`python -c "import wagtail_modeltranslation; print(wagtail_modeltranslation.__version__)"`; \
echo ""; \
echo "=== The current version is $$CURRENT - what's the next one?"; \
echo "==========================================================="; \
echo "1 - new major version"; \
echo "2 - new minor version"; \
echo "3 - patch"; \
echo "4 - keep the current version"; \
echo ""; \
read yn; \
case $$yn in \
1 ) bumpversion major; break;; \
2 ) bumpversion minor; break;; \
3 ) bumpversion patch; break;; \
4 ) break;; \
* ) echo "Please answer 1-3.";; \
esac \
done
@python setup.py bdist_wheel && twine upload dist/*

View file

@ -1,6 +1,6 @@
Metadata-Version: 1.0
Name: wagtail-modeltranslation
Version: 0.10.6
Version: 0.8.1
Summary: Translates Wagtail CMS models using a registration approach.
Home-page: https://github.com/infoportugal/wagtail-modeltranslation
Author: InfoPortugal S.A.

11
Pipfile
View file

@ -1,11 +0,0 @@
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[packages]
bumpversion = "*"
wheel = "*"
[dev-packages]
twine = "*"

143
Pipfile.lock generated
View file

@ -1,143 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "191a6f860a13836c57a16587784ceca36f791bfae1270cf937286a496e891114"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"name": "pypi",
"url": "https://pypi.python.org/simple",
"verify_ssl": true
}
]
},
"default": {
"bumpversion": {
"hashes": [
"sha256:6744c873dd7aafc24453d8b6a1a0d6d109faf63cd0cd19cb78fd46e74932c77e",
"sha256:6753d9ff3552013e2130f7bc03c1007e24473b4835952679653fb132367bdd57"
],
"index": "pypi",
"version": "==0.5.3"
},
"wheel": {
"hashes": [
"sha256:5e79117472686ac0c4aef5bad5172ea73a1c2d1646b808c35926bd26bdfb0c08",
"sha256:62fcfa03d45b5b722539ccbc07b190e4bfff4bb9e3a4d470dd9f6a0981002565"
],
"index": "pypi",
"version": "==0.33.4"
}
},
"develop": {
"bleach": {
"hashes": [
"sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16",
"sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"
],
"version": "==3.1.0"
},
"certifi": {
"hashes": [
"sha256:59b7658e26ca9c7339e00f8f4636cdfe59d34fa37b9b04f6f9e9926b3cece1a5",
"sha256:b26104d6835d1f5e49452a26eb2ff87fe7090b89dfcaee5ea2212697e1e1d7ae"
],
"version": "==2019.3.9"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"docutils": {
"hashes": [
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
],
"version": "==0.14"
},
"idna": {
"hashes": [
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
],
"version": "==2.8"
},
"pkginfo": {
"hashes": [
"sha256:7424f2c8511c186cd5424bbf31045b77435b37a8d604990b79d4e70d741148bb",
"sha256:a6d9e40ca61ad3ebd0b72fbadd4fba16e4c0e4df0428c041e01e06eb6ee71f32"
],
"version": "==1.5.0.1"
},
"pygments": {
"hashes": [
"sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
"sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"
],
"version": "==2.4.2"
},
"readme-renderer": {
"hashes": [
"sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f",
"sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d"
],
"version": "==24.0"
},
"requests": {
"hashes": [
"sha256:11e007a8a2aa0323f5a921e9e6a2d7e4e67d9877e85773fba9ba6419025cbeb4",
"sha256:9cf5292fcd0f598c671cfc1e0d7d1a7f13bb8085e9a590f48c010551dc6c4b31"
],
"version": "==2.22.0"
},
"requests-toolbelt": {
"hashes": [
"sha256:380606e1d10dc85c3bd47bf5a6095f815ec007be7a8b69c878507068df059e6f",
"sha256:968089d4584ad4ad7c171454f0a5c6dac23971e9472521ea3b6d49d610aa6fc0"
],
"version": "==0.9.1"
},
"six": {
"hashes": [
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
],
"version": "==1.12.0"
},
"tqdm": {
"hashes": [
"sha256:0a860bf2683fdbb4812fe539a6c22ea3f1777843ea985cb8c3807db448a0f7ab",
"sha256:e288416eecd4df19d12407d0c913cbf77aa8009d7fddb18f632aded3bdbdda6b"
],
"version": "==4.32.1"
},
"twine": {
"hashes": [
"sha256:0fb0bfa3df4f62076cab5def36b1a71a2e4acb4d1fa5c97475b048117b1a6446",
"sha256:d6c29c933ecfc74e9b1d9fa13aa1f87c5d5770e119f5a4ce032092f0ff5b14dc"
],
"index": "pypi",
"version": "==1.13.0"
},
"urllib3": {
"hashes": [
"sha256:b246607a25ac80bedac05c6f282e3cdaf3afb65420fd024ac94435cabe6e18d1",
"sha256:dbe59173209418ae49d485b87d1681aefa36252ee85884c31346debd19463232"
],
"version": "==1.25.3"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
}
}
}

View file

@ -58,7 +58,6 @@ Quick start
...
'wagtail_modeltranslation',
'wagtail_modeltranslation.makemigrations',
'wagtail_modeltranslation.migrate',
)
3. Add 'django.middleware.locale.LocaleMiddleware' to ``MIDDLEWARE`` on your ``settings.py``::

View file

@ -7,7 +7,7 @@ Installation
Requirements
============
* Wagtail >= 1.12
* Wagtail >= 1.4
@ -48,7 +48,6 @@ To setup the application please follow these steps:
...
'wagtail_modeltranslation',
'wagtail_modeltranslation.makemigrations',
'wagtail_modeltranslation.migrate',
)
- Add 'django.middleware.locale.LocaleMiddleware' to ``MIDDLEWARE`` (``MIDDLEWARE_CLASSES`` before django 1.10).
@ -89,7 +88,7 @@ To setup the application please follow these steps:
To learn more about preparing Wagtail for Internationalisation check the `Wagtail i18n docs <http://docs.wagtail.io/en/latest/advanced_topics/i18n/>`_.
2. Create a ``translation.py`` file in your app directory and register ``TranslationOptions`` for every model you want to translate and for all subclasses of Page model.
2. Create a ``translation.py`` file in your app directory and register ``TranslationOptions`` for every model you want to translate.
.. code-block:: console

View file

@ -28,15 +28,3 @@ This setting behaves as the above but should be used for panels that are compose
.. code-block:: python
WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS = ['app_x.module_y.PanelZ']
``WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Default: ``True``
This setting makes slug and url_path localized. If True, each page will have a slug and url_path per language.
.. code-block:: python
WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS = True

View file

@ -5,7 +5,10 @@ import sys
import django
from django.conf import settings
from django.core.management import call_command
from wagtail import VERSION
try:
from wagtail import VERSION
except ImportError:
VERSION = 1, 6, 3 # assume it's 1.6.3, the latest version without VERSION
def runtests():
@ -33,7 +36,7 @@ def runtests():
# Configure test environment
import wagtail
if VERSION < (2,):
if VERSION[0] < 2:
WAGTAIL_MODULES = [
'wagtail.wagtailcore',
'wagtail.wagtailadmin',
@ -68,7 +71,7 @@ def runtests():
]
WAGTAIL_CORE = 'wagtail.core'
settings.configure(
DATABASES=DATABASES,
INSTALLED_APPS=[
@ -90,7 +93,8 @@ def runtests():
MIDDLEWARE_CLASSES=(),
)
django.setup()
if django.VERSION >= (1, 7):
django.setup()
failures = call_command(
'test', 'wagtail_modeltranslation', interactive=False, failfast=False, verbosity=2)

View file

@ -1,7 +0,0 @@
[bumpversion]
current_version = 0.10.6
commit = True
tag = True
[bumpversion:file:wagtail_modeltranslation/__init__.py]

View file

@ -1,24 +1,9 @@
#!/usr/bin/env python
import re
import os
from setuptools import setup
def get_version(*file_paths):
filename = os.path.join(os.path.dirname(__file__), *file_paths)
version_file = open(filename).read()
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
if version_match:
return version_match.group(1)
raise RuntimeError('Please assure that the package version is defined as "__version__ = x.x.x" in ' + filename)
version = get_version("wagtail_modeltranslation", "__init__.py")
setup(
name='wagtail-modeltranslation',
version=version,
version='0.8.1',
description='Translates Wagtail CMS models using a registration approach.',
long_description=(
'The modeltranslation application can be used to translate dynamic '
@ -44,18 +29,18 @@ setup(
'wagtail_modeltranslation.migrate.management',
'wagtail_modeltranslation.migrate.management.commands'],
package_data={'wagtail_modeltranslation': ['static/wagtail_modeltranslation/css/*.css',
'static/wagtail_modeltranslation/js/*.js',
'templates/*.html']},
install_requires=['wagtail>=1.12', 'django-modeltranslation>=0.13'],
'static/wagtail_modeltranslation/js/*.js']},
install_requires=[
'wagtail(>=1.4,<2)', 'django-modeltranslation(>=0.12.2)'],
download_url='https://github.com/infoportugal/wagtail-modeltranslation/archive/v0.8.tar.gz',
classifiers=[
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.2',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Operating System :: OS Independent',
'Environment :: Web Environment',
'Intended Audience :: Developers',

323
tox.ini
View file

@ -1,217 +1,158 @@
[tox]
envlist =
py38-2.7.X,
py37-2.7.X,
py36-2.7.X,
py35-2.7.X,
py34-2.7.X,
py37-2.6.X,
py36-2.6.X,
py35-2.6.X,
py37-2.5.X,
py36-2.5.X,
py35-2.5.X,
py34-2.5.X,
py37-2.4.X,
py36-2.4.X,
py35-2.4.X,
py34-2.4.X,
py36-2.3.X,
py35-2.3.X,
py34-2.3.X,
py36-2.2.X,
py35-2.2.X,
py34-2.2.X,
py36-2.1.X,
py35-2.1.X,
py34-2.1.X,
py36-2.0.X,
py35-2.0.X,
py34-2.0.X,
py36-1.13.X,
py35-1.13.X,
py34-1.13.X,
py27-1.13.X,
py36-1.12.X,
py35-1.12.X,
py34-1.12.X,
py27-1.12.X,
py35-1.9.X,
py34-1.9.X,
py33-1.9.X,
py27-1.9.X,
py35-1.8.X,
py34-1.8.X,
py33-1.8.X,
py27-1.8.X,
py35-1.7.X,
py34-1.7.X,
py33-1.7.X,
py27-1.7.X,
py35-1.6.X,
py34-1.6.X,
py33-1.6.X,
py27-1.6.X,
py35-1.5.X,
py34-1.5.X,
py33-1.5.X,
py27-1.5.X,
py35-1.4.X,
py34-1.4.X,
py33-1.4.X,
py27-1.4.X,
[testenv]
commands =
{envpython} runtests.py
[testenv:py38-2.7.X]
basepython = python3.8
deps =
wagtail>=2.7,<2.8
[testenv:py37-2.7.X]
basepython = python3.7
deps =
wagtail>=2.7,<2.8
[testenv:py36-2.7.X]
basepython = python3.6
deps =
wagtail>=2.7,<2.8
[testenv:py35-2.7.X]
[testenv:py35-1.9.X]
basepython = python3.5
deps =
wagtail>=2.7,<2.8
wagtail>=1.9,<1.10
[testenv:py37-2.6.X]
basepython = python3.7
deps =
wagtail>=2.6,<2.7
[testenv:py36-2.6.X]
basepython = python3.6
deps =
wagtail>=2.6,<2.7
[testenv:py35-2.6.X]
basepython = python3.5
deps =
wagtail>=2.6,<2.7
[testenv:py37-2.5.X]
basepython = python3.7
deps =
wagtail>=2.5,<2.6
[testenv:py36-2.5.X]
basepython = python3.6
deps =
wagtail>=2.5,<2.6
[testenv:py35-2.5.X]
basepython = python3.5
deps =
wagtail>=2.5,<2.6
[testenv:py34-2.5.X]
[testenv:py34-1.9.X]
basepython = python3.4
deps =
wagtail>=2.5,<2.6
wagtail>=1.9,<1.10
[testenv:py37-2.4.X]
basepython = python3.7
[testenv:py33-1.9.X]
basepython = python3.3
deps =
wagtail>=2.4,<2.5
Django>=1.8,<1.9
wagtail>=1.9,<1.10
[testenv:py36-2.4.X]
basepython = python3.6
deps =
wagtail>=2.4,<2.5
[testenv:py35-2.4.X]
basepython = python3.5
deps =
wagtail>=2.4,<2.5
[testenv:py34-2.4.X]
basepython = python3.4
deps =
wagtail>=2.4,<2.5
[testenv:py36-2.3.X]
basepython = python3.6
deps =
wagtail>=2.3,<2.4
[testenv:py35-2.3.X]
basepython = python3.5
deps =
wagtail>=2.3,<2.4
[testenv:py34-2.3.X]
basepython = python3.4
deps =
wagtail>=2.3,<2.4
[testenv:py36-2.2.X]
basepython = python3.6
deps =
wagtail>=2.2,<2.3
[testenv:py35-2.2.X]
basepython = python3.5
deps =
wagtail>=2.2,<2.3
[testenv:py34-2.2.X]
basepython = python3.4
deps =
wagtail>=2.2,<2.3
[testenv:py36-2.1.X]
basepython = python3.6
deps =
wagtail>=2.1,<2.2
[testenv:py35-2.1.X]
basepython = python3.5
deps =
wagtail>=2.1,<2.2
[testenv:py34-2.1.X]
basepython = python3.4
deps =
wagtail>=2.1,<2.2
[testenv:py36-2.0.X]
basepython = python3.6
deps =
wagtail>=2.0,<2.1
[testenv:py35-2.0.X]
basepython = python3.5
deps =
wagtail>=2.0,<2.1
[testenv:py34-2.0.X]
basepython = python3.4
deps =
wagtail>=2.0,<2.1
[testenv:py36-1.13.X]
basepython = python3.6
deps =
wagtail>=1.13,<2.0
[testenv:py35-1.13.X]
basepython = python3.5
deps =
wagtail>=1.13,<2.0
[testenv:py34-1.13.X]
basepython = python3.4
deps =
wagtail>=1.13,<2.0
[testenv:py27-1.13.X]
[testenv:py27-1.9.X]
basepython = python2.7
deps =
wagtail>=1.13,<2.0
wagtail>=1.9,<1.10
[testenv:py36-1.12.X]
basepython = python3.6
deps =
wagtail>=1.12,<1.13
[testenv:py35-1.12.X]
[testenv:py35-1.8.X]
basepython = python3.5
deps =
wagtail>=1.12,<1.13
wagtail>=1.8,<1.9
[testenv:py34-1.12.X]
[testenv:py34-1.8.X]
basepython = python3.4
deps =
wagtail>=1.12,<1.13
wagtail>=1.8,<1.9
[testenv:py27-1.12.X]
[testenv:py33-1.8.X]
basepython = python3.3
deps =
Django>=1.8,<1.9
wagtail>=1.8,<1.9
[testenv:py27-1.8.X]
basepython = python2.7
deps =
wagtail>=1.12,<1.13
wagtail>=1.8,<1.9
[testenv:py35-1.7.X]
basepython = python3.5
deps =
wagtail>=1.7,<1.8
[testenv:py34-1.7.X]
basepython = python3.4
deps =
wagtail>=1.7,<1.8
[testenv:py33-1.7.X]
basepython = python3.3
deps =
Django>=1.8,<1.9
wagtail>=1.7,<1.8
[testenv:py27-1.7.X]
basepython = python2.7
deps =
wagtail>=1.7,<1.8
[testenv:py35-1.6.X]
basepython = python3.5
deps =
wagtail>=1.6,<1.7
[testenv:py34-1.6.X]
basepython = python3.4
deps =
wagtail>=1.6,<1.7
[testenv:py33-1.6.X]
basepython = python3.3
deps =
Django>=1.8,<1.9
wagtail>=1.6,<1.7
[testenv:py27-1.6.X]
basepython = python2.7
deps =
wagtail>=1.6,<1.7
[testenv:py35-1.5.X]
basepython = python3.5
deps =
wagtail>=1.5,<1.6
[testenv:py34-1.5.X]
basepython = python3.4
deps =
wagtail>=1.5,<1.6
[testenv:py33-1.5.X]
basepython = python3.3
deps =
Django>=1.8,<1.9
wagtail>=1.5,<1.6
[testenv:py27-1.5.X]
basepython = python2.7
deps =
wagtail>=1.5,<1.6
[testenv:py35-1.4.X]
basepython = python3.5
deps =
wagtail>=1.4,<1.5
[testenv:py34-1.4.X]
basepython = python3.4
deps =
wagtail>=1.4,<1.5
[testenv:py33-1.4.X]
basepython = python3.3
deps =
Django>=1.8,<1.9
wagtail>=1.4,<1.5
[testenv:py27-1.4.X]
basepython = python2.7
deps =
wagtail>=1.4,<1.5

View file

@ -1,3 +1,3 @@
# coding: utf-8
__version__ = '0.10.6'
default_app_config = 'wagtail_modeltranslation.apps.ModeltranslationConfig'

View file

@ -10,22 +10,9 @@ class ModeltranslationConfig(AppConfig):
def ready(self):
from django.conf import settings
from modeltranslation import settings as mt_settings
# Add Wagtail defined fields as modeltranslation custom fields
wagtail_fields = (
'StreamField',
'RichTextField',
)
# update both the standard settings and the modeltranslation settings,
# as we cannot guarantee the load order, and so django_modeltranslation
# may bootstrap itself either before, or after, our ready() gets called.
custom_fields = getattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS', tuple())
setattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS', tuple(set(custom_fields + wagtail_fields)))
mt_custom_fields = getattr(mt_settings, 'CUSTOM_FIELDS', tuple())
setattr(mt_settings, 'CUSTOM_FIELDS', tuple(set(mt_custom_fields + wagtail_fields)))
setattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS', getattr(settings, 'MODELTRANSLATION_CUSTOM_FIELDS', ()) + (
'StreamField', 'RichTextField'))
from modeltranslation.models import handle_translation_registrations
handle_translation_registrations()

View file

@ -3,12 +3,7 @@ import copy
import logging
import types
from django.core.cache import cache
from django.core.exceptions import ValidationError
try:
from django.urls import reverse
except ImportError:
from django.core.urlresolvers import reverse
from django.db import transaction, connection
from django.db.models import Q, Value
from django.db.models.functions import Concat, Substr
@ -18,34 +13,32 @@ from django.utils.translation import ugettext_lazy as _
from modeltranslation import settings as mt_settings
from modeltranslation.translator import translator, NotRegistered
from modeltranslation.utils import build_localized_fieldname, get_language
from wagtail.contrib.settings.models import BaseSetting
from wagtail.contrib.settings.views import get_setting_edit_handler
from wagtail_modeltranslation.settings import CUSTOM_SIMPLE_PANELS, CUSTOM_COMPOSED_PANELS
from wagtail_modeltranslation.utils import compare_class_tree_depth
try:
from wagtail.contrib.routable_page.models import RoutablePageMixin
from wagtail.admin.edit_handlers import FieldPanel, \
MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel,\
extract_panel_definitions_from_model_class, ObjectList
from wagtail.core.models import Page, Site
MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel
from wagtail.core.models import Page
from wagtail.core.fields import StreamField, StreamValue
from wagtail.core.url_routing import RouteResult
from wagtail.core.utils import WAGTAIL_APPEND_SLASH
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.search.index import SearchField
from wagtail.snippets.models import get_snippet_models
from wagtail.snippets.views.snippets import SNIPPET_EDIT_HANDLERS
except ImportError:
from wagtail.contrib.wagtailroutablepage.models import RoutablePageMixin
from wagtail.wagtailadmin.edit_handlers import FieldPanel, \
MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel,\
extract_panel_definitions_from_model_class, ObjectList
from wagtail.wagtailcore.models import Page, Site
MultiFieldPanel, FieldRowPanel, InlinePanel, StreamFieldPanel, RichTextFieldPanel
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.fields import StreamField, StreamValue
from wagtail.wagtailcore.url_routing import RouteResult
from wagtail.wagtailcore.utils import WAGTAIL_APPEND_SLASH
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailsearch.index import SearchField
from wagtail.wagtailsnippets.models import get_snippet_models
from wagtail.wagtailsnippets.views.snippets import SNIPPET_EDIT_HANDLERS
from wagtail_modeltranslation.settings import CUSTOM_SIMPLE_PANELS, CUSTOM_COMPOSED_PANELS, TRANSLATE_SLUGS
from wagtail_modeltranslation.utils import compare_class_tree_depth
from wagtail import VERSION
logger = logging.getLogger('wagtail.core')
@ -117,35 +110,26 @@ class WagtailTranslator(object):
_patch_stream_field_meaningful_value(descriptor)
# OVERRIDE PAGE METHODS
if TRANSLATE_SLUGS:
model.set_url_path = _new_set_url_path
model.route = _new_route
model._update_descendant_url_paths = _new_update_descendant_url_paths
if not hasattr(model, '_get_site_root_paths'):
model.get_url_parts = _new_get_url_parts # Wagtail<1.11
model._get_site_root_paths = _new_get_site_root_paths
_patch_clean(model)
model.set_url_path = _new_set_url_path
model.route = _new_route
model._update_descendant_url_paths = _new_update_descendant_url_paths
_patch_clean(model)
if not model.save.__name__.startswith('localized'):
setattr(model, 'save', LocalizedSaveDescriptor(model.save))
if not model.save.__name__.startswith('localized'):
setattr(model, 'save', LocalizedSaveDescriptor(model.save))
def _patch_other_models(self, model):
if hasattr(model, 'edit_handler'):
edit_handler = model.edit_handler
for tab in edit_handler.children:
for tab in edit_handler:
tab.children = self._patch_panels(tab.children)
elif hasattr(model, 'panels'):
model.panels = self._patch_panels(model.panels)
else:
panels = extract_panel_definitions_from_model_class(model)
translation_registered_fields = translator.get_options_for_model(model).fields
panels = filter(lambda field: field.field_name not in translation_registered_fields, panels)
edit_handler = ObjectList(panels)
if VERSION < (2, 5):
SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to_model(model)
else:
SNIPPET_EDIT_HANDLERS[model] = edit_handler.bind_to(model=model)
if model in get_snippet_models() and model in SNIPPET_EDIT_HANDLERS:
del SNIPPET_EDIT_HANDLERS[model]
else:
get_setting_edit_handler.cache_clear()
def _patch_panels(self, panels_list, related_model=None):
"""
@ -262,9 +246,9 @@ def _localized_set_url_path(page, parent, language):
# for the current language. If the value for the current language is invalid we get the one
# for the default fallback language
slug = getattr(page, localized_slug_field, None) or \
getattr(page, default_localized_slug_field, None) or page.slug
getattr(page, default_localized_slug_field, None) or page.slug
parent_url_path = getattr(parent, localized_url_path_field, None) or \
getattr(parent, default_localized_url_path_field, None) or parent.url_path
getattr(parent, default_localized_url_path_field, None) or parent.url_path
setattr(page, localized_url_path_field, parent_url_path + slug + '/')
@ -402,64 +386,13 @@ def _localized_update_descendant_url_paths(page, old_url_path, new_url_path, lan
Substr(localized_url_path, len(old_url_path) + 1))}))
def _localized_site_get_site_root_paths():
"""
Localized version of ``Site.get_site_root_paths()``
"""
current_language = get_language()
cache_key = 'wagtail_site_root_paths_{}'.format(current_language)
result = cache.get(cache_key)
if result is None:
result = [
(site.id, site.root_page.url_path, site.root_url)
for site in Site.objects.select_related('root_page').order_by('-root_page__url_path')
]
cache.set(cache_key, result, 3600)
return result
def _new_get_site_root_paths(self, request=None):
"""
Return localized site_root_paths, using the cached copy on the
request object if available and if language is the same.
"""
# if we have a request, use that to cache site_root_paths; otherwise, use self
current_language = get_language()
cache_object = request if request else self
if not hasattr(cache_object, '_wagtail_cached_site_root_paths_language') or \
cache_object._wagtail_cached_site_root_paths_language != current_language:
cache_object._wagtail_cached_site_root_paths_language = current_language
cache_object._wagtail_cached_site_root_paths = _localized_site_get_site_root_paths()
return cache_object._wagtail_cached_site_root_paths
def _new_get_url_parts(self, request=None):
"""
For Wagtail<1.11 ``Page.get_url_parts()`` is patched so it uses ``self._get_site_root_paths(request)``
"""
for (site_id, root_path, root_url) in self._get_site_root_paths(request):
if self.url_path.startswith(root_path):
page_path = reverse('wagtail_serve', args=(self.url_path[len(root_path):],))
# Remove the trailing slash from the URL reverse generates if
# WAGTAIL_APPEND_SLASH is False and we're not trying to serve
# the root path
if not WAGTAIL_APPEND_SLASH and page_path != '/':
page_path = page_path.rstrip('/')
return (site_id, root_url, page_path)
def _update_translation_descendant_url_paths(old_record, page):
# update children paths, must be done for all languages to ensure fallbacks are applied
languages_changed = []
default_localized_url_path = build_localized_fieldname('url_path', mt_settings.DEFAULT_LANGUAGE)
for language in mt_settings.AVAILABLE_LANGUAGES:
localized_url_path = build_localized_fieldname('url_path', language)
old_url_path = getattr(old_record, localized_url_path) or getattr(old_record, default_localized_url_path) or ''
old_url_path = getattr(old_record, localized_url_path) or getattr(old_record, default_localized_url_path)
new_url_path = getattr(page, localized_url_path) or getattr(page, default_localized_url_path)
if old_url_path == new_url_path:
@ -538,11 +471,6 @@ class LocalizedSaveDescriptor(object):
if change_descendant_url_path:
_update_translation_descendant_url_paths(old_record, instance)
# Check if this is a root page of any sites and clear the 'wagtail_site_root_paths_XX' key if so
if Site.objects.filter(root_page=instance).exists():
for language in mt_settings.AVAILABLE_LANGUAGES:
cache.delete('wagtail_site_root_paths_{}'.format(language))
return result
def __get__(self, instance, owner=None):
@ -573,4 +501,5 @@ def patch_wagtail_models():
registered_models.sort(key=compare_class_tree_depth)
for model_class in registered_models:
WagtailTranslator(model_class)
if issubclass(model_class, Page) or model_class in get_snippet_models() or issubclass(model_class, BaseSetting):
WagtailTranslator(model_class)

View file

@ -1,107 +0,0 @@
# coding: utf-8
from django import forms
from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
try:
from wagtail.core.models import Page
from wagtail.admin import widgets
from wagtail.admin.forms.pages import CopyForm
except ImportError:
from wagtail.wagtailcore.models import Page
from wagtail.wagtailadmin import widgets
from wagtail.wagtailadmin.forms import CopyForm
class PatchedCopyForm(CopyForm):
def __init__(self, *args, **kwargs):
# CopyPage must be passed a 'page' kwarg indicating the page to be copied
self.page = kwargs.pop('page')
self.user = kwargs.pop('user', None)
can_publish = kwargs.pop('can_publish')
super(CopyForm, self).__init__(*args, **kwargs)
#self.fields['new_title'] = forms.CharField(initial=self.page.title, label=_("New title"))
for code, name in settings.LANGUAGES:
locale_title = "new_title_{}".format(code)
locale_label = "{} [{}]".format(_("New title"), code)
self.fields[locale_title] = forms.CharField(initial=self.page.title, label=locale_label)
#self.fields['new_slug'] = forms.SlugField(initial=self.page.slug, label=_("New slug"))
for code, name in settings.LANGUAGES:
locale_title = "new_slug_{}".format(code)
locale_label = "{} [{}]".format(_("New slug"), code)
self.fields[locale_title] = forms.SlugField(initial=self.page.slug, label=locale_label)
self.fields['new_parent_page'] = forms.ModelChoiceField(
initial=self.page.get_parent(),
queryset=Page.objects.all(),
widget=widgets.AdminPageChooser(can_choose_root=True, user_perms='copy_to'),
label=_("New parent page"),
help_text=_("This copy will be a child of this given parent page.")
)
pages_to_copy = self.page.get_descendants(inclusive=True)
subpage_count = pages_to_copy.count() - 1
if subpage_count > 0:
self.fields['copy_subpages'] = forms.BooleanField(
required=False, initial=True, label=_("Copy subpages"),
help_text=ungettext(
"This will copy %(count)s subpage.",
"This will copy %(count)s subpages.",
subpage_count) % {'count': subpage_count})
if can_publish:
pages_to_publish_count = pages_to_copy.live().count()
if pages_to_publish_count > 0:
# In the specific case that there are no subpages, customise the field label and help text
if subpage_count == 0:
label = _("Publish copied page")
help_text = _("This page is live. Would you like to publish its copy as well?")
else:
label = _("Publish copies")
help_text = ungettext(
"%(count)s of the pages being copied is live. Would you like to publish its copy?",
"%(count)s of the pages being copied are live. Would you like to publish their copies?",
pages_to_publish_count) % {'count': pages_to_publish_count}
self.fields['publish_copies'] = forms.BooleanField(
required=False, initial=True, label=label, help_text=help_text
)
def clean(self):
cleaned_data = super(CopyForm, self).clean()
# Make sure the slug isn't already in use
# slug = cleaned_data.get('new_slug')
# New parent page given in form or parent of source, if parent_page is empty
parent_page = cleaned_data.get('new_parent_page') or self.page.get_parent()
# check if user is allowed to create a page at given location.
if not parent_page.permissions_for_user(self.user).can_add_subpage():
raise ValidationError({
'new_parent_page': _("You do not have permission to copy to page \"%(page_title)s\"") % {'page_title': parent_page.get_admin_display_title()}
})
# Count the pages with the same slug within the context of our copy's parent page
for code, name in settings.LANGUAGES:
locale_slug = "new_slug_{}".format(code)
slug = cleaned_data.get(locale_slug)
param = 'slug_' + code
query = {param: slug}
if slug and parent_page.get_children().filter(**query).count():
raise ValidationError({
locale_slug: _("This slug is already in use within the context of its parent page \"%s\"" % parent_page)
})
# Don't allow recursive copies into self
if cleaned_data.get('copy_subpages') and (self.page == parent_page or parent_page.is_descendant_of(self.page)):
raise ValidationError({
'new_parent_page': _("You cannot copy a page into itself when copying subpages")
})
return cleaned_data

View file

@ -10,4 +10,3 @@ CUSTOM_SIMPLE_PANELS = [import_from_string(panel_class) for panel_class in
getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_SIMPLE_PANELS', [])]
CUSTOM_COMPOSED_PANELS = [import_from_string(panel_class) for panel_class in
getattr(settings, 'WAGTAILMODELTRANSLATION_CUSTOM_COMPOSED_PANELS', [])]
TRANSLATE_SLUGS = getattr(settings, 'WAGTAILMODELTRANSLATION_TRANSLATE_SLUGS', True)

View file

@ -7,47 +7,22 @@ $(document).ready(function(){
for (var i = 0; i < allStreamFields.length; i++) {
//Current Field with all content
var currentStreamField = allStreamFields[i];
//Current field header
var header;
//Current field name
var fieldLang = "";
//Current field language
var fieldName = "";
if(versionCompare(WAGTAIL_VERSION,'2.6.0', {zeroExtend: true})===-1){
// Wagtail < 2.6
header = $(currentStreamField).children('h2')[0];
//Search for the input field so that we can get is id to know the field's name.
var streamFieldDiv = $(currentStreamField).find('div.sequence-container.sequence-type-stream')[0];
var fieldInfos = $(streamFieldDiv).find('input')[0].id.split('-')[0];
var lastUnderscore = fieldInfos.lastIndexOf("_");
fieldName = fieldInfos.substring(0, lastUnderscore);
fieldLang = fieldInfos.substring(lastUnderscore + 1, fieldInfos.length);
} else if(versionCompare(WAGTAIL_VERSION,'2.7.0', {zeroExtend: true})===-1){
// Wagtail < 2.7
header = $(currentStreamField).children('.title-wrapper')[0];
//Search for the input field so that we can get is id to know the field's name.
var streamFieldDiv = $(currentStreamField).find('div.sequence-container.sequence-type-stream')[0];
var fieldInfos = $(streamFieldDiv).find('input')[0].id.split('-')[0];
var lastUnderscore = fieldInfos.lastIndexOf("_");
fieldName = fieldInfos.substring(0, lastUnderscore);
fieldLang = fieldInfos.substring(lastUnderscore + 1, fieldInfos.length);
} else {
// Wagtail >= 2.7
header = $(currentStreamField).children('.title-wrapper')[0];
//Search for the input field so that we can get is id to know the field's name.
var streamFieldDiv = $(currentStreamField).find('.field-content')[0];
var fieldInfos = $(streamFieldDiv).find('input')[0].id.split('-')[0];
var lastUnderscore = fieldInfos.lastIndexOf("_");
fieldName = fieldInfos.substring(0, lastUnderscore);
fieldLang = fieldInfos.substring(lastUnderscore + 1, fieldInfos.length);
}
//Current Field header
var header = $(currentStreamField).children('h2')[0];
//Search for the input field so that we can get is id to know the field's name.
var streamFieldDiv = $(currentStreamField).find('div.sequence-container.sequence-type-stream')[0];
var fieldInfos = $(streamFieldDiv).children('input')[0].id.split('-')[0];
var lastUnderscore = fieldInfos.lastIndexOf("_");
var fieldName = fieldInfos.substring(0, lastUnderscore);
var fieldLang = fieldInfos.substring(lastUnderscore + 1, fieldInfos.length);
//The cycle to create the buttons for copy each language field
header.innerHTML += '<div class="translation-field-copy-wrapper">Copy content from: </div>';
var copyContentString = 'Copy content from';
header.innerHTML += '<div class="translation-field-copy-wrapper">'+copyContentString+': </div>';
for (var j = 0; j < langs.length; j++) {
if (fieldLang != langs[j]) {
var currentFieldID = fieldName + '_' + fieldLang;
var targetFieldID = fieldName + '_' + langs [j];
$(header).children('.translation-field-copy-wrapper')[0].innerHTML += '<button class="button translation-field-copy" current-lang-code="' + currentFieldID + '" data-lang-code="' + targetFieldID + '">' + langs[j] + '</button>';
$(header).children('.translation-field-copy-wrapper')[0].innerHTML += '<button class="translation-field-copy" current-lang-code="'+ currentFieldID +'" data-lang-code="'+ targetFieldID +'">'+langs[j]+'</button>';
};
};
};
@ -80,11 +55,11 @@ function requestCopyField(originID, targetID) {
})
.done(function(data) {
/* Put the html data in the targetID field */
var wrapperDiv = $('#' + targetID + '-count').parents('.input')[0];
var wrapperDiv = $("#"+targetID+"-count").parents('.input')[0];
$(wrapperDiv).html(data);
})
.fail(function(error) {
console.log('wagtail-modeltranslation error: ' + error.responseText);
console.log("wagtail-modeltranslation error: %s", error.responseText);
})
}

View file

@ -1,78 +0,0 @@
/**
* Compares two software version numbers (e.g. "1.7.1" or "1.2b").
*
* This function was born in http://stackoverflow.com/a/6832721.
*
* @param {string} v1 The first version to be compared.
* @param {string} v2 The second version to be compared.
* @param {object} [options] Optional flags that affect comparison behavior.
* @param {boolean} [options.lexicographical = false] Switch to compare version strings lexicographically instead of naturally.
* @param {boolean} [options.zeroExtend = false] Switch to pad version with "zero" parts instead to be considered smaller.
* <ul>
* <li>
* <tt>lexicographical: true</tt> compares each part of the version strings lexicographically instead of
* naturally; this allows suffixes such as "b" or "dev" but will cause "1.10" to be considered smaller than
* "1.2".
* </li>
* <li>
* <tt>zeroExtend: true</tt> changes the result if one version string has less parts than the other. In
* this case the shorter string will be padded with "zero" parts instead of being considered smaller.
* </li>
* </ul>
* @returns {number|NaN}
* <ul>
* <li>0 if the versions are equal</li>
* <li>a negative integer (-1) if v1 < v2</li>
* <li>a positive integer (1) if v1 > v2</li>
* <li>NaN if either version string is in the wrong format</li>
* </ul>
*
* @copyright by Jon Papaioannou (["john", "papaioannou"].join(".") + "@gmail.com")
* @license This function is in the public domain. Do what you want with it, no strings attached.
*/
function versionCompare(v1, v2, options) {
var lexicographical = options && options.lexicographical,
zeroExtend = options && options.zeroExtend,
v1parts = v1.split('.'),
v2parts = v2.split('.');
function isValidPart(x) {
return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x);
}
if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) {
return NaN;
}
if (zeroExtend) {
while (v1parts.length < v2parts.length) v1parts.push("0");
while (v2parts.length < v1parts.length) v2parts.push("0");
}
if (!lexicographical) {
v1parts = v1parts.map(Number);
v2parts = v2parts.map(Number);
}
for (var i = 0; i < v1parts.length; ++i) {
if (v2parts.length == i) {
return 1;
}
if (v1parts[i] == v2parts[i]) {
continue;
}
else if (v1parts[i] > v2parts[i]) {
return 1;
}
else {
return -1;
}
}
if (v1parts.length != v2parts.length) {
return -1;
}
return 0;
}

View file

@ -1,36 +1,23 @@
$(document).ready(function () {
/* Only non-live pages should auto-populate the slug from the title */
if (!$('body').hasClass('page-is-live')) {
if(!translate_slugs) {
lang_code = default_lang.replace("-", "_");
title_selector = '#id_title_' + lang_code;
slug_selector = '#id_slug';
slugAutoPopulateTranslation(title_selector, slug_selector);
} else {
$.each(langs, function (idx, lang_code) {
lang_code = lang_code.replace("-", "_");
title_selector = '#id_title_' + lang_code;
slug_selector = '#id_slug_' + lang_code;
slugAutoPopulateTranslation(title_selector, slug_selector);
var slugFollowsTitle = false;
$.each(langs, function (idx, lang_code) {
lang_code = lang_code.replace("-", "_");
$('#id_title_' + lang_code).on('focus', function () {
/* slug should only follow the title field if its value matched the title's value at the time of focus */
var currentSlug = $('#id_slug_' + lang_code).val();
var slugifiedTitle = cleanForSlug(this.value);
slugFollowsTitle = (currentSlug == slugifiedTitle);
});
}
$('#id_title_' + lang_code).on('keyup keydown keypress blur', function () {
if (slugFollowsTitle) {
var slugifiedTitle = cleanForSlug(this.value);
$('#id_slug_' + lang_code).val(slugifiedTitle);
}
});
});
}
});
function slugAutoPopulateTranslation(title_selector, slug_selector) {
var slugFollowsTitle = false;
$(title_selector).on('focus', function () {
/* slug should only follow the title field if its value matched the title's value at the time of focus */
var currentSlug = $(slug_selector).val();
var slugifiedTitle = cleanForSlug(this.value, true);
slugFollowsTitle = (currentSlug == slugifiedTitle);
});
$(title_selector).on('keyup keydown keypress blur', function () {
if (slugFollowsTitle) {
var slugifiedTitle = cleanForSlug(this.value, true);
$(slug_selector).val(slugifiedTitle);
}
});
}

View file

@ -1,31 +0,0 @@
{% extends "wagtailadmin/base.html" %}
{% load i18n %}
{% block titletag %}{% blocktrans with title=page.get_admin_display_title %}Copy {{ title }}{% endblocktrans %}{% endblock %}
{% block content %}
{% trans "Copy" as copy_str %}
{% include "wagtailadmin/shared/header.html" with title=copy_str subtitle=page.get_admin_display_title icon="doc-empty-inverse" %}
<div class="nice-padding">
<form action="{% url 'wagtailadmin_pages:copy' page.id %}" method="POST" novalidate>
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}" />
<ul class="fields">
{% for field in form.visible_fields %}
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
{% endfor %}
{% if form.copy_subpages %}
{% include "wagtailadmin/shared/field_as_li.html" with field=form.copy_subpages %}
{% endif %}
</ul>
<input type="submit" value="{% trans 'Copy this page' %}" class="button">
</form>
</div>
{% endblock %}
{% block extra_js %}
{{ block.super }}
{% include "wagtailadmin/pages/_editor_js.html" %}
{% endblock %}

View file

@ -6,9 +6,9 @@ from django import template
from django.utils.translation import activate, get_language
try:
from django.urls import resolve
except ImportError:
from django.core.urlresolvers import resolve
except ImportError:
from django.urls import resolve
from six import iteritems

View file

@ -52,13 +52,9 @@ class PatchTestPage(WagtailPage):
@register_snippet
class PatchTestSnippetNoPanels(models.Model):
class PatchTestSnippet(models.Model):
name = models.CharField(max_length=10)
@register_snippet
class PatchTestSnippet(PatchTestSnippetNoPanels):
panels = [
FieldPanel('name')
]
@ -78,8 +74,7 @@ class FieldPanelSnippet(models.Model):
@register_snippet
class ImageChooserPanelSnippet(models.Model):
image = models.ForeignKey(
'wagtailimages.Image',
on_delete=models.CASCADE,
'wagtailimages.Image'
)
panels = [
@ -127,10 +122,7 @@ class MultiFieldPanelSnippet(FieldPanelSnippet, ImageChooserPanelSnippet, FieldR
class BaseInlineModel(MultiFieldPanelSnippet):
field_name = models.CharField(max_length=10)
image_chooser = models.ForeignKey(
'wagtailimages.Image',
on_delete=models.CASCADE,
)
image_chooser = models.ForeignKey('wagtailimages.Image')
fieldrow_name = models.CharField(max_length=10)
@ -166,8 +158,7 @@ class FieldPanelPage(WagtailPage):
class ImageChooserPanelPage(WagtailPage):
image = models.ForeignKey(
'wagtailimages.Image',
on_delete=models.CASCADE,
'wagtailimages.Image'
)
content_panels = [

View file

@ -21,5 +21,3 @@ MODELTRANSLATION_AUTO_POPULATE = False
MODELTRANSLATION_FALLBACK_LANGUAGES = {'default': (MODELTRANSLATION_DEFAULT_LANGUAGE,)}
ROOT_URLCONF = 'wagtail_modeltranslation.tests.urls'
TRANSLATE_SLUGS = True

View file

@ -3,7 +3,6 @@ import imp
import django
from django.apps import apps as django_apps
from django.core.cache import cache
from django.core.exceptions import ValidationError
from django.core.management import call_command
from django.http import HttpRequest
@ -13,10 +12,9 @@ from django.test.utils import override_settings
from django.utils.translation import get_language, trans_real
from modeltranslation import settings as mt_settings, translator
try:
from wagtail.snippets.views.snippets import get_snippet_edit_handler
from wagtail import VERSION
except ImportError:
from wagtail.wagtailsnippets.views.snippets import get_snippet_edit_handler
from wagtail import VERSION
VERSION = 1, 6, 3 # assume it's 1.6.3, the latest version without VERSION
from .util import page_factory
from wagtail_modeltranslation.tests.test_settings import TEST_SETTINGS
@ -48,7 +46,8 @@ class WagtailModeltranslationTransactionTestBase(TransactionTestCase):
if not WagtailModeltranslationTransactionTestBase.synced:
# In order to perform only one syncdb
WagtailModeltranslationTransactionTestBase.synced = True
mgr = dummy_context_mgr()
mgr = (override_settings(**TEST_SETTINGS) if django.VERSION < (1, 8)
else dummy_context_mgr())
with mgr:
# 1. Reload translation in case USE_I18N was False
from django.utils import translation as dj_trans
@ -99,14 +98,15 @@ class WagtailModeltranslationTransactionTestBase(TransactionTestCase):
# 5. makemigrations
from django.db import connections, DEFAULT_DB_ALIAS
call_command('makemigrations', verbosity=2, interactive=False)
# 6. Syncdb
call_command('migrate', verbosity=0, interactive=False, run_syncdb=True,
call_command('makemigrations', verbosity=2, interactive=False,
database=connections[DEFAULT_DB_ALIAS].alias)
# 6. Syncdb
call_command('migrate', verbosity=0, migrate=False, interactive=False, run_syncdb=True,
database=connections[DEFAULT_DB_ALIAS].alias, load_initial_data=False)
# 7. Make sure Page translation fields are created
call_command('sync_page_translation_fields', interactive=False, verbosity=0)
call_command('sync_page_translation_fields', interactive=False, verbosity=0, database=connections[DEFAULT_DB_ALIAS].alias)
# 8. patch wagtail models
from wagtail_modeltranslation.patch_wagtailadmin import patch_wagtail_models
@ -122,10 +122,6 @@ class WagtailModeltranslationTransactionTestBase(TransactionTestCase):
self._old_language = get_language()
trans_real.activate('de')
# ensure we have a fresh site cache
for language in mt_settings.AVAILABLE_LANGUAGES:
cache.delete('wagtail_site_root_paths_{}'.format(language))
def tearDown(self):
trans_real.activate(self._old_language)
@ -307,8 +303,6 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
def test_snippet_patching(self):
self.check_fieldpanel_patching(panels=models.FieldPanelSnippet.panels)
self.check_panels_patching(models.FieldPanelSnippet, ['name_de', 'name_en'])
self.check_imagechooserpanel_patching(panels=models.ImageChooserPanelSnippet.panels)
self.check_fieldrowpanel_patching(panels=models.FieldRowPanelSnippet.panels)
self.check_streamfieldpanel_patching(panels=models.StreamFieldPanelSnippet.panels)
@ -318,24 +312,6 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
# which is the SnippetInlineModel
self.check_inlinepanel_patching(panels=models.SnippetInlineModel.panels)
# Case we don't define panels on snippet
self.check_panels_patching(models.PatchTestSnippetNoPanels, ['name_de', 'name_en'])
def check_panels_patching(self, model, model_fields):
patched_edit_handler = get_snippet_edit_handler(model)
if VERSION[0] < 2:
form = patched_edit_handler.get_form_class(model)
else:
form = patched_edit_handler.get_form_class()
try:
# python 3
self.assertEqual(model_fields, list(form.base_fields.keys()))
except AttributeError:
# python 2.7
self.assertItemsEqual(model_fields, form.base_fields.keys())
def test_page_form(self):
"""
In this test we use the InlinePanelPage model because it has all the possible "patchable" fields
@ -344,7 +320,7 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
page_edit_handler = models.InlinePanelPage.get_edit_handler()
if VERSION < (2,):
if VERSION[0] < 2:
form = page_edit_handler.get_form_class(models.InlinePanelPage)
else:
form = page_edit_handler.get_form_class()
@ -377,9 +353,13 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
In this test we use the InlinePanelSnippet model because it has all the possible "patchable" fields
so if the created form has all fields the the form was correctly patched
"""
try:
from wagtail.snippets.views.snippets import get_snippet_edit_handler
except ImportError:
from wagtail.wagtailsnippets.views.snippets import get_snippet_edit_handler
snippet_edit_handler = get_snippet_edit_handler(models.InlinePanelSnippet)
if VERSION < (2,):
if VERSION[0] < 2:
form = snippet_edit_handler.get_form_class(models.InlinePanelSnippet)
else:
form = snippet_edit_handler.get_form_class()
@ -663,12 +643,12 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
# re-fetch to pick up latest from DB
grandchild1 = models.TestSlugPage1.objects.get(slug_de='grandchild1-untranslated')
self.assertEqual(grandchild1.url_path_de, '/root-untranslated/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_de, '/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.slug_en, None)
self.assertEqual(grandchild1.url_path_en, None)
grandgrandchild = models.TestSlugPage1.objects.get(slug_de='grandgrandchild-untranslated')
self.assertEqual(grandgrandchild.url_path_de,
'/root-untranslated/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
'/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
self.assertEqual(grandgrandchild.slug_en, None)
self.assertEqual(grandgrandchild.url_path_en, None)
@ -678,18 +658,18 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
child.slug_en = 'child-translated'
child.save()
self.assertEqual(child.url_path_de, '/root-untranslated/child-untranslated/')
self.assertEqual(child.url_path_en, '/root-untranslated/child-translated/')
self.assertEqual(child.url_path_de, '/child-untranslated/')
self.assertEqual(child.url_path_en, '/child-translated/')
grandchild1 = models.TestSlugPage1.objects.get(slug_de='grandchild1-untranslated')
self.assertEqual(grandchild1.url_path_de, '/root-untranslated/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_en, '/root-untranslated/child-translated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_de, '/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_en, '/child-translated/grandchild1-untranslated/')
grandgrandchild = models.TestSlugPage1.objects.get(slug_de='grandgrandchild-untranslated')
self.assertEqual(grandgrandchild.url_path_de,
'/root-untranslated/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
'/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
self.assertEqual(grandgrandchild.url_path_en,
'/root-untranslated/child-translated/grandchild1-untranslated/grandgrandchild-untranslated/')
'/child-translated/grandchild1-untranslated/grandgrandchild-untranslated/')
def test_fetch_translation_records(self):
"""
@ -853,59 +833,6 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
self.assertEqual(page_01.url, '/en/url-en-01/')
self.assertEqual(page_02.url, '/en/url-de-02/')
def test_root_page_slug(self):
site_pages = {
'model': models.TestRootPage,
'kwargs': {'title': 'root URL', 'slug_de': 'root-de', 'slug_en': 'root-en'},
'children': {
'child1': {
'model': models.TestSlugPage1,
'kwargs': {'title': 'child1 URL', 'slug_de': 'url-de-01', 'slug_en': 'url-en-01'},
},
'child2': {
'model': models.TestSlugPage2,
'kwargs': {'title': 'child2 URL', 'slug': 'url-de-02'},
},
'child3': {
'model': models.TestSlugPage2,
'kwargs': {'title': 'child3 URL', 'slug': 'url-de-03'},
},
},
}
page_factory.create_page_tree(site_pages)
request = HttpRequest()
site_root_page = site_pages['instance']
wagtail_page_01 = site_pages['children']['child1']['instance']
wagtail_page_02 = site_pages['children']['child2']['instance']
wagtail_page_03 = site_pages['children']['child3']['instance']
self.assertEqual(wagtail_page_01.url, '/de/url-de-01/')
self.assertEqual(wagtail_page_01.url_path, '/root-de/url-de-01/')
if VERSION >= (1, 11):
self.assertEqual(wagtail_page_02.get_url(request=request), '/de/url-de-02/') # with request
trans_real.activate('en')
self.assertEqual(wagtail_page_01.url, '/en/url-en-01/')
self.assertEqual(wagtail_page_01.url_path, '/root-en/url-en-01/')
if VERSION >= (1, 11):
self.assertEqual(wagtail_page_02.get_url(request=request), '/en/url-de-02/')
trans_real.activate('de')
# new request after changing language
self.assertEqual(wagtail_page_03.url, '/de/url-de-03/')
if VERSION >= (1, 11):
self.assertEqual(wagtail_page_01.get_url(request=HttpRequest()), '/de/url-de-01/')
# URL should not be broken after updating the root_page (ensure the cache is evicted)
self.assertEqual(wagtail_page_01.url, '/de/url-de-01/')
site_root_page.slug = 'new-root-de'
site_root_page.save()
wagtail_page_01_new = site_root_page.get_children().get(id=wagtail_page_01.id)
self.assertEqual(wagtail_page_01_new.url, '/de/url-de-01/')
def test_set_translation_url_paths_command(self):
"""
Assert set_translation_url_paths management command works correctly
@ -977,20 +904,20 @@ class WagtailModeltranslationTest(WagtailModeltranslationTestBase):
call_command('set_translation_url_paths', verbosity=0)
grandchild1 = models.TestSlugPage1.objects.get(slug_de='grandchild1-untranslated')
self.assertEqual(grandchild1.url_path_de, '/root-untranslated/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_en, '/root-untranslated/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_de, '/child-untranslated/grandchild1-untranslated/')
self.assertEqual(grandchild1.url_path_en, '/child-untranslated/grandchild1-untranslated/')
grandgrandchild = models.TestSlugPage1.objects.get(slug_de='grandgrandchild-untranslated')
self.assertEqual(grandgrandchild.url_path_de,
'/root-untranslated/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
'/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
self.assertEqual(grandgrandchild.url_path_en,
'/root-untranslated/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
'/child-untranslated/grandchild1-untranslated/grandgrandchild-untranslated/')
grandchild2 = models.TestSlugPage2.objects.get(slug_de='grandchild2-untranslated')
self.assertEqual(grandchild2.__dict__['url_path'], '/root-untranslated/child-untranslated/grandchild2-untranslated/')
self.assertEqual(grandchild2.url_path_de, '/root-untranslated/child-untranslated/grandchild2-untranslated/')
self.assertEqual(grandchild2.url_path_en, '/root-untranslated/child-untranslated/grandchild2-untranslated/')
self.assertEqual(grandchild2.__dict__['url_path'], '/child-untranslated/grandchild2-untranslated/')
self.assertEqual(grandchild2.url_path_de, '/child-untranslated/grandchild2-untranslated/')
self.assertEqual(grandchild2.url_path_en, '/child-untranslated/grandchild2-untranslated/')
grandgrandchild_translated = models.TestSlugPage1.objects.get(slug_de='grandgrandchild1-translated')
self.assertEqual(grandgrandchild_translated.url_path_de,
'/root-untranslated/child2-translated/grandchild1-translated/grandgrandchild1-translated/')
'/child2-translated/grandchild1-translated/grandgrandchild1-translated/')
self.assertEqual(grandgrandchild_translated.url_path_en,
'/root-untranslated/child2-translated-en/grandchild1-translated-en/grandgrandchild1-translated-en/')
'/child2-translated-en/grandchild1-translated-en/grandgrandchild1-translated-en/')

View file

@ -1,29 +1,12 @@
# coding: utf-8
from modeltranslation.translator import (TranslationOptions, register,
translator)
from modeltranslation.translator import translator, register, TranslationOptions
from wagtail_modeltranslation.tests.models import TestRootPage, TestSlugPage1, TestSlugPage2, PatchTestPage, \
PatchTestSnippet, FieldPanelPage, ImageChooserPanelPage, FieldRowPanelPage, MultiFieldPanelPage, InlinePanelPage, \
FieldPanelSnippet, ImageChooserPanelSnippet, FieldRowPanelSnippet, MultiFieldPanelSnippet, PageInlineModel, \
BaseInlineModel, StreamFieldPanelPage, StreamFieldPanelSnippet, SnippetInlineModel, InlinePanelSnippet, \
TestSlugPage1Subclass, RoutablePageTest
from wagtail_modeltranslation.tests.models import (BaseInlineModel,
FieldPanelPage,
FieldPanelSnippet,
FieldRowPanelPage,
FieldRowPanelSnippet,
ImageChooserPanelPage,
ImageChooserPanelSnippet,
InlinePanelPage,
InlinePanelSnippet,
MultiFieldPanelPage,
MultiFieldPanelSnippet,
PageInlineModel,
PatchTestPage,
PatchTestSnippet,
PatchTestSnippetNoPanels,
RoutablePageTest,
SnippetInlineModel,
StreamFieldPanelPage,
StreamFieldPanelSnippet,
TestRootPage, TestSlugPage1,
TestSlugPage1Subclass,
TestSlugPage2)
# Wagtail Models
@ -52,14 +35,11 @@ class PatchTestPageTranslationOptions(TranslationOptions):
fields = ('description',)
@register(PatchTestSnippetNoPanels)
class PatchTestSnippetNoPanelsTranslationOptions(TranslationOptions):
class PatchTestSnippetTranslationOptions(TranslationOptions):
fields = ('name',)
@register(PatchTestSnippet)
class PatchTestSnippetTranslationOptions(TranslationOptions):
pass
translator.register(PatchTestSnippet, PatchTestSnippetTranslationOptions)
# Panel Patching Models

View file

@ -1,3 +1,5 @@
class PageFactory(object):
def __init__(self, initial_path=0):
@ -31,24 +33,12 @@ class PageFactory(object):
if not nodes:
return None
from .models import TestRootPage
try:
from wagtail.core.models import Site
except ImportError:
from wagtail.wagtailcore.models import Site
# add a top root node to mimic Wagtail's real behaviour
all_nodes = {
'model': TestRootPage,
'kwargs': {'title': 'Root', 'slug': 'root', },
'children': {
'site_root': nodes,
},
}
self.create_instance(all_nodes)
site_root_node = nodes['instance']
site = Site.objects.create(root_page=site_root_node, hostname='localhost', port=80, is_default_site=True)
root_node = self.create_instance(nodes)
site = Site.objects.create(root_page=root_node)
return site
def create_instance(self, node, parent=None, order=None):

View file

@ -2,23 +2,17 @@
from modeltranslation.decorators import register
from modeltranslation.translator import TranslationOptions
from wagtail_modeltranslation import settings
try:
from wagtail.core.models import Page
except ImportError:
from wagtail.wagtailcore.models import Page
@register(Page)
class PageTR(TranslationOptions):
fields = (
'title',
'slug',
'seo_title',
'search_description',
'url_path',
)
if settings.TRANSLATE_SLUGS:
fields += (
'slug',
'url_path',
)

View file

@ -2,35 +2,21 @@
import json
from django.core.exceptions import PermissionDenied
from six import iteritems
from django.conf import settings
from django.conf.urls import url
from django.http import HttpResponse, QueryDict
from django.shortcuts import redirect, render
from django.templatetags.static import static
from django.utils.html import escape, format_html, format_html_join
from django.utils.translation import ugettext as _
from django.http import HttpResponse
from django.http import QueryDict
from django.utils.html import format_html, format_html_join, escape
from django.views.decorators.csrf import csrf_exempt
from wagtail_modeltranslation import settings as wmt_settings
from modeltranslation import settings as mt_settings
from .patch_wagtailadmin_forms import PatchedCopyForm
from six import iteritems
try:
from wagtail.core import hooks
from wagtail.core.models import Page
from wagtail.core.rich_text.pages import PageLinkHandler
from wagtail.core import __version__ as WAGTAIL_VERSION
from wagtail.admin import messages
from wagtail.admin.views.pages import get_valid_next_url_from_request
except ImportError:
from wagtail.wagtailcore import hooks
from wagtail.wagtailcore.models import Page
from wagtail.wagtailcore.rich_text import PageLinkHandler
from wagtail.wagtailcore import __version__ as WAGTAIL_VERSION
from wagtail.wagtailadmin import messages
from wagtail.wagtailadmin.views.pages import get_valid_next_url_from_request
@hooks.register('insert_editor_js')
@ -39,25 +25,15 @@ def translated_slugs():
'wagtail_modeltranslation/js/wagtail_translated_slugs.js',
]
js_includes = format_html_join('\n', '<script src="{0}"></script>', (
(static(filename),) for filename in js_files)
)
js_includes = format_html_join('\n', '<script src="{0}{1}"></script>', (
(settings.STATIC_URL, filename) for filename in js_files)
)
lang_codes = []
for lang in settings.LANGUAGES:
lang_codes.append("'%s'" % lang[0])
js_languages = """
<script>
var langs=[{langs}];
var default_lang='{default_lang}';
var translate_slugs={translate_slugs};
</script>
""".format(
langs=", ".join(lang_codes),
default_lang=mt_settings.DEFAULT_LANGUAGE,
translate_slugs='true' if wmt_settings.TRANSLATE_SLUGS else 'false'
)
js_languages = "<script>var langs=[%s];</script>" % (", ".join(lang_codes))
return format_html(js_languages) + js_includes
@ -83,13 +59,13 @@ def return_translation_target_field_rendered_html(request, page_id):
# Patch field prefixes from origin field to target field
target_field_patched = []
for item in origin_field_serialized:
patched_item = {'name': None, 'value': None}
patched_item = None
for att in iteritems(item):
target_value = att[1]
if att[0] == 'name':
target_value = att[1].replace(
origin_field_name, target_field_name)
patched_item["name"] = target_value
patched_item = {"name": target_value}
else:
patched_item["value"] = att[1]
@ -131,26 +107,21 @@ def streamfields_translation_copy():
# includes the javascript file in the html file
js_files = [
'wagtail_modeltranslation/js/version_compare.js',
'wagtail_modeltranslation/js/copy_stream_fields.js',
]
js_includes = format_html_join('\n', '<script src="{0}"></script>', (
(static(filename),) for filename in js_files)
)
js_includes = format_html_join('\n', '<script src="{0}{1}"></script>', (
(settings.STATIC_URL, filename) for filename in js_files)
)
js_wagtail_version = """
<script>
var WAGTAIL_VERSION='{wagtail_version}';
</script>
""".format(wagtail_version=WAGTAIL_VERSION)
return format_html(js_wagtail_version) + js_includes
return js_includes
@hooks.register('insert_editor_css')
def modeltranslation_page_editor_css():
filename = 'wagtail_modeltranslation/css/page_editor_modeltranslation.css'
return format_html('<link rel="stylesheet" href="{}" >'.format(static(filename)))
return format_html('<link rel="stylesheet" href="'
+ settings.STATIC_URL
+ 'wagtail_modeltranslation/css/page_editor_modeltranslation.css" >')
@hooks.register('register_rich_text_link_handler')
@ -176,70 +147,3 @@ def register_localized_page_link_handler():
return "<a>"
return ('page', LocalizedPageLinkHandler)
@hooks.register('before_copy_page')
def before_copy_page(request, page):
parent_page = page.get_parent()
can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()
form = PatchedCopyForm(request.POST or None, user=request.user, page=page, can_publish=can_publish)
next_url = get_valid_next_url_from_request(request)
if request.method == 'POST':
# Prefill parent_page in case the form is invalid (as prepopulated value for the form field,
# because ModelChoiceField seems to not fall back to the user given value)
parent_page = Page.objects.get(id=request.POST['new_parent_page'])
if form.is_valid():
# Receive the parent page (this should never be empty)
if form.cleaned_data['new_parent_page']:
parent_page = form.cleaned_data['new_parent_page']
if not page.permissions_for_user(request.user).can_copy_to(parent_page,
form.cleaned_data.get('copy_subpages')):
raise PermissionDenied
# Re-check if the user has permission to publish subpages on the new parent
can_publish = parent_page.permissions_for_user(request.user).can_publish_subpage()
update_attrs = {}
for code, name in settings.LANGUAGES:
slug = "slug_{}".format(code)
title = "title_{}".format(code)
update_attrs[slug] = form.cleaned_data["new_{}".format(slug)]
update_attrs[title] = form.cleaned_data["new_{}".format(title)]
# Copy the page
new_page = page.copy(
recursive=form.cleaned_data.get('copy_subpages'),
to=parent_page,
update_attrs=update_attrs,
keep_live=(can_publish and form.cleaned_data.get('publish_copies')),
user=request.user,
)
# Give a success message back to the user
if form.cleaned_data.get('copy_subpages'):
messages.success(
request,
_("Page '{0}' and {1} subpages copied.").format(
page.get_admin_display_title(), new_page.get_descendants().count())
)
else:
messages.success(request, _("Page '{0}' copied.").format(page.get_admin_display_title()))
for fn in hooks.get_hooks('after_copy_page'):
result = fn(request, page, new_page)
if hasattr(result, 'status_code'):
return result
# Redirect to explore of parent page
if next_url:
return redirect(next_url)
return redirect('wagtailadmin_explore', parent_page.id)
return render(request, 'modeltranslation_copy.html', {
'page': page,
'form': form,
'next': next_url
})