diff --git a/config/settings.py b/config/settings.py index ccc1f175d..e4a7666da 100644 --- a/config/settings.py +++ b/config/settings.py @@ -131,6 +131,8 @@ TIME_ZONE = "UTC" +USE_L10N = True + USE_I18N = True USE_TZ = True diff --git a/dsfr/admin.py b/dsfr/admin.py index 07e827915..36942f667 100644 --- a/dsfr/admin.py +++ b/dsfr/admin.py @@ -15,18 +15,34 @@ class DsfrConfigAdmin(admin.ModelAdmin): fieldsets = ( ("", {"fields": ("language",)}), ( - "Site", + _("Website"), { "fields": ( ("site_title", "beta_tag"), "site_tagline", - "notice", "mourning", ) }, ), ( - "En-tête", + _("Notice"), + { + "fields": ( + "notice_title", + "notice_description", + "notice_type", + "notice_link", + "notice_icon_class", + "notice_is_collapsible", + ), + "description": _( + "The important notice banner should only be used for essential and temporary information. \ + (Excessive or continuous use risks “drowning” the message.)" + ), + }, + ), + ( + _("Header"), { "fields": ( "header_brand", @@ -35,7 +51,7 @@ class DsfrConfigAdmin(admin.ModelAdmin): }, ), ( - "Pied de page", + _("Footer"), { "fields": ( "footer_brand", @@ -46,7 +62,7 @@ class DsfrConfigAdmin(admin.ModelAdmin): }, ), ( - "Logo opérateur", + _("Operator logo"), { "fields": ( "operator_logo_file", diff --git a/dsfr/constants.py b/dsfr/constants.py index 378db3f06..d550ccf89 100644 --- a/dsfr/constants.py +++ b/dsfr/constants.py @@ -57,6 +57,34 @@ (_("Illustration colors"), COLOR_CHOICES_ILLUSTRATION), ] +# Types allowed for the site Notice +NOTICE_TYPE_CHOICES = [ + ( + _("Generic notices"), + [ + ("info", _("Information")), + ("warning", _("Warning")), + ("alert", _("Alert")), + ], + ), + ( + _("Weather alert notices"), + [ + ("weather-orange", _("Orange weather alert")), + ("weather-red", _("Red weather alert")), + ("weather-purple", _("Purple weather alert")), + ], + ), + ( + _("Alert notices"), + [ + ("attack", _("Attack alert")), + ("witness", _("Call for witnesses")), + ("cyberattack", _("Cyberattack")), + ], + ), +] + # Ratio classes used for medias and cards IMAGE_RATIOS = [ ("fr-ratio-32x9", "32x9"), diff --git a/dsfr/locale/fr/LC_MESSAGES/django.mo b/dsfr/locale/fr/LC_MESSAGES/django.mo index 3e72743e8..1d02895c7 100644 Binary files a/dsfr/locale/fr/LC_MESSAGES/django.mo and b/dsfr/locale/fr/LC_MESSAGES/django.mo differ diff --git a/dsfr/locale/fr/LC_MESSAGES/django.po b/dsfr/locale/fr/LC_MESSAGES/django.po index 2e0bef32d..f70d4f31d 100644 --- a/dsfr/locale/fr/LC_MESSAGES/django.po +++ b/dsfr/locale/fr/LC_MESSAGES/django.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-19 12:48+0200\n" -"PO-Revision-Date: 2024-08-19 12:48+0200\n" +"POT-Creation-Date: 2024-08-23 09:51+0200\n" +"PO-Revision-Date: 2024-08-23 10:09+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr\n" @@ -18,7 +18,37 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.4.2\n" -#: dsfr/admin.py:59 +#: dsfr/admin.py:18 +msgid "Website" +msgstr "Site" + +#: dsfr/admin.py:28 +msgid "Notice" +msgstr "Bandeau d’information importante" + +#: dsfr/admin.py:39 +msgid "" +"The important notice banner should only be used for essential and temporary " +"information. (Excessive or continuous use risks " +"“drowning” the message.)" +msgstr "" +"Le bandeau d’information importante doit être utilisé uniquement pour une " +"information primordiale et temporaire. (Une utilisation excessive ou " +"continue risque de “noyer” le message)" + +#: dsfr/admin.py:45 +msgid "Header" +msgstr "En-tête" + +#: dsfr/admin.py:54 +msgid "Footer" +msgstr "Pied de page" + +#: dsfr/admin.py:65 dsfr/models.py:129 +msgid "Operator logo" +msgstr "Logo opérateur" + +#: dsfr/admin.py:75 msgid "Newsletter" msgstr "Lettre d’information" @@ -50,7 +80,7 @@ msgstr "Info" msgid "Success" msgstr "Succès" -#: dsfr/constants.py:23 +#: dsfr/constants.py:23 dsfr/constants.py:66 msgid "Warning" msgstr "Avertissement" @@ -74,6 +104,50 @@ msgstr "Couleurs illustratives" msgid "System colors" msgstr "Couleurs système" +#: dsfr/constants.py:63 +msgid "Generic notices" +msgstr "Bandeaux génériques" + +#: dsfr/constants.py:65 +msgid "Information" +msgstr "Information" + +#: dsfr/constants.py:67 +msgid "Alert" +msgstr "Alerte" + +#: dsfr/constants.py:71 +msgid "Weather alert notices" +msgstr "Bandeaux de vigilance météo" + +#: dsfr/constants.py:73 +msgid "Orange weather alert" +msgstr "Vigilance météo orange" + +#: dsfr/constants.py:74 +msgid "Red weather alert" +msgstr "Vigilance météo rouge" + +#: dsfr/constants.py:75 +msgid "Purple weather alert" +msgstr "Vigilance météo violette" + +#: dsfr/constants.py:79 +msgid "Alert notices" +msgstr "Bandeaux d’alerte" + +#: dsfr/constants.py:81 +msgid "Attack alert" +msgstr "Alerte attentat" + +#: dsfr/constants.py:82 +msgid "Call for witnesses" +msgstr "Appel à témoins" + +#: dsfr/constants.py:83 +msgid "Cyberattack" +msgstr "Cyberattaque" + #: dsfr/models.py:20 msgid "Language" msgstr "Langue" @@ -102,109 +176,137 @@ msgstr "Titre du site" msgid "Site tagline" msgstr "Sous-titre du site" -#: dsfr/models.py:42 -msgid "Important notice" -msgstr "Bandeau d’information importante" +#: dsfr/models.py:44 +msgid "Notice title" +msgstr "Titre du bandeau" + +#: dsfr/models.py:48 dsfr/models.py:55 +msgid "Can include HTML" +msgstr "Peut inclure du HTML" + +#: dsfr/models.py:52 +msgid "Notice description" +msgstr "Description du bandeau" -#: dsfr/models.py:46 +#: dsfr/models.py:59 +msgid "Notice type" +msgstr "Type de bandeau" + +#: dsfr/models.py:65 msgid "" -"The important notice banner should only be used for essential and temporary " -"information. (Excessive or continuous use risks “drowning” the " -"message.)" +"Use is strictly regulated, see documentation." msgstr "" -"Le bandeau d’information importante doit être utilisé uniquement pour une " -"information primordiale et temporaire. (Une utilisation excessive ou " -"continue risque de “noyer” le message)" +"L’usage de ce bandeau est strictement encadré, voir la documentation." -#: dsfr/models.py:53 +#: dsfr/models.py:71 +msgid "Notice link" +msgstr "Lien du bandeau" + +#: dsfr/models.py:74 +msgid "Standardized consultation link at the end of the notice." +msgstr "Lien de consultation standardisé à la fin du bandeau." + +#: dsfr/models.py:78 +msgid "Notice icon class" +msgstr "Classe d’icône du bandeau" + +#: dsfr/models.py:82 +msgid "For weather alerts only" +msgstr "Pour les bandeaux de vigilance météo uniquement" + +#: dsfr/models.py:85 +msgid "Collapsible?" +msgstr "Repliable ?" + +#: dsfr/models.py:89 msgid "Institution (header)" msgstr "Institution (en-tête)" -#: dsfr/models.py:59 +#: dsfr/models.py:95 msgid "Institution with line break (header)" msgstr "Institution avec césure (en-tête)" -#: dsfr/models.py:64 +#: dsfr/models.py:100 msgid "Show the BETA tag next to the title" msgstr "Afficher la mention BETA à côté du titre" -#: dsfr/models.py:68 +#: dsfr/models.py:104 msgid "Institution (footer)" -msgstr "Institution (pied" +msgstr "Institution (pied)" -#: dsfr/models.py:74 +#: dsfr/models.py:110 msgid "Institution with line break (footer)" msgstr "Institution avec césure (pied)" -#: dsfr/models.py:79 +#: dsfr/models.py:115 msgid "Description" msgstr "Description" -#: dsfr/models.py:82 +#: dsfr/models.py:118 msgid "Newsletter description" msgstr "Description de la lettre d’information" -#: dsfr/models.py:86 +#: dsfr/models.py:122 msgid "Newsletter registration URL" msgstr "URL d‘inscription à la lettre d’information" -#: dsfr/models.py:93 -msgid "Operator logo" -msgstr "Logo opérateur" - -#: dsfr/models.py:100 +#: dsfr/models.py:136 msgid "Logo alt text" msgstr "Alternative textuelle du logo" -#: dsfr/models.py:103 +#: dsfr/models.py:139 msgid "Must contain the text present in the image." msgstr "Doit impérativement contenir le texte présent dans l’image." -#: dsfr/models.py:106 +#: dsfr/models.py:142 msgid "Width (em)" msgstr "Largeur (em)" -#: dsfr/models.py:112 +#: dsfr/models.py:148 msgid "" "To be adjusted according to the width of the logo. Example for a " "vertical logo: 3.5, Example for a horizontal logo: 8." msgstr "" -"À ajuster en fonction de la largeur du logo. Exemple pour un logo vertical: " -"3.5, Exemple pour un logo horizontal: 8." +"À ajuster en fonction de la largeur du logo. Exemple pour un logo " +"vertical: 3.5, Exemple pour un logo horizontal: 8." -#: dsfr/models.py:118 +#: dsfr/models.py:154 msgid "Mourning" msgstr "Mise en berne" -#: dsfr/models.py:121 +#: dsfr/models.py:157 msgid "Accessibility compliance status" msgstr "Statut de conformité de l’accessibilité" -#: dsfr/models.py:128 +#: dsfr/models.py:164 msgid "Configuration" msgstr "Configuration" -#: dsfr/models.py:131 +#: dsfr/models.py:167 msgid "Site config:" msgstr "Configuration du site :" -#: dsfr/models.py:139 +#: dsfr/models.py:175 msgid "Title" msgstr "Titre" -#: dsfr/models.py:142 +#: dsfr/models.py:178 msgid "URL" msgstr "URL" -#: dsfr/models.py:147 +#: dsfr/models.py:183 msgid "Icon class" msgstr "Classe d’icône" -#: dsfr/models.py:154 +#: dsfr/models.py:190 msgid "Social media" msgstr "Réseau social" -#: dsfr/models.py:155 +#: dsfr/models.py:191 msgid "Social medias" msgstr "Réseaux sociaux" @@ -263,7 +365,7 @@ msgstr "Abonnez-vous à notre lettre d’information" #: dsfr/templates/dsfr/follow.html:18 msgctxt "Button title" msgid "Subscribe to our newsletter" -msgstr "S'abonner à notre lettre d’information" +msgstr "S’abonner à notre lettre d’information" #: dsfr/templates/dsfr/follow.html:24 msgid "Subscribe" @@ -271,7 +373,7 @@ msgstr "S’abonner" #: dsfr/templates/dsfr/follow.html:34 msgid "Follow us
on social media" -msgstr "Suivez-nous
sur les réseaux sociaux" +msgstr "Suivez-nous
sur les réseaux sociaux" #: dsfr/templates/dsfr/footer.html:9 msgid "Back to home page" diff --git a/dsfr/migrations/0009_dsfrconfig_notice_type_alter_dsfrconfig_notice.py b/dsfr/migrations/0009_dsfrconfig_notice_type_alter_dsfrconfig_notice.py new file mode 100644 index 000000000..4da002c53 --- /dev/null +++ b/dsfr/migrations/0009_dsfrconfig_notice_type_alter_dsfrconfig_notice.py @@ -0,0 +1,44 @@ +# Generated by Django 4.2.15 on 2024-08-23 06:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("dsfr", "0008_alter_dsfrsocialmedia_options_dsfrconfig_language_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="dsfrconfig", + name="notice_type", + field=models.CharField( + blank=True, + choices=[ + ("info", "Information"), + ("warning", "Warning"), + ("alert", "Alert"), + ("weather-orange", "Orange weather alert"), + ("weather-red", "Red weather alert"), + ("weather-purple", "Purple weather alert"), + ("attack", "Attack alert"), + ("witness", "Call for witnesses"), + ("cyberattack", "Cyberattack"), + ], + help_text='Use is strictly regulated, see documentation.', + max_length=20, + verbose_name="Notice type", + ), + ), + migrations.AlterField( + model_name="dsfrconfig", + name="notice", + field=models.TextField( + blank=True, + default="", + help_text="The important notice banner should only be used for essential and temporary information. (Excessive or continuous use risks “drowning” the message.)", + verbose_name="Important notice content", + ), + ), + ] diff --git a/dsfr/migrations/0010_dsfrconfig_notice_icon_class_alter_dsfrconfig_notice_and_more.py b/dsfr/migrations/0010_dsfrconfig_notice_icon_class_alter_dsfrconfig_notice_and_more.py new file mode 100644 index 000000000..730818ce8 --- /dev/null +++ b/dsfr/migrations/0010_dsfrconfig_notice_icon_class_alter_dsfrconfig_notice_and_more.py @@ -0,0 +1,71 @@ +# Generated by Django 4.2.15 on 2024-08-23 07:17 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("dsfr", "0009_dsfrconfig_notice_type_alter_dsfrconfig_notice"), + ] + + operations = [ + migrations.AddField( + model_name="dsfrconfig", + name="notice_icon_class", + field=models.CharField( + blank=True, + default="", + help_text="For weather alerts only", + max_length=200, + verbose_name="Notice icon class", + ), + ), + migrations.AlterField( + model_name="dsfrconfig", + name="notice", + field=models.TextField( + blank=True, + default="", + help_text="The important notice banner should only be used for essential and temporary information. (Excessive or continuous use risks “drowning” the message.)", + verbose_name="Notice content", + ), + ), + migrations.AlterField( + model_name="dsfrconfig", + name="notice_type", + field=models.CharField( + blank=True, + choices=[ + ( + "Generic notices", + [ + ("info", "Information"), + ("warning", "Warning"), + ("alert", "Alert"), + ], + ), + ( + "Weather alert notices", + [ + ("weather-orange", "Orange weather alert"), + ("weather-red", "Red weather alert"), + ("weather-purple", "Purple weather alert"), + ], + ), + ( + "Alert notices", + [ + ("attack", "Attack alert"), + ("witness", "Call for witnesses"), + ("cyberattack", "Cyberattack"), + ], + ), + ], + default="info", + help_text='Use is strictly regulated, see documentation.', + max_length=20, + verbose_name="Notice type", + ), + ), + ] diff --git a/dsfr/migrations/0011_rename_notice_dsfrconfig_notice_title.py b/dsfr/migrations/0011_rename_notice_dsfrconfig_notice_title.py new file mode 100644 index 000000000..a1326ff90 --- /dev/null +++ b/dsfr/migrations/0011_rename_notice_dsfrconfig_notice_title.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.15 on 2024-08-23 07:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("dsfr", "0010_dsfrconfig_notice_icon_class_alter_dsfrconfig_notice_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="dsfrconfig", + old_name="notice", + new_name="notice_title", + ), + ] diff --git a/dsfr/migrations/0012_dsfrconfig_notice_description_and_more.py b/dsfr/migrations/0012_dsfrconfig_notice_description_and_more.py new file mode 100644 index 000000000..f84623d82 --- /dev/null +++ b/dsfr/migrations/0012_dsfrconfig_notice_description_and_more.py @@ -0,0 +1,86 @@ +# Generated by Django 4.2.15 on 2024-08-23 07:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("dsfr", "0011_rename_notice_dsfrconfig_notice_title"), + ] + + operations = [ + migrations.AddField( + model_name="dsfrconfig", + name="notice_description", + field=models.TextField( + blank=True, + default="", + help_text="Can include HTML", + verbose_name="Notice description", + ), + ), + migrations.AddField( + model_name="dsfrconfig", + name="notice_is_collapsible", + field=models.BooleanField(default=False, verbose_name="Collapsible?"), + ), + migrations.AddField( + model_name="dsfrconfig", + name="notice_link", + field=models.URLField( + blank=True, + default="", + help_text="Standardized consultation link at the end of the notice.", + verbose_name="Notice link", + ), + ), + migrations.AlterField( + model_name="dsfrconfig", + name="notice_title", + field=models.CharField( + blank=True, + default="", + help_text="Can include HTML", + max_length=250, + verbose_name="Notice title", + ), + ), + migrations.AlterField( + model_name="dsfrconfig", + name="notice_type", + field=models.CharField( + blank=True, + choices=[ + ( + "Generic notices", + [ + ("info", "Information"), + ("warning", "Warning"), + ("alert", "Alert"), + ], + ), + ( + "Weather alert notices", + [ + ("weather-orange", "Orange weather alert"), + ("weather-red", "Red weather alert"), + ("weather-purple", "Purple weather alert"), + ], + ), + ( + "Alert notices", + [ + ("attack", "Attack alert"), + ("witness", "Call for witnesses"), + ("cyberattack", "Cyberattack"), + ], + ), + ], + default="info", + help_text='Use is strictly regulated, see documentation.', + max_length=20, + verbose_name="Notice type", + ), + ), + ] diff --git a/dsfr/models.py b/dsfr/models.py index 87fad2388..4399a6f4c 100644 --- a/dsfr/models.py +++ b/dsfr/models.py @@ -5,7 +5,7 @@ from django.db import models from django.utils.translation import gettext_lazy as _ -from dsfr.constants import DJANGO_DSFR_LANGUAGES +from dsfr.constants import DJANGO_DSFR_LANGUAGES, NOTICE_TYPE_CHOICES def validate_image_extension(value): @@ -38,16 +38,52 @@ class DsfrConfig(models.Model): site_tagline = models.CharField( _("Site tagline"), max_length=200, default=_("Site tagline"), blank=True ) - notice = models.TextField( - _("Important notice"), + + # Notice + notice_title = models.CharField( + _("Notice title"), + max_length=250, + default="", + blank=True, + help_text=_("Can include HTML"), + ) + + notice_description = models.TextField( + _("Notice description"), default="", blank=True, + help_text=_("Can include HTML"), + ) + + notice_type = models.CharField( + _("Notice type"), + choices=NOTICE_TYPE_CHOICES, + default="info", + blank=True, + max_length=20, help_text=_( - "The important notice banner should only be used for essential and temporary information. \ - (Excessive or continuous use risks “drowning” the message.)" + 'Use is strictly regulated, see \ + documentation.' ), ) + notice_link = models.URLField( + _("Notice link"), + default="", + blank=True, + help_text=_("Standardized consultation link at the end of the notice."), + ) + + notice_icon_class = models.CharField( + _("Notice icon class"), + max_length=200, + default="", + blank=True, + help_text=_("For weather alerts only"), + ) + + notice_is_collapsible = models.BooleanField(_("Collapsible?"), default=False) # type: ignore + # Header header_brand = models.CharField( _("Institution (header)"), diff --git a/dsfr/templates/dsfr/base.html b/dsfr/templates/dsfr/base.html index 84e59704e..452924ad0 100644 --- a/dsfr/templates/dsfr/base.html +++ b/dsfr/templates/dsfr/base.html @@ -38,8 +38,8 @@ {% dsfr_theme_modale %} - {% if SITE_CONFIG.notice %} - {% dsfr_notice title=SITE_CONFIG.notice %} + {% if SITE_CONFIG.notice_title or SITE_CONFIG.notice_description %} + {% dsfr_notice title=SITE_CONFIG.notice_title description=SITE_CONFIG.notice_description link=SITE_CONFIG.notice_link type=SITE_CONFIG.notice_type icon=SITE_CONFIG.notice_icon_class is_collapsible=SITE_CONFIG.notice_is_collapsible %} {% endif %}
diff --git a/dsfr/templatetags/dsfr_tags.py b/dsfr/templatetags/dsfr_tags.py index 81d3c1f77..187ae73d1 100644 --- a/dsfr/templatetags/dsfr_tags.py +++ b/dsfr/templatetags/dsfr_tags.py @@ -834,7 +834,7 @@ def dsfr_notice(*args, **kwargs) -> dict: } ``` - Possible values for type: + Possible values for type (list available in constant NOTICE_TYPE_CHOICES): - info - warning diff --git a/pyproject.toml b/pyproject.toml index c0d39a850..0056f78ff 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ authors = ["Sylvain Boissel "] description = "Integrate the French government Design System into a Django app" license = "MIT" name = "django-dsfr" -version = "1.3.0" +version = "1.3.1" classifiers = [ "Development Status :: 5 - Production/Stable", "Environment :: Web Environment",