summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mailman/Archiver/Archiver.py12
-rw-r--r--src/mailman/Archiver/HyperArch.py5
-rw-r--r--src/mailman/Utils.py128
-rw-r--r--src/mailman/app/membership.py12
-rw-r--r--src/mailman/app/moderator.py40
-rw-r--r--src/mailman/app/notifications.py36
-rw-r--r--src/mailman/chains/hold.py33
-rw-r--r--src/mailman/commands/cli_lists.py4
-rw-r--r--src/mailman/commands/docs/info.txt1
-rw-r--r--src/mailman/pipeline/acknowledge.py18
-rw-r--r--src/mailman/queue/digest.py20
-rw-r--r--src/mailman/utilities/i18n.py10
-rw-r--r--src/mailman/utilities/tests/test_templates.py3
13 files changed, 100 insertions, 222 deletions
diff --git a/src/mailman/Archiver/Archiver.py b/src/mailman/Archiver/Archiver.py
index f8d1baa46..fe1dec252 100644
--- a/src/mailman/Archiver/Archiver.py
+++ b/src/mailman/Archiver/Archiver.py
@@ -32,9 +32,9 @@ from cStringIO import StringIO
from string import Template
from zope.component import getUtility
-from mailman import Utils
from mailman.config import config
from mailman.interfaces.domain import IDomainManager
+from mailman.utilities.i18n import make
log = logging.getLogger('mailman.error')
@@ -111,11 +111,11 @@ class Archiver:
fp = open(indexfile, 'w')
finally:
os.umask(omask)
- fp.write(Utils.maketext(
- 'emptyarchive.html',
- {'listname': self.real_name,
- 'listinfo': self.GetScriptURL('listinfo'),
- }, mlist=self))
+ fp.write(make('emptyarchive.html',
+ mailing_list=self,
+ listname=self.real_name,
+ listinfo=self.GetScriptURL('listinfo'),
+ ))
if fp:
fp.close()
finally:
diff --git a/src/mailman/Archiver/HyperArch.py b/src/mailman/Archiver/HyperArch.py
index 218c46875..92b9de2f0 100644
--- a/src/mailman/Archiver/HyperArch.py
+++ b/src/mailman/Archiver/HyperArch.py
@@ -50,6 +50,7 @@ from mailman.Archiver import pipermail
from mailman.config import config
from mailman.core.i18n import _, ctime
from mailman.interfaces.listmanager import IListManager
+from mailman.utilities.i18n import find
from mailman.utilities.string import uncanonstr, websafe
@@ -183,8 +184,8 @@ def quick_maketext(templatefile, dict=None, lang=None, mlist=None):
template = _templatecache.get(filepath)
if filepath is None or template is None:
# Use the basic maketext, with defaults to get the raw template
- template, filepath = Utils.findtext(templatefile, lang=lang.code,
- raw=True, mlist=mlist)
+ template, filepath = find(templatefile, mailing_list=mlist,
+ language=lang.code)
_templatefilepathcache[cachekey] = filepath
_templatecache[filepath] = template
# Copied from Utils.maketext()
diff --git a/src/mailman/Utils.py b/src/mailman/Utils.py
index a26025fa3..cfd61eb7a 100644
--- a/src/mailman/Utils.py
+++ b/src/mailman/Utils.py
@@ -31,20 +31,13 @@ __all__ = [
import os
import re
-import errno
import logging
# pylint: disable-msg=E0611,W0403
from string import ascii_letters, digits, whitespace
-from zope.component import getUtility
import mailman.templates
-from mailman.config import config
-from mailman.core.i18n import _
-from mailman.interfaces.languages import ILanguageManager
-from mailman.utilities.string import expand
-
AT = '@'
CR = '\r'
@@ -139,124 +132,3 @@ def wrap(text, column=70, honor_leading_ws=True):
# end for text in lines
# the last two newlines are bogus
return wrapped[:-2]
-
-
-
-class OuterExit(Exception):
- pass
-
-def findtext(templatefile, raw_dict=None, raw=False, lang=None, mlist=None):
- # Make some text from a template file. The order of searches depends on
- # whether mlist and lang are provided. Once the templatefile is found,
- # string substitution is performed by interpolation in `dict'. If `raw'
- # is false, the resulting text is wrapped/filled by calling wrap().
- #
- # When looking for a template in a specific language, there are 4 places
- # that are searched, in this order:
- #
- # 1. the list-specific language directory
- # lists/<listname>/<language>
- #
- # 2. the domain-specific language directory
- # templates/<list.host_name>/<language>
- #
- # 3. the site-wide language directory
- # templates/site/<language>
- #
- # 4. the global default language directory
- # templates/<language>
- #
- # The first match found stops the search. In this way, you can specialize
- # templates at the desired level, or, if you use only the default
- # templates, you don't need to change anything. You should never modify
- # files in the templates/<language> subdirectory, since Mailman will
- # overwrite these when you upgrade. That's what the templates/site
- # language directories are for.
- #
- # A further complication is that the language to search for is determined
- # by both the `lang' and `mlist' arguments. The search order there is
- # that if lang is given, then the 4 locations above are searched,
- # substituting lang for <language>. If no match is found, and mlist is
- # given, then the 4 locations are searched using the list's preferred
- # language. After that, the server default language is used for
- # <language>. If that still doesn't yield a template, then the standard
- # distribution's English language template is used as an ultimate
- # fallback, and when lang is not 'en', the resulting template is passed
- # through the translation service. If this template is missing you've got
- # big problems. ;)
- #
- # A word on backwards compatibility: Mailman versions prior to 2.1 stored
- # templates in templates/*.{html,txt} and lists/<listname>/*.{html,txt}.
- # Those directories are no longer searched so if you've got customizations
- # in those files, you should move them to the appropriate directory based
- # on the above description. Mailman's upgrade script cannot do this for
- # you.
- #
- # The function has been revised and renamed as it now returns both the
- # template text and the path from which it retrieved the template. The
- # original function is now a wrapper which just returns the template text
- # as before, by calling this renamed function and discarding the second
- # item returned.
- #
- # Calculate the languages to scan
- languages = set()
- if lang is not None:
- languages.add(lang)
- if mlist is not None:
- languages.add(mlist.preferred_language.code)
- languages.add(config.mailman.default_language)
- assert None not in languages, 'None in languages'
- # Calculate the locations to scan
- searchdirs = []
- if mlist is not None:
- searchdirs.append(mlist.data_path)
- searchdirs.append(os.path.join(config.TEMPLATE_DIR, mlist.host_name))
- searchdirs.append(os.path.join(config.TEMPLATE_DIR, 'site'))
- searchdirs.append(config.TEMPLATE_DIR)
- # Start scanning
- fp = None
- try:
- for lang in languages:
- for dir in searchdirs:
- filename = os.path.join(dir, lang, templatefile)
- try:
- fp = open(filename)
- raise OuterExit
- except IOError, e:
- if e.errno != errno.ENOENT:
- raise
- # Okay, it doesn't exist, keep looping
- fp = None
- except OuterExit:
- pass
- if fp is None:
- # Try one last time with the distro English template, which, unless
- # you've got a really broken installation, must be there.
- try:
- filename = os.path.join(TEMPLATE_DIR, 'en', templatefile)
- fp = open(filename)
- except IOError, e:
- if e.errno != errno.ENOENT:
- raise
- # We never found the template. BAD!
- raise IOError(errno.ENOENT, 'No template file found', templatefile)
- else:
- # XXX BROKEN HACK
- data = fp.read()[:-1]
- template = _(data)
- fp.close()
- else:
- template = fp.read()
- fp.close()
- charset = getUtility(ILanguageManager)[lang].charset
- template = unicode(template, charset, 'replace')
- text = template
- if raw_dict is not None:
- text = expand(template, raw_dict)
- if raw:
- return text, filename
- return wrap(text), filename
-
-
-def maketext(templatefile, dict=None, raw=False, lang=None, mlist=None):
- return findtext(templatefile, dict, raw, lang, mlist)[0]
diff --git a/src/mailman/app/membership.py b/src/mailman/app/membership.py
index 8723fd781..fcbedc2f5 100644
--- a/src/mailman/app/membership.py
+++ b/src/mailman/app/membership.py
@@ -29,7 +29,6 @@ __all__ = [
from email.utils import formataddr
from zope.component import getUtility
-from mailman import Utils
from mailman.app.notifications import send_goodbye_message
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification
@@ -39,6 +38,7 @@ from mailman.interfaces.member import (
AlreadySubscribedError, MemberRole, MembershipIsBannedError,
NotAMemberError)
from mailman.interfaces.usermanager import IUserManager
+from mailman.utilities.i18n import make
@@ -149,10 +149,10 @@ def delete_member(mlist, address, admin_notif=None, userack=None):
user = getUtility(IUserManager).get_user(address)
realname = user.real_name
subject = _('$mlist.real_name unsubscription notification')
- text = Utils.maketext(
- 'adminunsubscribeack.txt',
- {'listname': mlist.real_name,
- 'member' : formataddr((realname, address)),
- }, mlist=mlist)
+ text = make('adminunsubscribeack.txt',
+ mailing_list=mlist,
+ listname=mlist.real_name,
+ member=formataddr((realname, address)),
+ )
msg = OwnerNotification(mlist, subject, text)
msg.send(mlist)
diff --git a/src/mailman/app/moderator.py b/src/mailman/app/moderator.py
index cdfedd44b..50a03c833 100644
--- a/src/mailman/app/moderator.py
+++ b/src/mailman/app/moderator.py
@@ -48,6 +48,7 @@ from mailman.interfaces.member import (
AlreadySubscribedError, DeliveryMode, NotAMemberError)
from mailman.interfaces.messages import IMessageStore
from mailman.interfaces.requests import IRequests, RequestType
+from mailman.utilities.i18n import make
NL = '\n'
@@ -209,12 +210,12 @@ def hold_subscription(mlist, address, realname, password, mode, language):
if mlist.admin_immed_notify:
subject = _(
'New subscription request to list $mlist.real_name from $address')
- text = Utils.maketext(
- 'subauth.txt',
- {'username' : address,
- 'listname' : mlist.fqdn_listname,
- 'admindb_url': mlist.script_url('admindb'),
- }, mlist=mlist)
+ text = make('subauth.txt',
+ mailing_list=mlist,
+ username=address,
+ listname=mlist.fqdn_listname,
+ admindb_url=mlist.script_url('admindb'),
+ )
# This message should appear to come from the <list>-owner so as
# to avoid any useless bounce processing.
msg = UserNotification(
@@ -281,12 +282,12 @@ def hold_unsubscription(mlist, address):
if mlist.admin_immed_notify:
subject = _(
'New unsubscription request from $mlist.real_name by $address')
- text = Utils.maketext(
- 'unsubauth.txt',
- {'address' : address,
- 'listname' : mlist.fqdn_listname,
- 'admindb_url': mlist.script_url('admindb'),
- }, mlist=mlist)
+ text = make('unsubauth.txt',
+ mailing_list=mlist,
+ address=address,
+ listname=mlist.fqdn_listname,
+ admindb_url=mlist.script_url('admindb'),
+ )
# This message should appear to come from the <list>-owner so as
# to avoid any useless bounce processing.
msg = UserNotification(
@@ -336,13 +337,14 @@ def _refuse(mlist, request, recip, comment, origmsg=None, lang=None):
lang = (mlist.preferred_language
if member is None
else member.preferred_language)
- text = Utils.maketext(
- 'refuse.txt',
- {'listname' : mlist.fqdn_listname,
- 'request' : request,
- 'reason' : comment,
- 'adminaddr': mlist.owner_address,
- }, lang=lang.code, mlist=mlist)
+ text = make('refuse.txt',
+ mailing_list=mlist,
+ language=lang.code,
+ listname=mlist.fqdn_listname,
+ request=request,
+ reason=comment,
+ adminaddr=mlist.owner_address,
+ )
with _.using(lang.code):
# add in original message, but not wrap/filled
if origmsg:
diff --git a/src/mailman/app/notifications.py b/src/mailman/app/notifications.py
index 985f4eece..d7e64a020 100644
--- a/src/mailman/app/notifications.py
+++ b/src/mailman/app/notifications.py
@@ -30,11 +30,12 @@ __all__ = [
from email.utils import formataddr
from lazr.config import as_boolean
-from mailman import Utils
+from mailman.Utils import wrap
from mailman.config import config
from mailman.core.i18n import _
from mailman.email.message import OwnerNotification, UserNotification
from mailman.interfaces.member import DeliveryMode
+from mailman.utilities.i18n import make
@@ -54,7 +55,7 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
:type delivery_mode: DeliveryMode
"""
if mlist.welcome_msg:
- welcome = Utils.wrap(mlist.welcome_msg) + '\n'
+ welcome = wrap(mlist.welcome_msg) + '\n'
else:
welcome = ''
# Find the IMember object which is subscribed to the mailing list, because
@@ -62,15 +63,16 @@ def send_welcome_message(mlist, address, language, delivery_mode, text=''):
member = mlist.members.get_member(address)
options_url = member.options_url
# Get the text from the template.
- text += Utils.maketext(
- 'subscribeack.txt', {
- 'real_name' : mlist.real_name,
- 'posting_address' : mlist.fqdn_listname,
- 'listinfo_url' : mlist.script_url('listinfo'),
- 'optionsurl' : options_url,
- 'request_address' : mlist.request_address,
- 'welcome' : welcome,
- }, lang=language.code, mlist=mlist)
+ text += make('subscribeack.txt',
+ mailing_list=mlist,
+ language=language.code,
+ real_name=mlist.real_name,
+ posting_address=mlist.fqdn_listname,
+ listinfo_url=mlist.script_url('listinfo'),
+ optionsurl=options_url,
+ request_address=mlist.request_address,
+ welcome=welcome,
+ )
if delivery_mode is not DeliveryMode.regular:
digmode = _(' (Digest mode)')
else:
@@ -98,7 +100,7 @@ def send_goodbye_message(mlist, address, language):
:type language: string
"""
if mlist.goodbye_msg:
- goodbye = Utils.wrap(mlist.goodbye_msg) + '\n'
+ goodbye = wrap(mlist.goodbye_msg) + '\n'
else:
goodbye = ''
msg = UserNotification(
@@ -124,10 +126,10 @@ def send_admin_subscription_notice(mlist, address, full_name, language):
with _.using(mlist.preferred_language.code):
subject = _('$mlist.real_name subscription notification')
full_name = full_name.encode(language.charset, 'replace')
- text = Utils.maketext(
- 'adminsubscribeack.txt',
- {'listname' : mlist.real_name,
- 'member' : formataddr((full_name, address)),
- }, mlist=mlist)
+ text = make('adminsubscribeack.txt',
+ mailing_list=mlist,
+ listname=mlist.real_name,
+ member=formataddr((full_name, address)),
+ )
msg = OwnerNotification(mlist, subject, text)
msg.send(mlist)
diff --git a/src/mailman/chains/hold.py b/src/mailman/chains/hold.py
index ff53621ab..fcd11ca72 100644
--- a/src/mailman/chains/hold.py
+++ b/src/mailman/chains/hold.py
@@ -35,7 +35,7 @@ from zope.component import getUtility
from zope.event import notify
from zope.interface import implements
-from mailman.Utils import maketext, wrap
+from mailman.Utils import wrap
from mailman.app.moderator import hold_message
from mailman.app.replybot import can_acknowledge
from mailman.chains.base import ChainNotification, TerminalChainBase
@@ -46,6 +46,7 @@ from mailman.interfaces.autorespond import IAutoResponseSet, Response
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.pending import IPendable, IPendings
from mailman.interfaces.usermanager import IUserManager
+from mailman.utilities.i18n import make
from mailman.utilities.string import oneline
@@ -103,14 +104,13 @@ def autorespond_to_sender(mlist, sender, lang=None):
log.info('hold autoresponse limit hit: %s', sender)
response_set.response_sent(address, Response.hold)
# Send this notification message instead.
- text = maketext(
- 'nomoretoday.txt',
- {'sender' : sender,
- 'listname': mlist.fqdn_listname,
- 'num' : todays_count,
- 'owneremail': mlist.owner_address,
- },
- lang=lang)
+ text = make('nomoretoday.txt',
+ language=lang,
+ sender=sender,
+ listname=mlist.fqdn_listname,
+ num=todays_count,
+ owneremail=mlist.owner_address,
+ )
with _.using(lang.code):
msg = UserNotification(
sender, mlist.owner_address,
@@ -194,8 +194,10 @@ class HoldChain(TerminalChainBase):
subject = _(
'Your message to $mlist.fqdn_listname awaits moderator approval')
send_language_code = msgdata.get('lang', language.code)
- text = maketext('postheld.txt', substitutions,
- lang=send_language_code, mlist=mlist)
+ text = make('postheld.txt',
+ mailing_list=mlist,
+ language=send_language_code,
+ **substitutions)
adminaddr = mlist.bounces_address
nmsg = UserNotification(
msg.sender, adminaddr, subject, text,
@@ -222,10 +224,11 @@ class HoldChain(TerminalChainBase):
mlist.owner_address,
subject, lang=language)
nmsg.set_type('multipart/mixed')
- text = MIMEText(
- maketext('postauth.txt', substitutions,
- raw=True, mlist=mlist),
- _charset=charset)
+ text = MIMEText(make('postauth.txt',
+ mailing_list=mlist,
+ wrap=False,
+ **substitutions),
+ _charset=charset)
dmsg = MIMEText(wrap(_("""\
If you reply to this message, keeping the Subject: header intact, Mailman will
discard the held message. Do this if the message is spam. If you reply to
diff --git a/src/mailman/commands/cli_lists.py b/src/mailman/commands/cli_lists.py
index a127dd816..021ce5991 100644
--- a/src/mailman/commands/cli_lists.py
+++ b/src/mailman/commands/cli_lists.py
@@ -30,7 +30,6 @@ __all__ = [
from zope.component import getUtility
from zope.interface import implements
-from mailman.Utils import maketext
from mailman.app.lifecycle import create_list, remove_list
from mailman.config import config
from mailman.core.constants import system_preferences
@@ -42,6 +41,7 @@ from mailman.interfaces.domain import (
BadDomainSpecificationError, IDomainManager)
from mailman.interfaces.languages import ILanguageManager
from mailman.interfaces.listmanager import IListManager, ListAlreadyExistsError
+from mailman.utilities.i18n import make
@@ -213,7 +213,7 @@ class Create:
requestaddr = mlist.request_address,
siteowner = mlist.no_reply_address,
)
- text = maketext('newlist.txt', d, mlist=mlist)
+ text = make('newlist.txt', mailing_list=mlist, **d)
# Set the I18N language to the list's preferred language so the
# header will match the template language. Stashing and restoring
# the old translation context is just (healthy? :) paranoia.
diff --git a/src/mailman/commands/docs/info.txt b/src/mailman/commands/docs/info.txt
index bccb78fda..12fce3223 100644
--- a/src/mailman/commands/docs/info.txt
+++ b/src/mailman/commands/docs/info.txt
@@ -74,6 +74,7 @@ The File System Hierarchy layout is the same every by definition.
PUBLIC_ARCHIVE_FILE_DIR = /var/lib/mailman/archives/public
QUEUE_DIR = /var/spool/mailman
SITE_PW_FILE = /var/lib/mailman/data/adm.pw
+ TEMPLATE_DIR = .../mailman/templates
VAR_DIR = /var/lib/mailman
diff --git a/src/mailman/pipeline/acknowledge.py b/src/mailman/pipeline/acknowledge.py
index fcde6d6a5..e5b49ffa0 100644
--- a/src/mailman/pipeline/acknowledge.py
+++ b/src/mailman/pipeline/acknowledge.py
@@ -31,11 +31,11 @@ __all__ = [
from zope.component import getUtility
from zope.interface import implements
-from mailman import Utils
from mailman.core.i18n import _
from mailman.email.message import UserNotification
from mailman.interfaces.handler import IHandler
from mailman.interfaces.languages import ILanguageManager
+from mailman.utilities.i18n import make
from mailman.utilities.string import oneline
@@ -71,13 +71,15 @@ class Acknowledge:
charset = language_manager[language.code].charset
# Now get the acknowledgement template.
realname = mlist.real_name
- text = Utils.maketext(
- 'postack.txt',
- {'subject' : oneline(original_subject, charset),
- 'listname' : realname,
- 'listinfo_url': mlist.script_url('listinfo'),
- 'optionsurl' : member.options_url,
- }, lang=language.code, mlist=mlist, raw=True)
+ text = make('postack.txt',
+ mailing_list=mlist,
+ language=language.code,
+ wrap=False,
+ subject=oneline(original_subject, charset),
+ listname=realname,
+ listinfo_url=mlist.script_url('listinfo'),
+ optionsurl=member.options_url,
+ )
# Craft the outgoing message, with all headers and attributes
# necessary for general delivery. Then enqueue it to the outgoing
# queue.
diff --git a/src/mailman/queue/digest.py b/src/mailman/queue/digest.py
index a2feff448..2541e14ed 100644
--- a/src/mailman/queue/digest.py
+++ b/src/mailman/queue/digest.py
@@ -38,7 +38,7 @@ from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.utils import formatdate, getaddresses, make_msgid
-from mailman.Utils import maketext, wrap
+from mailman.Utils import wrap
from mailman.config import config
from mailman.core.errors import DiscardMessage
from mailman.core.i18n import _
@@ -46,6 +46,7 @@ from mailman.interfaces.member import DeliveryMode, DeliveryStatus
from mailman.pipeline.decorate import decorate
from mailman.pipeline.scrubber import process as scrubber
from mailman.queue import Runner
+from mailman.utilities.i18n import make
from mailman.utilities.mailbox import Mailbox
from mailman.utilities.string import oneline
@@ -76,15 +77,14 @@ class Digester:
# digest header are separate MIME subobjects. In either case, it's
# the first thing in the digest, and we can calculate it now, so go
# ahead and add it now.
- self._masthead = maketext(
- 'masthead.txt', dict(
- real_name=mlist.real_name,
- got_list_email=mlist.posting_address,
- got_listinfo_url=mlist.script_url('listinfo'),
- got_request_email=mlist.request_address,
- got_owner_email=mlist.owner_address,
- ),
- mlist=mlist)
+ self._masthead = make('masthead.txt',
+ mailing_list=mlist,
+ real_name=mlist.real_name,
+ got_list_email=mlist.posting_address,
+ got_listinfo_url=mlist.script_url('listinfo'),
+ got_request_email=mlist.request_address,
+ got_owner_email=mlist.owner_address,
+ )
# Set things up for the table of contents.
self._header = decorate(mlist, mlist.digest_header)
self._toc = StringIO()
diff --git a/src/mailman/utilities/i18n.py b/src/mailman/utilities/i18n.py
index bb826e853..f84baa7c6 100644
--- a/src/mailman/utilities/i18n.py
+++ b/src/mailman/utilities/i18n.py
@@ -35,6 +35,7 @@ from zope.component import getUtility
from mailman.config import config
from mailman.core.constants import system_preferences
+from mailman.core.i18n import _
from mailman.interfaces.languages import ILanguageManager
from mailman.utilities.string import expand
@@ -184,14 +185,11 @@ def make(template_file, mailing_list=None, language=None, wrap=True, **kw):
"""
path, fp = find(template_file, mailing_list, language)
try:
- raw_text = fp.read()
+ # XXX BROKEN HACK
+ template = _(fp.read()[:-1])
finally:
fp.close()
- # The language is always the second to last path component.
- parts = path.split(os.sep)
- language_code = parts[-2]
- charset = getUtility(ILanguageManager)[language_code].charset
- template = unicode(raw_text, charset, 'replace')
+ assert isinstance(template, unicode), 'Translated template is not unicode'
text = expand(template, kw)
if wrap:
return wrap_text(text)
diff --git a/src/mailman/utilities/tests/test_templates.py b/src/mailman/utilities/tests/test_templates.py
index b95b181f7..2de43ae3c 100644
--- a/src/mailman/utilities/tests/test_templates.py
+++ b/src/mailman/utilities/tests/test_templates.py
@@ -260,7 +260,6 @@ It will not be wrapped.
self.assertEqual(make('nosub.txt', self.mlist), """\
This is a global template. It has no substitutions. It will be
wrapped.
-
""")
def test_substitutions(self):
@@ -269,7 +268,6 @@ wrapped.
howmany='a few'), """\
This is a very nice template. It has a few substitutions. It will be
wrapped.
-
""")
def test_substitutions_no_wrap(self):
@@ -279,7 +277,6 @@ wrapped.
This is a very nice template.
It has a few substitutions.
It will not be wrapped.
-
""")