mirror of
https://github.com/friendica/friendica
synced 2025-01-03 15:22:19 +00:00
Merge pull request #14090 from annando/bbcode
The BBCode conversion is split into several smaller functions
This commit is contained in:
commit
49a0b0fc3c
4 changed files with 711 additions and 590 deletions
|
@ -1317,10 +1317,8 @@ class BBCode
|
|||
|
||||
Hook::callAll('bbcode', $text);
|
||||
|
||||
$a = DI::app();
|
||||
|
||||
$text = self::performWithEscapedTags($text, ['code'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a, $uriid) {
|
||||
$text = self::performWithEscapedTags($text, ['noparse', 'nobb', 'pre'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $a, $uriid) {
|
||||
$text = self::performWithEscapedTags($text, ['code'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $uriid) {
|
||||
$text = self::performWithEscapedTags($text, ['noparse', 'nobb', 'pre'], function ($text) use ($try_oembed, $simple_html, $for_plaintext, $uriid) {
|
||||
/*
|
||||
* preg_match_callback function to replace potential Oembed tags with Oembed content
|
||||
*
|
||||
|
@ -1341,6 +1339,117 @@ class BBCode
|
|||
return $return;
|
||||
};
|
||||
|
||||
// Extract the private images which use data urls since preg has issues with
|
||||
// large data sizes. Stash them away while we do bbcode conversion, and then put them back
|
||||
// in after we've done all the regex matching. We cannot use any preg functions to do this.
|
||||
$extracted = self::extractImagesFromItemBody($text);
|
||||
$saved_image = $extracted['images'];
|
||||
|
||||
// General clean up of the content, for example unneeded blanks and new lines
|
||||
$text = self::normaliseInput($extracted['body']);
|
||||
|
||||
// Now the structural elements are converted
|
||||
$text = self::convertHeaderToHtml($text, $simple_html);
|
||||
$text = self::convertStylesToHtml($text, $simple_html);
|
||||
$text = self::convertListsToHtml($text);
|
||||
$text = self::convertTablesToHtml($text);
|
||||
$text = self::convertSpoilersToHtml($text);
|
||||
$text = self::convertStructuresToHtml($text);
|
||||
|
||||
// We add URL without a surrounding URL at this time, since at a earlier stage it would had been too early,
|
||||
// since the used regular expression won't touch URL inside of BBCode elements, but with the structural ones it should.
|
||||
// At a later stage we won't be able to exclude certain parts of the code.
|
||||
$text = self::performWithEscapedTags($text, ['url', 'img', 'audio', 'video', 'youtube', 'vimeo', 'share', 'attachment', 'iframe', 'bookmark', 'map', 'oembed'], function ($text) use ($simple_html, $for_plaintext) {
|
||||
if (!$for_plaintext) {
|
||||
$text = preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
|
||||
}
|
||||
return self::convertSmileysToHtml($text, $simple_html, $for_plaintext);
|
||||
});
|
||||
|
||||
// Now for some more complex BBCode elements (mostly non standard ones)
|
||||
$text = self::convertAttachmentsToHtml($text, $simple_html, $try_oembed, $uriid);
|
||||
$text = self::convertMapsToHtml($text, $simple_html);
|
||||
$text = self::convertQuotesToHtml($text);
|
||||
$text = self::convertVideoPlatformsToHtml($text, $try_oembed);
|
||||
$text = self::convertOEmbedToHtml($text, $uriid);
|
||||
$text = self::convertEventsToHtml($text, $simple_html, $uriid);
|
||||
|
||||
// Some simpler non standard elements
|
||||
$text = self::convertEmojisToHtml($text, $simple_html);
|
||||
$text = self::convertCryptToHtml($text);
|
||||
$text = self::convertIFramesToHtml($text);
|
||||
$text = self::convertMailToHtml($text);
|
||||
$text = self::convertAudioVideoToHtml($text, $simple_html, $try_oembed, $try_oembed_callback);
|
||||
|
||||
// At last, some standard elements. URL has to go last,
|
||||
// since some previous conversions use URL elements.
|
||||
$text = self::convertImagesToHtml($text, $simple_html, $uriid);
|
||||
$text = self::convertUrlToHtml($text, $simple_html, $for_plaintext, $try_oembed, $try_oembed_callback);
|
||||
|
||||
// If the post only consists of an emoji, we display it larger than normal.
|
||||
if (!$for_plaintext && DI::config()->get('system', 'big_emojis') && ($simple_html != self::DIASPORA) && Smilies::isEmojiPost($text)) {
|
||||
$text = '<span style="font-size: xx-large; line-height: normal;">' . $text . '</span>';
|
||||
}
|
||||
|
||||
// Sanitize the created HTML.
|
||||
$text = self::cleanupHtml($text);
|
||||
|
||||
// This needs to be called after the cleanup, since otherwise some links are invalidated
|
||||
$text = self::convertSharesToHtml($text, $simple_html, $try_oembed, $uriid);
|
||||
|
||||
// Insert the previously extracted embedded image again.
|
||||
return self::interpolateSavedImagesIntoItemBody($uriid, $text, $saved_image);
|
||||
}); // Escaped noparse, nobb, pre
|
||||
|
||||
// Remove escaping tags and replace new lines that remain
|
||||
$text = preg_replace_callback('/\[(noparse|nobb)](.*?)\[\/\1]/ism', function ($match) {
|
||||
return str_replace("\n", "<br>", $match[2]);
|
||||
}, $text);
|
||||
|
||||
// Additionally, [pre] tags preserve spaces
|
||||
$text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", function ($match) {
|
||||
return str_replace([' ', "\n"], [' ', "<br>"], htmlentities($match[1], ENT_NOQUOTES, 'UTF-8'));
|
||||
}, $text);
|
||||
|
||||
return $text;
|
||||
}); // Escaped code
|
||||
|
||||
$text = preg_replace_callback(
|
||||
"#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism",
|
||||
function ($matches) {
|
||||
if (strpos($matches[2], "\n") !== false) {
|
||||
$return = '<pre><code class="language-' . trim($matches[1]) . '">' . htmlentities(trim($matches[2], "\n\r"), ENT_NOQUOTES, 'UTF-8') . '</code></pre>';
|
||||
} else {
|
||||
$return = '<code>' . htmlentities($matches[2], ENT_NOQUOTES, 'UTF-8') . '</code>';
|
||||
}
|
||||
|
||||
return $return;
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// Default iframe allowed domains/path
|
||||
$allowedIframeDomains = DI::config()->get('system', 'no_oembed_rich_content') ? [] : ['www.youtube.com/embed/', 'player.vimeo.com/video/'];
|
||||
|
||||
$allowedIframeDomains = array_merge(
|
||||
$allowedIframeDomains,
|
||||
DI::config()->get('system', 'allowed_oembed') ?
|
||||
explode(',', DI::config()->get('system', 'allowed_oembed'))
|
||||
: []
|
||||
);
|
||||
|
||||
if (strpos($text, '<p>') !== false || strpos($text, '</p>') !== false) {
|
||||
$text = '<p>' . $text . '</p>';
|
||||
}
|
||||
|
||||
$text = HTML::purify($text, $allowedIframeDomains);
|
||||
DI::profiler()->stopRecording();
|
||||
|
||||
return trim($text);
|
||||
}
|
||||
|
||||
private static function normaliseInput(string $text): string
|
||||
{
|
||||
// Remove the abstract element. It is a non visible element.
|
||||
$text = self::stripAbstract($text);
|
||||
|
||||
|
@ -1351,20 +1460,6 @@ class BBCode
|
|||
$text = preg_replace("#\[(\w*)](\n*)#ism", '$2[$1]', $text);
|
||||
$text = preg_replace("#(\n*)\[/(\w*)]#ism", '[/$2]$1', $text);
|
||||
|
||||
// Extract the private images which use data urls since preg has issues with
|
||||
// large data sizes. Stash them away while we do bbcode conversion, and then put them back
|
||||
// in after we've done all the regex matching. We cannot use any preg functions to do this.
|
||||
|
||||
$extracted = self::extractImagesFromItemBody($text);
|
||||
$text = $extracted['body'];
|
||||
$saved_image = $extracted['images'];
|
||||
|
||||
// If we find any event code, turn it into an event.
|
||||
// After we're finished processing the bbcode we'll
|
||||
// replace all of the event code with a reformatted version.
|
||||
|
||||
$ev = Event::fromBBCode($text);
|
||||
|
||||
// Replace any html brackets with HTML Entities to prevent executing HTML or script
|
||||
// Don't use strip_tags here because it breaks [url] search by replacing & with amp
|
||||
|
||||
|
@ -1375,11 +1470,6 @@ class BBCode
|
|||
$text = preg_replace("/\s?\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1]$2[/share]\n", $text);
|
||||
$text = preg_replace("/\s?\[quote(.*?)\]\s?(.*?)\s?\[\/quote\]\s?/ism", "\n[quote$1]$2[/quote]\n", $text);
|
||||
|
||||
// when the content is meant exporting to other systems then remove the avatar picture since this doesn't really look good on these systems
|
||||
if (!$try_oembed) {
|
||||
$text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1$2]$3[/share]", $text);
|
||||
}
|
||||
|
||||
// Remove linefeeds inside of the table elements. See issue #6799
|
||||
$search = [
|
||||
"\n[th]", "[th]\n", " [th]", "\n[/th]", "[/th]\n", "[/th] ",
|
||||
|
@ -1428,6 +1518,38 @@ class BBCode
|
|||
} while ($oldtext != $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertEventsToHtml(string $text, int $simple_html, int $uriid): string
|
||||
{
|
||||
// If we find any event code, turn it into an event.
|
||||
// After we're finished processing the bbcode we'll
|
||||
// replace all of the event code with a reformatted version.
|
||||
|
||||
$ev = Event::fromBBCode($text);
|
||||
|
||||
// If we found an event earlier, strip out all the event code and replace with a reformatted version.
|
||||
// Replace the event-start section with the entire formatted event. The other bbcode is stripped.
|
||||
// Summary (e.g. title) is required, earlier revisions only required description (in addition to
|
||||
// start which is always required). Allow desc with a missing summary for compatibility.
|
||||
|
||||
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
|
||||
$sub = Event::getHTML($ev, $simple_html, $uriid);
|
||||
|
||||
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism", $sub, $text);
|
||||
$text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism", '', $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertAttachmentsToHtml(string $text, int $simple_html, bool $try_oembed, int $uriid): string
|
||||
{
|
||||
/// @todo Have a closer look at the different html modes
|
||||
// Handle attached links or videos
|
||||
if ($simple_html == self::NPF) {
|
||||
|
@ -1440,16 +1562,11 @@ class BBCode
|
|||
$text = self::convertAttachment($text, $simple_html, $try_oembed, [], $uriid);
|
||||
}
|
||||
|
||||
$nosmile = strpos($text, '[nosmile]') !== false;
|
||||
$text = str_replace('[nosmile]', '', $text);
|
||||
|
||||
// Replace non graphical smilies for external posts
|
||||
if (!$nosmile) {
|
||||
$text = self::performWithEscapedTags($text, ['url', 'img', 'audio', 'video', 'youtube', 'vimeo', 'share', 'attachment', 'iframe', 'bookmark'], function ($text) use ($simple_html, $for_plaintext) {
|
||||
return Smilies::replace($text, ($simple_html != self::INTERNAL) || $for_plaintext);
|
||||
});
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertMapsToHtml(string $text, int $simple_html): string
|
||||
{
|
||||
// leave open the possibility of [map=something]
|
||||
// this is replaced in Item::prepareBody() which has knowledge of the item location
|
||||
if (strpos($text, '[/map]') !== false) {
|
||||
|
@ -1476,6 +1593,11 @@ class BBCode
|
|||
$text = preg_replace("/\[map\]/", '<p class="map"></p>', $text);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertHeaderToHtml(string $text, int $simple_html): string
|
||||
{
|
||||
// Check for headers
|
||||
|
||||
if ($simple_html == self::INTERNAL) {
|
||||
|
@ -1504,20 +1626,48 @@ class BBCode
|
|||
$text = preg_replace("(\[h6\](.*?)\[\/h6\])ism", '</p><h6>$1</h6><p>', $text);
|
||||
}
|
||||
|
||||
// Check for paragraph
|
||||
$text = preg_replace("(\[p\](.*?)\[\/p\])ism", '<p>$1</p>', $text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Check for bold text
|
||||
$text = preg_replace("(\[b\](.*?)\[\/b\])ism", '<strong>$1</strong>', $text);
|
||||
private static function convertEmojisToHtml(string $text, int $simple_html): string
|
||||
{
|
||||
// Mastodon Emoji (internal tag, do not document for users)
|
||||
if ($simple_html == self::MASTODON_API) {
|
||||
$text = preg_replace("(\[emoji=(.*?)](.*?)\[/emoji])ism", '$2', $text);
|
||||
} else {
|
||||
$text = preg_replace("(\[emoji=(.*?)](.*?)\[/emoji])ism", '<span class="mastodon emoji"><img src="$1" alt="$2" title="$2"/></span>', $text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Check for Italics text
|
||||
$text = preg_replace("(\[i\](.*?)\[\/i\])ism", '<em>$1</em>', $text);
|
||||
private static function convertStylesToHtml(string $text, int $simple_html): string
|
||||
{
|
||||
// Markdown is designed to pass through HTML elements that it can't handle itself,
|
||||
// so that the other system would parse the original HTML element.
|
||||
// But Diaspora has chosen not to do this and doesn't parse HTML elements.
|
||||
// So we need to make some changes here.
|
||||
if ($simple_html == BBCode::DIASPORA) {
|
||||
$elements = ['big', 'small'];
|
||||
foreach ($elements as $bbcode) {
|
||||
$text = preg_replace("(\[" . $bbcode . "\](.*?)\[\/" . $bbcode . "\])ism", '$1', $text);
|
||||
}
|
||||
|
||||
// Check for Underline text
|
||||
$text = preg_replace("(\[u\](.*?)\[\/u\])ism", '<u>$1</u>', $text);
|
||||
$elements = ['del' => 's', 'ins' => 'em', 'kbd' => 'code', 'mark' => 'strong',
|
||||
'samp' => 'code', 'u' => 'em', 'var' => 'em'];
|
||||
foreach ($elements as $bbcode => $html) {
|
||||
$text = preg_replace("(\[" . $bbcode . "\](.*?)\[\/" . $bbcode . "\])ism", '<' . $html . '>$1</' . $html . '>', $text);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for strike-through text
|
||||
$text = preg_replace("(\[s\](.*?)\[\/s\])ism", '<s>$1</s>', $text);
|
||||
// Several easy to replace HTML elements
|
||||
// @todo add the new elements to the documentation by the end of 2024 so that most systems will support them.
|
||||
$elements = ['b', 'del', 'em', 'i', 'ins', 'kbd', 'mark',
|
||||
's', 'samp', 'small', 'strong', 'sub', 'sup', 'u', 'var'];
|
||||
foreach ($elements as $element) {
|
||||
$text = preg_replace("(\[" . $element . "\](.*?)\[\/" . $element . "\])ism", '<' . $element . '>$1</' . $element . '>', $text);
|
||||
}
|
||||
|
||||
$text = preg_replace("(\[big\](.*?)\[\/big\])ism", "<span style=\"font-size: larger;\">$1</span>", $text);
|
||||
|
||||
// Check for over-line text
|
||||
$text = preg_replace("(\[o\](.*?)\[\/o\])ism", '<span class="overline">$1</span>', $text);
|
||||
|
@ -1535,7 +1685,6 @@ class BBCode
|
|||
$text = preg_replace("(\[size=(.*?)\](.*?)\[\/size\])ism", "$2", $text);
|
||||
}
|
||||
|
||||
|
||||
// Check for centered text
|
||||
$text = preg_replace("(\[center\](.*?)\[\/center\])ism", '<div style="text-align:center;">$1</div>', $text);
|
||||
|
||||
|
@ -1545,13 +1694,6 @@ class BBCode
|
|||
// Check for inline custom CSS
|
||||
$text = preg_replace("(\[style=(.*?)\](.*?)\[\/style\])ism", '<span style="$1">$2</span>', $text);
|
||||
|
||||
// Mastodon Emoji (internal tag, do not document for users)
|
||||
if ($simple_html == self::MASTODON_API) {
|
||||
$text = preg_replace("(\[emoji=(.*?)](.*?)\[/emoji])ism", '$2', $text);
|
||||
} else {
|
||||
$text = preg_replace("(\[emoji=(.*?)](.*?)\[/emoji])ism", '<span class="mastodon emoji"><img src="$1" alt="$2" title="$2"/></span>', $text);
|
||||
}
|
||||
|
||||
// Check for CSS classes
|
||||
// @deprecated since 2021.12, left for backward-compatibility reasons
|
||||
$text = preg_replace("(\[class=(.*?)\](.*?)\[\/class\])ism", '<span class="$1">$2</span>', $text);
|
||||
|
@ -1559,6 +1701,27 @@ class BBCode
|
|||
$text = str_replace("\n\n", '</p><p>', $text);
|
||||
$text = str_replace("\n", '<br>', $text);
|
||||
|
||||
// Check for font change text
|
||||
$text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertTablesToHtml(string $text): string
|
||||
{
|
||||
$text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '<th>$1</th>', $text);
|
||||
$text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '<td>$1</td>', $text);
|
||||
$text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '<tr>$1</tr>', $text);
|
||||
$text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '</p><table>$1</table><p>', $text);
|
||||
|
||||
$text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '</p><table border="1" >$1</table><p>', $text);
|
||||
$text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '</p><table border="0" >$1</table><p>', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertListsToHtml(string $text): string
|
||||
{
|
||||
// handle nested lists
|
||||
$endlessloop = 0;
|
||||
|
||||
|
@ -1582,25 +1745,11 @@ class BBCode
|
|||
$text = str_replace("[*]", "<li>", $text);
|
||||
$text = str_replace("[li]", "<li>", $text);
|
||||
|
||||
$text = preg_replace("/\[th\](.*?)\[\/th\]/sm", '<th>$1</th>', $text);
|
||||
$text = preg_replace("/\[td\](.*?)\[\/td\]/sm", '<td>$1</td>', $text);
|
||||
$text = preg_replace("/\[tr\](.*?)\[\/tr\]/sm", '<tr>$1</tr>', $text);
|
||||
$text = preg_replace("/\[table\](.*?)\[\/table\]/sm", '</p><table>$1</table><p>', $text);
|
||||
|
||||
$text = preg_replace("/\[table border=1\](.*?)\[\/table\]/sm", '</p><table border="1" >$1</table><p>', $text);
|
||||
$text = preg_replace("/\[table border=0\](.*?)\[\/table\]/sm", '</p><table border="0" >$1</table><p>', $text);
|
||||
|
||||
$text = str_replace('[hr]', '</p><hr /><p>', $text);
|
||||
|
||||
if (!$for_plaintext) {
|
||||
$text = self::performWithEscapedTags($text, ['url', 'img', 'audio', 'video', 'youtube', 'vimeo', 'share', 'attachment', 'iframe', 'bookmark'], function ($text) {
|
||||
return preg_replace(Strings::autoLinkRegEx(), '[url]$1[/url]', $text);
|
||||
});
|
||||
return $text;
|
||||
}
|
||||
|
||||
// Check for font change text
|
||||
$text = preg_replace("/\[font=(.*?)\](.*?)\[\/font\]/sm", "<span style=\"font-family: $1;\">$2</span>", $text);
|
||||
|
||||
private static function convertSpoilersToHtml(string $text): string
|
||||
{
|
||||
// Declare the format for [spoiler] layout
|
||||
$SpoilerLayout = '<details class="spoiler"><summary>' . DI::l10n()->t('Click to open/close') . '</summary>$1</details>';
|
||||
|
||||
|
@ -1623,6 +1772,28 @@ class BBCode
|
|||
);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertStructuresToHtml(string $text): string
|
||||
{
|
||||
$text = preg_replace("(\[p\](.*?)\[\/p\])ism", '<p>$1</p>', $text);
|
||||
// Check for paragraph
|
||||
return str_replace('[hr]', '</p><hr /><p>', $text);
|
||||
}
|
||||
|
||||
private static function convertSmileysToHtml(string $text, int $simple_html, bool $for_plaintext): string
|
||||
{
|
||||
if (strpos($text, '[nosmile]') !== false) {
|
||||
$text = str_replace('[nosmile]', '', $text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
return Smilies::replace($text, ($simple_html != self::INTERNAL) || $for_plaintext);
|
||||
}
|
||||
|
||||
private static function convertQuotesToHtml(string $text): string
|
||||
{
|
||||
// Declare the format for [quote] layout
|
||||
$QuoteLayout = '</p><blockquote>$1</blockquote><p>';
|
||||
|
||||
|
@ -1647,7 +1818,11 @@ class BBCode
|
|||
);
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertImagesToHtml(string $text, int $simple_html, int $uriid): string
|
||||
{
|
||||
// [img=widthxheight]image source[/img]
|
||||
$text = preg_replace_callback(
|
||||
"/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism",
|
||||
|
@ -1700,10 +1875,18 @@ class BBCode
|
|||
|
||||
$text = self::convertImages($text, $simple_html, $uriid);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertCryptToHtml(string $text): string
|
||||
{
|
||||
$text = preg_replace("/\[crypt\](.*?)\[\/crypt\]/ism", '<br><img src="' . DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
|
||||
$text = preg_replace("/\[crypt(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' . DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
|
||||
//$text = preg_replace("/\[crypt=(.*?)\](.*?)\[\/crypt\]/ism", '<br><img src="' .DI::baseUrl() . '/images/lock_icon.gif" alt="' . DI::l10n()->t('Encrypted content') . '" title="' . '$1' . ' ' . DI::l10n()->t('Encrypted content') . '" /><br>', $text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertAudioVideoToHtml(string $text, int $simple_html, bool $try_oembed, \Closure $try_oembed_callback): string
|
||||
{
|
||||
// Simplify "video" element
|
||||
$text = preg_replace('(\[video[^\]]*?\ssrc\s?=\s?([^\s\]]+)[^\]]*?\].*?\[/video\])ism', '[video]$1[/video]', $text);
|
||||
|
||||
|
@ -1732,190 +1915,54 @@ class BBCode
|
|||
$text = preg_replace_callback("/\[video\](.*?)\[\/video\]/ism", $try_oembed_callback, $text);
|
||||
$text = preg_replace_callback("/\[audio\](.*?)\[\/audio\]/ism", $try_oembed_callback, $text);
|
||||
|
||||
$text = preg_replace(
|
||||
"/\[video\](.*?)\[\/video\]/ism",
|
||||
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace("/\[video\](.*?)\[\/video\]/ism", '[url]$1[/url]', $text);
|
||||
$text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", '<audio src="$1" controls><a href="$1">$1</a></audio>', $text);
|
||||
} else {
|
||||
$text = preg_replace(
|
||||
"/\[video\](.*?)\[\/video\]/ism",
|
||||
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace(
|
||||
"/\[audio\](.*?)\[\/audio\]/ism",
|
||||
'<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace("/\[video\](.*?)\[\/video\]/ism", '[url]$1[/url]', $text);
|
||||
$text = preg_replace("/\[audio\](.*?)\[\/audio\]/ism", '[url]$1[/url]', $text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertIFramesToHtml(string $text): string
|
||||
{
|
||||
// Backward compatibility, [iframe] support has been removed in version 2020.12
|
||||
$text = preg_replace_callback("/\[(iframe)\](.*?)\[\/iframe\]/ism", [self::class, 'sanitizeLinksCallback'], $text);
|
||||
$text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '<a href="$1">$1</a>', $text);
|
||||
$text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '[url]$1[/url]', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertVideoPlatformsToHtml(string $text, bool $try_oembed): string
|
||||
{
|
||||
$a = DI::app();
|
||||
$text = self::normalizeVideoLinks($text);
|
||||
|
||||
// Youtube extensions
|
||||
if ($try_oembed && OEmbed::isAllowedURL('https://www.youtube.com/embed/')) {
|
||||
$text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '<iframe width="' . $a->getThemeInfoValue('videowidth') . '" height="' . $a->getThemeInfoValue('videoheight') . '" src="https://www.youtube.com/embed/$1" frameborder="0" ></iframe>', $text);
|
||||
} else {
|
||||
$text = preg_replace(
|
||||
"/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism",
|
||||
'<a href="https://www.youtube.com/watch?v=$1" target="_blank" rel="noopener noreferrer">https://www.youtube.com/watch?v=$1</a>',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '[url]https://www.youtube.com/watch?v=$1[/url]', $text);
|
||||
}
|
||||
|
||||
// Vimeo extensions
|
||||
if ($try_oembed && OEmbed::isAllowedURL('https://player.vimeo.com/video')) {
|
||||
$text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '<iframe width="' . $a->getThemeInfoValue('videowidth') . '" height="' . $a->getThemeInfoValue('videoheight') . '" src="https://player.vimeo.com/video/$1" frameborder="0" ></iframe>', $text);
|
||||
} else {
|
||||
$text = preg_replace(
|
||||
"/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism",
|
||||
'<a href="https://vimeo.com/$1" target="_blank" rel="noopener noreferrer">https://vimeo.com/$1</a>',
|
||||
$text
|
||||
);
|
||||
$text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '[url]https://vimeo.com/$1[/url]', $text);
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertOEmbedToHtml(string $text, int $uriid): string
|
||||
{
|
||||
// oembed tag
|
||||
$text = OEmbed::BBCode2HTML($text, $uriid);
|
||||
|
||||
// Avoid triple linefeeds through oembed
|
||||
$text = str_replace("<br style='clear:left'></span><br><br>", "<br style='clear:left'></span><br>", $text);
|
||||
|
||||
// If we found an event earlier, strip out all the event code and replace with a reformatted version.
|
||||
// Replace the event-start section with the entire formatted event. The other bbcode is stripped.
|
||||
// Summary (e.g. title) is required, earlier revisions only required description (in addition to
|
||||
// start which is always required). Allow desc with a missing summary for compatibility.
|
||||
|
||||
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
|
||||
$sub = Event::getHTML($ev, $simple_html, $uriid);
|
||||
|
||||
$text = preg_replace("/\[event\-summary\](.*?)\[\/event\-summary\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-description\](.*?)\[\/event\-description\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-start\](.*?)\[\/event\-start\]/ism", $sub, $text);
|
||||
$text = preg_replace("/\[event\-finish\](.*?)\[\/event\-finish\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-location\](.*?)\[\/event\-location\]/ism", '', $text);
|
||||
$text = preg_replace("/\[event\-id\](.*?)\[\/event\-id\]/ism", '', $text);
|
||||
}
|
||||
|
||||
if (!$for_plaintext && DI::config()->get('system', 'big_emojis') && ($simple_html != self::DIASPORA) && Smilies::isEmojiPost($text)) {
|
||||
$text = '<span style="font-size: xx-large; line-height: normal;">' . $text . '</span>';
|
||||
}
|
||||
|
||||
$text = self::convertUrlToHtml($text, $simple_html, $for_plaintext, $try_oembed, $try_oembed_callback);
|
||||
|
||||
// we may need to restrict this further if it picks up too many strays
|
||||
// link acct:user@host to a webfinger profile redirector
|
||||
|
||||
$text = preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', '<a href="' . DI::baseUrl() . '/acctlink?addr=$1@$2" target="extlink">acct:$1@$2</a>', $text);
|
||||
|
||||
// Perform MAIL Search
|
||||
$text = preg_replace_callback("/\[(mail)\](.*?)\[\/mail\]/ism", [self::class, 'sanitizeLinksCallback'], $text);
|
||||
$text = preg_replace("/\[mail\](.*?)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $text);
|
||||
$text = preg_replace("/\[mail\=(.*?)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $text);
|
||||
|
||||
/// @todo What is the meaning of these lines?
|
||||
$text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $text);
|
||||
$text = preg_replace('/\&\#039\;/', '\'', $text);
|
||||
|
||||
// Currently deactivated, it made problems with " inside of alt texts.
|
||||
//$text = preg_replace('/\"\;/', '"', $text);
|
||||
|
||||
// fix any escaped ampersands that may have been converted into links
|
||||
$text = preg_replace('/\<([^>]*?)(src|href)=(.*?)\&\;(.*?)\>/ism', '<$1$2=$3&$4>', $text);
|
||||
|
||||
// sanitizes src attributes (http and redir URLs for displaying in a web page, cid used for inline images in emails)
|
||||
$allowed_src_protocols = ['//', 'http://', 'https://', 'contact/redir/', 'cid:'];
|
||||
|
||||
array_walk($allowed_src_protocols, function (&$value) {
|
||||
$value = preg_quote($value, '#');
|
||||
});
|
||||
|
||||
$text = preg_replace(
|
||||
'#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism',
|
||||
'<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">',
|
||||
$text
|
||||
);
|
||||
|
||||
// sanitize href attributes (only allowlisted protocols URLs)
|
||||
// default value for backward compatibility
|
||||
$allowed_link_protocols = DI::config()->get('system', 'allowed_link_protocols', []);
|
||||
|
||||
// Always allowed protocol even if config isn't set or not including it
|
||||
$allowed_link_protocols[] = '//';
|
||||
$allowed_link_protocols[] = 'http://';
|
||||
$allowed_link_protocols[] = 'https://';
|
||||
$allowed_link_protocols[] = 'contact/redir/';
|
||||
|
||||
array_walk($allowed_link_protocols, function (&$value) {
|
||||
$value = preg_quote($value, '#');
|
||||
});
|
||||
|
||||
$regex = '#<([^>]*?)(href)="(?!' . implode('|', $allowed_link_protocols) . ')(.*?)"(.*?)>#ism';
|
||||
$text = preg_replace($regex, '<$1$2="javascript:void(0)"$4 data-original-href="$3" class="invalid-href" title="' . DI::l10n()->t('Invalid link protocol') . '">', $text);
|
||||
|
||||
// Shared content
|
||||
$text = self::convertShare(
|
||||
$text,
|
||||
function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) {
|
||||
return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html);
|
||||
},
|
||||
$uriid
|
||||
);
|
||||
|
||||
$text = self::interpolateSavedImagesIntoItemBody($uriid, $text, $saved_image);
|
||||
|
||||
return $text;
|
||||
}); // Escaped noparse, nobb, pre
|
||||
|
||||
// Remove escaping tags and replace new lines that remain
|
||||
$text = preg_replace_callback('/\[(noparse|nobb)](.*?)\[\/\1]/ism', function ($match) {
|
||||
return str_replace("\n", "<br>", $match[2]);
|
||||
}, $text);
|
||||
|
||||
// Additionally, [pre] tags preserve spaces
|
||||
$text = preg_replace_callback("/\[pre\](.*?)\[\/pre\]/ism", function ($match) {
|
||||
return str_replace([' ', "\n"], [' ', "<br>"], htmlentities($match[1], ENT_NOQUOTES, 'UTF-8'));
|
||||
}, $text);
|
||||
|
||||
return $text;
|
||||
}); // Escaped code
|
||||
|
||||
$text = preg_replace_callback(
|
||||
"#\[code(?:=([^\]]*))?\](.*?)\[\/code\]#ism",
|
||||
function ($matches) {
|
||||
if (strpos($matches[2], "\n") !== false) {
|
||||
$return = '<pre><code class="language-' . trim($matches[1]) . '">' . htmlentities(trim($matches[2], "\n\r"), ENT_NOQUOTES, 'UTF-8') . '</code></pre>';
|
||||
} else {
|
||||
$return = '<code>' . htmlentities($matches[2], ENT_NOQUOTES, 'UTF-8') . '</code>';
|
||||
}
|
||||
|
||||
return $return;
|
||||
},
|
||||
$text
|
||||
);
|
||||
|
||||
// Default iframe allowed domains/path
|
||||
$allowedIframeDomains = DI::config()->get('system', 'no_oembed_rich_content') ? [] : ['www.youtube.com/embed/', 'player.vimeo.com/video/'];
|
||||
|
||||
$allowedIframeDomains = array_merge(
|
||||
$allowedIframeDomains,
|
||||
DI::config()->get('system', 'allowed_oembed') ?
|
||||
explode(',', DI::config()->get('system', 'allowed_oembed'))
|
||||
: []
|
||||
);
|
||||
|
||||
if (strpos($text, '<p>') !== false || strpos($text, '</p>') !== false) {
|
||||
$text = '<p>' . $text . '</p>';
|
||||
}
|
||||
|
||||
$text = HTML::purify($text, $allowedIframeDomains);
|
||||
DI::profiler()->stopRecording();
|
||||
|
||||
return trim($text);
|
||||
}
|
||||
|
||||
private static function convertUrlToHtml(string $text, int $simple_html, bool $for_plaintext, bool $try_oembed, \Closure $try_oembed_callback): string
|
||||
|
@ -2046,7 +2093,10 @@ class BBCode
|
|||
$text = preg_replace("/\[url\=(" . preg_quote(DI::baseUrl(), '/') . ".*?)\](.*?)\[\/url\]/ism", '<a href="$1">$2</a>', $text);
|
||||
|
||||
$text = preg_replace("/\[url\=(.*?)\](.*?)\[\/url\]/ism", '<a href="$1" target="_blank" rel="noopener noreferrer">$2</a>', $text);
|
||||
return $text;
|
||||
|
||||
// we may need to restrict this further if it picks up too many strays
|
||||
// link acct:user@host to a webfinger profile redirector
|
||||
return preg_replace('/acct:([^@]+)@((?!\-)(?:[a-zA-Z\d\-]{0,62}[a-zA-Z\d]\.){1,126}(?!\d+)[a-zA-Z\d]{1,63})/', '<a href="' . DI::baseUrl() . '/acctlink?addr=$1@$2" target="extlink">acct:$1@$2</a>', $text);
|
||||
}
|
||||
|
||||
private static function escapeUrl(string $url): string
|
||||
|
@ -2088,6 +2138,78 @@ class BBCode
|
|||
return $text;
|
||||
}
|
||||
|
||||
private static function convertMailToHtml(string $text): string
|
||||
{
|
||||
$text = preg_replace_callback("/\[(mail)\](.*?)\[\/mail\]/ism", [self::class, 'sanitizeLinksCallback'], $text);
|
||||
$text = preg_replace("/\[mail\](.*?)\[\/mail\]/", '<a href="mailto:$1">$1</a>', $text);
|
||||
$text = preg_replace("/\[mail\=(.*?)\](.*?)\[\/mail\]/", '<a href="mailto:$1">$2</a>', $text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function convertSharesToHtml(string $text, int $simple_html, bool $try_oembed, int $uriid): string
|
||||
{
|
||||
// Shared content
|
||||
// when the content is meant exporting to other systems then remove the avatar picture since this doesn't really look good on these systems
|
||||
if (!$try_oembed) {
|
||||
$text = preg_replace("/\[share(.*?)avatar\s?=\s?'.*?'\s?(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism", "\n[share$1$2]$3[/share]", $text);
|
||||
}
|
||||
|
||||
$text = self::convertShare(
|
||||
$text,
|
||||
function (array $attributes, array $author_contact, $content, $is_quote_share) use ($simple_html) {
|
||||
return self::convertShareCallback($attributes, $author_contact, $content, $is_quote_share, $simple_html);
|
||||
},
|
||||
$uriid
|
||||
);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
private static function cleanupHtml(string $text): string
|
||||
{
|
||||
/// @todo What is the meaning of these lines?
|
||||
$text = preg_replace('/\[\&\;([#a-z0-9]+)\;\]/', '&$1;', $text);
|
||||
$text = preg_replace('/\&\#039\;/', '\'', $text);
|
||||
|
||||
// Currently deactivated, it made problems with " inside of alt texts.
|
||||
//$text = preg_replace('/\"\;/', '"', $text);
|
||||
|
||||
// fix any escaped ampersands that may have been converted into links
|
||||
$text = preg_replace('/\<([^>]*?)(src|href)=(.*?)\&\;(.*?)\>/ism', '<$1$2=$3&$4>', $text);
|
||||
|
||||
// sanitizes src attributes (http and redir URLs for displaying in a web page, cid used for inline images in emails)
|
||||
$allowed_src_protocols = ['//', 'http://', 'https://', 'contact/redir/', 'cid:'];
|
||||
|
||||
array_walk($allowed_src_protocols, function (&$value) {
|
||||
$value = preg_quote($value, '#');
|
||||
});
|
||||
|
||||
$text = preg_replace(
|
||||
'#<([^>]*?)(src)="(?!' . implode('|', $allowed_src_protocols) . ')(.*?)"(.*?)>#ism',
|
||||
'<$1$2=""$4 data-original-src="$3" class="invalid-src" title="' . DI::l10n()->t('Invalid source protocol') . '">',
|
||||
$text
|
||||
);
|
||||
|
||||
// sanitize href attributes (only allowlisted protocols URLs)
|
||||
// default value for backward compatibility
|
||||
$allowed_link_protocols = DI::config()->get('system', 'allowed_link_protocols', []);
|
||||
|
||||
// Always allowed protocol even if config isn't set or not including it
|
||||
$allowed_link_protocols[] = '//';
|
||||
$allowed_link_protocols[] = 'http://';
|
||||
$allowed_link_protocols[] = 'https://';
|
||||
$allowed_link_protocols[] = 'contact/redir/';
|
||||
|
||||
array_walk($allowed_link_protocols, function (&$value) {
|
||||
$value = preg_quote($value, '#');
|
||||
});
|
||||
|
||||
$regex = '#<([^>]*?)(href)="(?!' . implode('|', $allowed_link_protocols) . ')(.*?)"(.*?)>#ism';
|
||||
$text = preg_replace($regex, '<$1$2="javascript:void(0)"$4 data-original-href="$3" class="invalid-href" title="' . DI::l10n()->t('Invalid link protocol') . '">', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the "abstract" tag from the provided text
|
||||
*
|
||||
|
|
|
@ -253,13 +253,12 @@ class HTML
|
|||
self::tagToBBCode($doc, 'span', ['class' => 'type-link'], '[class=type-link]', '[/class]');
|
||||
self::tagToBBCode($doc, 'span', ['class' => 'type-video'], '[class=type-video]', '[/class]');
|
||||
|
||||
self::tagToBBCode($doc, 'strong', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'em', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'b', [], '[b]', '[/b]');
|
||||
self::tagToBBCode($doc, 'i', [], '[i]', '[/i]');
|
||||
self::tagToBBCode($doc, 'u', [], '[u]', '[/u]');
|
||||
self::tagToBBCode($doc, 's', [], '[s]', '[/s]');
|
||||
self::tagToBBCode($doc, 'del', [], '[s]', '[/s]');
|
||||
$elements = ['b', 'del', 'em', 'i', 'ins', 'kbd', 'mark',
|
||||
's', 'samp', 'strong', 'sub', 'sup', 'u', 'var'];
|
||||
foreach ($elements as $element) {
|
||||
self::tagToBBCode($doc, $element, [], '[' . $element . ']', '[/' . $element . ']');
|
||||
}
|
||||
|
||||
self::tagToBBCode($doc, 'strike', [], '[s]', '[/s]');
|
||||
|
||||
self::tagToBBCode($doc, 'big', [], "[size=large]", "[/size]");
|
||||
|
|
|
@ -67,7 +67,7 @@ class DirectMessageTest extends FixtureTest
|
|||
->toArray();
|
||||
|
||||
self::assertEquals('item_title', $directMessage['title']);
|
||||
self::assertEquals('<strong>item_body</strong>', $directMessage['text']);
|
||||
self::assertEquals('<b>item_body</b>', $directMessage['text']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: 2024.06-dev\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-04-07 16:31+0000\n"
|
||||
"POT-Creation-Date: 2024-04-13 11:02+0000\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"
|
||||
|
@ -957,7 +957,7 @@ msgstr ""
|
|||
msgid "Enter user nickname: "
|
||||
msgstr ""
|
||||
|
||||
#: src/Console/User.php:182 src/Model/User.php:820
|
||||
#: src/Console/User.php:182 src/Model/User.php:822
|
||||
#: src/Module/Api/Twitter/ContactEndpoint.php:74
|
||||
#: src/Module/Moderation/Users/Active.php:71
|
||||
#: src/Module/Moderation/Users/Blocked.php:71
|
||||
|
@ -1381,7 +1381,7 @@ msgstr ""
|
|||
msgid "Public post"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Conversation.php:424 src/Content/Widget/VCard.php:130
|
||||
#: src/Content/Conversation.php:424 src/Content/Widget/VCard.php:131
|
||||
#: src/Model/Profile.php:482 src/Module/Admin/Logs/View.php:92
|
||||
#: src/Module/Post/Edit.php:181
|
||||
msgid "Message"
|
||||
|
@ -1733,7 +1733,7 @@ msgstr ""
|
|||
|
||||
#: src/Content/Feature.php:130 src/Content/GroupManager.php:147
|
||||
#: src/Content/Nav.php:278 src/Content/Text/HTML.php:881
|
||||
#: src/Content/Widget.php:538 src/Model/User.php:1386
|
||||
#: src/Content/Widget.php:538 src/Model/User.php:1388
|
||||
msgid "Groups"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2266,39 +2266,39 @@ msgstr ""
|
|||
msgid "last"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:767 src/Content/Text/BBCode.php:1764
|
||||
#: src/Content/Text/BBCode.php:1765
|
||||
#: src/Content/Text/BBCode.php:701 src/Content/Text/BBCode.php:1843
|
||||
#: src/Content/Text/BBCode.php:1844
|
||||
msgid "Image/photo"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:985
|
||||
#: src/Content/Text/BBCode.php:919
|
||||
#, php-format
|
||||
msgid ""
|
||||
"<a href=\"%1$s\" target=\"_blank\" rel=\"noopener noreferrer\">%2$s</a> %3$s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:1010 src/Model/Item.php:4014
|
||||
#: src/Model/Item.php:4020 src/Model/Item.php:4021
|
||||
#: src/Content/Text/BBCode.php:944 src/Model/Item.php:4021
|
||||
#: src/Model/Item.php:4027 src/Model/Item.php:4028
|
||||
msgid "Link to source"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:1671 src/Content/Text/HTML.php:905
|
||||
#: src/Content/Text/BBCode.php:1724 src/Content/Text/HTML.php:905
|
||||
msgid "Click to open/close"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:1704
|
||||
#: src/Content/Text/BBCode.php:1779
|
||||
msgid "$1 wrote:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:1769 src/Content/Text/BBCode.php:1770
|
||||
#: src/Content/Text/BBCode.php:1853 src/Content/Text/BBCode.php:1854
|
||||
msgid "Encrypted content"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:2033
|
||||
#: src/Content/Text/BBCode.php:2159
|
||||
msgid "Invalid source protocol"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/BBCode.php:2052
|
||||
#: src/Content/Text/BBCode.php:2178
|
||||
msgid "Invalid link protocol"
|
||||
msgstr ""
|
||||
|
||||
|
@ -2310,7 +2310,7 @@ msgstr ""
|
|||
msgid "The end"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Text/HTML.php:860 src/Content/Widget/VCard.php:126
|
||||
#: src/Content/Text/HTML.php:860 src/Content/Widget/VCard.php:127
|
||||
#: src/Model/Profile.php:476 src/Module/Contact/Profile.php:477
|
||||
msgid "Follow"
|
||||
msgstr ""
|
||||
|
@ -2483,27 +2483,27 @@ msgstr[1] ""
|
|||
msgid "More Trending Tags"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:104 src/Model/Contact.php:1205
|
||||
#: src/Content/Widget/VCard.php:105 src/Model/Contact.php:1205
|
||||
#: src/Model/Profile.php:461
|
||||
msgid "Post to group"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:109 src/Model/Contact.php:1209
|
||||
#: src/Content/Widget/VCard.php:110 src/Model/Contact.php:1209
|
||||
#: src/Model/Profile.php:465 src/Module/Moderation/Item/Source.php:85
|
||||
msgid "Mention"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:119 src/Model/Profile.php:380
|
||||
#: src/Content/Widget/VCard.php:120 src/Model/Profile.php:380
|
||||
#: src/Module/Contact/Profile.php:413 src/Module/Profile/Profile.php:199
|
||||
msgid "XMPP:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:120 src/Model/Profile.php:381
|
||||
#: src/Content/Widget/VCard.php:121 src/Model/Profile.php:381
|
||||
#: src/Module/Contact/Profile.php:415 src/Module/Profile/Profile.php:203
|
||||
msgid "Matrix:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:121 src/Model/Event.php:82
|
||||
#: src/Content/Widget/VCard.php:122 src/Model/Event.php:82
|
||||
#: src/Model/Event.php:109 src/Model/Event.php:471 src/Model/Event.php:960
|
||||
#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:411
|
||||
#: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187
|
||||
|
@ -2511,18 +2511,18 @@ msgstr ""
|
|||
msgid "Location:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:124 src/Model/Profile.php:489
|
||||
#: src/Content/Widget/VCard.php:125 src/Model/Profile.php:489
|
||||
#: src/Module/Notifications/Introductions.php:201
|
||||
msgid "Network:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:128 src/Model/Contact.php:1237
|
||||
#: src/Content/Widget/VCard.php:129 src/Model/Contact.php:1237
|
||||
#: src/Model/Contact.php:1249 src/Model/Profile.php:478
|
||||
#: src/Module/Contact/Profile.php:469
|
||||
msgid "Unfollow"
|
||||
msgstr ""
|
||||
|
||||
#: src/Content/Widget/VCard.php:134 src/Model/Contact.php:1207
|
||||
#: src/Content/Widget/VCard.php:135 src/Model/Contact.php:1207
|
||||
#: src/Model/Profile.php:463
|
||||
msgid "View group"
|
||||
msgstr ""
|
||||
|
@ -3568,7 +3568,7 @@ msgstr[1] ""
|
|||
msgid "Poll end: %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/Item.php:3997 src/Model/Item.php:3998
|
||||
#: src/Model/Item.php:4004 src/Model/Item.php:4005
|
||||
msgid "View on separate page"
|
||||
msgstr ""
|
||||
|
||||
|
@ -3726,145 +3726,145 @@ msgstr ""
|
|||
msgid "Contact information and Social Networks"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:229 src/Model/User.php:1299
|
||||
#: src/Model/User.php:231 src/Model/User.php:1301
|
||||
msgid "SERIOUS ERROR: Generation of security keys failed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:729 src/Model/User.php:762
|
||||
#: src/Model/User.php:731 src/Model/User.php:764
|
||||
msgid "Login failed"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:794
|
||||
#: src/Model/User.php:796
|
||||
msgid "Not enough information to authenticate"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:919
|
||||
#: src/Model/User.php:921
|
||||
msgid "Password can't be empty"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:961
|
||||
#: src/Model/User.php:963
|
||||
msgid "Empty passwords are not allowed."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:965
|
||||
#: src/Model/User.php:967
|
||||
msgid ""
|
||||
"The new password has been exposed in a public data dump, please choose "
|
||||
"another."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:969
|
||||
#: src/Model/User.php:971
|
||||
msgid "The password length is limited to 72 characters."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:973
|
||||
#: src/Model/User.php:975
|
||||
msgid "The password can't contain white spaces nor accentuated letters"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1182
|
||||
#: src/Model/User.php:1184
|
||||
msgid "Passwords do not match. Password unchanged."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1189
|
||||
#: src/Model/User.php:1191
|
||||
msgid "An invitation is required."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1193
|
||||
#: src/Model/User.php:1195
|
||||
msgid "Invitation could not be verified."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1201
|
||||
#: src/Model/User.php:1203
|
||||
msgid "Invalid OpenID url"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1214 src/Security/Authentication.php:230
|
||||
#: src/Model/User.php:1216 src/Security/Authentication.php:230
|
||||
msgid ""
|
||||
"We encountered a problem while logging in with the OpenID you provided. "
|
||||
"Please check the correct spelling of the ID."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1214 src/Security/Authentication.php:230
|
||||
#: src/Model/User.php:1216 src/Security/Authentication.php:230
|
||||
msgid "The error message was:"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1220
|
||||
#: src/Model/User.php:1222
|
||||
msgid "Please enter the required information."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1234
|
||||
#: src/Model/User.php:1236
|
||||
#, php-format
|
||||
msgid ""
|
||||
"system.username_min_length (%s) and system.username_max_length (%s) are "
|
||||
"excluding each other, swapping values."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1241
|
||||
#: src/Model/User.php:1243
|
||||
#, php-format
|
||||
msgid "Username should be at least %s character."
|
||||
msgid_plural "Username should be at least %s characters."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: src/Model/User.php:1245
|
||||
#: src/Model/User.php:1247
|
||||
#, php-format
|
||||
msgid "Username should be at most %s character."
|
||||
msgid_plural "Username should be at most %s characters."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: src/Model/User.php:1253
|
||||
#: src/Model/User.php:1255
|
||||
msgid "That doesn't appear to be your full (First Last) name."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1258
|
||||
#: src/Model/User.php:1260
|
||||
msgid "Your email domain is not among those allowed on this site."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1262
|
||||
#: src/Model/User.php:1264
|
||||
msgid "Not a valid email address."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1265
|
||||
#: src/Model/User.php:1267
|
||||
msgid "The nickname was blocked from registration by the nodes admin."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1269 src/Model/User.php:1275
|
||||
#: src/Model/User.php:1271 src/Model/User.php:1277
|
||||
msgid "Cannot use that email."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1281
|
||||
#: src/Model/User.php:1283
|
||||
msgid "Your nickname can only contain a-z, 0-9 and _."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1289 src/Model/User.php:1346
|
||||
#: src/Model/User.php:1291 src/Model/User.php:1348
|
||||
msgid "Nickname is already registered. Please choose another."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1333 src/Model/User.php:1337
|
||||
#: src/Model/User.php:1335 src/Model/User.php:1339
|
||||
msgid "An error occurred during registration. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1360
|
||||
#: src/Model/User.php:1362
|
||||
msgid "An error occurred creating your default profile. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1367
|
||||
#: src/Model/User.php:1369
|
||||
msgid "An error occurred creating your self contact. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1372
|
||||
#: src/Model/User.php:1374
|
||||
msgid "Friends"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1376
|
||||
#: src/Model/User.php:1378
|
||||
msgid ""
|
||||
"An error occurred creating your default contact circle. Please try again."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1418
|
||||
#: src/Model/User.php:1420
|
||||
msgid "Profile Photos"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1600
|
||||
#: src/Model/User.php:1602
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -3872,7 +3872,7 @@ msgid ""
|
|||
"\t\t\tthe administrator of %2$s has set up an account for you."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1603
|
||||
#: src/Model/User.php:1605
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -3908,12 +3908,12 @@ msgid ""
|
|||
"\t\tThank you and welcome to %4$s."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1635 src/Model/User.php:1741
|
||||
#: src/Model/User.php:1637 src/Model/User.php:1743
|
||||
#, php-format
|
||||
msgid "Registration details for %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1655
|
||||
#: src/Model/User.php:1657
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -3929,12 +3929,12 @@ msgid ""
|
|||
"\t\t"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1674
|
||||
#: src/Model/User.php:1676
|
||||
#, php-format
|
||||
msgid "Registration at %s"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1698
|
||||
#: src/Model/User.php:1700
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -3943,7 +3943,7 @@ msgid ""
|
|||
"\t\t\t"
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1706
|
||||
#: src/Model/User.php:1708
|
||||
#, php-format
|
||||
msgid ""
|
||||
"\n"
|
||||
|
@ -3981,7 +3981,7 @@ msgid ""
|
|||
"\t\t\tThank you and welcome to %2$s."
|
||||
msgstr ""
|
||||
|
||||
#: src/Model/User.php:1768
|
||||
#: src/Model/User.php:1770
|
||||
msgid ""
|
||||
"User with delegates can't be removed, please remove delegate users first"
|
||||
msgstr ""
|
||||
|
@ -8920,11 +8920,11 @@ msgstr ""
|
|||
msgid "Show unread"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Notifications/Ping.php:223
|
||||
#: src/Module/Notifications/Ping.php:220
|
||||
msgid "{0} requested registration"
|
||||
msgstr ""
|
||||
|
||||
#: src/Module/Notifications/Ping.php:232
|
||||
#: src/Module/Notifications/Ping.php:229
|
||||
#, php-format
|
||||
msgid "{0} and %d others requested registration"
|
||||
msgstr ""
|
||||
|
|
Loading…
Reference in a new issue