Merge remote-tracking branch 'upstream/2021.09-rc' into user-contact

This commit is contained in:
Michael 2021-09-13 12:31:30 +00:00
commit 5abc1543fd
22 changed files with 4837 additions and 4275 deletions

View file

@ -42,6 +42,9 @@ Some examples of common known configuration files:
Addons can define their own default configuration values in `addon/[addon]/config/[addon].config.php` which is loaded when the addon is activated.
If needed, an alternative `config` path can be used by using the `FRIENDICA_CONFIG_DIR` environment variable (full path required!).
This is useful in case of hardening the system by separating configuration from program binaries.
### Static Configuration location
The `static` directory holds the codebase default configurations files.

View file

@ -20,6 +20,7 @@
*/
use Friendica\App;
use Friendica\BaseModule;
use Friendica\Content\ContactSelector;
use Friendica\Content\Feature;
use Friendica\Core\ACL;
@ -396,6 +397,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
$threadsid = -1;
$page_template = Renderer::getMarkupTemplate("conversation.tpl");
$formSecurityToken = BaseModule::getFormSecurityToken('contact_action');
if (!empty($items)) {
if (in_array($mode, ['community', 'contacts'])) {
@ -502,7 +504,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link']),
'linktitle' => DI::l10n()->t('View %s\'s profile @ %s', $profile_name, $item['author-link']),
'profile_url' => $profile_link,
'item_photo_menu_html' => item_photo_menu($item),
'item_photo_menu_html' => item_photo_menu($item, $formSecurityToken),
'name' => $profile_name,
'sparkle' => $sparkle,
'lock' => false,
@ -590,7 +592,7 @@ function conversation(App $a, array $items, $mode, $update, $preview = false, $o
}
}
$threads = $conv->getTemplateData($conv_responses);
$threads = $conv->getTemplateData($conv_responses, $formSecurityToken);
if (!$threads) {
Logger::log('[ERROR] conversation : Failed to get template data.', Logger::DEBUG);
$threads = [];
@ -782,7 +784,7 @@ function conversation_add_children(array $parents, $block_authors, $order, $uid)
return $items;
}
function item_photo_menu($item)
function item_photo_menu($item, string $formSecurityToken)
{
DI::profiler()->startRecording('rendering');
$sub_link = '';
@ -825,8 +827,8 @@ function item_photo_menu($item)
if (!empty($pcid)) {
$contact_url = 'contact/' . $pcid;
$posts_link = $contact_url . '/posts';
$block_link = $item['self'] ? '' : $contact_url . '/block';
$ignore_link = $item['self'] ? '' : $contact_url . '/ignore';
$block_link = $item['self'] ? '' : $contact_url . '/block?t=' . $formSecurityToken;
$ignore_link = $item['self'] ? '' : $contact_url . '/ignore?t=' . $formSecurityToken;
}
if ($cid && !$item['self']) {

View file

@ -25,6 +25,7 @@ use Exception;
use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\App\Module;
use Friendica\Factory\ConfigFactory;
use Friendica\Module\Maintenance;
use Friendica\Security\Authentication;
use Friendica\Core\Config\Cache;
@ -352,7 +353,7 @@ class App
$this->profiler->update($this->config);
Core\Hook::loadHooks();
$loader = new ConfigFileLoader($this->getBasePath());
$loader = (new ConfigFactory())->createConfigFileLoader($this->getBasePath(), $_SERVER);
Core\Hook::callAll('load_config', $loader);
}

View file

@ -30,6 +30,45 @@ use Friendica\Util\ConfigFileLoader;
class ConfigFactory
{
/**
* The key of the $_SERVER variable to override the config directory
*
* @var string
*/
const CONFIG_DIR_ENV = 'FRIENDICA_CONFIG_DIR';
/**
* The Sub directory of the config-files
*
* @var string
*/
const CONFIG_DIR = 'config';
/**
* The Sub directory of the static config-files
*
* @var string
*/
const STATIC_DIR = 'static';
/**
* @param string $basePath The basepath of FRIENDICA
* @param array $serer the $_SERVER array
*
* @return ConfigFileLoader
*/
public function createConfigFileLoader(string $basePath, array $server = [])
{
if (!empty($server[self::CONFIG_DIR_ENV]) && is_dir($server[self::CONFIG_DIR_ENV])) {
$configDir = $server[self::CONFIG_DIR_ENV];
} else {
$configDir = $basePath . DIRECTORY_SEPARATOR . self::CONFIG_DIR;
}
$staticDir = $basePath . DIRECTORY_SEPARATOR . self::STATIC_DIR;
return new ConfigFileLoader($basePath, $configDir, $staticDir);
}
/**
* @param ConfigFileLoader $loader The Config Cache loader (INI/config/.htconfig)
*

View file

@ -29,6 +29,7 @@ use Friendica\Core\Update;
use Friendica\Database\DBA;
use Friendica\Database\DBStructure;
use Friendica\DI;
use Friendica\Factory\ConfigFactory;
use Friendica\Model\Register;
use Friendica\Module\BaseAdmin;
use Friendica\Network\HTTPException\InternalServerErrorException;
@ -151,7 +152,7 @@ class Summary extends BaseAdmin
}
// check legacy basepath settings
$configLoader = new ConfigFileLoader($a->getBasePath());
$configLoader = (new ConfigFactory())->createConfigFileLoader($a->getBasePath(), $_SERVER);
$configCache = new Cache();
$configLoader->setupCache($configCache);
$confBasepath = $configCache->get('system', 'basepath');

View file

@ -125,6 +125,7 @@ class Post
* Get data in a form usable by a conversation template
*
* @param array $conv_responses conversation responses
* @param string $formSecurityToken A security Token to avoid CSF attacks
* @param integer $thread_level default = 1
*
* @return mixed The data requested on success
@ -132,7 +133,7 @@ class Post
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
public function getTemplateData(array $conv_responses, $thread_level = 1)
public function getTemplateData(array $conv_responses, string $formSecurityToken, $thread_level = 1)
{
$a = DI::app();
@ -458,7 +459,7 @@ class Post
'vwall' => DI::l10n()->t('via Wall-To-Wall:'),
'profile_url' => $profile_link,
'name' => $profile_name,
'item_photo_menu_html' => item_photo_menu($item),
'item_photo_menu_html' => item_photo_menu($item, $formSecurityToken),
'thumb' => DI::baseUrl()->remove(Contact::getAvatarUrlForUrl($item['author-link'], $item['uid'], Proxy::SIZE_THUMB)),
'osparkle' => $osparkle,
'sparkle' => $sparkle,
@ -532,7 +533,7 @@ class Post
$nb_children = count($children);
if ($nb_children > 0) {
foreach ($children as $child) {
$result['children'][] = $child->getTemplateData($conv_responses, $thread_level + 1);
$result['children'][] = $child->getTemplateData($conv_responses, $formSecurityToken, $thread_level + 1);
}
// Collapse

View file

@ -190,12 +190,13 @@ class Thread
* We should find a way to avoid using those arguments (at least most of them)
*
* @param array $conv_responses data
* @param string $formSecurityToken A security Token to avoid CSF attacks
*
* @return mixed The data requested on success
* false on failure
* @throws \Exception
*/
public function getTemplateData($conv_responses)
public function getTemplateData($conv_responses, string $formSecurityToken)
{
$result = [];
@ -204,7 +205,7 @@ class Thread
continue;
}
$item_data = $item->getTemplateData($conv_responses);
$item_data = $item->getTemplateData($conv_responses, $formSecurityToken);
if (!$item_data) {
Logger::log('[ERROR] Conversation::getTemplateData : Failed to get item template data ('. $item->getId() .').', Logger::DEBUG);

View file

@ -35,20 +35,6 @@ use Friendica\Core\Config\Cache;
*/
class ConfigFileLoader
{
/**
* The Sub directory of the config-files
*
* @var string
*/
const CONFIG_DIR = 'config';
/**
* The Sub directory of the static config-files
*
* @var string
*/
const STATIC_DIR = 'static';
/**
* The default name of the user defined ini file
*
@ -83,11 +69,16 @@ class ConfigFileLoader
*/
private $staticDir;
public function __construct(string $basePath)
/**
* @param string $baseDir The base
* @param string $configDir
* @param string $staticDir
*/
public function __construct(string $baseDir, string $configDir, string $staticDir)
{
$this->baseDir = $basePath;
$this->configDir = $this->baseDir . DIRECTORY_SEPARATOR . self::CONFIG_DIR;
$this->staticDir = $this->baseDir . DIRECTORY_SEPARATOR . self::STATIC_DIR;
$this->baseDir = $baseDir;
$this->configDir = $configDir;
$this->staticDir = $staticDir;
}
/**
@ -102,7 +93,7 @@ class ConfigFileLoader
*
* @throws Exception
*/
public function setupCache(Cache $config, array $server = [], $raw = false)
public function setupCache(Cache $config, array $server = [], bool $raw = false)
{
// Load static config files first, the order is important
$config->load($this->loadStaticConfig('defaults'), Cache::SOURCE_FILE);
@ -185,7 +176,7 @@ class ConfigFileLoader
$filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
Addon::DIRECTORY . DIRECTORY_SEPARATOR . // addon/
$name . DIRECTORY_SEPARATOR . // openstreetmap/
self::CONFIG_DIR . DIRECTORY_SEPARATOR . // config/
'config'. DIRECTORY_SEPARATOR . // config/
$name . ".config.php"; // openstreetmap.config.php
if (file_exists($filepath)) {
@ -206,9 +197,8 @@ class ConfigFileLoader
*/
public function loadEnvConfig(array $server)
{
$filepath = $this->baseDir . DIRECTORY_SEPARATOR . // /var/www/html/
self::STATIC_DIR . DIRECTORY_SEPARATOR . // static/
"env.config.php"; // env.config.php
$filepath = $this->staticDir . DIRECTORY_SEPARATOR . // /var/www/html/static/
"env.config.php"; // env.config.php
if (!file_exists($filepath)) {
return [];

View file

@ -74,9 +74,12 @@ return [
]
],
Util\ConfigFileLoader::class => [
'shared' => true,
'constructParams' => [
[Dice::INSTANCE => '$basepath'],
'instanceOf' => Factory\ConfigFactory::class,
'call' => [
['createConfigFileLoader', [
[Dice::INSTANCE => '$basepath'],
$_SERVER,
], Dice::CHAIN_CALL],
],
],
Config\Cache::class => [

View file

@ -43,6 +43,7 @@ trait VFSTrait
'static' => [],
'test' => [],
'logs' => [],
'config2' => [],
];
// create a virtual directory and copy all needed files and folders to it

View file

@ -55,7 +55,7 @@ class DatabaseCacheTest extends CacheTest
// load real config to avoid mocking every config-entry which is related to the Database class
$configFactory = new ConfigFactory();
$loader = new ConfigFileLoader($this->root->url());
$loader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), []);
$configCache = $configFactory->createCache($loader);
$dba = new StaticDatabase($configCache, $profiler, $logger);

View file

@ -57,7 +57,7 @@ class DatabaseLockDriverTest extends LockTest
// load real config to avoid mocking every config-entry which is related to the Database class
$configFactory = new ConfigFactory();
$loader = new ConfigFileLoader($this->root->url());
$loader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), []);
$configCache = $configFactory->createCache($loader);
$dba = new StaticDatabase($configCache, $profiler, $logger);

View file

@ -73,7 +73,7 @@ class StorageManagerTest extends DatabaseTest
// load real config to avoid mocking every config-entry which is related to the Database class
$configFactory = new ConfigFactory();
$loader = new ConfigFileLoader($this->root->url());
$loader = $configFactory->createConfigFileLoader($this->root->url(), []);
$configCache = $configFactory->createCache($loader);
$this->dba = new StaticDatabase($configCache, $profiler, $this->logger);

View file

@ -33,7 +33,7 @@ class ProcessTest extends DatabaseTest
// load real config to avoid mocking every config-entry which is related to the Database class
$configFactory = new ConfigFactory();
$loader = new ConfigFileLoader($this->root->url());
$loader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), []);
$configCache = $configFactory->createCache($loader);
$this->dba = new StaticDatabase($configCache, $profiler, $logger);

View file

@ -55,7 +55,7 @@ class DatabaseStorageTest extends StorageTest
// load real config to avoid mocking every config-entry which is related to the Database class
$configFactory = new ConfigFactory();
$loader = new ConfigFileLoader($this->root->url());
$loader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), []);
$configCache = $configFactory->createCache($loader);
$dba = new StaticDatabase($configCache, $profiler, $logger);

View file

@ -22,6 +22,7 @@
namespace Friendica\Test\src\Util\Config;
use Friendica\Core\Config\Cache;
use Friendica\Factory\ConfigFactory;
use Friendica\Test\MockedTest;
use Friendica\Test\Util\VFSTrait;
use Friendica\Util\ConfigFileLoader;
@ -45,7 +46,11 @@ class ConfigFileLoaderTest extends MockedTest
{
$this->delConfigFile('local.config.php');
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -67,7 +72,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent('<?php return true;');
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -91,7 +100,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent(file_get_contents($file));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -123,7 +136,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent(file_get_contents($file));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -154,7 +171,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root)
->setContent(file_get_contents($file));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -203,7 +224,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('addon')->getChild('test')->getChild('config'))
->setContent(file_get_contents($file));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$conf = $configFileLoader->loadAddonConfig('test');
@ -235,7 +260,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -264,7 +293,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.ini.php'));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -293,7 +326,11 @@ class ConfigFileLoaderTest extends MockedTest
->at($this->root->getChild('config'))
->setContent(file_get_contents($fileDir . 'B.ini.php'));
$configFileLoader = new ConfigFileLoader($this->root->url());
$configFileLoader = new ConfigFileLoader(
$this->root->url(),
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::CONFIG_DIR,
$this->root->url() . DIRECTORY_SEPARATOR . ConfigFactory::STATIC_DIR
);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
@ -301,4 +338,44 @@ class ConfigFileLoaderTest extends MockedTest
self::assertEquals('admin@test.it', $configCache->get('config', 'admin_email'));
self::assertEmpty($configCache->get('system', 'NewKey'));
}
/**
* Test that using a wrong configuration directory leads to the "normal" config path
*/
public function testWrongEnvDir()
{
$this->delConfigFile('local.config.php');
$configFileLoader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => '/a/wrong/dir/']);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
self::assertEquals($this->root->url(), $configCache->get('system', 'basepath'));
}
/**
* Test that a different location of the configuration directory produces the expected output
*/
public function testRightEnvDir()
{
$this->delConfigFile('local.config.php');
$fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'..' . DIRECTORY_SEPARATOR .
'datasets' . DIRECTORY_SEPARATOR .
'config' . DIRECTORY_SEPARATOR;
vfsStream::newFile('B.config.php')
->at($this->root->getChild('config2'))
->setContent(file_get_contents($fileDir . 'B.config.php'));
$configFileLoader = (new ConfigFactory())->createConfigFileLoader($this->root->url(), ['FRIENDICA_CONFIG_DIR' => $this->root->getChild('config2')->url()]);
$configCache = new Cache();
$configFileLoader->setupCache($configCache);
self::assertEquals('newValue', $configCache->get('system', 'newKey'));
}
}

File diff suppressed because it is too large Load diff

View file

@ -1326,6 +1326,8 @@ $a->strings["Don't embed private images in posts"] = "Private Bilder nicht in Be
$a->strings["Don't replace locally-hosted private photos in posts with an embedded copy of the image. This means that contacts who receive posts containing private photos will have to authenticate and load each image, which may take a while."] = "Ersetze lokal gehostete, private Fotos in Beiträgen nicht mit einer eingebetteten Kopie des Bildes. Dies bedeutet, dass Kontakte, die Beiträge mit privaten Fotos erhalten, sich zunächst auf den jeweiligen Servern authentifizieren müssen, bevor die Bilder geladen und angezeigt werden, was eine gewisse Zeit dauert.";
$a->strings["Explicit Content"] = "Sensibler Inhalt";
$a->strings["Set this to announce that your node is used mostly for explicit content that might not be suited for minors. This information will be published in the node information and might be used, e.g. by the global directory, to filter your node from listings of nodes to join. Additionally a note about this will be shown at the user registration page."] = "Wähle dies, um anzuzeigen, dass dein Knoten hauptsächlich für explizite Inhalte verwendet wird, die möglicherweise nicht für Minderjährige geeignet sind. Diese Info wird in der Knoteninformation veröffentlicht und kann durch das Globale Verzeichnis genutzt werden, um deinen Knoten von den Auflistungen auszuschließen. Zusätzlich wird auf der Registrierungsseite ein Hinweis darüber angezeigt.";
$a->strings["Proxify external content"] = "Proxy für externe Inhalte";
$a->strings["Route external content via the proxy functionality. This is used for example for some OEmbed accesses and in some other rare cases."] = "Externe Inhalte werden durch einen Proxy geleitet. Die wird z.B. für das aufrufen von OEmbed Inhalten verwendet und einigen anderen seltenen Fällen.";
$a->strings["Allow Users to set remote_self"] = "Nutzern erlauben, das remote_self Flag zu setzen";
$a->strings["With checking this, every user is allowed to mark every contact as a remote_self in the repair contact dialog. Setting this flag on a contact causes mirroring every posting of that contact in the users stream."] = "Ist dies ausgewählt, kann jeder Nutzer jeden seiner Kontakte als remote_self (entferntes Konto) im \"Erweitert\"-Reiter der Kontaktansicht markieren. Nach dem Setzen dieses Flags werden alle Top-Level-Beiträge dieser Kontakte automatisch in den Stream dieses Nutzers gepostet (gespiegelt).";
$a->strings["Enable multiple registrations"] = "Erlaube Mehrfachregistrierung";

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -338,7 +338,7 @@ $a->strings["Tags: "] = "Ключевые слова: ";
$a->strings["[Select tags to remove]"] = "[выберите тэги для удаления]";
$a->strings["New album name"] = "Название нового альбома";
$a->strings["Caption"] = "Подпись";
$a->strings["Add a Tag"] = "Добавить ключевое слово (тег)";
$a->strings["Add a Tag"] = "Добавить тег";
$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"] = "Пример: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping";
$a->strings["Do not rotate"] = "Не поворачивать";
$a->strings["Rotate CW (right)"] = "Поворот по часовой стрелке (направо)";
@ -402,10 +402,6 @@ $a->strings["Social Networks"] = "Социальные сети";
$a->strings["General Social Media Settings"] = "Общие настройки социальных медиа";
$a->strings["Accept only top level posts by contacts you follow"] = "Получать начальные записи только от ваших контактов";
$a->strings["The system does an auto completion of threads when a comment arrives. This has got the side effect that you can receive posts that had been started by a non-follower but had been commented by someone you follow. This setting deactivates this behaviour. When activated, you strictly only will receive posts from people you really do follow."] = "Система автоматически загружает диалоги, когда получает комментарии. Это может приводить к тому, что вы можете видеть записи от людей, на которых вы не подписаны, потому что их прокомментировал кто-то из ваших контактов. Эта настройка отключает такое поведение и вы будете видеть только записи тех людей, на которых подписаны.";
$a->strings["Disable Content Warning"] = "Отключить предупреждение о содержании";
$a->strings["Users on networks like Mastodon or Pleroma are able to set a content warning field which collapse their post by default. This disables the automatic collapsing and sets the content warning as the post title. Doesn't affect any other content filtering you eventually set up."] = "Пользователи некоторых сетей, таких как Mastodon или Pleroma, могут использовать \"предупреждение о содержании\", сворачивающее их записи. Эта настройка отключает это свёртывание и помещает \"предупреждение о содержимом\" в заголовок записи. Это не влияет на другие фильтры, которые вы можете настроить.";
$a->strings["Disable intelligent shortening"] = "Отключить умное сокращение";
$a->strings["Normally the system tries to find the best link to add to shortened posts. If this option is enabled then every shortened post will always point to the original friendica post."] = "Обычно система пытается найти лучшую ссылку для добавления к сокращенной записи. Если эта настройка включена, то каждая сокращенная запись будет указывать на оригинальную запись в Friendica.";
$a->strings["Attach the link title"] = "Присоединять заголовок ссылок";
$a->strings["When activated, the title of the attached link will be added as a title on posts to Diaspora. This is mostly helpful with \"remote-self\" contacts that share feed content."] = "Если включено. заголовок добавленной ссылки будет добавлен к записи в Диаспоре как заголовок. Это в основном нужно для контактов \"мой двойник\", которые публикуют содержимое ленты.";
$a->strings["Repair OStatus subscriptions"] = "Починить подписки OStatus";
@ -486,7 +482,7 @@ $a->strings["This option makes every posted picture accessible via the direct li
$a->strings["Allow friends to post to your profile page?"] = "Разрешить друзьям оставлять сообщения на страницу вашего профиля?";
$a->strings["Your contacts may write posts on your profile wall. These posts will be distributed to your contacts"] = "Ваши контакты могут оставлять записи на стене вашего профиля. Эти записи будут распространены вашим подписчикам.";
$a->strings["Allow friends to tag your posts?"] = "Разрешить друзьям отмечать ваши сообщения?";
$a->strings["Your contacts can add additional tags to your posts."] = "Ваши контакты могут добавлять дополнительные тэги к вашим записям.";
$a->strings["Your contacts can add additional tags to your posts."] = "Ваши контакты могут добавлять дополнительные теги к вашим записям.";
$a->strings["Permit unknown people to send you private mail?"] = "Разрешить незнакомым людям отправлять вам личные сообщения?";
$a->strings["Friendica network users may send you private messages even if they are not in your contact list."] = "Пользователи Френдики могут отправлять вам личные сообщения даже если их нет в вашем списке контактов.";
$a->strings["Maximum private messages per day from unknown people:"] = "Максимальное количество личных сообщений от незнакомых людей в день:";
@ -520,6 +516,8 @@ $a->strings["Text-only notification emails"] = "Только текстовые
$a->strings["Send text only notification emails, without the html part"] = "Отправлять только текстовые уведомления, без HTML";
$a->strings["Show detailled notifications"] = "Показывать подробные уведомления";
$a->strings["Per default, notifications are condensed to a single notification per item. When enabled every notification is displayed."] = "По-умолчанию уведомления группируются в одно для каждой записи. Эта настройка показывает все уведомления по отдельности.";
$a->strings["Show notifications of ignored contacts"] = "Показывать уведомления игнорируемых контактов";
$a->strings["You don't see posts from ignored contacts. But you still see their comments. This setting controls if you want to still receive regular notifications that are caused by ignored contacts or not."] = "Вы не видите записи от игнорируемых контактов, но вы видите их комментарии. Эта настройка определяет, хотите ли вы получать уведомления от действий игнорируемых контактов или нет.";
$a->strings["Advanced Account/Page Type Settings"] = "Расширенные настройки учётной записи";
$a->strings["Change the behaviour of this account for special situations"] = "Измените поведение этого аккаунта в специальных ситуациях";
$a->strings["Import Contacts"] = "Импорт контактов";
@ -562,6 +560,7 @@ $a->strings["If you wish for %s to respond, please check that the privacy settin
$a->strings["No system theme config value set."] = "Настройки системной темы не установлены.";
$a->strings["You must be logged in to use addons. "] = "Вы должны войти в систему, чтобы использовать аддоны.";
$a->strings["Delete this item?"] = "Удалить этот элемент?";
$a->strings["Block this author? They won't be able to follow you nor see your public posts, and you won't be able to see their posts and their notifications."] = "Заблокировать этого автора? Они не смогут подписаться на вас или видеть ваши записи, вы не будете видеть их записи и получать от них уведомления.";
$a->strings["toggle mobile"] = "мобильная версия";
$a->strings["Method not allowed for this module. Allowed method(s): %s"] = "Метод не разрешён для этого модуля. Разрешенный метод(ы): %s";
$a->strings["Page not found."] = "Страница не найдена.";
@ -1055,6 +1054,7 @@ $a->strings["Reload active addons"] = "Перезагрузить активны
$a->strings["There are currently no addons available on your node. You can find the official addon repository at %1\$s and might find other interesting addons in the open addon registry at %2\$s"] = "На вашем узле пока нет доступных дополнений. Вы можете найти официальный репозиторий дополнений на %1\$s и найти больше интересных дополнений в открытой библиотеке на %2\$s";
$a->strings["Pending"] = "В ожидании";
$a->strings["Blocked"] = "Заблокированы";
$a->strings["List of blocked users"] = "Заблокированные пользователи";
$a->strings["Private Forum"] = "Закрытый форум";
$a->strings["Relay"] = "Ретранслятор";
$a->strings["%s contact unblocked"] = [
@ -1299,22 +1299,19 @@ $a->strings["Only search in tags"] = "Искать только в тегах";
$a->strings["On large systems the text search can slow down the system extremely."] = "На больших системах текстовый поиск может сильно замедлить систему.";
$a->strings["New base url"] = "Новый базовый url";
$a->strings["Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users."] = "Изменить основной URL для этого сервера. Будет отправлено сообщение о перемещении сервера всем контактам из Friendica и Diaspora для всех пользователей.";
$a->strings["RINO Encryption"] = "RINO шифрование";
$a->strings["Encryption layer between nodes."] = "Слой шифрования между узлами.";
$a->strings["Disabled"] = "Отключенный";
$a->strings["Enabled"] = "Включено";
$a->strings["Maximum number of parallel workers"] = "Максимальное число параллельно работающих worker'ов";
$a->strings["Enable fastlane"] = "Включить fastlane";
$a->strings["Direct relay transfer"] = "Прямая ретрансляция";
$a->strings["Enables the direct transfer to other servers without using the relay servers"] = "Разрешает прямую отправку на другие серверы без использования ретрансляторов";
$a->strings["Relay scope"] = "Область ретрансляции";
$a->strings["Can be \"all\" or \"tags\". \"all\" means that every public post should be received. \"tags\" means that only posts with selected tags should be received."] = "Допустимые значения \"all\" или \"tags\". \"all\" означает, что любые публичные записи будут получены. \"tags\" включает приём публичных записей с выбранными тэгами.";
$a->strings["Disabled"] = "Отключенный";
$a->strings["all"] = "all";
$a->strings["tags"] = "tags";
$a->strings["Server tags"] = "Тэги сервера";
$a->strings["Comma separated list of tags for the \"tags\" subscription."] = "Список тэгов, разделённых запятыми, используемый для подписки в режиме \"tags\"";
$a->strings["Allow user tags"] = "Разрешить пользовательские тэги";
$a->strings["If enabled, the tags from the saved searches will used for the \"tags\" subscription in addition to the \"relay_server_tags\"."] = "Если включено, то тэги. на которые подписались пользователи, будут добавлены в подписку в дополнение к тэгам сервера.";
$a->strings["If enabled, the tags from the saved searches will used for the \"tags\" subscription in addition to the \"relay_server_tags\"."] = "Если включено, то теги. на которые подписались пользователи, будут добавлены в подписку в дополнение к тегам сервера.";
$a->strings["Start Relocation"] = "Начать перемещение";
$a->strings["Invalid storage backend setting value."] = "Недопустимое значение типа хранилища.";
$a->strings["Database (legacy)"] = "База данных (устаревшее)";
@ -1380,6 +1377,7 @@ $a->strings["%s user unblocked"] = [
3 => "%s пользователей разблокировано",
];
$a->strings["User \"%s\" unblocked"] = "Пользователь \"%s\" разблокирован";
$a->strings["Blocked Users"] = "Заблокированные";
$a->strings["New User"] = "Новый пользователь";
$a->strings["Add User"] = "Добавить пользователя";
$a->strings["Name of the new user."] = "Имя нового пользователя.";
@ -1444,12 +1442,12 @@ $a->strings["%d contact edited."] = [
];
$a->strings["Could not access contact record."] = "Не удалось получить доступ к записи контакта.";
$a->strings["Failed to update contact record."] = "Не удалось обновить запись контакта.";
$a->strings["You can't block yourself"] = "Вы не можете заблокировать сами себя";
$a->strings["Contact has been blocked"] = "Контакт заблокирован";
$a->strings["Contact has been unblocked"] = "Контакт разблокирован";
$a->strings["You can't ignore yourself"] = "Вы не можете игнорировать сами себя";
$a->strings["Contact has been ignored"] = "Контакт проигнорирован";
$a->strings["Contact has been unignored"] = "У контакта отменено игнорирование";
$a->strings["Contact has been archived"] = "Контакт заархивирован";
$a->strings["Contact has been unarchived"] = "Контакт разархивирован";
$a->strings["Drop contact"] = "Удалить контакт";
$a->strings["Do you really want to delete this contact?"] = "Вы действительно хотите удалить этот контакт?";
$a->strings["Yes"] = "Да";
@ -1511,8 +1509,6 @@ $a->strings["Organize your contact groups"] = "Настроить группы
$a->strings["Search your contacts"] = "Поиск ваших контактов";
$a->strings["Results for: %s"] = "Результаты для: %s";
$a->strings["Update"] = "Обновление";
$a->strings["Archive"] = "Архивировать";
$a->strings["Unarchive"] = "Разархивировать";
$a->strings["Batch Actions"] = "Пакетные действия";
$a->strings["Posts and Comments"] = "Записи и комментарии";
$a->strings["View all known contacts"] = "Показать все известные контакты";
@ -1525,7 +1521,6 @@ $a->strings["Pending incoming contact request"] = "Входящий запрос
$a->strings["Refetch contact data"] = "Обновить данные контакта";
$a->strings["Toggle Blocked status"] = "Изменить статус блокированности (заблокировать/разблокировать)";
$a->strings["Toggle Ignored status"] = "Изменить статус игнорирования";
$a->strings["Toggle Archive status"] = "Сменить статус архивации (архивирова/не архивировать)";
$a->strings["Delete contact"] = "Удалить контакт";
$a->strings["Contact update failed."] = "Обновление контакта неудачное.";
$a->strings["<strong>WARNING: This is highly advanced</strong> and if you enter incorrect information your communications with this contact may stop working."] = "<strong>ВНИМАНИЕ: Это крайне важно!</strong> Если вы введете неверную информацию, ваша связь с этим контактом перестанет работать.";
@ -1969,9 +1964,15 @@ $a->strings["Private Message"] = "Личное сообщение";
$a->strings["Edit"] = "Редактировать";
$a->strings["Delete globally"] = "Удалить везде";
$a->strings["Remove locally"] = "Убрать для себя";
$a->strings["Block %s"] = "Заблокировать %s";
$a->strings["Save to folder"] = "Сохранить в папку";
$a->strings["I will attend"] = "Я буду";
$a->strings["I will not attend"] = "Меня не будет";
$a->strings["I might attend"] = "Возможно";
$a->strings["Ignore thread"] = "Игнорировать тему";
$a->strings["Unignore thread"] = "Не игнорировать тему";
$a->strings["Toggle ignore status"] = "Переключить игнорирование";
$a->strings["Add tag"] = "Добавить тег";
$a->strings["Quote share this"] = "Поделиться с комментарием";
$a->strings["Quote Share"] = "Цитировать";
$a->strings["Reshare this"] = "Поделиться этим с подписчиками";