Merge pull request #13597 from annando/ISO-639-1

Use ISO-639-1 for the language detection
This commit is contained in:
Hypolite Petovan 2023-11-03 11:07:01 -07:00 committed by GitHub
commit c222775bdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 254 additions and 232 deletions

View File

@ -35,13 +35,13 @@ final class Channel extends Timeline
*/ */
public function getTimelines(int $uid): Timelines public function getTimelines(int $uid): Timelines
{ {
$language = User::getLanguageCode($uid); $iso639 = new \Matriphe\ISO639\ISO639;
$languages = $this->l10n->getAvailableLanguages(true); $native = $iso639->nativeByCode1(User::getLanguageCode($uid));
$tabs = [ $tabs = [
new ChannelEntity(ChannelEntity::FORYOU, $this->l10n->t('For you'), $this->l10n->t('Posts from contacts you interact with and who interact with you'), 'y'), new ChannelEntity(ChannelEntity::FORYOU, $this->l10n->t('For you'), $this->l10n->t('Posts from contacts you interact with and who interact with you'), 'y'),
new ChannelEntity(ChannelEntity::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'), new ChannelEntity(ChannelEntity::WHATSHOT, $this->l10n->t('What\'s Hot'), $this->l10n->t('Posts with a lot of interactions'), 'h'),
new ChannelEntity(ChannelEntity::LANGUAGE, $languages[$language], $this->l10n->t('Posts in %s', $languages[$language]), 'g'), new ChannelEntity(ChannelEntity::LANGUAGE, $native, $this->l10n->t('Posts in %s', $native), 'g'),
new ChannelEntity(ChannelEntity::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'), new ChannelEntity(ChannelEntity::FOLLOWERS, $this->l10n->t('Followers'), $this->l10n->t('Posts from your followers that you don\'t follow'), 'f'),
new ChannelEntity(ChannelEntity::SHARERSOFSHARERS, $this->l10n->t('Sharers of sharers'), $this->l10n->t('Posts from accounts that are followed by accounts that you follow'), 'r'), new ChannelEntity(ChannelEntity::SHARERSOFSHARERS, $this->l10n->t('Sharers of sharers'), $this->l10n->t('Posts from accounts that are followed by accounts that you follow'), 'r'),
new ChannelEntity(ChannelEntity::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'), new ChannelEntity(ChannelEntity::IMAGE, $this->l10n->t('Images'), $this->l10n->t('Posts with images'), 'i'),

View File

@ -378,7 +378,7 @@ class L10n
* *
* @return array * @return array
*/ */
public function getAvailableLanguages(bool $additional = false): array public function getAvailableLanguages(): array
{ {
$langs = []; $langs = [];
$strings_file_paths = glob('view/lang/*/strings.php'); $strings_file_paths = glob('view/lang/*/strings.php');
@ -392,107 +392,94 @@ class L10n
$path_array = explode('/', $strings_file_path); $path_array = explode('/', $strings_file_path);
$langs[$path_array[2]] = self::LANG_NAMES[$path_array[2]] ?? $path_array[2]; $langs[$path_array[2]] = self::LANG_NAMES[$path_array[2]] ?? $path_array[2];
} }
if ($additional) {
// See https://github.com/friendica/friendica/issues/10511
// Persian is manually added to language detection until a persian translation is provided for the interface, at
// which point it will be automatically available through `getAvailableLanguages()` and this should be removed.
// Additionally some more languages are added to that list that are used in the Fediverse.
$additional_langs = [
'af' => 'Afrikaans',
'az-Latn' => 'azərbaycan dili',
'bs-Latn' => 'bosanski jezik',
'be' => 'беларуская мова',
'bn' => 'বাংলা',
'cy' => 'Cymraeg',
'el-monoton' => 'ελληνικά',
'eu' => 'euskara, euskera',
'fa' => 'فارسی',
'ga' => 'Gaeilge',
'gl' => 'galego',
'he' => 'עברית',
'hi' => 'हिन्दी, हिंदी',
'hr' => 'hrvatski jezik',
'hy' => 'Հայերեն',
'id' => 'Bahasa Indonesia',
'jv' => 'basa Jawa',
'ka' => 'ქართული',
'ko' => '한국어, 조선어',
'lt' => 'lietuvių kalba',
'lv' => 'latviešu valoda',
'ms-Latn' => 'bahasa Melayu, بهاس ملايو‎',
'sr-Cyrl' => 'српски језик',
'sk' => 'slovenčina, slovenský jazyk',
'sl' => 'slovenski jezik, slovenščina',
'sq' => 'Shqip',
'sw' => 'Kiswahili',
'ta' => 'தமிழ்',
'th' => 'ไทย',
'tl' => 'Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔',
'tr' => 'Türkçe',
'pt-PT' => 'português',
'uk' => 'українська мова',
'uz' => 'Oʻzbek, Ўзбек, أۇزبېك‎',
'vi' => 'Việt Nam',
'zh-hant' => '繁體',
];
$langs = array_merge($additional_langs, $langs);
ksort($langs);
}
} }
return $langs; return $langs;
} }
/** /**
* The language detection routine uses some slightly different language codes. * Get language codes that are detectable by our language detection routines.
* This function changes the language array accordingly. * Languages are excluded that aren't used often and that tend to false detections.
* The listed codes are a collection of both the official ISO 639-1 codes and
* the codes that are used by our built-in language detection routine.
* When the detection is done, the result only consists of the official ISO 639-1 codes.
* *
* @param array $languages
* @return array * @return array
*/ */
public function convertForLanguageDetection(array $languages): array public function getDetectableLanguages(): array
{ {
foreach ($languages as $key => $language) { $additional_langs = [
$newkey = $this->convertCodeForLanguageDetection($key); 'af', 'az', 'az-Cyrl', 'az-Latn', 'be', 'bn', 'bs', 'bs-Cyrl', 'bs-Latn',
if ($newkey != $key) { 'cy', 'da', 'el', 'el-monoton', 'el-polyton', 'en', 'eu', 'fa', 'fi',
if (!isset($languages[$newkey])) { 'ga', 'gl', 'gu', 'he', 'hi', 'hr', 'hy', 'id', 'in', 'iu', 'iw', 'jv', 'jw',
$languages[$newkey] = $language; 'ka', 'km', 'ko', 'lt', 'lv', 'mo', 'ms', 'ms-Arab', 'ms-Latn', 'nb', 'nn', 'no',
} 'pt', 'pt-PT', 'pt-BR', 'ro', 'sa', 'sk', 'sl', 'sq', 'sr', 'sr-Cyrl', 'sr-Latn', 'sw',
unset($languages[$key]); 'ta', 'th', 'tl', 'tr', 'ug', 'uk', 'uz', 'vi', 'zh', 'zh-Hant', 'zh-Hans',
} ];
if (in_array('cld2', get_loaded_extensions())) {
$additional_langs = array_merge($additional_langs,
['dv', 'kn', 'lo', 'ml', 'or', 'pa', 'sd', 'si', 'te', 'yi']);
} }
ksort($languages); $langs = array_merge($additional_langs, array_keys($this->getAvailableLanguages()));
sort($langs);
return $langs;
}
/**
* Return a list of supported languages with their two byte language codes.
*
* @param bool $international If set to true, additionally the international language name is returned as well.
* @return array
*/
public function getLanguageCodes(bool $international = false): array
{
$iso639 = new \Matriphe\ISO639\ISO639;
$languages = [];
foreach ($this->getDetectableLanguages() as $code) {
$code = $this->toISO6391($code);
$native = $iso639->nativeByCode1($code);
$language = $iso639->languageByCode1($code);
if ($native != $language && $international) {
$languages[$code] = $this->t('%s (%s)', $native, $language);
} else {
$languages[$code] = $native;
}
}
return $languages; return $languages;
} }
/** /**
* The language detection routine uses some slightly different language codes. * Convert the language code to ISO639-1
* This function changes the language codes accordingly. * It also converts old codes to their new counterparts.
* *
* @param string $language * @param string $code
* @return string * @return string
*/ */
public function convertCodeForLanguageDetection(string $language): string public function toISO6391(string $code): string
{ {
switch ($language) { if ((strlen($code) > 2) && (substr($code, 2, 1) == '-')) {
case 'da-dk': $code = substr($code, 0, 2);
return 'da';
case 'en-us':
case 'en-gb':
return 'en';
case 'fi-fi':
return 'fi';
case 'nb-no':
return 'nb';
case 'pt-br':
return 'pt-BR';
case 'zh-cn':
return 'zh-Hans';
default:
return $language;
} }
if (in_array($code, ['nb', 'nn'])) {
$code = 'no';
}
if ($code == 'in') {
$code = 'id';
}
if ($code == 'iw') {
$code = 'he';
}
if ($code == 'jw') {
$code = 'jv';
}
if ($code == 'mo') {
$code = 'ro';
}
return $code;
} }
/** /**

View File

@ -2034,15 +2034,12 @@ class Item
return []; return [];
} }
$availableLanguages = DI::l10n()->getAvailableLanguages(true); $ld = new Language(DI::l10n()->getDetectableLanguages());
$availableLanguages = DI::l10n()->convertForLanguageDetection($availableLanguages);
$ld = new Language(array_keys($availableLanguages));
$result = []; $result = [];
foreach (self::splitByBlocks($searchtext) as $block) { foreach (self::splitByBlocks($searchtext) as $block) {
$languages = $ld->detect($block)->limit(0, $count)->close() ?: []; $languages = $ld->detect($block)->close() ?: [];
$data = [ $data = [
'text' => $block, 'text' => $block,
@ -2057,10 +2054,32 @@ class Item
} }
} }
arsort($result); $result = self::compactLanguages($result);
$result = array_slice($result, 0, $count);
return $result; arsort($result);
return array_slice($result, 0, $count);
}
/**
* Concert the language code in the detection result to ISO 639-1.
* On duplicates the system uses the higher quality value.
*
* @param array $result
* @return array
*/
private static function compactLanguages(array $result): array
{
$languages = [];
foreach ($result as $language => $quality) {
if ($quality == 0) {
continue;
}
$code = DI::l10n()->toISO6391($language);
if (empty($languages[$code]) || ($languages[$code] < $quality)) {
$languages[$code] = $quality;
}
}
return $languages;
} }
/** /**
@ -2143,7 +2162,15 @@ class Item
$used_languages = ''; $used_languages = '';
foreach (json_decode($item['language'], true) as $language => $reliability) { foreach (json_decode($item['language'], true) as $language => $reliability) {
$used_languages .= $iso639->nativeByCode1(substr($language, 0, 2)) . ' (' . $iso639->languageByCode1(substr($language, 0, 2)) . ' - ' . $language . "): " . number_format($reliability, 5) . '\n'; $code = DI::l10n()->toISO6391($language);
$native = $iso639->nativeByCode1($code);
$language = $iso639->languageByCode1($code);
if ($native != $language) {
$used_languages .= DI::l10n()->t('%s (%s - %s): %s', $native, $language, $code, number_format($reliability, 5)) . '\n';
} else {
$used_languages .= DI::l10n()->t('%s (%s): %s', $native, $code, number_format($reliability, 5)) . '\n';
}
} }
$used_languages = DI::l10n()->t('Detected languages in this post:\n%s', $used_languages); $used_languages = DI::l10n()->t('Detected languages in this post:\n%s', $used_languages);
return $used_languages; return $used_languages;

View File

@ -35,9 +35,6 @@ use Friendica\Model\Verb;
use Friendica\Protocol\Activity; use Friendica\Protocol\Activity;
use Friendica\Protocol\Relay; use Friendica\Protocol\Relay;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Strings;
// Channel
class Engagement class Engagement
{ {

View File

@ -127,7 +127,6 @@ class User
case 'community': case 'community':
return User::ACCOUNT_TYPE_COMMUNITY; return User::ACCOUNT_TYPE_COMMUNITY;
} }
return null; return null;
} }
@ -425,7 +424,7 @@ class User
* @return array user * @return array user
* @throws Exception * @throws Exception
*/ */
public static function getFirstAdmin(array $fields = []) : array public static function getFirstAdmin(array $fields = []): array
{ {
if (!empty(DI::config()->get('config', 'admin_nickname'))) { if (!empty(DI::config()->get('config', 'admin_nickname'))) {
return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields); return self::getByNickname(DI::config()->get('config', 'admin_nickname'), $fields);
@ -560,22 +559,20 @@ class User
return $default_circle; return $default_circle;
} }
/** /**
* Fetch the language code from the given user. If the code is invalid, return the system language * Fetch the language code from the given user. If the code is invalid, return the system language
* *
* @param integer $uid User-Id * @param integer $uid User-Id
* @return string * @return string
*/ */
public static function getLanguageCode(int $uid): string public static function getLanguageCode(int $uid): string
{ {
$owner = self::getOwnerDataById($uid); $owner = self::getOwnerDataById($uid);
$languages = DI::l10n()->getAvailableLanguages(true); $language = DI::l10n()->toISO6391($owner['language']);
if (in_array($owner['language'], array_keys($languages))) { if (in_array($language, array_keys(DI::l10n()->getLanguageCodes()))) {
$language = $owner['language']; return $language;
} else {
$language = DI::config()->get('system', 'language');
} }
return $language; return DI::l10n()->toISO6391(DI::config()->get('system', 'language'));
} }
/** /**
@ -1480,7 +1477,7 @@ class User
Photo::delete(['uid' => $register['uid']]); Photo::delete(['uid' => $register['uid']]);
return DBA::delete('user', ['uid' => $register['uid']]) && return DBA::delete('user', ['uid' => $register['uid']]) &&
Register::deleteByHash($register['hash']); Register::deleteByHash($register['hash']);
} }
/** /**

View File

@ -304,7 +304,7 @@ class Timeline extends BaseModule
} elseif ($this->selectedTab == ChannelEntity::AUDIO) { } elseif ($this->selectedTab == ChannelEntity::AUDIO) {
$condition = ["`media-type` & ?", 4]; $condition = ["`media-type` & ?", 4];
} elseif ($this->selectedTab == ChannelEntity::LANGUAGE) { } elseif ($this->selectedTab == ChannelEntity::LANGUAGE) {
$condition = ["JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?", $this->l10n->convertCodeForLanguageDetection(User::getLanguageCode($uid))]; $condition = ["JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?", User::getLanguageCode($uid)];
} elseif (is_numeric($this->selectedTab)) { } elseif (is_numeric($this->selectedTab)) {
$condition = $this->getUserChannelConditions($this->selectedTab, $this->session->getLocalUserId()); $condition = $this->getUserChannelConditions($this->selectedTab, $this->session->getLocalUserId());
} }
@ -421,7 +421,6 @@ class Timeline extends BaseModule
{ {
$conditions = []; $conditions = [];
$languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]); $languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]);
$languages = $this->l10n->convertForLanguageDetection($languages);
foreach ($languages as $language) { foreach ($languages as $language) {
$conditions[] = "JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?"; $conditions[] = "JSON_EXTRACT(JSON_KEYS(language), '$[0]') = ?";
$condition[] = $language; $condition[] = $language;

View File

@ -260,7 +260,7 @@ class Display extends BaseSettings
$bookmarked_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', $this->getAvailableTimelines($uid, true)->column('code')); $bookmarked_timelines = $this->pConfig->get($uid, 'system', 'network_timelines', $this->getAvailableTimelines($uid, true)->column('code'));
$enabled_timelines = $this->pConfig->get($uid, 'system', 'enabled_timelines', $this->getAvailableTimelines($uid, false)->column('code')); $enabled_timelines = $this->pConfig->get($uid, 'system', 'enabled_timelines', $this->getAvailableTimelines($uid, false)->column('code'));
$channel_languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]); $channel_languages = $this->pConfig->get($uid, 'channel', 'languages', [User::getLanguageCode($uid)]);
$languages = $this->l10n->getAvailableLanguages(true); $languages = $this->l10n->getLanguageCodes(true);
$timelines = []; $timelines = [];
foreach ($this->getAvailableTimelines($uid) as $timeline) { foreach ($this->getAvailableTimelines($uid) as $timeline) {

View File

@ -242,7 +242,7 @@ class Temporal
// First day of the week (0 = Sunday) // First day of the week (0 = Sunday)
$firstDay = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'first_day_of_week', 0); $firstDay = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'calendar', 'first_day_of_week', 0);
$lang = substr(DI::l10n()->getCurrentLang(), 0, 2); $lang = DI::l10n()->toISO6391(DI::l10n()->getCurrentLang());
// Check if the detected language is supported by the picker // Check if the detected language is supported by the picker
if (!in_array($lang, if (!in_array($lang,

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: 2023.09-rc\n" "Project-Id-Version: 2023.09-rc\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-11-01 14:57+0100\n" "POT-Creation-Date: 2023-11-03 05:35+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -961,7 +961,7 @@ msgstr ""
msgid "Enter user nickname: " msgid "Enter user nickname: "
msgstr "" msgstr ""
#: src/Console/User.php:182 src/Model/User.php:739 #: src/Console/User.php:182 src/Model/User.php:736
#: src/Module/Api/Twitter/ContactEndpoint.php:74 #: src/Module/Api/Twitter/ContactEndpoint.php:74
#: src/Module/Moderation/Users/Active.php:71 #: src/Module/Moderation/Users/Active.php:71
#: src/Module/Moderation/Users/Blocked.php:71 #: src/Module/Moderation/Users/Blocked.php:71
@ -1749,7 +1749,7 @@ msgstr ""
#: src/Content/GroupManager.php:152 src/Content/Nav.php:278 #: src/Content/GroupManager.php:152 src/Content/Nav.php:278
#: src/Content/Text/HTML.php:880 src/Content/Widget.php:537 #: src/Content/Text/HTML.php:880 src/Content/Widget.php:537
#: src/Model/User.php:1301 #: src/Model/User.php:1298
msgid "Groups" msgid "Groups"
msgstr "" msgstr ""
@ -1770,7 +1770,7 @@ msgstr ""
msgid "Create new group" msgid "Create new group"
msgstr "" msgstr ""
#: src/Content/Item.php:332 src/Model/Item.php:3089 #: src/Content/Item.php:332 src/Model/Item.php:3116
msgid "event" msgid "event"
msgstr "" msgstr ""
@ -1778,7 +1778,7 @@ msgstr ""
msgid "status" msgid "status"
msgstr "" msgstr ""
#: src/Content/Item.php:341 src/Model/Item.php:3091 #: src/Content/Item.php:341 src/Model/Item.php:3118
#: src/Module/Post/Tag/Add.php:123 #: src/Module/Post/Tag/Add.php:123
msgid "photo" msgid "photo"
msgstr "" msgstr ""
@ -2189,8 +2189,8 @@ msgid ""
"<a href=\"%1$s\" target=\"_blank\" rel=\"noopener noreferrer\">%2$s</a> %3$s" "<a href=\"%1$s\" target=\"_blank\" rel=\"noopener noreferrer\">%2$s</a> %3$s"
msgstr "" msgstr ""
#: src/Content/Text/BBCode.php:994 src/Model/Item.php:3822 #: src/Content/Text/BBCode.php:994 src/Model/Item.php:3849
#: src/Model/Item.php:3828 src/Model/Item.php:3829 #: src/Model/Item.php:3855 src/Model/Item.php:3856
msgid "Link to source" msgid "Link to source"
msgstr "" msgstr ""
@ -2733,8 +2733,8 @@ msgstr ""
#: src/Core/Installer.php:516 #: src/Core/Installer.php:516
msgid "" msgid ""
"The web installer needs to be able to create a file called \"local.config." "The web installer needs to be able to create a file called \"local.config.php"
"php\" in the \"config\" folder of your web server and it is unable to do so." "\" in the \"config\" folder of your web server and it is unable to do so."
msgstr "" msgstr ""
#: src/Core/Installer.php:517 #: src/Core/Installer.php:517
@ -2852,158 +2852,163 @@ msgstr ""
msgid "Could not connect to database." msgid "Could not connect to database."
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:430 #: src/Core/L10n.php:446
#, php-format
msgid "%s (%s)"
msgstr ""
#: src/Core/L10n.php:494 src/Model/Event.php:430
#: src/Module/Settings/Display.php:278 #: src/Module/Settings/Display.php:278
msgid "Monday" msgid "Monday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:431 #: src/Core/L10n.php:494 src/Model/Event.php:431
#: src/Module/Settings/Display.php:279 #: src/Module/Settings/Display.php:279
msgid "Tuesday" msgid "Tuesday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:432 #: src/Core/L10n.php:494 src/Model/Event.php:432
#: src/Module/Settings/Display.php:280 #: src/Module/Settings/Display.php:280
msgid "Wednesday" msgid "Wednesday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:433 #: src/Core/L10n.php:494 src/Model/Event.php:433
#: src/Module/Settings/Display.php:281 #: src/Module/Settings/Display.php:281
msgid "Thursday" msgid "Thursday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:434 #: src/Core/L10n.php:494 src/Model/Event.php:434
#: src/Module/Settings/Display.php:282 #: src/Module/Settings/Display.php:282
msgid "Friday" msgid "Friday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:435 #: src/Core/L10n.php:494 src/Model/Event.php:435
#: src/Module/Settings/Display.php:283 #: src/Module/Settings/Display.php:283
msgid "Saturday" msgid "Saturday"
msgstr "" msgstr ""
#: src/Core/L10n.php:507 src/Model/Event.php:429 #: src/Core/L10n.php:494 src/Model/Event.php:429
#: src/Module/Settings/Display.php:277 #: src/Module/Settings/Display.php:277
msgid "Sunday" msgid "Sunday"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:450 #: src/Core/L10n.php:498 src/Model/Event.php:450
msgid "January" msgid "January"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:451 #: src/Core/L10n.php:498 src/Model/Event.php:451
msgid "February" msgid "February"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:452 #: src/Core/L10n.php:498 src/Model/Event.php:452
msgid "March" msgid "March"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:453 #: src/Core/L10n.php:498 src/Model/Event.php:453
msgid "April" msgid "April"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Core/L10n.php:530 src/Model/Event.php:441 #: src/Core/L10n.php:498 src/Core/L10n.php:517 src/Model/Event.php:441
msgid "May" msgid "May"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:454 #: src/Core/L10n.php:498 src/Model/Event.php:454
msgid "June" msgid "June"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:455 #: src/Core/L10n.php:498 src/Model/Event.php:455
msgid "July" msgid "July"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:456 #: src/Core/L10n.php:498 src/Model/Event.php:456
msgid "August" msgid "August"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:457 #: src/Core/L10n.php:498 src/Model/Event.php:457
msgid "September" msgid "September"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:458 #: src/Core/L10n.php:498 src/Model/Event.php:458
msgid "October" msgid "October"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:459 #: src/Core/L10n.php:498 src/Model/Event.php:459
msgid "November" msgid "November"
msgstr "" msgstr ""
#: src/Core/L10n.php:511 src/Model/Event.php:460 #: src/Core/L10n.php:498 src/Model/Event.php:460
msgid "December" msgid "December"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:422 #: src/Core/L10n.php:513 src/Model/Event.php:422
msgid "Mon" msgid "Mon"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:423 #: src/Core/L10n.php:513 src/Model/Event.php:423
msgid "Tue" msgid "Tue"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:424 #: src/Core/L10n.php:513 src/Model/Event.php:424
msgid "Wed" msgid "Wed"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:425 #: src/Core/L10n.php:513 src/Model/Event.php:425
msgid "Thu" msgid "Thu"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:426 #: src/Core/L10n.php:513 src/Model/Event.php:426
msgid "Fri" msgid "Fri"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:427 #: src/Core/L10n.php:513 src/Model/Event.php:427
msgid "Sat" msgid "Sat"
msgstr "" msgstr ""
#: src/Core/L10n.php:526 src/Model/Event.php:421 #: src/Core/L10n.php:513 src/Model/Event.php:421
msgid "Sun" msgid "Sun"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:437 #: src/Core/L10n.php:517 src/Model/Event.php:437
msgid "Jan" msgid "Jan"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:438 #: src/Core/L10n.php:517 src/Model/Event.php:438
msgid "Feb" msgid "Feb"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:439 #: src/Core/L10n.php:517 src/Model/Event.php:439
msgid "Mar" msgid "Mar"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:440 #: src/Core/L10n.php:517 src/Model/Event.php:440
msgid "Apr" msgid "Apr"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:442 #: src/Core/L10n.php:517 src/Model/Event.php:442
msgid "Jun" msgid "Jun"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:443 #: src/Core/L10n.php:517 src/Model/Event.php:443
msgid "Jul" msgid "Jul"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:444 #: src/Core/L10n.php:517 src/Model/Event.php:444
msgid "Aug" msgid "Aug"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 #: src/Core/L10n.php:517
msgid "Sep" msgid "Sep"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:446 #: src/Core/L10n.php:517 src/Model/Event.php:446
msgid "Oct" msgid "Oct"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:447 #: src/Core/L10n.php:517 src/Model/Event.php:447
msgid "Nov" msgid "Nov"
msgstr "" msgstr ""
#: src/Core/L10n.php:530 src/Model/Event.php:448 #: src/Core/L10n.php:517 src/Model/Event.php:448
msgid "Dec" msgid "Dec"
msgstr "" msgstr ""
@ -3401,81 +3406,91 @@ msgstr ""
msgid "Happy Birthday %s" msgid "Happy Birthday %s"
msgstr "" msgstr ""
#: src/Model/Item.php:2148 #: src/Model/Item.php:2170
#, php-format
msgid "%s (%s - %s): %s"
msgstr ""
#: src/Model/Item.php:2172
#, php-format
msgid "%s (%s): %s"
msgstr ""
#: src/Model/Item.php:2175
#, php-format #, php-format
msgid "Detected languages in this post:\\n%s" msgid "Detected languages in this post:\\n%s"
msgstr "" msgstr ""
#: src/Model/Item.php:3093 #: src/Model/Item.php:3120
msgid "activity" msgid "activity"
msgstr "" msgstr ""
#: src/Model/Item.php:3095 #: src/Model/Item.php:3122
msgid "comment" msgid "comment"
msgstr "" msgstr ""
#: src/Model/Item.php:3098 src/Module/Post/Tag/Add.php:123 #: src/Model/Item.php:3125 src/Module/Post/Tag/Add.php:123
msgid "post" msgid "post"
msgstr "" msgstr ""
#: src/Model/Item.php:3268 #: src/Model/Item.php:3295
#, php-format #, php-format
msgid "%s is blocked" msgid "%s is blocked"
msgstr "" msgstr ""
#: src/Model/Item.php:3270 #: src/Model/Item.php:3297
#, php-format #, php-format
msgid "%s is ignored" msgid "%s is ignored"
msgstr "" msgstr ""
#: src/Model/Item.php:3272 #: src/Model/Item.php:3299
#, php-format #, php-format
msgid "Content from %s is collapsed" msgid "Content from %s is collapsed"
msgstr "" msgstr ""
#: src/Model/Item.php:3276 #: src/Model/Item.php:3303
#, php-format #, php-format
msgid "Content warning: %s" msgid "Content warning: %s"
msgstr "" msgstr ""
#: src/Model/Item.php:3729 #: src/Model/Item.php:3756
msgid "bytes" msgid "bytes"
msgstr "" msgstr ""
#: src/Model/Item.php:3760 #: src/Model/Item.php:3787
#, php-format #, php-format
msgid "%2$s (%3$d%%, %1$d vote)" msgid "%2$s (%3$d%%, %1$d vote)"
msgid_plural "%2$s (%3$d%%, %1$d votes)" msgid_plural "%2$s (%3$d%%, %1$d votes)"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/Item.php:3762 #: src/Model/Item.php:3789
#, php-format #, php-format
msgid "%2$s (%1$d vote)" msgid "%2$s (%1$d vote)"
msgid_plural "%2$s (%1$d votes)" msgid_plural "%2$s (%1$d votes)"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/Item.php:3767 #: src/Model/Item.php:3794
#, php-format #, php-format
msgid "%d voter. Poll end: %s" msgid "%d voter. Poll end: %s"
msgid_plural "%d voters. Poll end: %s" msgid_plural "%d voters. Poll end: %s"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/Item.php:3769 #: src/Model/Item.php:3796
#, php-format #, php-format
msgid "%d voter." msgid "%d voter."
msgid_plural "%d voters." msgid_plural "%d voters."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/Item.php:3771 #: src/Model/Item.php:3798
#, php-format #, php-format
msgid "Poll end: %s" msgid "Poll end: %s"
msgstr "" msgstr ""
#: src/Model/Item.php:3805 src/Model/Item.php:3806 #: src/Model/Item.php:3832 src/Model/Item.php:3833
msgid "View on separate page" msgid "View on separate page"
msgstr "" msgstr ""
@ -3633,145 +3648,145 @@ msgstr ""
msgid "Contact information and Social Networks" msgid "Contact information and Social Networks"
msgstr "" msgstr ""
#: src/Model/User.php:226 src/Model/User.php:1214 #: src/Model/User.php:225 src/Model/User.php:1211
msgid "SERIOUS ERROR: Generation of security keys failed." msgid "SERIOUS ERROR: Generation of security keys failed."
msgstr "" msgstr ""
#: src/Model/User.php:648 src/Model/User.php:681 #: src/Model/User.php:645 src/Model/User.php:678
msgid "Login failed" msgid "Login failed"
msgstr "" msgstr ""
#: src/Model/User.php:713 #: src/Model/User.php:710
msgid "Not enough information to authenticate" msgid "Not enough information to authenticate"
msgstr "" msgstr ""
#: src/Model/User.php:834 #: src/Model/User.php:831
msgid "Password can't be empty" msgid "Password can't be empty"
msgstr "" msgstr ""
#: src/Model/User.php:876 #: src/Model/User.php:873
msgid "Empty passwords are not allowed." msgid "Empty passwords are not allowed."
msgstr "" msgstr ""
#: src/Model/User.php:880 #: src/Model/User.php:877
msgid "" msgid ""
"The new password has been exposed in a public data dump, please choose " "The new password has been exposed in a public data dump, please choose "
"another." "another."
msgstr "" msgstr ""
#: src/Model/User.php:884 #: src/Model/User.php:881
msgid "The password length is limited to 72 characters." msgid "The password length is limited to 72 characters."
msgstr "" msgstr ""
#: src/Model/User.php:888 #: src/Model/User.php:885
msgid "The password can't contain white spaces nor accentuated letters" msgid "The password can't contain white spaces nor accentuated letters"
msgstr "" msgstr ""
#: src/Model/User.php:1097 #: src/Model/User.php:1094
msgid "Passwords do not match. Password unchanged." msgid "Passwords do not match. Password unchanged."
msgstr "" msgstr ""
#: src/Model/User.php:1104 #: src/Model/User.php:1101
msgid "An invitation is required." msgid "An invitation is required."
msgstr "" msgstr ""
#: src/Model/User.php:1108 #: src/Model/User.php:1105
msgid "Invitation could not be verified." msgid "Invitation could not be verified."
msgstr "" msgstr ""
#: src/Model/User.php:1116 #: src/Model/User.php:1113
msgid "Invalid OpenID url" msgid "Invalid OpenID url"
msgstr "" msgstr ""
#: src/Model/User.php:1129 src/Security/Authentication.php:241 #: src/Model/User.php:1126 src/Security/Authentication.php:241
msgid "" msgid ""
"We encountered a problem while logging in with the OpenID you provided. " "We encountered a problem while logging in with the OpenID you provided. "
"Please check the correct spelling of the ID." "Please check the correct spelling of the ID."
msgstr "" msgstr ""
#: src/Model/User.php:1129 src/Security/Authentication.php:241 #: src/Model/User.php:1126 src/Security/Authentication.php:241
msgid "The error message was:" msgid "The error message was:"
msgstr "" msgstr ""
#: src/Model/User.php:1135 #: src/Model/User.php:1132
msgid "Please enter the required information." msgid "Please enter the required information."
msgstr "" msgstr ""
#: src/Model/User.php:1149 #: src/Model/User.php:1146
#, php-format #, php-format
msgid "" msgid ""
"system.username_min_length (%s) and system.username_max_length (%s) are " "system.username_min_length (%s) and system.username_max_length (%s) are "
"excluding each other, swapping values." "excluding each other, swapping values."
msgstr "" msgstr ""
#: src/Model/User.php:1156 #: src/Model/User.php:1153
#, php-format #, php-format
msgid "Username should be at least %s character." msgid "Username should be at least %s character."
msgid_plural "Username should be at least %s characters." msgid_plural "Username should be at least %s characters."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/User.php:1160 #: src/Model/User.php:1157
#, php-format #, php-format
msgid "Username should be at most %s character." msgid "Username should be at most %s character."
msgid_plural "Username should be at most %s characters." msgid_plural "Username should be at most %s characters."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/Model/User.php:1168 #: src/Model/User.php:1165
msgid "That doesn't appear to be your full (First Last) name." msgid "That doesn't appear to be your full (First Last) name."
msgstr "" msgstr ""
#: src/Model/User.php:1173 #: src/Model/User.php:1170
msgid "Your email domain is not among those allowed on this site." msgid "Your email domain is not among those allowed on this site."
msgstr "" msgstr ""
#: src/Model/User.php:1177 #: src/Model/User.php:1174
msgid "Not a valid email address." msgid "Not a valid email address."
msgstr "" msgstr ""
#: src/Model/User.php:1180 #: src/Model/User.php:1177
msgid "The nickname was blocked from registration by the nodes admin." msgid "The nickname was blocked from registration by the nodes admin."
msgstr "" msgstr ""
#: src/Model/User.php:1184 src/Model/User.php:1190 #: src/Model/User.php:1181 src/Model/User.php:1187
msgid "Cannot use that email." msgid "Cannot use that email."
msgstr "" msgstr ""
#: src/Model/User.php:1196 #: src/Model/User.php:1193
msgid "Your nickname can only contain a-z, 0-9 and _." msgid "Your nickname can only contain a-z, 0-9 and _."
msgstr "" msgstr ""
#: src/Model/User.php:1204 src/Model/User.php:1261 #: src/Model/User.php:1201 src/Model/User.php:1258
msgid "Nickname is already registered. Please choose another." msgid "Nickname is already registered. Please choose another."
msgstr "" msgstr ""
#: src/Model/User.php:1248 src/Model/User.php:1252 #: src/Model/User.php:1245 src/Model/User.php:1249
msgid "An error occurred during registration. Please try again." msgid "An error occurred during registration. Please try again."
msgstr "" msgstr ""
#: src/Model/User.php:1275 #: src/Model/User.php:1272
msgid "An error occurred creating your default profile. Please try again." msgid "An error occurred creating your default profile. Please try again."
msgstr "" msgstr ""
#: src/Model/User.php:1282 #: src/Model/User.php:1279
msgid "An error occurred creating your self contact. Please try again." msgid "An error occurred creating your self contact. Please try again."
msgstr "" msgstr ""
#: src/Model/User.php:1287 #: src/Model/User.php:1284
msgid "Friends" msgid "Friends"
msgstr "" msgstr ""
#: src/Model/User.php:1291 #: src/Model/User.php:1288
msgid "" msgid ""
"An error occurred creating your default contact circle. Please try again." "An error occurred creating your default contact circle. Please try again."
msgstr "" msgstr ""
#: src/Model/User.php:1335 #: src/Model/User.php:1332
msgid "Profile Photos" msgid "Profile Photos"
msgstr "" msgstr ""
#: src/Model/User.php:1515 #: src/Model/User.php:1512
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -3779,7 +3794,7 @@ msgid ""
"\t\t\tthe administrator of %2$s has set up an account for you." "\t\t\tthe administrator of %2$s has set up an account for you."
msgstr "" msgstr ""
#: src/Model/User.php:1518 #: src/Model/User.php:1515
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -3815,12 +3830,12 @@ msgid ""
"\t\tThank you and welcome to %4$s." "\t\tThank you and welcome to %4$s."
msgstr "" msgstr ""
#: src/Model/User.php:1550 src/Model/User.php:1656 #: src/Model/User.php:1547 src/Model/User.php:1653
#, php-format #, php-format
msgid "Registration details for %s" msgid "Registration details for %s"
msgstr "" msgstr ""
#: src/Model/User.php:1570 #: src/Model/User.php:1567
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -3836,12 +3851,12 @@ msgid ""
"\t\t" "\t\t"
msgstr "" msgstr ""
#: src/Model/User.php:1589 #: src/Model/User.php:1586
#, php-format #, php-format
msgid "Registration at %s" msgid "Registration at %s"
msgstr "" msgstr ""
#: src/Model/User.php:1613 #: src/Model/User.php:1610
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -3850,7 +3865,7 @@ msgid ""
"\t\t\t" "\t\t\t"
msgstr "" msgstr ""
#: src/Model/User.php:1621 #: src/Model/User.php:1618
#, php-format #, php-format
msgid "" msgid ""
"\n" "\n"
@ -3871,8 +3886,8 @@ msgid ""
"profile\n" "profile\n"
"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n" "\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n"
"\n" "\n"
"\t\t\tWe recommend adding a profile photo, adding some profile " "\t\t\tWe recommend adding a profile photo, adding some profile \"keywords"
"\"keywords\" (very useful\n" "\" (very useful\n"
"\t\t\tin making new friends) - and perhaps what country you live in; if you " "\t\t\tin making new friends) - and perhaps what country you live in; if you "
"do not wish\n" "do not wish\n"
"\t\t\tto be more specific than that.\n" "\t\t\tto be more specific than that.\n"
@ -3888,7 +3903,7 @@ msgid ""
"\t\t\tThank you and welcome to %2$s." "\t\t\tThank you and welcome to %2$s."
msgstr "" msgstr ""
#: src/Model/User.php:1683 #: src/Model/User.php:1680
msgid "" msgid ""
"User with delegates can't be removed, please remove delegate users first" "User with delegates can't be removed, please remove delegate users first"
msgstr "" msgstr ""
@ -5362,9 +5377,9 @@ msgstr ""
#: src/Module/Admin/Summary.php:98 #: src/Module/Admin/Summary.php:98
msgid "" msgid ""
"The last update failed. Please run \"php bin/console.php dbstructure " "The last update failed. Please run \"php bin/console.php dbstructure update"
"update\" from the command line and have a look at the errors that might " "\" from the command line and have a look at the errors that might appear. "
"appear. (Some of the errors are possibly inside the logfile.)" "(Some of the errors are possibly inside the logfile.)"
msgstr "" msgstr ""
#: src/Module/Admin/Summary.php:102 #: src/Module/Admin/Summary.php:102
@ -5515,8 +5530,8 @@ msgstr ""
#, php-format #, php-format
msgid "" msgid ""
"Show some informations regarding the needed information to operate the node " "Show some informations regarding the needed information to operate the node "
"according e.g. to <a href=\"%s\" target=\"_blank\" rel=\"noopener " "according e.g. to <a href=\"%s\" target=\"_blank\" rel=\"noopener noreferrer"
"noreferrer\">EU-GDPR</a>." "\">EU-GDPR</a>."
msgstr "" msgstr ""
#: src/Module/Admin/Tos.php:81 #: src/Module/Admin/Tos.php:81
@ -8849,8 +8864,8 @@ msgstr ""
#: src/Module/Profile/Profile.php:158 #: src/Module/Profile/Profile.php:158
#, php-format #, php-format
msgid "" msgid ""
"You're currently viewing your profile as <b>%s</b> <a href=\"%s\" " "You're currently viewing your profile as <b>%s</b> <a href=\"%s\" class="
"class=\"btn btn-sm pull-right\">Cancel</a>" "\"btn btn-sm pull-right\">Cancel</a>"
msgstr "" msgstr ""
#: src/Module/Profile/Profile.php:167 #: src/Module/Profile/Profile.php:167
@ -9398,8 +9413,8 @@ msgstr ""
#: src/Module/Security/TwoFactor/Verify.php:100 #: src/Module/Security/TwoFactor/Verify.php:100
#, php-format #, php-format
msgid "" msgid ""
"If you do not have access to your authentication code you can use a <a " "If you do not have access to your authentication code you can use a <a href="
"href=\"%s\">two-factor recovery code</a>." "\"%s\">two-factor recovery code</a>."
msgstr "" msgstr ""
#: src/Module/Security/TwoFactor/Verify.php:101 #: src/Module/Security/TwoFactor/Verify.php:101
@ -11050,8 +11065,8 @@ msgstr ""
#: src/Module/Settings/TwoFactor/Verify.php:152 #: src/Module/Settings/TwoFactor/Verify.php:152
#, php-format #, php-format
msgid "" msgid ""
"<p>Or you can open the following URL in your mobile device:</p><p><a " "<p>Or you can open the following URL in your mobile device:</p><p><a href="
"href=\"%s\">%s</a></p>" "\"%s\">%s</a></p>"
msgstr "" msgstr ""
#: src/Module/Settings/TwoFactor/Verify.php:159 #: src/Module/Settings/TwoFactor/Verify.php:159
@ -11160,9 +11175,9 @@ msgstr ""
msgid "" msgid ""
"At any point in time a logged in user can export their account data from the " "At any point in time a logged in user can export their account data from the "
"<a href=\"%1$s/settings/userexport\">account settings</a>. If the user wants " "<a href=\"%1$s/settings/userexport\">account settings</a>. If the user wants "
"to delete their account they can do so at <a href=\"%1$s/settings/" "to delete their account they can do so at <a href=\"%1$s/settings/removeme\">"
"removeme\">%1$s/settings/removeme</a>. The deletion of the account will be " "%1$s/settings/removeme</a>. The deletion of the account will be permanent. "
"permanent. Deletion of the data will also be requested from the nodes of the " "Deletion of the data will also be requested from the nodes of the "
"communication partners." "communication partners."
msgstr "" msgstr ""