Skip to content

Commit dbe37e2

Browse files
committed
feat(legal): easier customization
- customization of the legal menu - clarified when LEGAL_URL / PRIVACY_URL are applied - support for customizing legal CSS - the legal app can now utilize external documents - clarified the customization documentation
1 parent 7262be6 commit dbe37e2

18 files changed

Lines changed: 365 additions & 63 deletions

File tree

docs/admin/config.rst

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,60 @@ Defaults to -1.
13151315
* :setting:`IP_BEHIND_REVERSE_PROXY`
13161316
* :setting:`IP_PROXY_HEADER`
13171317

1318+
.. setting:: LEGAL_DOCUMENT_CSS_CLASS
1319+
1320+
LEGAL_DOCUMENT_CSS_CLASS
1321+
------------------------
1322+
1323+
.. versionadded:: 2026.7
1324+
1325+
CSS class added to the wrappers around legal document templates.
1326+
1327+
Defaults to ``"tos"``, which enables the built-in legal document numbering and
1328+
spacing rules. Set this to an empty string to render legal documents without
1329+
the built-in numbering.
1330+
1331+
.. code-block:: python
1332+
1333+
LEGAL_DOCUMENT_CSS_CLASS = ""
1334+
1335+
.. seealso::
1336+
1337+
:ref:`legal`
1338+
1339+
.. setting:: LEGAL_HIDDEN_DOCUMENTS
1340+
1341+
LEGAL_HIDDEN_DOCUMENTS
1342+
----------------------
1343+
1344+
.. versionadded:: 2026.7
1345+
1346+
List of legal document page identifiers to hide from the legal module.
1347+
1348+
The ``index`` page is always visible. Supported document identifiers are
1349+
``terms``, ``cookies``, ``privacy``, and ``contracts``.
1350+
1351+
Hidden pages are removed from the legal menu and return a 404 response when
1352+
requested directly. Hiding ``terms`` or ``privacy`` is not recommended when
1353+
terms of service confirmation is enabled.
1354+
1355+
When ``terms`` or ``privacy`` is hidden, links exposed through the
1356+
``terms_url`` and ``privacy_url`` template variables use :setting:`LEGAL_URL`
1357+
and :setting:`PRIVACY_URL` as fallbacks when configured. If no fallback URL is
1358+
configured, the related link is omitted.
1359+
1360+
With terms of service confirmation enabled, hiding ``terms`` and setting
1361+
:setting:`LEGAL_URL` makes the confirmation page link to the external terms
1362+
document instead of embedding :file:`legal/documents/tos.html`.
1363+
1364+
.. code-block:: python
1365+
1366+
LEGAL_HIDDEN_DOCUMENTS = ("contracts",)
1367+
1368+
.. seealso::
1369+
1370+
:ref:`legal`
1371+
13181372
.. setting:: LEGAL_TOS_DATE
13191373

13201374
LEGAL_TOS_DATE
@@ -1344,8 +1398,9 @@ URL where your Weblate instance shows its legal documents.
13441398

13451399
.. hint::
13461400

1347-
Useful if you host your legal documents outside Weblate for embedding them inside Weblate.
1348-
Please check :ref:`legal` for details.
1401+
Useful if you host your legal documents outside Weblate instead of using
1402+
the :ref:`legal` module. When the legal module is enabled, Weblate links to
1403+
the internal legal pages by default.
13491404

13501405
Example:
13511406

@@ -1586,8 +1641,9 @@ URL where your Weblate instance shows its privacy policy.
15861641

15871642
.. hint::
15881643

1589-
Useful if you host your legal documents outside Weblate for embedding them inside Weblate,
1590-
please check :ref:`legal` for details.
1644+
Useful if you host your privacy policy outside Weblate instead of using
1645+
the :ref:`legal` module. When the legal module is enabled, Weblate links to
1646+
the internal legal pages by default.
15911647

15921648
Example:
15931649

docs/admin/install/docker.rst

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,10 @@ Generic settings
908908
:file:`/app/data/python/customize/templates/legal/documents`, see
909909
:ref:`docker-static-override`.
910910

911+
Recreate the Docker container after changing this environment variable,
912+
for example using :program:`docker compose up -d`. Restarting an existing
913+
container does not apply changed environment values.
914+
911915
**Example:**
912916

913917
.. code-block:: yaml
@@ -920,6 +924,35 @@ Generic settings
920924
* :ref:`legal`
921925
* :ref:`docker-static-override`
922926

927+
.. envvar:: WEBLATE_LEGAL_DOCUMENT_CSS_CLASS
928+
929+
Configures :setting:`LEGAL_DOCUMENT_CSS_CLASS` in Docker deployments with
930+
:envvar:`WEBLATE_LEGAL_INTEGRATION` enabled.
931+
932+
Set this to an empty string to disable the built-in legal document
933+
numbering.
934+
935+
**Example:**
936+
937+
.. code-block:: yaml
938+
939+
environment:
940+
WEBLATE_LEGAL_DOCUMENT_CSS_CLASS: ""
941+
942+
.. envvar:: WEBLATE_LEGAL_HIDDEN_DOCUMENTS
943+
944+
Configures :setting:`LEGAL_HIDDEN_DOCUMENTS` in Docker deployments with
945+
:envvar:`WEBLATE_LEGAL_INTEGRATION` enabled.
946+
947+
Provide a comma-separated list of legal document page identifiers.
948+
949+
**Example:**
950+
951+
.. code-block:: yaml
952+
953+
environment:
954+
WEBLATE_LEGAL_HIDDEN_DOCUMENTS: contracts
955+
923956
.. envvar:: WEBLATE_PUBLIC_ENGAGE
924957

925958
Enables :setting:`PUBLIC_ENGAGE`.

docs/admin/optionals.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ following templates in the documents:
138138
Privacy policy document
139139
:file:`legal/documents/summary.html`
140140
Short overview of the terms of service and privacy policy
141+
:file:`legal/documents/contracts.html`
142+
Subcontractor information
143+
144+
The legal module embeds these templates inside Weblate and uses
145+
:file:`legal/documents/tos.html` for terms of service confirmation. This is
146+
separate from :setting:`LEGAL_URL` and :setting:`PRIVACY_URL`, which are meant
147+
for linking to externally hosted legal documents from the footer when the
148+
legal module is not enabled. When the legal module is enabled, Weblate links to
149+
the internal legal pages by default.
141150

142151
On changing the terms of service documents, please adjust
143152
:setting:`LEGAL_TOS_DATE` so that users are forced to agree with the updated
@@ -193,11 +202,41 @@ Installation
193202
:file:`/app/data/python/customize/templates/legal/documents`, see
194203
:ref:`docker-static-override`.
195204

205+
Recreate the Docker container after changing environment variables, for
206+
example using :program:`docker compose up -d`. Restarting an existing
207+
container does not apply changed environment values.
208+
196209
Usage
197210
+++++
198211

199212
After installation and editing, the legal documents are shown in the Weblate UI.
200213

214+
The legal document templates are regular Django templates. Text is translated
215+
only when you use Django translation tags such as ``{% translate %}`` or
216+
``{% blocktranslate %}``; plain HTML text is shown as written.
217+
218+
Legal pages and the sign-in and registration overview provide ``terms_url`` and
219+
``privacy_url`` variables for linking to the terms of service and privacy
220+
policy documents.
221+
222+
By default, legal document wrappers use the ``tos`` CSS class. This class
223+
automatically numbers ``h2`` headings, paragraphs with ``item``, ``subitem``,
224+
or ``subsubitem`` classes, and top-level ordered list items. If your legal
225+
text already contains numbering, set :setting:`LEGAL_DOCUMENT_CSS_CLASS` to an
226+
empty string to disable this styling.
227+
228+
Use :setting:`LEGAL_HIDDEN_DOCUMENTS` to hide optional legal pages such as
229+
subcontractors from the legal menu. Hidden pages return a 404 response when
230+
requested directly. If ``terms`` or ``privacy`` is hidden, links using
231+
``terms_url`` or ``privacy_url`` fall back to :setting:`LEGAL_URL` or
232+
:setting:`PRIVACY_URL` when configured, otherwise the link is omitted.
233+
234+
To use externally hosted legal documents with terms confirmation, configure
235+
:setting:`LEGAL_HIDDEN_DOCUMENTS` to hide ``terms`` and ``privacy`` and set
236+
:setting:`LEGAL_URL` and :setting:`PRIVACY_URL`. The confirmation page then
237+
links to those external documents without requiring a
238+
:file:`legal/documents/tos.html` template override.
239+
201240
.. _avatars:
202241

203242
Avatars

docs/changes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ Weblate 2026.7
77

88
.. rubric:: Improvements
99

10+
* Documented :ref:`legal` customizations and added options to hide legal pages or disable document numbering.
11+
1012
.. rubric:: Bug fixes
1113

1214
.. rubric:: Compatibility

weblate/legal/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
class WeblateLegalConf(AppConf):
2929
# Current TOS date
3030
LEGAL_TOS_DATE = DEFAULT_TOS_DATE
31+
# CSS class for styling legal document templates
32+
LEGAL_DOCUMENT_CSS_CLASS = "tos"
33+
# Legal documents to hide from the UI
34+
LEGAL_HIDDEN_DOCUMENTS = ()
3135

3236
class Meta:
3337
prefix = ""

weblate/legal/templates/legal/confirm.html

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,26 @@
1616
<h4 class="card-title">{% translate "You have to agree to the General Terms and Conditions" %}</h4>
1717
</div>
1818
<div class="card-body">
19-
<p>{% translate "Please read following General Terms and Conditions document:" %}</p>
20-
<div class="list-group-item pre-scrollable tos">{% include "legal/documents/tos.html" %}</div>
19+
{% if terms_document_hidden %}
20+
<p>{% translate "Please read following legal documents:" %}</p>
21+
<ul>
22+
{% if terms_url %}
23+
<li>
24+
<a href="{{ terms_url }}">{% translate "General Terms and Conditions" %}</a>
25+
</li>
26+
{% endif %}
27+
{% if privacy_url %}
28+
<li>
29+
<a href="{{ privacy_url }}">{% translate "Privacy Policy" %}</a>
30+
</li>
31+
{% endif %}
32+
</ul>
33+
{% else %}
34+
<p>{% translate "Please read following General Terms and Conditions document:" %}</p>
35+
<div class="list-group-item pre-scrollable{% if legal_document_css_class %} {{ legal_document_css_class }}{% endif %}">
36+
{% include "legal/documents/tos.html" %}
37+
</div>
38+
{% endif %}
2139
{{ form|crispy }}
2240
{% csrf_token %}
2341
</div>

weblate/legal/templates/legal/contracts.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
<div class="card-header">
2020
<h4 class="card-title">{% translate "Subcontractors" %}</h4>
2121
</div>
22-
<div class="card-body tos">{% include "legal/documents/contracts.html" %}</div>
22+
<div class="card-body{% if legal_document_css_class %} {{ legal_document_css_class }}{% endif %}">
23+
{% include "legal/documents/contracts.html" %}
24+
</div>
2325
</div>
2426

2527
{% endblock content %}

weblate/legal/templates/legal/cookies.html

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,24 @@ <h4 class="card-title">{% translate "Cookies Policy" %}</h4>
2121
</div>
2222
<div class="card-body">
2323

24-
<p>
25-
{% blocktranslate %}This page is based on the General Terms and Conditions and the Privacy Policy, you should still read the original documents to fully understand them:{% endblocktranslate %}
26-
</p>
27-
28-
<ul>
29-
<li>
30-
<a href="{% url 'legal:terms' %}">{% translate "General Terms and Conditions" %}</a>
31-
</li>
32-
<li>
33-
<a href="{% url 'legal:privacy' %}">{% translate "Privacy Policy" %}</a>
34-
</li>
35-
</ul>
24+
{% if terms_url or privacy_url %}
25+
<p>
26+
{% blocktranslate %}This page is based on the General Terms and Conditions and the Privacy Policy, you should still read the original documents to fully understand them:{% endblocktranslate %}
27+
</p>
28+
29+
<ul>
30+
{% if terms_url %}
31+
<li>
32+
<a href="{{ terms_url }}">{% translate "General Terms and Conditions" %}</a>
33+
</li>
34+
{% endif %}
35+
{% if privacy_url %}
36+
<li>
37+
<a href="{{ privacy_url }}">{% translate "Privacy Policy" %}</a>
38+
</li>
39+
{% endif %}
40+
</ul>
41+
{% endif %}
3642

3743
<p>
3844
{% blocktranslate %}Cookies are used on this site for the following:{% endblocktranslate %}

weblate/legal/templates/legal/index.html

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,24 @@ <h4 class="card-title">{% translate "Legal Terms Overview" %}</h4>
2020

2121
{% include 'legal/documents/summary.html' %}
2222

23-
<p>
24-
{% blocktranslate %}This page is based on the General Terms and Conditions and the Privacy Policy, you should still read the original documents to fully understand them:{% endblocktranslate %}
25-
</p>
26-
27-
<ul>
28-
<li>
29-
<a href="{% url 'legal:terms' %}">{% translate "General Terms and Conditions" %}</a>
30-
</li>
31-
<li>
32-
<a href="{% url 'legal:privacy' %}">{% translate "Privacy Policy" %}</a>
33-
</li>
34-
</ul>
23+
{% if terms_url or privacy_url %}
24+
<p>
25+
{% blocktranslate %}This page is based on the General Terms and Conditions and the Privacy Policy, you should still read the original documents to fully understand them:{% endblocktranslate %}
26+
</p>
27+
28+
<ul>
29+
{% if terms_url %}
30+
<li>
31+
<a href="{{ terms_url }}">{% translate "General Terms and Conditions" %}</a>
32+
</li>
33+
{% endif %}
34+
{% if privacy_url %}
35+
<li>
36+
<a href="{{ privacy_url }}">{% translate "Privacy Policy" %}</a>
37+
</li>
38+
{% endif %}
39+
</ul>
40+
{% endif %}
3541

3642
</div>
3743
</div>

weblate/legal/templates/legal/privacy.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
<div class="card-header">
2020
<h4 class="card-title">{% translate "Privacy Policy" %}</h4>
2121
</div>
22-
<div class="card-body tos">{% include "legal/documents/privacy.html" %}</div>
22+
<div class="card-body{% if legal_document_css_class %} {{ legal_document_css_class }}{% endif %}">
23+
{% include "legal/documents/privacy.html" %}
24+
</div>
2325
</div>
2426

2527
{% endblock content %}

0 commit comments

Comments
 (0)