merge default doc-dc
authorDamien Correia
Wed, 06 Jun 2018 13:36:56 +0200
branchdoc-dc
changeset 658 b0bfac7e3160
parent 657 652a551b127e (current diff)
parent 590 4fafaf94701d (diff)
child 659 8ba76f7719b4
merge default
--- a/src/pyams_content/component/association/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/association/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -83,6 +83,7 @@
 
 
 ASSOCIATION_PARAGRAPH_TYPE = 'Associations'
+ASSOCIATION_PARAGRAPH_NAME = _("Associations")
 ASSOCIATION_PARAGRAPH_RENDERERS = 'PyAMS.associations.renderers'
 
 
--- a/src/pyams_content/component/association/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/association/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -17,7 +17,7 @@
 
 # import interfaces
 from pyams_content.component.association.interfaces import IAssociationParagraph, ASSOCIATION_PARAGRAPH_TYPE, \
-    ASSOCIATION_PARAGRAPH_RENDERERS
+    ASSOCIATION_PARAGRAPH_RENDERERS, ASSOCIATION_PARAGRAPH_NAME
 from pyams_content.component.extfile.interfaces import IExtFileContainerTarget
 from pyams_content.component.links.interfaces import ILinkContainerTarget
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
@@ -36,8 +36,6 @@
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IAssociationParagraph, IExtFileContainerTarget, ILinkContainerTarget)
 @factory_config(provided=IAssociationParagraph)
@@ -45,7 +43,7 @@
     """Associations paragraph"""
 
     icon_class = 'fa-link'
-    icon_hint = _("Associations paragraph")
+    icon_hint = ASSOCIATION_PARAGRAPH_NAME
 
     renderer = FieldProperty(IAssociationParagraph['renderer'])
 
@@ -54,7 +52,7 @@
 class AssociationParagraphFactory(BaseParagraphFactory):
     """Associations paragraph factory"""
 
-    name = _("Associations paragraph")
+    name = ASSOCIATION_PARAGRAPH_NAME
     content_type = AssociationParagraph
 
 
--- a/src/pyams_content/component/gallery/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/gallery/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -127,6 +127,7 @@
 
 
 GALLERY_PARAGRAPH_TYPE = 'Gallery'
+GALLERY_PARAGRAPH_NAME = _("Medias gallery")
 
 
 class IGalleryParagraph(IGallery, IBaseParagraph):
--- a/src/pyams_content/component/gallery/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/gallery/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -16,7 +16,7 @@
 # import standard library
 
 # import interfaces
-from pyams_content.component.gallery.interfaces import IGalleryParagraph, GALLERY_PARAGRAPH_TYPE
+from pyams_content.component.gallery.interfaces import IGalleryParagraph, GALLERY_PARAGRAPH_TYPE, GALLERY_PARAGRAPH_NAME
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, INegotiator, II18nManager
@@ -29,22 +29,20 @@
 from pyams_utils.traversing import get_parent
 from zope.interface import implementer
 
-from pyams_content import _
-
 
 @implementer(IGalleryParagraph)
 class Gallery(BaseGallery, BaseParagraph):
     """Gallery class"""
 
     icon_class = 'fa-picture-o'
-    icon_hint = _("Medias gallery")
+    icon_hint = GALLERY_PARAGRAPH_NAME
 
 
 @utility_config(name=GALLERY_PARAGRAPH_TYPE, provides=IParagraphFactory)
 class GalleryFactory(BaseParagraphFactory):
     """Gallery paragraph factory"""
 
-    name = _("Medias gallery")
+    name = GALLERY_PARAGRAPH_NAME
     content_type = Gallery
 
 
--- a/src/pyams_content/component/illustration/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/illustration/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -68,6 +68,7 @@
 
 
 ILLUSTRATION_PARAGRAPH_TYPE = 'Illustration'
+ILLUSTRATION_PARAGRAPH_NAME = _("Illustration")
 
 
 class IIllustrationParagraph(IIllustration, IBaseParagraph):
--- a/src/pyams_content/component/illustration/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/illustration/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -16,7 +16,8 @@
 # import standard library
 
 # import interfaces
-from pyams_content.component.illustration.interfaces import IIllustrationParagraph, ILLUSTRATION_PARAGRAPH_TYPE
+from pyams_content.component.illustration.interfaces import IIllustrationParagraph, ILLUSTRATION_PARAGRAPH_TYPE, \
+    ILLUSTRATION_PARAGRAPH_NAME
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.features.checker.interfaces import IContentChecker
 from pyams_i18n.interfaces import II18n
@@ -29,22 +30,20 @@
 from pyams_utils.request import check_request
 from zope.interface import implementer
 
-from pyams_content import _
-
 
 @implementer(IIllustrationParagraph)
 class Illustration(BaseIllustration, BaseParagraph):
     """Illustration class"""
 
     icon_class = 'fa-file-image-o'
-    icon_hint = _("Illustration")
+    icon_hint = ILLUSTRATION_PARAGRAPH_NAME
 
 
 @utility_config(name=ILLUSTRATION_PARAGRAPH_TYPE, provides=IParagraphFactory)
 class IllustrationFactory(BaseParagraphFactory):
     """Illustration paragraph factory"""
 
-    name = _("Illustration")
+    name = ILLUSTRATION_PARAGRAPH_NAME
     content_type = Illustration
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/audio.py	Wed Jun 06 13:36:56 2018 +0200
@@ -0,0 +1,95 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.illustration.interfaces import IIllustrationTarget
+from pyams_content.component.paragraph.interfaces import IParagraphFactory
+from pyams_content.component.paragraph.interfaces.audio import IAudioParagraph, AUDIO_PARAGRAPH_TYPE, \
+    AUDIO_PARAGRAPH_RENDERERS, AUDIO_PARAGRAPH_NAME
+from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
+from pyams_i18n.interfaces import II18nManager, INegotiator, II18n
+
+# import packages
+from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory
+from pyams_content.features.renderer import RenderersVocabulary
+from pyams_file.property import FileProperty
+from pyams_utils.adapter import adapter_config
+from pyams_utils.factory import factory_config
+from pyams_utils.registry import utility_config, get_utility
+from pyams_utils.traversing import get_parent
+from pyams_utils.vocabulary import vocabulary_config
+from zope.interface import implementer
+from zope.schema.fieldproperty import FieldProperty
+
+
+@implementer(IAudioParagraph, IIllustrationTarget)
+@factory_config(provided=IAudioParagraph)
+class AudioParagraph(BaseParagraph):
+    """Audio paragraph class"""
+
+    icon_class = 'fa-volume-up'
+    icon_hint = AUDIO_PARAGRAPH_NAME
+
+    body = FieldProperty(IAudioParagraph['body'])
+    description = FieldProperty(IAudioParagraph['description'])
+    author = FieldProperty(IAudioParagraph['author'])
+    data = FileProperty(IAudioParagraph['data'])
+    renderer = FieldProperty(IAudioParagraph['renderer'])
+
+
+@utility_config(name=AUDIO_PARAGRAPH_TYPE, provides=IParagraphFactory)
+class AudioParagraphFactory(BaseParagraphFactory):
+    """Audio paragraph factory"""
+
+    name = AUDIO_PARAGRAPH_NAME
+    content_type = AudioParagraph
+
+
+@adapter_config(context=IAudioParagraph, provides=IContentChecker)
+class AudioParagraphContentChecker(BaseParagraphContentChecker):
+    """Audio paragraph content checker"""
+
+    def inner_check(self, request):
+        output = []
+        translate = request.localizer.translate
+        manager = get_parent(self.context, II18nManager)
+        if manager is not None:
+            langs = manager.get_languages()
+        else:
+            negotiator = get_utility(INegotiator)
+            langs = (negotiator.server_language, )
+        i18n = II18n(self.context)
+        for lang in langs:
+            value = i18n.get_attribute('title', lang, request)
+            if not value:
+                field_title = translate(IAudioParagraph['title'].title)
+                if len(langs) == 1:
+                    output.append(translate(MISSING_VALUE).format(field=field_title))
+                else:
+                    output.append(translate(MISSING_LANG_VALUE).format(field=field_title, lang=lang))
+        for attr in ('author', 'data'):
+            value = getattr(self.context, attr)
+            if not value:
+                output.append(translate(MISSING_VALUE).format(field=translate(IAudioParagraph[attr].title)))
+        return output
+
+
+@vocabulary_config(name=AUDIO_PARAGRAPH_RENDERERS)
+class AudioParagraphRendererVocabulary(RenderersVocabulary):
+    """Audio paragraph renderers vocabulary"""
+
+    content_interface = IAudioParagraph
--- a/src/pyams_content/component/paragraph/contact.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/contact.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,7 +18,7 @@
 # import interfaces
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.contact import have_gis, IContactParagraph, CONTACT_PARAGRAPH_TYPE, \
-    CONTACT_PARAGRAPH_RENDERERS
+    CONTACT_PARAGRAPH_RENDERERS, CONTACT_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_file.interfaces import IImage, IResponsiveImage
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
@@ -35,8 +35,6 @@
 from zope.interface import implementer, alsoProvides
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IContactParagraph)
 @factory_config(provided=IContactParagraph)
@@ -44,7 +42,7 @@
     """Contact paragraph"""
 
     icon_class = 'fa-id-card-o'
-    icon_hint = _("Contact card")
+    icon_hint = CONTACT_PARAGRAPH_NAME
 
     name = FieldProperty(IContactParagraph['name'])
     charge = FieldProperty(IContactParagraph['charge'])
@@ -73,7 +71,7 @@
 class ContactParagraphFactory(BaseParagraphFactory):
     """Contact paragraph factory"""
 
-    name = _("Contact card")
+    name = CONTACT_PARAGRAPH_NAME
     content_type = ContactParagraph
     secondary_menu = True
 
--- a/src/pyams_content/component/paragraph/frame.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/frame.py	Wed Jun 06 13:36:56 2018 +0200
@@ -21,7 +21,7 @@
 from pyams_content.component.links.interfaces import ILinkContainerTarget
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.frame import IFrameParagraph, FRAME_PARAGRAPH_TYPE, \
-    FRAME_PARAGRAPH_RENDERERS
+    FRAME_PARAGRAPH_RENDERERS, FRAME_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 
@@ -36,8 +36,6 @@
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 #
 # Frame paragraph
@@ -49,7 +47,7 @@
     """Framed text paragraph"""
 
     icon_class = 'fa-list-alt'
-    icon_hint = _("Framed text")
+    icon_hint = FRAME_PARAGRAPH_NAME
 
     body = FieldProperty(IFrameParagraph['body'])
     renderer = FieldProperty(IFrameParagraph['renderer'])
@@ -59,7 +57,7 @@
 class FrameParagraphFactory(BaseParagraphFactory):
     """Framed text paragraph factory"""
 
-    name = _("Framed text paragraph")
+    name = FRAME_PARAGRAPH_NAME
     content_type = FrameParagraph
     secondary_menu = True
 
--- a/src/pyams_content/component/paragraph/header.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/header.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,7 +18,7 @@
 # import interfaces
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.header import IHeaderParagraph, HEADER_PARAGRAPH_TYPE, \
-    HEADER_PARAGRAPH_RENDERERS
+    HEADER_PARAGRAPH_RENDERERS, HEADER_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 
@@ -34,8 +34,6 @@
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IHeaderParagraph)
 @factory_config(provided=IHeaderParagraph)
@@ -43,7 +41,7 @@
     """Header paragraph"""
 
     icon_class = 'fa-download fa-rotate-180'
-    icon_hint = _("Header")
+    icon_hint = HEADER_PARAGRAPH_NAME
 
     @property
     def title(self):
@@ -58,7 +56,7 @@
 class HeaderParagraphFactory(BaseParagraphFactory):
     """Header paragraph factory"""
 
-    name = _("Header paragraph")
+    name = HEADER_PARAGRAPH_NAME
     content_type = HeaderParagraph
 
 
--- a/src/pyams_content/component/paragraph/html.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/html.py	Wed Jun 06 13:36:56 2018 +0200
@@ -22,8 +22,9 @@
 from pyams_content.component.illustration.interfaces import IIllustrationTarget
 from pyams_content.component.links.interfaces import ILinkContainerTarget, IInternalLink, IExternalLink, IMailtoLink
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
-from pyams_content.component.paragraph.interfaces.html import RAW_PARAGRAPH_TYPE, IRawParagraph, HTML_PARAGRAPH_TYPE, \
-    IHTMLParagraph, RAW_PARAGRAPH_RENDERERS, HTML_PARAGRAPH_RENDERERS
+from pyams_content.component.paragraph.interfaces.html import \
+    RAW_PARAGRAPH_TYPE, RAW_PARAGRAPH_NAME, RAW_PARAGRAPH_RENDERERS, IRawParagraph, \
+    HTML_PARAGRAPH_TYPE, HTML_PARAGRAPH_NAME, HTML_PARAGRAPH_RENDERERS, IHTMLParagraph
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 from pyams_sequence.interfaces import ISequentialIntIds
@@ -47,8 +48,6 @@
 from zope.lifecycleevent import ObjectCreatedEvent
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 #
 # Raw HTML paragraph
@@ -60,7 +59,7 @@
     """Raw HTML paragraph"""
 
     icon_class = 'fa-code'
-    icon_hint = _("Raw HTML ")
+    icon_hint = RAW_PARAGRAPH_NAME
 
     body = FieldProperty(IRawParagraph['body'])
     renderer = FieldProperty(IRawParagraph['renderer'])
@@ -70,7 +69,7 @@
 class RawParagraphFactory(BaseParagraphFactory):
     """Raw paragraph factory"""
 
-    name = _("Raw HTML paragraph")
+    name = RAW_PARAGRAPH_NAME
     content_type = RawParagraph
 
 
@@ -116,7 +115,7 @@
     """HTML paragraph"""
 
     icon_class = 'fa-font'
-    icon_hint = _("Rich text")
+    icon_hint = HTML_PARAGRAPH_NAME
 
     body = FieldProperty(IHTMLParagraph['body'])
     renderer = FieldProperty(IHTMLParagraph['renderer'])
@@ -126,7 +125,7 @@
 class HTMLParagraphFactory(BaseParagraphFactory):
     """HTML paragraph factory"""
 
-    name = _("Rich text paragraph")
+    name = HTML_PARAGRAPH_NAME
     content_type = HTMLParagraph
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/interfaces/audio.py	Wed Jun 06 13:36:56 2018 +0200
@@ -0,0 +1,59 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.paragraph.interfaces import IBaseParagraph
+
+# import packages
+from pyams_file.schema import AudioField
+from pyams_i18n.schema import I18nHTMLField, I18nTextField
+from zope.schema import TextLine, Choice
+
+from pyams_content import _
+
+
+#
+# Audio paragraph
+#
+
+AUDIO_PARAGRAPH_TYPE = 'Audio'
+AUDIO_PARAGRAPH_NAME = _("Audio")
+AUDIO_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.audio.renderers'
+
+
+class IAudioParagraph(IBaseParagraph):
+    """Audio paragraph"""
+
+    body = I18nHTMLField(title=_("Body"),
+                         required=False)
+
+    description = I18nTextField(title=_("Description"),
+                                description=_("File description displayed by front-office template"),
+                                required=False)
+
+    author = TextLine(title=_("Author"),
+                      description=_("Name of document's author"),
+                      required=False)
+
+    data = AudioField(title=_("Audio data"),
+                      description=_("Audio file content"),
+                      required=True)
+
+    renderer = Choice(title=_("Audio template"),
+                      description=_("Presentation template used for this audio file"),
+                      vocabulary=AUDIO_PARAGRAPH_RENDERERS,
+                      default='default')
--- a/src/pyams_content/component/paragraph/interfaces/contact.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/contact.py	Wed Jun 06 13:36:56 2018 +0200
@@ -40,6 +40,7 @@
 #
 
 CONTACT_PARAGRAPH_TYPE = 'Contact'
+CONTACT_PARAGRAPH_NAME = _("Contact card")
 CONTACT_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.contact.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/frame.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/frame.py	Wed Jun 06 13:36:56 2018 +0200
@@ -30,6 +30,7 @@
 #
 
 FRAME_PARAGRAPH_TYPE = 'FramedText'
+FRAME_PARAGRAPH_NAME = _("Framed text")
 FRAME_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.text.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/header.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/header.py	Wed Jun 06 13:36:56 2018 +0200
@@ -30,6 +30,7 @@
 #
 
 HEADER_PARAGRAPH_TYPE = 'Header'
+HEADER_PARAGRAPH_NAME = _("Header")
 HEADER_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.header.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/html.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/html.py	Wed Jun 06 13:36:56 2018 +0200
@@ -30,6 +30,7 @@
 #
 
 RAW_PARAGRAPH_TYPE = 'raw'
+RAW_PARAGRAPH_NAME = _("Raw HTML ")
 RAW_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.raw.renderers'
 
 
@@ -52,6 +53,7 @@
 #
 
 HTML_PARAGRAPH_TYPE = 'HTML'
+HTML_PARAGRAPH_NAME = _("Rich text")
 HTML_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.html.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/keynumber.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/keynumber.py	Wed Jun 06 13:36:56 2018 +0200
@@ -73,6 +73,7 @@
 
 
 KEYNUMBER_PARAGRAPH_TYPE = 'KeyNumbers'
+KEYNUMBER_PARAGRAPH_NAME = _("Key numbers")
 KEYNUMBER_PARAGRAPH_RENDERERS = 'PyAMS.keynumbers.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/keypoint.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/keypoint.py	Wed Jun 06 13:36:56 2018 +0200
@@ -30,6 +30,7 @@
 #
 
 KEYPOINTS_PARAGRAPH_TYPE = 'Keypoints'
+KEYPOINTS_PARAGRAPH_NAME = _("Key points")
 KEYPOINTS_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.keypoint.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/milestone.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/milestone.py	Wed Jun 06 13:36:56 2018 +0200
@@ -73,6 +73,7 @@
 
 
 MILESTONE_PARAGRAPH_TYPE = 'Milestones'
+MILESTONE_PARAGRAPH_NAME = _("Milestones")
 MILESTONE_PARAGRAPH_RENDERERS = 'PyAMS.milestones.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/pictogram.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/pictogram.py	Wed Jun 06 13:36:56 2018 +0200
@@ -77,6 +77,7 @@
 
 
 PICTOGRAM_PARAGRAPH_TYPE = 'Pictograms'
+PICTOGRAM_PARAGRAPH_NAME = _("Pictograms")
 PICTOGRAM_PARAGRAPH_RENDERERS = 'MyAMS.pictograms.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/verbatim.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/verbatim.py	Wed Jun 06 13:36:56 2018 +0200
@@ -30,6 +30,7 @@
 #
 
 VERBATIM_PARAGRAPH_TYPE = 'Verbatim'
+VERBATIM_PARAGRAPH_NAME = _("Verbatim")
 VERBATIM_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.verbatim.renderers'
 
 
--- a/src/pyams_content/component/paragraph/interfaces/video.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/interfaces/video.py	Wed Jun 06 13:36:56 2018 +0200
@@ -31,6 +31,7 @@
 #
 
 VIDEO_PARAGRAPH_TYPE = 'Video'
+VIDEO_PARAGRAPH_NAME = _("Video")
 VIDEO_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.video.renderers'
 
 
--- a/src/pyams_content/component/paragraph/keynumber.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/keynumber.py	Wed Jun 06 13:36:56 2018 +0200
@@ -20,7 +20,7 @@
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.keynumber import IKeyNumber, IKeyNumberContainer, \
     IKeyNumberContainerTarget, KEYNUMBER_CONTAINER_KEY, IKeyNumberParagraph, KEYNUMBER_PARAGRAPH_TYPE, \
-    KEYNUMBER_PARAGRAPH_RENDERERS
+    KEYNUMBER_PARAGRAPH_RENDERERS, KEYNUMBER_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_form.interfaces.form import IFormContextPermissionChecker
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
@@ -47,8 +47,6 @@
 from zope.location import locate
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 #
 # Key number class and adapters
@@ -180,7 +178,7 @@
 class KeyNumberContainerContentChecker(BaseContentChecker):
     """Key numbers container content checker"""
 
-    label = _("Key numbers")
+    label = KEYNUMBER_PARAGRAPH_NAME
     sep = '\n'
     weight = 200
 
@@ -203,8 +201,8 @@
 class KeyNumberParagraph(BaseParagraph):
     """Key numbers paragraph"""
 
-    icon_class = 'fa-list-ol'
-    icon_hint = _("Key numbers")
+    icon_class = 'fa-dashboard'
+    icon_hint = KEYNUMBER_PARAGRAPH_NAME
 
     renderer = FieldProperty(IKeyNumberParagraph['renderer'])
 
@@ -213,7 +211,7 @@
 class KeyNumberParagraphFactory(BaseParagraphFactory):
     """Key numbers paragraph factory"""
 
-    name = _("Key numbers paragraph")
+    name = KEYNUMBER_PARAGRAPH_NAME
     content_type = KeyNumberParagraph
 
 
--- a/src/pyams_content/component/paragraph/keypoint.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/keypoint.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,7 +18,7 @@
 # import interfaces
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.keypoint import IKeypointsParagraph, KEYPOINTS_PARAGRAPH_TYPE, \
-    KEYPOINTS_PARAGRAPH_RENDERERS
+    KEYPOINTS_PARAGRAPH_RENDERERS, KEYPOINTS_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 
@@ -28,27 +28,19 @@
 from pyams_utils.adapter import adapter_config
 from pyams_utils.factory import factory_config
 from pyams_utils.registry import utility_config, get_utility
-from pyams_utils.text import get_text_start
 from pyams_utils.traversing import get_parent
 from pyams_utils.vocabulary import vocabulary_config
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IKeypointsParagraph)
 @factory_config(provided=IKeypointsParagraph)
 class KeypointsParagraph(BaseParagraph):
     """Key points paragraph"""
 
-    icon_class = 'fa-key'
-    icon_hint = _("Key points")
-
-    @property
-    def title(self):
-        body = II18n(self).query_attribute('body')
-        return get_text_start(body, 50, 10)
+    icon_class = 'fa-list-ol'
+    icon_hint = KEYPOINTS_PARAGRAPH_NAME
 
     body = FieldProperty(IKeypointsParagraph['body'])
     renderer = FieldProperty(IKeypointsParagraph['renderer'])
@@ -58,7 +50,7 @@
 class KeypointsParagraphFactory(BaseParagraphFactory):
     """Key points paragraph factory"""
 
-    name = _("Key points paragraph")
+    name = KEYPOINTS_PARAGRAPH_NAME
     content_type = KeypointsParagraph
     secondary_menu = True
 
--- a/src/pyams_content/component/paragraph/milestone.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/milestone.py	Wed Jun 06 13:36:56 2018 +0200
@@ -21,7 +21,7 @@
     IParagraphFactory
 from pyams_content.component.paragraph.interfaces.milestone import IMilestone, IMilestoneContainer, \
     IMilestoneContainerTarget, MILESTONE_CONTAINER_KEY, IMilestoneParagraph, MILESTONE_PARAGRAPH_TYPE, \
-    MILESTONE_PARAGRAPH_RENDERERS
+    MILESTONE_PARAGRAPH_RENDERERS, MILESTONE_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
 from pyams_form.interfaces.form import IFormContextPermissionChecker
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
@@ -196,7 +196,7 @@
 class MilestoneContainerContentChecker(BaseContentChecker):
     """Milestones container content checker"""
 
-    label = _("Milestones")
+    label = MILESTONE_PARAGRAPH_NAME
     sep = '\n'
     weight = 200
 
@@ -219,7 +219,7 @@
     """Milestones paragraph"""
 
     icon_class = 'fa-arrows-h'
-    icon_hint = _("Milestones")
+    icon_hint = MILESTONE_PARAGRAPH_NAME
 
     renderer = FieldProperty(IMilestoneParagraph['renderer'])
 
@@ -228,7 +228,7 @@
 class MilestoneParagraphFactory(BaseParagraphFactory):
     """Milestones paragraph factory"""
 
-    name = _("Milestones paragraph")
+    name = MILESTONE_PARAGRAPH_NAME
     content_type = MilestoneParagraph
 
 
--- a/src/pyams_content/component/paragraph/pictogram.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/pictogram.py	Wed Jun 06 13:36:56 2018 +0200
@@ -21,7 +21,7 @@
 from pyams_content.component.paragraph import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.pictogram import IPictogramItem, IPictogramContainerTarget, \
     IPictogramContainer, PICTOGRAM_CONTAINER_KEY, IPictogramParagraph, PICTOGRAM_PARAGRAPH_TYPE, \
-    PICTOGRAM_PARAGRAPH_RENDERERS
+    PICTOGRAM_PARAGRAPH_RENDERERS, PICTOGRAM_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
 from pyams_content.reference.pictograms.interfaces import IPictogramTable
 from pyams_form.interfaces.form import IFormContextPermissionChecker
@@ -186,7 +186,7 @@
 class PictogramContainerContentChecker(BaseContentChecker):
     """Pictogram container content checker"""
 
-    label = _("Pictograms")
+    label = PICTOGRAM_PARAGRAPH_NAME
     sep = '\n'
     weight = 210
 
@@ -209,7 +209,7 @@
     """Pictograms paragraph"""
 
     icon_class = 'fa-linode'
-    icon_hint = _("Pictograms")
+    icon_hint = PICTOGRAM_PARAGRAPH_NAME
 
     renderer = FieldProperty(IPictogramParagraph['renderer'])
 
@@ -218,7 +218,7 @@
 class PictogramParagraphFactory(BaseParagraphFactory):
     """Pictograms paragraph factory"""
 
-    name = _("Pictograms paragraph")
+    name = PICTOGRAM_PARAGRAPH_NAME
     content_type = PictogramParagraph
 
 
--- a/src/pyams_content/component/paragraph/verbatim.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/verbatim.py	Wed Jun 06 13:36:56 2018 +0200
@@ -19,7 +19,7 @@
 from pyams_content.component.illustration.interfaces import IIllustrationTarget
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.verbatim import IVerbatimParagraph, VERBATIM_PARAGRAPH_TYPE, \
-    VERBATIM_PARAGRAPH_RENDERERS
+    VERBATIM_PARAGRAPH_RENDERERS, VERBATIM_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 
@@ -34,8 +34,6 @@
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 #
 # Frame paragraph
@@ -47,7 +45,7 @@
     """Verbatim paragraph"""
 
     icon_class = 'fa-quote-right'
-    icon_hint = _("Verbatim")
+    icon_hint = VERBATIM_PARAGRAPH_NAME
 
     quote = FieldProperty(IVerbatimParagraph['quote'])
     author = FieldProperty(IVerbatimParagraph['author'])
@@ -59,7 +57,7 @@
 class VerbatimParagraphFactory(BaseParagraphFactory):
     """Verbatim paragraph factory"""
 
-    name = _("Verbatim paragraph")
+    name = VERBATIM_PARAGRAPH_NAME
     content_type = VerbatimParagraph
     secondary_menu = True
 
--- a/src/pyams_content/component/paragraph/video.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/video.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,14 +18,12 @@
 # import interfaces
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.paragraph.interfaces.video import IVideoParagraph, VIDEO_PARAGRAPH_TYPE, \
-    VIDEO_PARAGRAPH_RENDERERS
+    VIDEO_PARAGRAPH_RENDERERS, VIDEO_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18nManager, INegotiator, II18n
-from zope.lifecycleevent.interfaces import IObjectAddedEvent, IObjectModifiedEvent
 
 # import packages
 from pyams_content.component.paragraph import BaseParagraph, BaseParagraphContentChecker, BaseParagraphFactory
-from pyams_content.component.paragraph.html import check_associations
 from pyams_content.features.renderer import RenderersVocabulary
 from pyams_file.property import FileProperty
 from pyams_utils.adapter import adapter_config
@@ -33,12 +31,9 @@
 from pyams_utils.registry import utility_config, get_utility
 from pyams_utils.traversing import get_parent
 from pyams_utils.vocabulary import vocabulary_config
-from pyramid.events import subscriber
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IVideoParagraph)
 @factory_config(provided=IVideoParagraph)
@@ -46,7 +41,7 @@
     """Video paragraph class"""
 
     icon_class = 'fa-film'
-    icon_hint = _("Video")
+    icon_hint = VIDEO_PARAGRAPH_NAME
 
     body = FieldProperty(IVideoParagraph['body'])
     description = FieldProperty(IVideoParagraph['description'])
@@ -59,26 +54,10 @@
 class VideoParagraphFactory(BaseParagraphFactory):
     """Video paragraph factory"""
 
-    name = _("Video")
+    name = VIDEO_PARAGRAPH_NAME
     content_type = VideoParagraph
 
 
-@subscriber(IObjectAddedEvent, context_selector=IVideoParagraph)
-def handle_added_video_paragraph(event):
-    """Check for new associations from added paragraph"""
-    paragraph = event.object
-    for lang, body in (paragraph.body or {}).items():
-        check_associations(paragraph, body, lang, notify=False)
-
-
-@subscriber(IObjectModifiedEvent, context_selector=IVideoParagraph)
-def handle_modified_video_paragraph(event):
-    """Check for new associations from modified paragraph"""
-    paragraph = event.object
-    for lang, body in (paragraph.body or {}).items():
-        check_associations(paragraph, body, lang, notify=False)
-
-
 @adapter_config(context=IVideoParagraph, provides=IContentChecker)
 class VideoParagraphContentChecker(BaseParagraphContentChecker):
     """Video paragraph content checker"""
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pyams_content/component/paragraph/zmi/audio.py	Wed Jun 06 13:36:56 2018 +0200
@@ -0,0 +1,182 @@
+#
+# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+
+__docformat__ = 'restructuredtext'
+
+
+# import standard library
+
+# import interfaces
+from pyams_content.component.association.zmi.interfaces import IAssociationsParentForm
+from pyams_content.component.paragraph.interfaces import IParagraphContainerTarget, IParagraphContainer
+from pyams_content.component.paragraph.interfaces.audio import IAudioParagraph, AUDIO_PARAGRAPH_TYPE
+from pyams_content.component.paragraph.zmi.interfaces import IParagraphInnerEditor, IParagraphContainerView
+from pyams_content.interfaces import MANAGE_CONTENT_PERMISSION
+from pyams_form.interfaces.form import IInnerForm
+from pyams_skin.interfaces.viewlet import IToolbarAddingMenu
+from pyams_skin.layer import IPyAMSLayer
+from pyams_zmi.interfaces import IPropertiesEditForm
+from transaction.interfaces import ITransactionManager
+from z3c.form.interfaces import INPUT_MODE
+
+# import packages
+from pyams_content.component.paragraph.audio import AudioParagraph
+from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \
+    BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons
+from pyams_content.features.renderer.zmi.widget import RendererFieldWidget
+from pyams_form.group import NamedWidgetsGroup
+from pyams_pagelet.pagelet import pagelet_config
+from pyams_skin.event import get_json_form_refresh_event, get_json_widget_refresh_event
+from pyams_utils.adapter import adapter_config
+from pyams_viewlet.viewlet import viewlet_config
+from pyams_zmi.form import AdminDialogAddForm
+from pyramid.view import view_config
+from z3c.form import field, button
+from zope.interface import implementer
+
+from pyams_content import _
+
+
+@viewlet_config(name='add-audio-paragraph.menu', context=IParagraphContainerTarget, view=IParagraphContainerView,
+                layer=IPyAMSLayer, manager=IToolbarAddingMenu, weight=80)
+class AudioParagraphAddMenu(BaseParagraphAddMenu):
+    """Audio paragraph add menu"""
+
+    label = _("Audio paragraph...")
+    label_css_class = 'fa fa-fw fa-volume-up'
+    url = 'add-audio-paragraph.html'
+    paragraph_type = AUDIO_PARAGRAPH_TYPE
+
+
+@pagelet_config(name='add-audio-paragraph.html', context=IParagraphContainerTarget, layer=IPyAMSLayer,
+                permission=MANAGE_CONTENT_PERMISSION)
+class AudioParagraphAddForm(AdminDialogAddForm):
+    """Audio paragraph add form"""
+
+    legend = _("Add new audio paragraph")
+    dialog_class = 'modal-large'
+    icon_css_class = 'fa fa-fw fa-volume-up'
+
+    fields = field.Fields(IAudioParagraph).omit('__parent__', '__name__', 'visible')
+    ajax_handler = 'add-audio-paragraph.json'
+    edit_permission = MANAGE_CONTENT_PERMISSION
+
+    def updateWidgets(self, prefix=None):
+        super(AudioParagraphAddForm, self).updateWidgets(prefix)
+        if 'description' in self.widgets:
+            self.widgets['description'].widget_css_class = 'textarea'
+        if 'body' in self.widgets:
+            self.widgets['body'].label = ''
+            
+    def updateGroups(self):
+        self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',),
+                                         bordered=False,
+                                         legend=_("HTML content"),
+                                         css_class='inner switcher padding-right-10 no-y-padding pull-left',
+                                         switch=True,
+                                         display_mode='auto'))
+        self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets,
+                                         ('description', 'author', 'data', 'renderer'),
+                                         bordered=False))
+        super(AudioParagraphAddForm, self).updateGroups()
+
+    def create(self, data):
+        return AudioParagraph()
+
+    def add(self, object):
+        IParagraphContainer(self.context).append(object)
+
+
+@view_config(name='add-audio-paragraph.json', context=IParagraphContainerTarget, request_type=IPyAMSLayer,
+             permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class AudioParagraphAJAXAddForm(BaseParagraphAJAXAddForm, AudioParagraphAddForm):
+    """Audio paragraph add form, JSON renderer"""
+
+
+@pagelet_config(name='properties.html', context=IAudioParagraph, layer=IPyAMSLayer,
+                permission=MANAGE_CONTENT_PERMISSION)
+class AudioParagraphPropertiesEditForm(BaseParagraphPropertiesEditForm):
+    """Audio paragraph properties edit form"""
+
+    prefix = 'audio_properties.'
+
+    legend = _("Edit audio properties")
+    dialog_class = 'modal-large'
+    icon_css_class = 'fa fa-fw fa-volume-up'
+
+    fields = field.Fields(IAudioParagraph).omit('__parent__', '__name__', 'visible')
+    fields['renderer'].widgetFactory = RendererFieldWidget
+
+    ajax_handler = 'properties.json'
+    edit_permission = MANAGE_CONTENT_PERMISSION
+
+    def updateWidgets(self, prefix=None):
+        super(AudioParagraphPropertiesEditForm, self).updateWidgets(prefix)
+        if 'description' in self.widgets:
+            self.widgets['description'].widget_css_class = 'textarea'
+        if 'body' in self.widgets:
+            self.widgets['body'].label = ''
+            
+    def updateGroups(self):
+        self.add_group(NamedWidgetsGroup(self, 'body_group', self.widgets, ('body',),
+                                         bordered=False,
+                                         fieldset_class='margin-top-10 padding-y-5',
+                                         legend=_("HTML content"),
+                                         css_class='inner switcher padding-right-10 no-y-padding pull-left',
+                                         switch=True,
+                                         display_mode='auto'))
+        self.add_group(NamedWidgetsGroup(self, 'data_group', self.widgets,
+                                         ('description', 'author', 'data', 'renderer'),
+                                         bordered=False))
+        super(AudioParagraphPropertiesEditForm, self).updateGroups()
+
+
+@view_config(name='properties.json', context=IAudioParagraph, request_type=IPyAMSLayer,
+             permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class AudioParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, AudioParagraphPropertiesEditForm):
+    """Audio paragraph properties edit form, JSON renderer"""
+
+
+@adapter_config(context=(IAudioParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
+@implementer(IInnerForm, IPropertiesEditForm, IAssociationsParentForm)
+class AudioParagraphPropertiesInnerEditForm(AudioParagraphPropertiesEditForm):
+    """Audio paragraph properties inner edit form"""
+
+    legend = None
+    ajax_handler = 'inner-properties.json'
+
+    @property
+    def buttons(self):
+        if self.mode == INPUT_MODE:
+            return button.Buttons(IParagraphEditFormButtons)
+        else:
+            return button.Buttons()
+
+
+@view_config(name='inner-properties.json', context=IAudioParagraph, request_type=IPyAMSLayer,
+             permission=MANAGE_CONTENT_PERMISSION, renderer='json', xhr=True)
+class AudioParagraphPropertiesInnerAJAXEditForm(BaseParagraphAJAXEditForm, AudioParagraphPropertiesInnerEditForm):
+    """Audio paragraph properties inner deit form, JSON renderer"""
+
+    def get_ajax_output(self, changes):
+        output = super(AudioParagraphPropertiesInnerAJAXEditForm, self).get_ajax_output(changes)
+        updated = changes.get(IAudioParagraph, ())
+        if 'data' in updated:
+            # we have to commit transaction to be able to handle blobs...
+            ITransactionManager(self.context).get().commit()
+            output.setdefault('events', []).append(
+                get_json_form_refresh_event(self.context, self.request, AudioParagraphPropertiesInnerEditForm))
+        elif 'renderer' in updated:
+            output.setdefault('events', []).append(
+                get_json_widget_refresh_event(self.context, self.request,
+                                              AudioParagraphPropertiesInnerEditForm, 'renderer'))
+        return output
--- a/src/pyams_content/component/paragraph/zmi/keynumber.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/keynumber.py	Wed Jun 06 13:36:56 2018 +0200
@@ -74,7 +74,7 @@
     """Key number paragraph add menu"""
     
     label = _("Key numbers...")
-    label_css_class = 'fa fa-fw fa-list-ol'
+    label_css_class = 'fa fa-fw fa-dashboard'
     url = 'add-keynumber-paragraph.html'
     paragraph_type = KEYNUMBER_PARAGRAPH_TYPE
     
@@ -85,7 +85,7 @@
     """Key number paragraph add form"""
     
     legend = _("Add new key number paragraph")
-    icon_css_class = 'fa fa-fw fa-list-ol'
+    icon_css_class = 'fa fa-fw fa-dashboard'
     
     fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
     ajax_handler = 'add-keynumber-paragraph.json'
@@ -117,7 +117,7 @@
         return II18n(content).query_attribute('title', request=self.request)
 
     legend = _("Edit key number paragraph properties")
-    icon_css_class = 'fa fa-fw fa-list-ol'
+    icon_css_class = 'fa fa-fw fa-dashboard'
 
     fields = field.Fields(IKeyNumberParagraph).select('title', 'renderer')
     fields['renderer'].widgetFactory = RendererFieldWidget
@@ -306,7 +306,7 @@
     """Key number add form"""
 
     legend = _("Add new keynumber")
-    icon_css_class = 'fa fa-fw fa-list-ol'
+    icon_css_class = 'fa fa-fw fa-dashboard'
 
     fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible')
     ajax_handler = 'add-keynumber.json'
@@ -339,7 +339,7 @@
     prefix = 'keynumber_properties.'
 
     legend = _("Edit keynumber properties")
-    icon_css_class = 'fa fa-fw fa-list-ol'
+    icon_css_class = 'fa fa-fw fa-dashboard'
 
     fields = field.Fields(IKeyNumber).omit('__parent__', '__name__', 'visible')
     ajax_handler = 'properties.json'
--- a/src/pyams_content/component/paragraph/zmi/keypoint.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/keypoint.py	Wed Jun 06 13:36:56 2018 +0200
@@ -48,7 +48,7 @@
     """Key points paragraph add menu"""
 
     label = _("Key points...")
-    label_css_class = 'fa fa-fw fa-key'
+    label_css_class = 'fa fa-fw fa-list-ol'
     url = 'add-keypoints-paragraph.html'
     paragraph_type = KEYPOINTS_PARAGRAPH_TYPE
 
@@ -59,9 +59,9 @@
     """Key points paragraph add form"""
 
     legend = _("Add new key points paragraph")
-    icon_css_class = 'fa fa-fw fa-key'
+    icon_css_class = 'fa fa-fw fa-list-ol'
 
-    fields = field.Fields(IKeypointsParagraph).select('body', 'renderer')
+    fields = field.Fields(IKeypointsParagraph).omit('__parent__', '__name__', 'visible')
     ajax_handler = 'add-keypoints-paragraph.json'
     edit_permission = MANAGE_CONTENT_PERMISSION
 
@@ -91,9 +91,9 @@
     prefix = 'keypoints_properties.'
 
     legend = _("Edit key points paragraph properties")
-    icon_css_class = 'fa fa-fw fa-key'
+    icon_css_class = 'fa fa-fw fa-list-ol'
 
-    fields = field.Fields(IKeypointsParagraph).select('body', 'renderer')
+    fields = field.Fields(IKeypointsParagraph).omit('__parent__', '__name__', 'visible')
     fields['renderer'].widgetFactory = RendererFieldWidget
 
     ajax_handler = 'properties.json'
@@ -110,13 +110,6 @@
 class KeypointsParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, KeypointsParagraphPropertiesEditForm):
     """Key points paragraph properties edit form, JSON renderer"""
 
-    def get_ajax_output(self, changes):
-        output = super(KeypointsParagraphPropertiesAJAXEditForm, self).get_ajax_output(changes)
-        if 'body' in changes.get(IKeypointsParagraph, ()):
-            output.setdefault('events', []).append(
-                get_json_paragraph_refresh_event(self.context, self.request))
-        return output
-
 
 @adapter_config(context=(IKeypointsParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
 @implementer(IInnerForm)
--- a/src/pyams_content/component/paragraph/zmi/milestone.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/milestone.py	Wed Jun 06 13:36:56 2018 +0200
@@ -280,13 +280,9 @@
             return self.defaultValue
         try:
             vocabulary = getVocabularyRegistry().get(obj, 'PyAMS content paragraphs')
+            return vocabulary.getTermByToken(obj.anchor).title
         except LookupError:
-            paragraph = IParagraphContainer(target).get(obj.anchor)
-            if paragraph is None:
-                return self.defaultValue
-            return II18n(paragraph).query_attribute('title', request=self.request) or self.defaultValue
-        else:
-            return vocabulary.getTermByToken(obj.anchor).title
+            return self.request.localizer.translate(_("(missing paragraph)")).format(obj.anchor)
 
 
 @adapter_config(name='trash', context=(IMilestoneContainerTarget, IPyAMSLayer, MilestonesTable), provides=IColumn)
--- a/src/pyams_content/component/paragraph/zmi/video.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/paragraph/zmi/video.py	Wed Jun 06 13:36:56 2018 +0200
@@ -29,7 +29,6 @@
 from z3c.form.interfaces import INPUT_MODE
 
 # import packages
-from pyams_content.component.association.zmi import AssociationsTable
 from pyams_content.component.paragraph.video import VideoParagraph
 from pyams_content.component.paragraph.zmi import BaseParagraphAJAXAddForm, BaseParagraphAJAXEditForm, \
     BaseParagraphAddMenu, BaseParagraphPropertiesEditForm, IParagraphEditFormButtons
@@ -146,18 +145,6 @@
 class VideoParagraphPropertiesAJAXEditForm(BaseParagraphAJAXEditForm, VideoParagraphPropertiesEditForm):
     """Video paragraph properties edit form, JSON renderer"""
 
-    def get_ajax_output(self, changes):
-        output = super(VideoParagraphPropertiesAJAXEditForm, self).get_ajax_output(changes)
-        if 'body' in changes.get(IVideoParagraph, ()):
-            associations_table = AssociationsTable(self.context, self.request)
-            associations_table.update()
-            output.setdefault('events', []).append({
-                'event': 'PyAMS_content.changed_item',
-                'options': {'handler': 'PyAMS_content.associations.refreshAssociations',
-                            'object_name': associations_table.id,
-                            'table': associations_table.render()}})
-        return output
-
 
 @adapter_config(context=(IVideoParagraph, IPyAMSLayer), provides=IParagraphInnerEditor)
 @implementer(IInnerForm, IPropertiesEditForm, IAssociationsParentForm)
@@ -183,15 +170,6 @@
     def get_ajax_output(self, changes):
         output = super(VideoParagraphPropertiesInnerAJAXEditForm, self).get_ajax_output(changes)
         updated = changes.get(IVideoParagraph, ())
-        if 'body' in updated:
-            associations_table = AssociationsTable(self.context, self.request)
-            associations_table.update()
-            output.setdefault('events', []).append({
-                'event': 'PyAMS_content.changed_item',
-                'options': {'handler': 'PyAMS_content.associations.refreshAssociations',
-                            'object_name': associations_table.id,
-                            'table': associations_table.render()}
-            })
         if 'data' in updated:
             # we have to commit transaction to be able to handle blobs...
             ITransactionManager(self.context).get().commit()
--- a/src/pyams_content/component/video/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/video/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -65,6 +65,7 @@
 
 
 EXTERNAL_VIDEO_PARAGRAPH_TYPE = 'External video'
+EXTERNAL_VIDEO_PARAGRAPH_NAME = _("External video")
 EXTERNAL_VIDEO_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.video.renderers'
 
 
--- a/src/pyams_content/component/video/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/component/video/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,7 +18,7 @@
 # import interfaces
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.component.video.interfaces import IExternalVideoParagraph, EXTERNAL_VIDEO_PARAGRAPH_TYPE, \
-    EXTERNAL_VIDEO_PARAGRAPH_RENDERERS
+    EXTERNAL_VIDEO_PARAGRAPH_RENDERERS, EXTERNAL_VIDEO_PARAGRAPH_NAME
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_i18n.interfaces import II18n, II18nManager, INegotiator
 
@@ -35,8 +35,6 @@
 from zope.interface import implementer
 from zope.schema.fieldproperty import FieldProperty
 
-from pyams_content import _
-
 
 @implementer(IExternalVideoParagraph)
 @factory_config(provided=IExternalVideoParagraph)
@@ -44,7 +42,7 @@
     """External video paragraph"""
 
     icon_class = 'fa-youtube-play'
-    icon_hint = _("External video")
+    icon_hint = EXTERNAL_VIDEO_PARAGRAPH_NAME
 
     body = FieldProperty(IExternalVideoParagraph['body'])
     renderer = FieldProperty(IExternalVideoParagraph['renderer'])
@@ -54,7 +52,7 @@
 class ExternalVideoParagraphFactory(BaseParagraphFactory):
     """External video paragraph factory"""
 
-    name = _("External video")
+    name = EXTERNAL_VIDEO_PARAGRAPH_NAME
     content_type = ExternalVideoParagraph
 
 
--- a/src/pyams_content/features/alert/interfaces.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/features/alert/interfaces.py	Wed Jun 06 13:36:56 2018 +0200
@@ -62,8 +62,8 @@
                      default='info',
                      vocabulary=ALERT_GRAVITY_VOCABULARY)
 
-    header = I18nTextLineField(title=_("Header"),
-                               description=_("Short alert header"),
+    header = I18nTextLineField(title=_('alert-header', default="Heading"),
+                               description=_("Short alert header (Alert, Important...)"),
                                required=False)
 
     message = I18nTextLineField(title=_("Message"),
--- a/src/pyams_content/features/alert/zmi/container.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/features/alert/zmi/container.py	Wed Jun 06 13:36:56 2018 +0200
@@ -155,7 +155,7 @@
 class AlertContainerHeaderColumn(I18nColumn, I18nAttrColumn):
     """Alert container header column"""
 
-    _header = _("Header")
+    _header = _('alert-header', default="Heading")
     attrName = 'header'
     weight = 20
 
Binary file src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.mo has changed
--- a/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/locales/fr/LC_MESSAGES/pyams_content.po	Wed Jun 06 13:36:56 2018 +0200
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-06 10:19+0200\n"
+"POT-Creation-Date: 2018-06-06 13:20+0200\n"
 "PO-Revision-Date: 2015-09-10 10:42+0200\n"
 "Last-Translator: Thierry Florac <tflorac@ulthar.net>\n"
 "Language-Team: French\n"
@@ -76,11 +76,6 @@
 msgid "Guest user (role)"
 msgstr "Invité (rôle)"
 
-#: src/pyams_content/component/gallery/paragraph.py:40
-#: src/pyams_content/component/gallery/paragraph.py:47
-msgid "Medias gallery"
-msgstr "Galerie de médias"
-
 #: src/pyams_content/component/gallery/__init__.py:154
 msgid "Gallery"
 msgstr "Galerie de médias"
@@ -141,8 +136,9 @@
 #: src/pyams_content/component/gallery/interfaces/__init__.py:61
 #: src/pyams_content/component/extfile/interfaces/__init__.py:44
 #: src/pyams_content/component/illustration/interfaces/__init__.py:56
-#: src/pyams_content/component/paragraph/interfaces/video.py:47
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:43
+#: src/pyams_content/component/paragraph/interfaces/video.py:48
+#: src/pyams_content/component/paragraph/interfaces/audio.py:48
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:44
 #: src/pyams_content/component/video/interfaces/__init__.py:52
 msgid "Author"
 msgstr "Auteur"
@@ -150,7 +146,8 @@
 #: src/pyams_content/component/gallery/zmi/interfaces.py:41
 #: src/pyams_content/component/gallery/interfaces/__init__.py:62
 #: src/pyams_content/component/extfile/interfaces/__init__.py:45
-#: src/pyams_content/component/paragraph/interfaces/video.py:48
+#: src/pyams_content/component/paragraph/interfaces/video.py:49
+#: src/pyams_content/component/paragraph/interfaces/audio.py:49
 #: src/pyams_content/component/video/interfaces/__init__.py:53
 msgid "Name of document's author"
 msgstr "Sous la forme \"Prénom Nom / Organisme\""
@@ -178,15 +175,19 @@
 msgid "Zoom image"
 msgstr "Agrandir l'image"
 
+#: src/pyams_content/component/gallery/interfaces/__init__.py:130
+msgid "Medias gallery"
+msgstr "Galerie de médias"
+
 #: src/pyams_content/component/gallery/interfaces/__init__.py:47
 #: src/pyams_content/component/illustration/interfaces/__init__.py:41
-#: src/pyams_content/component/illustration/interfaces/__init__.py:76
+#: src/pyams_content/component/illustration/interfaces/__init__.py:77
 msgid "Image or video data"
 msgstr "Fichier (image ou vidéo)"
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:48
 #: src/pyams_content/component/illustration/interfaces/__init__.py:42
-#: src/pyams_content/component/illustration/interfaces/__init__.py:77
+#: src/pyams_content/component/illustration/interfaces/__init__.py:78
 msgid "Image or video content"
 msgstr ""
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu..."
@@ -214,7 +215,8 @@
 #: src/pyams_content/component/gallery/interfaces/__init__.py:98
 #: src/pyams_content/component/extfile/interfaces/__init__.py:40
 #: src/pyams_content/component/illustration/interfaces/__init__.py:52
-#: src/pyams_content/component/paragraph/interfaces/video.py:43
+#: src/pyams_content/component/paragraph/interfaces/video.py:44
+#: src/pyams_content/component/paragraph/interfaces/audio.py:44
 #: src/pyams_content/component/links/interfaces/__init__.py:37
 #: src/pyams_content/component/video/interfaces/__init__.py:48
 #: src/pyams_content/shared/common/interfaces/__init__.py:145
@@ -238,6 +240,7 @@
 
 #: src/pyams_content/component/gallery/interfaces/__init__.py:73
 #: src/pyams_content/component/extfile/interfaces/__init__.py:89
+#: src/pyams_content/component/paragraph/interfaces/audio.py:52
 msgid "Audio data"
 msgstr "Fichier"
 
@@ -318,8 +321,7 @@
 
 #: src/pyams_content/component/extfile/__init__.py:253
 #: src/pyams_content/component/extfile/__init__.py:257
-#: src/pyams_content/component/paragraph/video.py:49
-#: src/pyams_content/component/paragraph/video.py:62
+#: src/pyams_content/component/paragraph/interfaces/video.py:34
 msgid "Video"
 msgstr "Vidéo"
 
@@ -382,15 +384,15 @@
 
 #: src/pyams_content/component/extfile/zmi/__init__.py:386
 msgid "Add audio file"
-msgstr "Audio téléchargeable"
+msgstr "Bande son téléchargeable"
 
 #: src/pyams_content/component/extfile/zmi/__init__.py:398
 msgid "Add new audio file"
-msgstr "Ajout d'un fichier audio téléchargeable"
+msgstr "Ajout d'une bande son téléchargeable"
 
 #: src/pyams_content/component/extfile/zmi/__init__.py:427
 msgid "Update audio file properties"
-msgstr "Propriétés du fichier audio téléchargeable"
+msgstr "Propriétés de la bande son téléchargeable"
 
 #: src/pyams_content/component/extfile/zmi/__init__.py:50
 msgid "External file type"
@@ -408,7 +410,8 @@
 msgstr "Titre présenté aux internautes"
 
 #: src/pyams_content/component/extfile/interfaces/__init__.py:41
-#: src/pyams_content/component/paragraph/interfaces/video.py:44
+#: src/pyams_content/component/paragraph/interfaces/video.py:45
+#: src/pyams_content/component/paragraph/interfaces/audio.py:45
 #: src/pyams_content/component/video/interfaces/__init__.py:49
 msgid "File description displayed by front-office template"
 msgstr "Description du fichier, présentée aux internautes"
@@ -453,7 +456,7 @@
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu..."
 
 #: src/pyams_content/component/extfile/interfaces/__init__.py:81
-#: src/pyams_content/component/paragraph/interfaces/video.py:51
+#: src/pyams_content/component/paragraph/interfaces/video.py:52
 msgid "Video data"
 msgstr "Fichier"
 
@@ -463,15 +466,15 @@
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
 
 #: src/pyams_content/component/extfile/interfaces/__init__.py:90
+#: src/pyams_content/component/paragraph/interfaces/audio.py:53
 msgid "Audio file content"
 msgstr ""
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
 
-#: src/pyams_content/component/illustration/paragraph.py:40
-#: src/pyams_content/component/illustration/paragraph.py:47
 #: src/pyams_content/component/illustration/__init__.py:132
 #: src/pyams_content/component/illustration/zmi/__init__.py:54
 #: src/pyams_content/component/illustration/zmi/__init__.py:81
+#: src/pyams_content/component/illustration/interfaces/__init__.py:71
 msgid "Illustration"
 msgstr "Illustration"
 
@@ -515,16 +518,6 @@
 "><strong>ATTENTION :</strong> certains modes de rendu ne prennent pas en "
 "compte tous les types de médias !</span>"
 
-#: src/pyams_content/component/paragraph/milestone.py:199
-#: src/pyams_content/component/paragraph/milestone.py:222
-#: src/pyams_content/component/paragraph/zmi/milestone.py:303
-msgid "Milestones"
-msgstr "Chronologie"
-
-#: src/pyams_content/component/paragraph/milestone.py:231
-msgid "Milestones paragraph"
-msgstr "Chronologie"
-
 #: src/pyams_content/component/paragraph/milestone.py:140
 msgid "Selected paragraph is missing"
 msgstr "le bloc sélectionné est introuvable"
@@ -533,15 +526,6 @@
 msgid "Selected paragraph is not visible"
 msgstr "le bloc sélectionné n'est pas visible"
 
-#: src/pyams_content/component/paragraph/keypoint.py:46
-#: src/pyams_content/component/paragraph/interfaces/keypoint.py:39
-msgid "Key points"
-msgstr "Points clés"
-
-#: src/pyams_content/component/paragraph/keypoint.py:61
-msgid "Key points paragraph"
-msgstr "Points clés"
-
 #: src/pyams_content/component/paragraph/container.py:73
 msgid "Paragraphs"
 msgstr "Blocs de contenu"
@@ -550,78 +534,10 @@
 msgid "no visible paragraph"
 msgstr "aucun bloc de contenu visible"
 
-#: src/pyams_content/component/paragraph/pictogram.py:189
-#: src/pyams_content/component/paragraph/pictogram.py:212
-#: src/pyams_content/component/paragraph/zmi/pictogram.py:305
-msgid "Pictograms"
-msgstr "Pictogrammes"
-
-#: src/pyams_content/component/paragraph/pictogram.py:221
-msgid "Pictograms paragraph"
-msgstr "Pictogrammes"
-
 #: src/pyams_content/component/paragraph/pictogram.py:134
 msgid "Selected pictogram is missing"
 msgstr "le pictogramme sélectionné est introuvable"
 
-#: src/pyams_content/component/paragraph/keynumber.py:183
-#: src/pyams_content/component/paragraph/keynumber.py:207
-#: src/pyams_content/component/paragraph/zmi/keynumber.py:282
-msgid "Key numbers"
-msgstr "Chiffres-clés"
-
-#: src/pyams_content/component/paragraph/keynumber.py:216
-msgid "Key numbers paragraph"
-msgstr "Chiffres-clés"
-
-#: src/pyams_content/component/paragraph/frame.py:52
-msgid "Framed text"
-msgstr "Encadré"
-
-#: src/pyams_content/component/paragraph/frame.py:62
-msgid "Framed text paragraph"
-msgstr "Encadré"
-
-#: src/pyams_content/component/paragraph/verbatim.py:50
-msgid "Verbatim"
-msgstr "Verbatim"
-
-#: src/pyams_content/component/paragraph/verbatim.py:62
-msgid "Verbatim paragraph"
-msgstr "Verbatim"
-
-#: src/pyams_content/component/paragraph/html.py:63
-msgid "Raw HTML "
-msgstr "Code HTML"
-
-#: src/pyams_content/component/paragraph/html.py:73
-msgid "Raw HTML paragraph"
-msgstr "Code HTML"
-
-#: src/pyams_content/component/paragraph/html.py:119
-msgid "Rich text"
-msgstr "Texte enrichi"
-
-#: src/pyams_content/component/paragraph/html.py:129
-msgid "Rich text paragraph"
-msgstr "Texte enrichi"
-
-#: src/pyams_content/component/paragraph/contact.py:47
-#: src/pyams_content/component/paragraph/contact.py:76
-msgid "Contact card"
-msgstr "Fiche contact"
-
-#: src/pyams_content/component/paragraph/header.py:46
-#: src/pyams_content/component/paragraph/interfaces/header.py:39
-#: src/pyams_content/features/alert/interfaces.py:65
-#: src/pyams_content/features/alert/zmi/container.py:158
-msgid "Header"
-msgstr "Chapô"
-
-#: src/pyams_content/component/paragraph/header.py:61
-msgid "Header paragraph"
-msgstr "Chapô"
-
 #: src/pyams_content/component/paragraph/zmi/milestone.py:77
 msgid "Milestones..."
 msgstr "Chronologie"
@@ -644,22 +560,31 @@
 msgid "Anchor"
 msgstr "Ancre"
 
-#: src/pyams_content/component/paragraph/zmi/milestone.py:318
+#: src/pyams_content/component/paragraph/zmi/milestone.py:299
+#: src/pyams_content/component/paragraph/interfaces/milestone.py:76
+msgid "Milestones"
+msgstr "Chronologie"
+
+#: src/pyams_content/component/paragraph/zmi/milestone.py:314
 msgid "Add milestone"
 msgstr "Ajouter un jalon"
 
-#: src/pyams_content/component/paragraph/zmi/milestone.py:329
+#: src/pyams_content/component/paragraph/zmi/milestone.py:325
 msgid "Add new milestone"
 msgstr "Ajout d'un jalon"
 
-#: src/pyams_content/component/paragraph/zmi/milestone.py:362
+#: src/pyams_content/component/paragraph/zmi/milestone.py:358
 msgid "Edit milestone properties"
 msgstr "Propriétés du jalon"
 
-#: src/pyams_content/component/paragraph/zmi/milestone.py:351
+#: src/pyams_content/component/paragraph/zmi/milestone.py:347
 msgid "Milestone was correctly added"
 msgstr "Le jalon a été ajouté."
 
+#: src/pyams_content/component/paragraph/zmi/milestone.py:285
+msgid "(missing paragraph)"
+msgstr "(paragraphe supprimé)"
+
 #: src/pyams_content/component/paragraph/zmi/keypoint.py:50
 msgid "Key points..."
 msgstr "Points clés"
@@ -732,21 +657,23 @@
 msgid "Paragraph was correctly added."
 msgstr "Le bloc a été ajouté."
 
-#: src/pyams_content/component/paragraph/zmi/video.py:55
+#: src/pyams_content/component/paragraph/zmi/video.py:54
 msgid "Video paragraph..."
 msgstr "Vidéo"
 
-#: src/pyams_content/component/paragraph/zmi/video.py:66
+#: src/pyams_content/component/paragraph/zmi/video.py:65
 msgid "Add new video paragraph"
 msgstr "Ajout d'une vidéo"
 
-#: src/pyams_content/component/paragraph/zmi/video.py:113
+#: src/pyams_content/component/paragraph/zmi/video.py:112
 #: src/pyams_content/component/video/zmi/paragraph.py:209
 msgid "Edit video properties"
 msgstr "Propriétés de la vidéo"
 
-#: src/pyams_content/component/paragraph/zmi/video.py:84
-#: src/pyams_content/component/paragraph/zmi/video.py:134
+#: src/pyams_content/component/paragraph/zmi/video.py:83
+#: src/pyams_content/component/paragraph/zmi/video.py:133
+#: src/pyams_content/component/paragraph/zmi/audio.py:83
+#: src/pyams_content/component/paragraph/zmi/audio.py:133
 #: src/pyams_content/component/video/zmi/paragraph.py:103
 #: src/pyams_content/component/video/zmi/paragraph.py:238
 msgid "HTML content"
@@ -816,6 +743,11 @@
 msgid "Associated text"
 msgstr "Texte associé"
 
+#: src/pyams_content/component/paragraph/zmi/pictogram.py:305
+#: src/pyams_content/component/paragraph/interfaces/pictogram.py:80
+msgid "Pictograms"
+msgstr "Pictogrammes"
+
 #: src/pyams_content/component/paragraph/zmi/pictogram.py:320
 #: src/pyams_content/reference/pictograms/zmi/__init__.py:62
 msgid "Add pictogram"
@@ -851,6 +783,18 @@
 msgid "Default header: {0}"
 msgstr "En-tête par défaut : {0}"
 
+#: src/pyams_content/component/paragraph/zmi/audio.py:54
+msgid "Audio paragraph..."
+msgstr "Bande son"
+
+#: src/pyams_content/component/paragraph/zmi/audio.py:65
+msgid "Add new audio paragraph"
+msgstr "Ajout d'une bande son"
+
+#: src/pyams_content/component/paragraph/zmi/audio.py:112
+msgid "Edit audio properties"
+msgstr "Propriétés de la bande son"
+
 #: src/pyams_content/component/paragraph/zmi/keynumber.py:76
 msgid "Key numbers..."
 msgstr "Chiffres-clés"
@@ -874,6 +818,11 @@
 msgid "key-number-label"
 msgstr "En-tête"
 
+#: src/pyams_content/component/paragraph/zmi/keynumber.py:282
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:76
+msgid "Key numbers"
+msgstr "Chiffres-clés"
+
 #: src/pyams_content/component/paragraph/zmi/keynumber.py:297
 msgid "Add keynumber"
 msgstr "Ajouter un chiffre-clé"
@@ -991,31 +940,36 @@
 msgid "Paragraph to which this milestone should lead"
 msgstr "Bloc de contenu vers lequel ce jalon doit conduire"
 
-#: src/pyams_content/component/paragraph/interfaces/milestone.py:82
+#: src/pyams_content/component/paragraph/interfaces/milestone.py:83
 msgid "Milestones template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/milestone.py:83
+#: src/pyams_content/component/paragraph/interfaces/milestone.py:84
 msgid "Presentation template used for milestones"
 msgstr "Modèle de présentation utilisé par ce bloc de contenu"
 
+#: src/pyams_content/component/paragraph/interfaces/keypoint.py:33
 #: src/pyams_content/component/paragraph/interfaces/keypoint.py:40
+msgid "Key points"
+msgstr "Points clés"
+
+#: src/pyams_content/component/paragraph/interfaces/keypoint.py:41
 msgid "Enter one key point by line, without hyphen or prefix"
 msgstr ""
 "Indiquez un point clé par ligne, sans tiret. Passez à la ligne entre chaque "
 "point clé, la mise en forme sera effectuée automatiquement."
 
-#: src/pyams_content/component/paragraph/interfaces/keypoint.py:43
+#: src/pyams_content/component/paragraph/interfaces/keypoint.py:44
 msgid "Presentation template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/keypoint.py:44
-#: src/pyams_content/component/paragraph/interfaces/frame.py:43
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:52
-#: src/pyams_content/component/paragraph/interfaces/html.py:45
-#: src/pyams_content/component/paragraph/interfaces/html.py:65
-#: src/pyams_content/shared/imagemap/interfaces/__init__.py:99
-#: src/pyams_content/shared/logo/interfaces/__init__.py:75
+#: src/pyams_content/component/paragraph/interfaces/keypoint.py:45
+#: src/pyams_content/component/paragraph/interfaces/frame.py:44
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:53
+#: src/pyams_content/component/paragraph/interfaces/html.py:46
+#: src/pyams_content/component/paragraph/interfaces/html.py:67
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:100
+#: src/pyams_content/shared/logo/interfaces/__init__.py:76
 msgid "Presentation template used for this paragraph"
 msgstr "Mode de rendu utilisé par ce bloc de contenu"
 
@@ -1045,24 +999,25 @@
 msgid "List of paragraphs automatically added to a new content"
 msgstr "Liste des types de blocs ajoutés automatiquement aux nouveaux contenus"
 
-#: src/pyams_content/component/paragraph/interfaces/video.py:40
-#: src/pyams_content/component/paragraph/interfaces/html.py:61
-#: src/pyams_content/component/video/interfaces/__init__.py:74
+#: src/pyams_content/component/paragraph/interfaces/video.py:41
+#: src/pyams_content/component/paragraph/interfaces/audio.py:41
+#: src/pyams_content/component/paragraph/interfaces/html.py:63
+#: src/pyams_content/component/video/interfaces/__init__.py:75
 msgid "Body"
 msgstr "Contenu HTML"
 
-#: src/pyams_content/component/paragraph/interfaces/video.py:52
+#: src/pyams_content/component/paragraph/interfaces/video.py:53
 msgid "Video file content"
 msgstr ""
 "Cliquez sur le bouton 'Parcourir...' pour sélectionner un nouveau contenu"
 
-#: src/pyams_content/component/paragraph/interfaces/video.py:55
-#: src/pyams_content/component/video/interfaces/__init__.py:77
+#: src/pyams_content/component/paragraph/interfaces/video.py:56
+#: src/pyams_content/component/video/interfaces/__init__.py:78
 msgid "Video template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/video.py:56
-#: src/pyams_content/component/video/interfaces/__init__.py:78
+#: src/pyams_content/component/paragraph/interfaces/video.py:57
+#: src/pyams_content/component/video/interfaces/__init__.py:79
 msgid "Presentation template used for this video"
 msgstr "Mode de rendu utilisé par cette vidéo"
 
@@ -1097,14 +1052,26 @@
 msgid "Additional text associated to this pictogram"
 msgstr "Texte complémentaire associé à ce pictogramme"
 
-#: src/pyams_content/component/paragraph/interfaces/pictogram.py:86
+#: src/pyams_content/component/paragraph/interfaces/pictogram.py:87
 msgid "Pictograms template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/pictogram.py:87
+#: src/pyams_content/component/paragraph/interfaces/pictogram.py:88
 msgid "Presentation template used for pictograms"
 msgstr "Modèle de présentation utilisé par ce bloc de contenu"
 
+#: src/pyams_content/component/paragraph/interfaces/audio.py:34
+msgid "Audio"
+msgstr "Bande son"
+
+#: src/pyams_content/component/paragraph/interfaces/audio.py:56
+msgid "Audio template"
+msgstr "Mode de rendu"
+
+#: src/pyams_content/component/paragraph/interfaces/audio.py:57
+msgid "Presentation template used for this audio file"
+msgstr "Mode de rendu utilisé pour cette bande son"
+
 #: src/pyams_content/component/paragraph/interfaces/keynumber.py:41
 msgid "Is this key number visible in front-office?"
 msgstr "Si 'non', ce chiffre-clé ne sera pas présenté aux internautes"
@@ -1125,52 +1092,68 @@
 "La présentation de cette information peut varier en fonction du mode de "
 "rendu choisi"
 
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:82
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:83
 msgid "Key numbers template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/keynumber.py:83
+#: src/pyams_content/component/paragraph/interfaces/keynumber.py:84
 msgid "Presentation template used for key numbers"
 msgstr "Modèle de présentation utilisé par ce bloc de contenu"
 
-#: src/pyams_content/component/paragraph/interfaces/frame.py:39
+#: src/pyams_content/component/paragraph/interfaces/frame.py:33
+msgid "Framed text"
+msgstr "Encadré"
+
+#: src/pyams_content/component/paragraph/interfaces/frame.py:40
 msgid "Frame body"
 msgstr "Contenu"
 
-#: src/pyams_content/component/paragraph/interfaces/frame.py:42
+#: src/pyams_content/component/paragraph/interfaces/frame.py:43
 msgid "Text template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:39
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:33
+msgid "Verbatim"
+msgstr "Verbatim"
+
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:40
 msgid "Quoted text"
 msgstr "Citation"
 
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:40
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:41
 msgid "Quotation marks will be added automatically by presentation template"
 msgstr "Les guillemets seront ajoutés automatiquement par le mode de rendu..."
 
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:44
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:45
 msgid "Name of the quote author"
 msgstr "Nom de l'auteur de la citation"
 
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:47
-#: src/pyams_content/component/paragraph/interfaces/contact.py:53
-msgid "In charge of"
-msgstr "Fonction"
-
 #: src/pyams_content/component/paragraph/interfaces/verbatim.py:48
+#: src/pyams_content/component/paragraph/interfaces/contact.py:54
+msgid "In charge of"
+msgstr "Fonction"
+
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:49
 msgid "Label of author function"
 msgstr "Fonction de l'auteur"
 
-#: src/pyams_content/component/paragraph/interfaces/verbatim.py:51
+#: src/pyams_content/component/paragraph/interfaces/verbatim.py:52
 msgid "Verbatim template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/html.py:39
+#: src/pyams_content/component/paragraph/interfaces/html.py:33
+msgid "Raw HTML "
+msgstr "Code HTML"
+
+#: src/pyams_content/component/paragraph/interfaces/html.py:56
+msgid "Rich text"
+msgstr "Texte enrichi"
+
+#: src/pyams_content/component/paragraph/interfaces/html.py:40
 msgid "Raw HTML code"
 msgstr "Code HTML"
 
-#: src/pyams_content/component/paragraph/interfaces/html.py:40
+#: src/pyams_content/component/paragraph/interfaces/html.py:41
 msgid ""
 "This HTML code will be used 'as is', without any transformation. Use with "
 "care!!"
@@ -1178,76 +1161,85 @@
 "Ce code HTML sera utilisé en l'état et intégré dans les pages sans "
 "modification. À utiliser avec précaution !!!"
 
-#: src/pyams_content/component/paragraph/interfaces/html.py:44
+#: src/pyams_content/component/paragraph/interfaces/html.py:45
 msgid "Raw HTML code template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/html.py:64
+#: src/pyams_content/component/paragraph/interfaces/html.py:66
 msgid "Body template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:49
+#: src/pyams_content/component/paragraph/interfaces/contact.py:43
+msgid "Contact card"
+msgstr "Fiche contact"
+
+#: src/pyams_content/component/paragraph/interfaces/contact.py:50
 msgid "Contact identity"
 msgstr "Nom du contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:50
+#: src/pyams_content/component/paragraph/interfaces/contact.py:51
 msgid "Name of the contact"
 msgstr "Nom complet du contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:54
+#: src/pyams_content/component/paragraph/interfaces/contact.py:55
 msgid "Label of contact function"
 msgstr "Fonction du contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:57
+#: src/pyams_content/component/paragraph/interfaces/contact.py:58
 msgid "Email address"
 msgstr "Adresse de messagerie"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:58
+#: src/pyams_content/component/paragraph/interfaces/contact.py:59
 msgid "Contact email address"
 msgstr "Adresse de messagerie \"stricte\", soit uniquement \"xxx@yyy.com\""
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:61
-msgid "Contact form"
-msgstr "Formulaire de contact"
-
 #: src/pyams_content/component/paragraph/interfaces/contact.py:62
+msgid "Contact form"
+msgstr "Formulaire de contact"
+
+#: src/pyams_content/component/paragraph/interfaces/contact.py:63
 msgid "Reference of contact form"
 msgstr "Référence d'un formulaire de contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:66
+#: src/pyams_content/component/paragraph/interfaces/contact.py:67
 msgid "Photo"
 msgstr "Photo"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:67
+#: src/pyams_content/component/paragraph/interfaces/contact.py:68
 msgid "Use 'browse' button to select contact picture"
 msgstr "Utilisez le bouton 'Parcourir' pour sélectionner la photo du contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:75
+#: src/pyams_content/component/paragraph/interfaces/contact.py:76
 msgid "Address"
 msgstr "Adresse"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:78
+#: src/pyams_content/component/paragraph/interfaces/contact.py:79
 msgid "Contact template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:79
+#: src/pyams_content/component/paragraph/interfaces/contact.py:80
 msgid "Presentation template used for this contact"
 msgstr "Modèle de présentation utilisé pour ce contact"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:71
+#: src/pyams_content/component/paragraph/interfaces/contact.py:72
 msgid "GPS location"
 msgstr "Position GPS"
 
-#: src/pyams_content/component/paragraph/interfaces/contact.py:72
+#: src/pyams_content/component/paragraph/interfaces/contact.py:73
 msgid "GPS coordinates used to locate contact"
 msgstr "Coordonnées GPS de situation du contact"
 
-#: src/pyams_content/component/paragraph/interfaces/header.py:42
+#: src/pyams_content/component/paragraph/interfaces/header.py:33
+#: src/pyams_content/component/paragraph/interfaces/header.py:40
+msgid "Header"
+msgstr "Chapô"
+
+#: src/pyams_content/component/paragraph/interfaces/header.py:43
 #: src/pyams_content/features/header/interfaces/__init__.py:39
 msgid "Header template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/paragraph/interfaces/header.py:43
+#: src/pyams_content/component/paragraph/interfaces/header.py:44
 #: src/pyams_content/features/header/interfaces/__init__.py:40
 msgid "Presentation template used for this header"
 msgstr "Mode de rendu utilisé par ce chapô"
@@ -1279,13 +1271,9 @@
 msgid "Selected themes"
 msgstr "Thèmes sélectionnés"
 
-#: src/pyams_content/component/association/paragraph.py:48
-#: src/pyams_content/component/association/paragraph.py:57
-msgid "Associations paragraph"
-msgstr "Liens et pièces jointes"
-
 #: src/pyams_content/component/association/container.py:88
 #: src/pyams_content/component/association/zmi/__init__.py:296
+#: src/pyams_content/component/association/interfaces/__init__.py:86
 msgid "Associations"
 msgstr "Liens et pièces jointes"
 
@@ -1327,11 +1315,11 @@
 msgid "Is this item visible in front-office?"
 msgstr "Si 'non', ce lien ne sera pas présenté aux internautes"
 
-#: src/pyams_content/component/association/interfaces/__init__.py:92
+#: src/pyams_content/component/association/interfaces/__init__.py:93
 msgid "Associations template"
 msgstr "Mode de rendu"
 
-#: src/pyams_content/component/association/interfaces/__init__.py:93
+#: src/pyams_content/component/association/interfaces/__init__.py:94
 msgid "Presentation template used for associations"
 msgstr "Modèle de présentation utilisé par ce bloc de contenu"
 
@@ -1453,9 +1441,8 @@
 "Nom de la boîte aux lettres, tel qu'il sera affiché dans l'application de "
 "messagerie."
 
-#: src/pyams_content/component/video/paragraph.py:47
-#: src/pyams_content/component/video/paragraph.py:57
 #: src/pyams_content/component/video/__init__.py:73
+#: src/pyams_content/component/video/interfaces/__init__.py:68
 msgid "External video"
 msgstr "Vidéo externe"
 
@@ -3538,12 +3525,6 @@
 msgid "Other terms"
 msgstr "Autres thèmes"
 
-#: src/pyams_content/shared/imagemap/paragraph.py:47
-#: src/pyams_content/shared/imagemap/paragraph.py:60
-#: src/pyams_content/shared/imagemap/interfaces/__init__.py:35
-msgid "Image map"
-msgstr "Image cliquable"
-
 #: src/pyams_content/shared/imagemap/paragraph.py:91
 msgid "no selected image map"
 msgstr "aucune image cliquable sélectionnée"
@@ -3643,6 +3624,11 @@
 msgid "Edit image map properties"
 msgstr "Propriétés de l'image"
 
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:35
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:88
+msgid "Image map"
+msgstr "Image cliquable"
+
 #: src/pyams_content/shared/imagemap/interfaces/__init__.py:50
 msgid "Internal or external link associated with this map area"
 msgstr "Lien interne ou externe associé à cette zone"
@@ -3667,18 +3653,18 @@
 msgid "List of defined map areas"
 msgstr "Liste des zones cliquables définies sur l'image"
 
-#: src/pyams_content/shared/imagemap/interfaces/__init__.py:94
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:95
 #: src/pyams_content/features/alert/interfaces.py:73
 msgid "Internal reference"
 msgstr "Référence interne"
 
-#: src/pyams_content/shared/imagemap/interfaces/__init__.py:95
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:96
 msgid "Reference to image map object"
 msgstr ""
 "Référence interne de l'image cliquable. Vous pouvez la rechercher par des "
 "mots de son titre, ou par son numéro interne (précédé d'un '+')."
 
-#: src/pyams_content/shared/imagemap/interfaces/__init__.py:98
+#: src/pyams_content/shared/imagemap/interfaces/__init__.py:99
 msgid "Image map template"
 msgstr "Mode de rendu"
 
@@ -3846,7 +3832,9 @@
 
 #: src/pyams_content/shared/site/interfaces/__init__.py:59
 msgid "Heading displayed according to presentation template"
-msgstr "Ce chapô pourra être affiché ou non en fonction du modèle de présentation retenu"
+msgstr ""
+"Ce chapô pourra être affiché ou non en fonction du modèle de présentation "
+"retenu"
 
 #: src/pyams_content/shared/site/interfaces/__init__.py:62
 msgid "Navigation title"
@@ -3866,21 +3854,16 @@
 msgid "If 'no', link is not visible"
 msgstr "Si 'non', le lien ne sera pas visible"
 
-#: src/pyams_content/shared/logo/paragraph.py:46
-#: src/pyams_content/shared/logo/paragraph.py:63
-msgid "Logos"
-msgstr "Logos"
-
-#: src/pyams_content/shared/logo/paragraph.py:94
+#: src/pyams_content/shared/logo/paragraph.py:95
 msgid "no selected logo"
 msgstr "aucun logo sélectionné"
 
-#: src/pyams_content/shared/logo/paragraph.py:100
+#: src/pyams_content/shared/logo/paragraph.py:101
 #, python-format
 msgid "logo '{0}' can't be found"
 msgstr "le logo '{0}' est introuvable"
 
-#: src/pyams_content/shared/logo/paragraph.py:108
+#: src/pyams_content/shared/logo/paragraph.py:109
 #, python-format
 msgid "logo '{0}' is not published"
 msgstr "le logo '{0}' n'est pas publié"
@@ -3923,15 +3906,19 @@
 msgid "Logo"
 msgstr "Logo"
 
-#: src/pyams_content/shared/logo/interfaces/__init__.py:70
-msgid "Logos references"
-msgstr "Logos sélectionnés"
+#: src/pyams_content/shared/logo/interfaces/__init__.py:64
+msgid "Logos"
+msgstr "Logos"
 
 #: src/pyams_content/shared/logo/interfaces/__init__.py:71
+msgid "Logos references"
+msgstr "Logos sélectionnés"
+
+#: src/pyams_content/shared/logo/interfaces/__init__.py:72
 msgid "List of internal logos references"
 msgstr "Liste de références internes vers les logos à afficher"
 
-#: src/pyams_content/shared/logo/interfaces/__init__.py:74
+#: src/pyams_content/shared/logo/interfaces/__init__.py:75
 msgid "Logos template"
 msgstr "Mode de rendu"
 
@@ -4557,11 +4544,17 @@
 
 #: src/pyams_content/features/alert/interfaces.py:60
 msgid "Alert gravity will affect rendered alert style"
-msgstr "Le niveau de gravité chosi affectera le style de rendu de l'alerte"
+msgstr "Le niveau de gravité choisi affectera le style de rendu de l'alerte"
+
+#. Default: Heading
+#: src/pyams_content/features/alert/interfaces.py:65
+#: src/pyams_content/features/alert/zmi/container.py:158
+msgid "alert-header"
+msgstr "En-tête"
 
 #: src/pyams_content/features/alert/interfaces.py:66
-msgid "Short alert header"
-msgstr "En-tête de l'alerte"
+msgid "Short alert header (Alert, Important...)"
+msgstr "En-tête de l'alerte (« Alerte », « Important », « Prudence »...)"
 
 #: src/pyams_content/features/alert/interfaces.py:69
 #: src/pyams_content/features/alert/zmi/container.py:170
@@ -4610,7 +4603,7 @@
 "Maximum interval between alert displays on a given device, given in hours; "
 "set to 0 to always display the alert"
 msgstr ""
-"Cet intervalle est donnée en heures ; passé ce délai, pour un internaute "
+"Cet intervalle est donné en heures ; passé ce délai, pour un internaute "
 "donné, l'alerte apparaîtra à nouveau. Si aucun intervalle n'est indiqué, "
 "l'alerte s'affichera en permanence."
 
@@ -4882,6 +4875,33 @@
 msgid "Hidden header"
 msgstr "Ne pas afficher d'en-tête de pages"
 
+#~ msgid "Milestones paragraph"
+#~ msgstr "Chronologie"
+
+#~ msgid "Key points paragraph"
+#~ msgstr "Points clés"
+
+#~ msgid "Pictograms paragraph"
+#~ msgstr "Pictogrammes"
+
+#~ msgid "Key numbers paragraph"
+#~ msgstr "Chiffres-clés"
+
+#~ msgid "Framed text paragraph"
+#~ msgstr "Encadré"
+
+#~ msgid "Verbatim paragraph"
+#~ msgstr "Verbatim"
+
+#~ msgid "Raw HTML paragraph"
+#~ msgstr "Code HTML"
+
+#~ msgid "Rich text paragraph"
+#~ msgstr "Texte enrichi"
+
+#~ msgid "Header paragraph"
+#~ msgstr "Chapô"
+
 #~ msgid "File legend, as shown in front-office"
 #~ msgstr "Titre du fichier, tel que présenté aux internautes"
 
--- a/src/pyams_content/locales/pyams_content.pot	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/locales/pyams_content.pot	Wed Jun 06 13:36:56 2018 +0200
@@ -6,7 +6,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE 1.0\n"
-"POT-Creation-Date: 2018-06-06 10:19+0200\n"
+"POT-Creation-Date: 2018-06-06 13:20+0200\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -77,11 +77,6 @@
 msgid "Guest user (role)"
 msgstr ""
 
-#: ./src/pyams_content/component/gallery/paragraph.py:40
-#: ./src/pyams_content/component/gallery/paragraph.py:47
-msgid "Medias gallery"
-msgstr ""
-
 #: ./src/pyams_content/component/gallery/__init__.py:154
 msgid "Gallery"
 msgstr ""
@@ -140,8 +135,9 @@
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:61
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:44
 #: ./src/pyams_content/component/illustration/interfaces/__init__.py:56
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:47
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:43
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:48
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:48
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:44
 #: ./src/pyams_content/component/video/interfaces/__init__.py:52
 msgid "Author"
 msgstr ""
@@ -149,7 +145,8 @@
 #: ./src/pyams_content/component/gallery/zmi/interfaces.py:41
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:62
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:45
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:48
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:49
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:49
 #: ./src/pyams_content/component/video/interfaces/__init__.py:53
 msgid "Name of document's author"
 msgstr ""
@@ -175,15 +172,19 @@
 msgid "Zoom image"
 msgstr ""
 
+#: ./src/pyams_content/component/gallery/interfaces/__init__.py:130
+msgid "Medias gallery"
+msgstr ""
+
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:47
 #: ./src/pyams_content/component/illustration/interfaces/__init__.py:41
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:76
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:77
 msgid "Image or video data"
 msgstr ""
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:48
 #: ./src/pyams_content/component/illustration/interfaces/__init__.py:42
-#: ./src/pyams_content/component/illustration/interfaces/__init__.py:77
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:78
 msgid "Image or video content"
 msgstr ""
 
@@ -206,7 +207,8 @@
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:98
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:40
 #: ./src/pyams_content/component/illustration/interfaces/__init__.py:52
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:43
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:44
 #: ./src/pyams_content/component/links/interfaces/__init__.py:37
 #: ./src/pyams_content/component/video/interfaces/__init__.py:48
 #: ./src/pyams_content/shared/common/interfaces/__init__.py:145
@@ -228,6 +230,7 @@
 
 #: ./src/pyams_content/component/gallery/interfaces/__init__.py:73
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:89
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:52
 msgid "Audio data"
 msgstr ""
 
@@ -305,8 +308,7 @@
 
 #: ./src/pyams_content/component/extfile/__init__.py:253
 #: ./src/pyams_content/component/extfile/__init__.py:257
-#: ./src/pyams_content/component/paragraph/video.py:49
-#: ./src/pyams_content/component/paragraph/video.py:62
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:34
 msgid "Video"
 msgstr ""
 
@@ -395,7 +397,8 @@
 msgstr ""
 
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:41
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:45
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:45
 #: ./src/pyams_content/component/video/interfaces/__init__.py:49
 msgid "File description displayed by front-office template"
 msgstr ""
@@ -435,7 +438,7 @@
 msgstr ""
 
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:81
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:51
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:52
 msgid "Video data"
 msgstr ""
 
@@ -444,14 +447,14 @@
 msgstr ""
 
 #: ./src/pyams_content/component/extfile/interfaces/__init__.py:90
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:53
 msgid "Audio file content"
 msgstr ""
 
-#: ./src/pyams_content/component/illustration/paragraph.py:40
-#: ./src/pyams_content/component/illustration/paragraph.py:47
 #: ./src/pyams_content/component/illustration/__init__.py:132
 #: ./src/pyams_content/component/illustration/zmi/__init__.py:54
 #: ./src/pyams_content/component/illustration/zmi/__init__.py:81
+#: ./src/pyams_content/component/illustration/interfaces/__init__.py:71
 msgid "Illustration"
 msgstr ""
 
@@ -488,16 +491,6 @@
 msgid "Presentation template used for illustration"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/milestone.py:199
-#: ./src/pyams_content/component/paragraph/milestone.py:222
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:303
-msgid "Milestones"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/milestone.py:231
-msgid "Milestones paragraph"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/milestone.py:140
 msgid "Selected paragraph is missing"
 msgstr ""
@@ -506,15 +499,6 @@
 msgid "Selected paragraph is not visible"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/keypoint.py:46
-#: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:39
-msgid "Key points"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/keypoint.py:61
-msgid "Key points paragraph"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/container.py:73
 msgid "Paragraphs"
 msgstr ""
@@ -523,78 +507,10 @@
 msgid "no visible paragraph"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/pictogram.py:189
-#: ./src/pyams_content/component/paragraph/pictogram.py:212
-#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:305
-msgid "Pictograms"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/pictogram.py:221
-msgid "Pictograms paragraph"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/pictogram.py:134
 msgid "Selected pictogram is missing"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/keynumber.py:183
-#: ./src/pyams_content/component/paragraph/keynumber.py:207
-#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:282
-msgid "Key numbers"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/keynumber.py:216
-msgid "Key numbers paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/frame.py:52
-msgid "Framed text"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/frame.py:62
-msgid "Framed text paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/verbatim.py:50
-msgid "Verbatim"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/verbatim.py:62
-msgid "Verbatim paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/html.py:63
-msgid "Raw HTML "
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/html.py:73
-msgid "Raw HTML paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/html.py:119
-msgid "Rich text"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/html.py:129
-msgid "Rich text paragraph"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/contact.py:47
-#: ./src/pyams_content/component/paragraph/contact.py:76
-msgid "Contact card"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/header.py:46
-#: ./src/pyams_content/component/paragraph/interfaces/header.py:39
-#: ./src/pyams_content/features/alert/interfaces.py:65
-#: ./src/pyams_content/features/alert/zmi/container.py:158
-msgid "Header"
-msgstr ""
-
-#: ./src/pyams_content/component/paragraph/header.py:61
-msgid "Header paragraph"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/zmi/milestone.py:77
 msgid "Milestones..."
 msgstr ""
@@ -617,22 +533,31 @@
 msgid "Anchor"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:318
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:299
+#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:76
+msgid "Milestones"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:314
 msgid "Add milestone"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:329
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:325
 msgid "Add new milestone"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:362
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:358
 msgid "Edit milestone properties"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/milestone.py:351
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:347
 msgid "Milestone was correctly added"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/zmi/milestone.py:285
+msgid "(missing paragraph)"
+msgstr ""
+
 #: ./src/pyams_content/component/paragraph/zmi/keypoint.py:50
 msgid "Key points..."
 msgstr ""
@@ -695,21 +620,23 @@
 msgid "Paragraph was correctly added."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/video.py:55
+#: ./src/pyams_content/component/paragraph/zmi/video.py:54
 msgid "Video paragraph..."
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/video.py:66
+#: ./src/pyams_content/component/paragraph/zmi/video.py:65
 msgid "Add new video paragraph"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/video.py:113
+#: ./src/pyams_content/component/paragraph/zmi/video.py:112
 #: ./src/pyams_content/component/video/zmi/paragraph.py:209
 msgid "Edit video properties"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/zmi/video.py:84
-#: ./src/pyams_content/component/paragraph/zmi/video.py:134
+#: ./src/pyams_content/component/paragraph/zmi/video.py:83
+#: ./src/pyams_content/component/paragraph/zmi/video.py:133
+#: ./src/pyams_content/component/paragraph/zmi/audio.py:83
+#: ./src/pyams_content/component/paragraph/zmi/audio.py:133
 #: ./src/pyams_content/component/video/zmi/paragraph.py:103
 #: ./src/pyams_content/component/video/zmi/paragraph.py:238
 msgid "HTML content"
@@ -777,6 +704,11 @@
 msgid "Associated text"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/zmi/pictogram.py:305
+#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:80
+msgid "Pictograms"
+msgstr ""
+
 #: ./src/pyams_content/component/paragraph/zmi/pictogram.py:320
 #: ./src/pyams_content/reference/pictograms/zmi/__init__.py:62
 msgid "Add pictogram"
@@ -812,6 +744,18 @@
 msgid "Default header: {0}"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/zmi/audio.py:54
+msgid "Audio paragraph..."
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/audio.py:65
+msgid "Add new audio paragraph"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/zmi/audio.py:112
+msgid "Edit audio properties"
+msgstr ""
+
 #: ./src/pyams_content/component/paragraph/zmi/keynumber.py:76
 msgid "Key numbers..."
 msgstr ""
@@ -835,6 +779,11 @@
 msgid "key-number-label"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/zmi/keynumber.py:282
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:76
+msgid "Key numbers"
+msgstr ""
+
 #: ./src/pyams_content/component/paragraph/zmi/keynumber.py:297
 msgid "Add keynumber"
 msgstr ""
@@ -950,29 +899,34 @@
 msgid "Paragraph to which this milestone should lead"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:82
+#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:83
 msgid "Milestones template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:83
+#: ./src/pyams_content/component/paragraph/interfaces/milestone.py:84
 msgid "Presentation template used for milestones"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:33
 #: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:40
+msgid "Key points"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:41
 msgid "Enter one key point by line, without hyphen or prefix"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:43
-msgid "Presentation template"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:44
-#: ./src/pyams_content/component/paragraph/interfaces/frame.py:43
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:52
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:45
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:65
-#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:99
-#: ./src/pyams_content/shared/logo/interfaces/__init__.py:75
+msgid "Presentation template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/keypoint.py:45
+#: ./src/pyams_content/component/paragraph/interfaces/frame.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:53
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:46
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:67
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:100
+#: ./src/pyams_content/shared/logo/interfaces/__init__.py:76
 msgid "Presentation template used for this paragraph"
 msgstr ""
 
@@ -1002,23 +956,24 @@
 msgid "List of paragraphs automatically added to a new content"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:40
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:61
-#: ./src/pyams_content/component/video/interfaces/__init__.py:74
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:41
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:41
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:63
+#: ./src/pyams_content/component/video/interfaces/__init__.py:75
 msgid "Body"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:52
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:53
 msgid "Video file content"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/video.py:55
-#: ./src/pyams_content/component/video/interfaces/__init__.py:77
-msgid "Video template"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/video.py:56
 #: ./src/pyams_content/component/video/interfaces/__init__.py:78
+msgid "Video template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/video.py:57
+#: ./src/pyams_content/component/video/interfaces/__init__.py:79
 msgid "Presentation template used for this video"
 msgstr ""
 
@@ -1051,14 +1006,26 @@
 msgid "Additional text associated to this pictogram"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:86
+#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:87
 msgid "Pictograms template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:87
+#: ./src/pyams_content/component/paragraph/interfaces/pictogram.py:88
 msgid "Presentation template used for pictograms"
 msgstr ""
 
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:34
+msgid "Audio"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:56
+msgid "Audio template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/audio.py:57
+msgid "Presentation template used for this audio file"
+msgstr ""
+
 #: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:41
 msgid "Is this key number visible in front-office?"
 msgstr ""
@@ -1076,127 +1043,152 @@
 msgid "The way this text will be rendered depends on presentation template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:82
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:83
 msgid "Key numbers template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:83
+#: ./src/pyams_content/component/paragraph/interfaces/keynumber.py:84
 msgid "Presentation template used for key numbers"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/frame.py:39
+#: ./src/pyams_content/component/paragraph/interfaces/frame.py:33
+msgid "Framed text"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/frame.py:40
 msgid "Frame body"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/frame.py:42
+#: ./src/pyams_content/component/paragraph/interfaces/frame.py:43
 msgid "Text template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:39
-msgid "Quoted text"
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:33
+msgid "Verbatim"
 msgstr ""
 
 #: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:40
+msgid "Quoted text"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:41
 msgid "Quotation marks will be added automatically by presentation template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:45
 msgid "Name of the quote author"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:47
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:53
-msgid "In charge of"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:48
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:54
+msgid "In charge of"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:49
 msgid "Label of author function"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:51
+#: ./src/pyams_content/component/paragraph/interfaces/verbatim.py:52
 msgid "Verbatim template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:39
-msgid "Raw HTML code"
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:33
+msgid "Raw HTML "
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:56
+msgid "Rich text"
 msgstr ""
 
 #: ./src/pyams_content/component/paragraph/interfaces/html.py:40
+msgid "Raw HTML code"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:41
 msgid ""
 "This HTML code will be used 'as is', without any transformation. Use with "
 "care!!"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:44
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:45
 msgid "Raw HTML code template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/html.py:64
+#: ./src/pyams_content/component/paragraph/interfaces/html.py:66
 msgid "Body template"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:49
-msgid "Contact identity"
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:43
+msgid "Contact card"
 msgstr ""
 
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:50
+msgid "Contact identity"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:51
 msgid "Name of the contact"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:54
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:55
 msgid "Label of contact function"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:57
-msgid "Email address"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:58
+msgid "Email address"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:59
 msgid "Contact email address"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:61
-msgid "Contact form"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:62
+msgid "Contact form"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:63
 msgid "Reference of contact form"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:66
-msgid "Photo"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:67
+msgid "Photo"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:68
 msgid "Use 'browse' button to select contact picture"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:75
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:76
 msgid "Address"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:78
-msgid "Contact template"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:79
+msgid "Contact template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:80
 msgid "Presentation template used for this contact"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/contact.py:71
-msgid "GPS location"
-msgstr ""
-
 #: ./src/pyams_content/component/paragraph/interfaces/contact.py:72
+msgid "GPS location"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/contact.py:73
 msgid "GPS coordinates used to locate contact"
 msgstr ""
 
-#: ./src/pyams_content/component/paragraph/interfaces/header.py:42
-#: ./src/pyams_content/features/header/interfaces/__init__.py:39
-msgid "Header template"
+#: ./src/pyams_content/component/paragraph/interfaces/header.py:33
+#: ./src/pyams_content/component/paragraph/interfaces/header.py:40
+msgid "Header"
 msgstr ""
 
 #: ./src/pyams_content/component/paragraph/interfaces/header.py:43
+#: ./src/pyams_content/features/header/interfaces/__init__.py:39
+msgid "Header template"
+msgstr ""
+
+#: ./src/pyams_content/component/paragraph/interfaces/header.py:44
 #: ./src/pyams_content/features/header/interfaces/__init__.py:40
 msgid "Presentation template used for this header"
 msgstr ""
@@ -1228,13 +1220,9 @@
 msgid "Selected themes"
 msgstr ""
 
-#: ./src/pyams_content/component/association/paragraph.py:48
-#: ./src/pyams_content/component/association/paragraph.py:57
-msgid "Associations paragraph"
-msgstr ""
-
 #: ./src/pyams_content/component/association/container.py:88
 #: ./src/pyams_content/component/association/zmi/__init__.py:296
+#: ./src/pyams_content/component/association/interfaces/__init__.py:86
 msgid "Associations"
 msgstr ""
 
@@ -1276,11 +1264,11 @@
 msgid "Is this item visible in front-office?"
 msgstr ""
 
-#: ./src/pyams_content/component/association/interfaces/__init__.py:92
+#: ./src/pyams_content/component/association/interfaces/__init__.py:93
 msgid "Associations template"
 msgstr ""
 
-#: ./src/pyams_content/component/association/interfaces/__init__.py:93
+#: ./src/pyams_content/component/association/interfaces/__init__.py:94
 msgid "Presentation template used for associations"
 msgstr ""
 
@@ -1394,9 +1382,8 @@
 msgid "Address as displayed in address book"
 msgstr ""
 
-#: ./src/pyams_content/component/video/paragraph.py:47
-#: ./src/pyams_content/component/video/paragraph.py:57
 #: ./src/pyams_content/component/video/__init__.py:73
+#: ./src/pyams_content/component/video/interfaces/__init__.py:68
 msgid "External video"
 msgstr ""
 
@@ -3327,12 +3314,6 @@
 msgid "Other terms"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/paragraph.py:47
-#: ./src/pyams_content/shared/imagemap/paragraph.py:60
-#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:35
-msgid "Image map"
-msgstr ""
-
 #: ./src/pyams_content/shared/imagemap/paragraph.py:91
 msgid "no selected image map"
 msgstr ""
@@ -3432,6 +3413,11 @@
 msgid "Edit image map properties"
 msgstr ""
 
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:35
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:88
+msgid "Image map"
+msgstr ""
+
 #: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:50
 msgid "Internal or external link associated with this map area"
 msgstr ""
@@ -3456,16 +3442,16 @@
 msgid "List of defined map areas"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:94
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:95
 #: ./src/pyams_content/features/alert/interfaces.py:73
 msgid "Internal reference"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:95
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:96
 msgid "Reference to image map object"
 msgstr ""
 
-#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:98
+#: ./src/pyams_content/shared/imagemap/interfaces/__init__.py:99
 msgid "Image map template"
 msgstr ""
 
@@ -3647,21 +3633,16 @@
 msgid "If 'no', link is not visible"
 msgstr ""
 
-#: ./src/pyams_content/shared/logo/paragraph.py:46
-#: ./src/pyams_content/shared/logo/paragraph.py:63
-msgid "Logos"
-msgstr ""
-
-#: ./src/pyams_content/shared/logo/paragraph.py:94
+#: ./src/pyams_content/shared/logo/paragraph.py:95
 msgid "no selected logo"
 msgstr ""
 
-#: ./src/pyams_content/shared/logo/paragraph.py:100
+#: ./src/pyams_content/shared/logo/paragraph.py:101
 #, python-format
 msgid "logo '{0}' can't be found"
 msgstr ""
 
-#: ./src/pyams_content/shared/logo/paragraph.py:108
+#: ./src/pyams_content/shared/logo/paragraph.py:109
 #, python-format
 msgid "logo '{0}' is not published"
 msgstr ""
@@ -3704,15 +3685,19 @@
 msgid "Logo"
 msgstr ""
 
-#: ./src/pyams_content/shared/logo/interfaces/__init__.py:70
-msgid "Logos references"
+#: ./src/pyams_content/shared/logo/interfaces/__init__.py:64
+msgid "Logos"
 msgstr ""
 
 #: ./src/pyams_content/shared/logo/interfaces/__init__.py:71
+msgid "Logos references"
+msgstr ""
+
+#: ./src/pyams_content/shared/logo/interfaces/__init__.py:72
 msgid "List of internal logos references"
 msgstr ""
 
-#: ./src/pyams_content/shared/logo/interfaces/__init__.py:74
+#: ./src/pyams_content/shared/logo/interfaces/__init__.py:75
 msgid "Logos template"
 msgstr ""
 
@@ -4335,8 +4320,14 @@
 msgid "Alert gravity will affect rendered alert style"
 msgstr ""
 
+#. Default: Heading
+#: ./src/pyams_content/features/alert/interfaces.py:65
+#: ./src/pyams_content/features/alert/zmi/container.py:158
+msgid "alert-header"
+msgstr ""
+
 #: ./src/pyams_content/features/alert/interfaces.py:66
-msgid "Short alert header"
+msgid "Short alert header (Alert, Important...)"
 msgstr ""
 
 #: ./src/pyams_content/features/alert/interfaces.py:69
--- a/src/pyams_content/shared/imagemap/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/shared/imagemap/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -85,6 +85,7 @@
 
 
 IMAGEMAP_PARAGRAPH_TYPE = 'ImageMap'
+IMAGEMAP_PARAGRAPH_NAME = _("Image map")
 IMAGEMAP_PARAGRAPH_RENDERERS = 'PyAMS.paragraph.imagemap.renderers'
 
 
--- a/src/pyams_content/shared/imagemap/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/shared/imagemap/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -19,7 +19,7 @@
 from pyams_content.component.paragraph.interfaces import IParagraphFactory
 from pyams_content.features.checker.interfaces import IContentChecker, ERROR_VALUE, MISSING_VALUE, MISSING_LANG_VALUE
 from pyams_content.shared.imagemap.interfaces import IImageMapParagraph, IMAGEMAP_PARAGRAPH_TYPE, \
-    IMAGEMAP_PARAGRAPH_RENDERERS
+    IMAGEMAP_PARAGRAPH_RENDERERS, IMAGEMAP_PARAGRAPH_NAME
 from pyams_i18n.interfaces import II18nManager, INegotiator, II18n
 from pyams_workflow.interfaces import IWorkflow, IWorkflowState
 
@@ -44,7 +44,7 @@
     """Image map paragraph"""
 
     icon_class = 'fa-location-arrow'
-    icon_hint = _("Image map")
+    icon_hint = IMAGEMAP_PARAGRAPH_NAME
 
     reference = FieldProperty(IImageMapParagraph['reference'])
     renderer = FieldProperty(IImageMapParagraph['renderer'])
@@ -57,7 +57,7 @@
 class ImageMapParagraphFactory(BaseParagraphFactory):
     """Image map paragraph factory"""
 
-    name = _("Image map")
+    name = IMAGEMAP_PARAGRAPH_NAME
     content_type = ImageMapParagraph
     secondary_menu = True
 
--- a/src/pyams_content/shared/logo/interfaces/__init__.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/shared/logo/interfaces/__init__.py	Wed Jun 06 13:36:56 2018 +0200
@@ -61,6 +61,7 @@
 
 
 LOGOS_PARAGRAPH_TYPE = 'Logos'
+LOGOS_PARAGRAPH_NAME = _("Logos")
 LOGOS_PARAGRAPH_RENDERERS = 'PyAMS.shared.logos.renderers'
 
 
--- a/src/pyams_content/shared/logo/paragraph.py	Wed Jun 06 11:20:14 2018 +0200
+++ b/src/pyams_content/shared/logo/paragraph.py	Wed Jun 06 13:36:56 2018 +0200
@@ -18,7 +18,8 @@
 # import interfaces
 from pyams_content.features.checker.interfaces import IContentChecker, MISSING_VALUE, MISSING_LANG_VALUE, ERROR_VALUE
 from pyams_content.features.renderer.interfaces import IContentRenderer
-from pyams_content.shared.logo.interfaces import ILogosParagraph, LOGOS_PARAGRAPH_TYPE, LOGOS_PARAGRAPH_RENDERERS
+from pyams_content.shared.logo.interfaces import ILogosParagraph, LOGOS_PARAGRAPH_TYPE, LOGOS_PARAGRAPH_RENDERERS, \
+    LOGOS_PARAGRAPH_NAME
 from pyams_i18n.interfaces import II18nManager, INegotiator, II18n
 from pyams_workflow.interfaces import IWorkflow, IWorkflowState
 
@@ -43,7 +44,7 @@
     """Logos paragraph"""
 
     icon_class = 'fa-th-large'
-    icon_hint = _("Logos")
+    icon_hint = LOGOS_PARAGRAPH_NAME
 
     references = FieldProperty(ILogosParagraph['references'])
     renderer = FieldProperty(ILogosParagraph['renderer'])
@@ -60,7 +61,7 @@
 class LogosParagraphFactory(BaseParagraphFactory):
     """Logos paragraph factory"""
 
-    name = _("Logos")
+    name = LOGOS_PARAGRAPH_NAME
     content_type = LogosParagraph
     secondary_menu = True