Merge pull request #3351 from pixelfed/staging

Staging
This commit is contained in:
daniel 2022-04-02 16:36:46 -06:00 committed by GitHub
commit a691b27829
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 559 additions and 189 deletions

View file

@ -118,6 +118,9 @@
- Updated PlaceController, require authentication. ([e7783af6](https://github.com/pixelfed/pixelfed/commit/e7783af6)) - Updated PlaceController, require authentication. ([e7783af6](https://github.com/pixelfed/pixelfed/commit/e7783af6))
- Updated PublicApiController, disable legacy public access to local timeline. ([6ba7d433](https://github.com/pixelfed/pixelfed/commit/6ba7d433)) - Updated PublicApiController, disable legacy public access to local timeline. ([6ba7d433](https://github.com/pixelfed/pixelfed/commit/6ba7d433))
- Updated DiscoverController, cache public tag feed and only include local posts for unauthenticated users. ([0541aed5](https://github.com/pixelfed/pixelfed/commit/0541aed5)) - Updated DiscoverController, cache public tag feed and only include local posts for unauthenticated users. ([0541aed5](https://github.com/pixelfed/pixelfed/commit/0541aed5))
- Updated DiscoverController, improve tag feed performance. ([d8ff40eb](https://github.com/pixelfed/pixelfed/commit/d8ff40eb))
- Updated ApiV1Controller, fix timeline pagination. ([a5cdc28b](https://github.com/pixelfed/pixelfed/commit/a5cdc28b))
- Updated ApiV1Controller, add missing pagination header. ([5649873a](https://github.com/pixelfed/pixelfed/commit/5649873a))
- ([](https://github.com/pixelfed/pixelfed/commit/)) - ([](https://github.com/pixelfed/pixelfed/commit/))
## [v0.11.2 (2022-01-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.1...v0.11.2) ## [v0.11.2 (2022-01-09)](https://github.com/pixelfed/pixelfed/compare/v0.11.1...v0.11.2)

View file

@ -1684,7 +1684,7 @@ class ApiV1Controller extends Controller
->whereIn('profile_id', $following) ->whereIn('profile_id', $following)
->whereIn('visibility',['public', 'unlisted', 'private']) ->whereIn('visibility',['public', 'unlisted', 'private'])
->latest() ->latest()
->take($limit) ->take(($limit * 2))
->get() ->get()
->map(function($s) use($pid) { ->map(function($s) use($pid) {
$status = StatusService::getMastodon($s['id']); $status = StatusService::getMastodon($s['id']);
@ -1701,8 +1701,8 @@ class ApiV1Controller extends Controller
->filter(function($status) { ->filter(function($status) {
return $status && isset($status['account']); return $status && isset($status['account']);
}) })
->values() ->take($limit)
->toArray(); ->values();
} else { } else {
$res = Status::select( $res = Status::select(
'id', 'id',
@ -1715,7 +1715,7 @@ class ApiV1Controller extends Controller
->whereIn('profile_id', $following) ->whereIn('profile_id', $following)
->whereIn('visibility',['public', 'unlisted', 'private']) ->whereIn('visibility',['public', 'unlisted', 'private'])
->latest() ->latest()
->take($limit) ->take(($limit * 2))
->get() ->get()
->map(function($s) use($pid) { ->map(function($s) use($pid) {
$status = StatusService::getMastodon($s['id']); $status = StatusService::getMastodon($s['id']);
@ -1732,11 +1732,118 @@ class ApiV1Controller extends Controller
->filter(function($status) { ->filter(function($status) {
return $status && isset($status['account']); return $status && isset($status['account']);
}) })
->values() ->take($limit)
->toArray(); ->values();
} }
return $this->json($res); $baseUrl = config('app.url') . '/api/v1/timelines/home?limit=' . $limit . '&';
$minId = $res->map(function($s) {
return ['id' => $s['id']];
})->min('id');
$maxId = $res->map(function($s) {
return ['id' => $s['id']];
})->max('id');
if($minId == $maxId) {
$minId = null;
}
if($maxId) {
$link = '<'.$baseUrl.'max_id='.$maxId.'>; rel="next"';
}
if($minId) {
$link = '<'.$baseUrl.'min_id='.$minId.'>; rel="prev"';
}
if($maxId && $minId) {
$link = '<'.$baseUrl.'max_id='.$maxId.'>; rel="next",<'.$baseUrl.'min_id='.$minId.'>; rel="prev"';
}
$headers = isset($link) ? ['Link' => $link] : [];
return $this->json($res->toArray(), 200, $headers);
}
/**
* GET /api/v1/timelines/public
*
*
* @return StatusTransformer
*/
public function timelinePublic(Request $request)
{
$this->validate($request,[
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'limit' => 'nullable|integer|max:100'
]);
$min = $request->input('min_id');
$max = $request->input('max_id');
$limit = $request->input('limit') ?? 20;
$user = $request->user();
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
Cache::remember('api:v1:timelines:public:cache_check', 10368000, function() {
if(PublicTimelineService::count() == 0) {
PublicTimelineService::warmCache(true, 400);
}
});
if ($max) {
$feed = PublicTimelineService::getRankedMaxId($max, $limit + 5);
} else if ($min) {
$feed = PublicTimelineService::getRankedMinId($min, $limit + 5);
} else {
$feed = PublicTimelineService::get(0, $limit + 5);
}
$res = collect($feed)
->map(function($k) use($user) {
$status = StatusService::getMastodon($k);
if(!$status || !isset($status['account']) || !isset($status['account']['id'])) {
return false;
}
if($user) {
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $status['id']);
}
return $status;
})
->filter(function($s) use($filtered) {
return $s && isset($s['account']) && in_array($s['account']['id'], $filtered) == false;
})
->take($limit)
->values();
// ->toArray();
$baseUrl = config('app.url') . '/api/v1/timelines/public?limit=' . $limit . '&';
$minId = $res->map(function($s) {
return ['id' => $s['id']];
})->min('id');
$maxId = $res->map(function($s) {
return ['id' => $s['id']];
})->max('id');
if($minId == $maxId) {
$minId = null;
}
if($maxId) {
$link = '<'.$baseUrl.'max_id='.$maxId.'>; rel="next"';
}
if($minId) {
$link = '<'.$baseUrl.'min_id='.$minId.'>; rel="prev"';
}
if($maxId && $minId) {
$link = '<'.$baseUrl.'max_id='.$maxId.'>; rel="next",<'.$baseUrl.'min_id='.$minId.'>; rel="prev"';
}
$headers = isset($link) ? ['Link' => $link] : [];
return $this->json($res->toArray(), 200, $headers);
} }
/** /**
@ -1805,62 +1912,6 @@ class ApiV1Controller extends Controller
return $this->json($dms); return $this->json($dms);
} }
/**
* GET /api/v1/timelines/public
*
*
* @return StatusTransformer
*/
public function timelinePublic(Request $request)
{
$this->validate($request,[
'min_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'max_id' => 'nullable|integer|min:0|max:' . PHP_INT_MAX,
'limit' => 'nullable|integer|max:100'
]);
$min = $request->input('min_id');
$max = $request->input('max_id');
$limit = $request->input('limit') ?? 20;
$user = $request->user();
$filtered = $user ? UserFilterService::filters($user->profile_id) : [];
Cache::remember('api:v1:timelines:public:cache_check', 10368000, function() {
if(PublicTimelineService::count() == 0) {
PublicTimelineService::warmCache(true, 400);
}
});
if ($max) {
$feed = PublicTimelineService::getRankedMaxId($max, $limit);
} else if ($min) {
$feed = PublicTimelineService::getRankedMinId($min, $limit);
} else {
$feed = PublicTimelineService::get(0, $limit);
}
$res = collect($feed)
->map(function($k) use($user) {
$status = StatusService::getMastodon($k);
if(!$status || !isset($status['account']) || !isset($status['account']['id'])) {
return false;
}
if($user) {
$status['favourited'] = (bool) LikeService::liked($user->profile_id, $k);
$status['reblogged'] = (bool) ReblogService::get($user->profile_id, $status['id']);
}
return $status;
})
->filter(function($s) use($filtered) {
return $s && isset($s['account']) && in_array($s['account']['id'], $filtered) == false;
})
->values()
->toArray();
return $this->json($res);
}
/** /**
* GET /api/v1/statuses/{id} * GET /api/v1/statuses/{id}
* *

View file

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Переклад рядків входу
|--------------------------------------------------------------------------
|
| Наступні рядки використовуються при автентифікації для різних
| повідомлень, які ми показуємо користувачкам і користувачам. Можете
| вільно редагувати ці переклади відповідно до потреб вашого застосунку.
|
*/
'failed' => 'Особові дані не збігаються з нашими записами.',
'throttle' => 'Забагато спроб входу. Повторіть спробу через :seconds секунд.',
];

View file

@ -0,0 +1,11 @@
<?php
return [
'compose' => [
'invalid' => [
'album' => 'Мусить містити знімок, відеозапис чи декілька знімків.',
],
],
];

View file

@ -0,0 +1,28 @@
<?php
return [
'helpcenter' => 'Довідка',
'whatsnew' => 'Що нового',
'gettingStarted' => 'Як розпочати',
'sharingMedia' => 'Поширення медіа',
'profile' => 'Профіль',
'stories' => 'Сторі',
'hashtags' => 'Хештеги',
'discover' => 'Цікаве',
'directMessages' => 'Прямі листи',
'timelines' => 'Стрічки',
'embed' => 'Експорт',
'communityGuidelines' => 'Правила спільноти',
'whatIsTheFediverse' => 'Що таке федіверс?',
'controllingVisibility' => 'Керування видимістю',
'blockingAccounts' => 'Блокування облікових записів',
'safetyTips' => 'Поради безпеки',
'reportSomething' => 'Скарга на щось',
'dataPolicy' => 'Політика даних',
'taggingPeople' => 'Позначення людей'
];

View file

@ -0,0 +1,19 @@
<?php
return [
'search' => 'Пошук',
'home' => 'Дім',
'local' => 'Поруч',
'network' => 'Мережа',
'discover' => 'Цікаве',
'viewMyProfile' => 'Переглянути свій профіль',
'myProfile' => 'Мій профіль',
'myTimeline' => 'Моя стрічка',
'publicTimeline' => 'Загальнодоступна стрічка',
'remoteFollow' => 'Стеження ззовні',
'settings' => 'Параметри',
'admin' => 'Адміністрування',
'logout' => 'Вийти',
'directMessages' => 'Прямі листи',
'composePost' => 'Написати допис',
];

View file

@ -0,0 +1,12 @@
<?php
return [
'likedPhoto' => 'ставить уподобання під ваш допис.',
'likedComment' => 'ставить уподобання під ваш коментар.',
'startedFollowingYou' => 'починає за вами стежити.',
'commented' => 'коментує ваш допис.',
'mentionedYou' => 'згадує вам.',
'shared' => 'поширює ваш допис.',
];

View file

@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Переклади рядків пагінації
|--------------------------------------------------------------------------
|
| Бібліотека поділу на сторінки використовує ці переклади рядків
| у посиланнях на сторінки. Можете вільно редагувати ці переклади
| відповідно до потреб вашого застосунку.
|
*/
'previous' => '« Назад',
'next' => 'Далі »',
];

View file

@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Переклади рядків скидання паролю
|--------------------------------------------------------------------------
|
| Ці переклади усталені рядки, що відповідають причинам, якими
| брокер паролів пояснює, чому спроба оновлення пароля не вдалася,
| наприклад через хибний токен чи хибний новий пароль.
|
*/
'password' => 'Паролі мусять містити принаймні шість символів і збігатися.',
'reset' => 'Пароль скинуто!',
'sent' => 'Якщо ваша адреса е-пошти — в нашій базі, посилання для відновлення пароля е-пошти буде надіслано за кілька хвилин. Перевірте теку спаму, якщо лист не надходить.',
'token' => 'Токен відновлення пароля хибний.',
'user' => 'Якщо ваша адреса е-пошти — в нашій базі, посилання для відновлення пароля е-пошти буде надіслано за кілька хвилин. Перевірте теку спаму, якщо лист не надходить.',
];

View file

@ -0,0 +1,15 @@
<?php
return [
'emptyTimeline' => 'Дописів іще нема.',
'emptyFollowers' => 'Ніхто ще не стежить.',
'emptyFollowing' => 'Ще ні за ким не стежить.',
'emptySaved' => 'Ви ще не зберігали дописів.',
'savedWarning' => 'Лише ви можете переглянути, що зберегли',
'privateProfileWarning' => 'Обліковий запис приватний',
'alreadyFollow' => 'Уже стежите за :username?',
'loginToSeeProfile' => 'для перегляду їхніх фото й відео.',
'status.disabled.header' => 'Профіль недоступний',
'status.disabled.body' => 'На жаль, профіль зараз недоступний. Будь ласка, повторіть спробу згодом.',
];

View file

@ -0,0 +1,20 @@
<?php
return [
'about' => 'Про застосунок',
'help' => 'Довідка',
'language' => 'Мова',
'fediverse' => 'Федіверс',
'opensource' => 'Вільне ПЗ',
'terms' => 'Умови',
'privacy' => 'Приватність',
'l10nWip' => 'Переклад іще в роботі',
'currentLocale' => 'Поточна мова',
'selectLocale' => 'Оберіть підтримувану мову',
'contact' => 'Сконтактувати',
'contact-us' => 'Напишіть нам',
'places' => 'Місця',
'profiles' => 'Профілі',
];

View file

@ -0,0 +1,7 @@
<?php
return [
'emptyPersonalTimeline' => 'Ваша стрічка порожня.',
];

View file

@ -0,0 +1,122 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'Потрібно прийняти :attribute.',
'active_url' => ':attribute — хибна URL-адреса.',
'after' => ':attribute мусить бути пізніше, ніж :date.',
'after_or_equal' => ':attribute мусить бути не раніше, ніж :date.',
'alpha' => ':attribute може містити лише літери.',
'alpha_dash' => ':attribute може містити лише літери, цифри й дефіси.',
'alpha_num' => ':attribute може містити лише літери й цифри.',
'array' => ':attribute мусить бути масивом.',
'before' => ':attribute мусить бути раніше, ніж :date.',
'before_or_equal' => ':attribute мусить бути не пізніше, ніж :date.',
'between' => [
'numeric' => ':attribute мусить бути між :min і :max.',
'file' => ':attribute мусить містити від :min до :max кілобайтів.',
'string' => ':attribute мусить містити від :min до :max знаків.',
'array' => ':attribute мусить містити від :min до :max пунктів.',
],
'boolean' => 'Поле :attribute мусить бути істинним чи хибним.',
'confirmed' => 'Підтвердження :attribute не збігається.',
'date' => ':attribute — хибна дата.',
'date_format' => ':attribute не відповідає формату :format.',
'different' => ':attribute та :other мусять відрізнятися.',
'digits' => ':attribute мусить містити :digits цифр.',
'digits_between' => ':attribute мусить містити від :min до :max цифр.',
'dimensions' => ':attribute має хибну ширину чи висоту.',
'distinct' => 'Поле :attribute містить дубль.',
'email' => ':attribute мусить бути чинною адресою е-пошти.',
'exists' => ':attribute — не ок.',
'file' => ':attribute мусить бути файлом.',
'filled' => 'Полю :attribute бракує значення.',
'image' => ':attribute мусить бути зображенням.',
'in' => ':attribute — не ок.',
'in_array' => 'Поля :attribute нема серед :other.',
'integer' => ':attribute мусить бути числом.',
'ip' => ':attribute мусить бути чинною IP-адресою.',
'ipv4' => ':attribute мусить бути чинною IPv4-адресою.',
'ipv6' => ':attribute мусить бути чинною IPv6-адресою.',
'json' => ':attribute мусить бути чинним JSON-рядком.',
'max' => [
'numeric' => ':attribute мусить не перевищувати :max.',
'file' => ':attribute мусить містити не більше, ніж :max кілобайтів.',
'string' => ':attribute мусить містити не більше, ніж :max символів.',
'array' => ':attribute мусить містити не більше, ніж :max пунктів.',
],
'mimes' => ':attribute мусить бути файлом: :values.',
'mimetypes' => ':attribute мусить бути файлом: :values.',
'min' => [
'numeric' => ':attribute мусить бути не менше, ніж :max.',
'file' => ':attribute мусить містити не менше, ніж :max кілобайтів.',
'string' => ':attribute мусить містити не менше, ніж :max символів.',
'array' => ':attribute мусить містити не менше, ніж :max пунктів.',
],
'not_in' => ':attribute містить хибний вибір.',
'not_regex' => 'Формат :attribute хибний.',
'numeric' => ':attribute мусить бути числом.',
'present' => 'Бракує поля :attribute.',
'regex' => 'Формат :attribute хибний.',
'required' => "Поле :attribute обов'язкове.",
'required_if' => "Поле :attribute обов'язкове, коли :other — :value.",
'required_unless' => "Поле :attribute обов'язкове unless :other is in :values.",
'required_with' => "Поле :attribute обов'язкове, коли є :values.",
'required_with_all' => "Поле :attribute обов'язкове, коли є :values.",
'required_without' => "Поле :attribute обов'язкове, коли бракує :values.",
'required_without_all' => "Поле :attribute обов'язкове, коли бракує :values.",
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => ':attribute мусить бути :size.',
'file' => ':attribute мусить містити :size кілобайтів.',
'string' => ':attribute мусить містити :size символів.',
'array' => ':attribute мусить містити :size пунктів.',
],
'string' => ':attribute мусить бути рядком.',
'timezone' => ':attribute мусить бути чинним поясом.',
'unique' => ':attribute уже зайнято.',
'uploaded' => 'Не вдалося вивантажити :attribute.',
'url' => 'Формат :attribute хибний.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [],
];

View file

@ -3,184 +3,206 @@
return [ return [
'common' => [ 'common' => [
'comment' => 'Comment', 'comment' => 'Коментувати',
'commented' => 'Commented', 'commented' => 'Прокоментовано',
'comments' => 'Comments', 'comments' => 'Коментарі',
'like' => 'Like', 'like' => 'Вподобати',
'liked' => 'Liked', 'liked' => 'Вподобано',
'likes' => 'Likes', 'likes' => 'Вподобання',
'share' => 'Share', 'share' => 'Поширити',
'shared' => 'Shared', 'shared' => 'Поширено',
'shares' => 'Shares', 'shares' => 'Поширення',
'unshare' => 'Unshare', 'unshare' => 'Не поширювати',
'bookmark' => 'Закладка',
'cancel' => 'Cancel', 'cancel' => 'Скасувати',
'copyLink' => 'Copy Link', 'copyLink' => 'Копіювати посилання',
'delete' => 'Delete', 'delete' => 'Видалити',
'error' => 'Error', 'error' => 'Помилка',
'errorMsg' => 'Something went wrong. Please try again later.', 'errorMsg' => 'Щось пішло не так. Повторіть спробу згодом',
'oops' => 'Oops!', 'oops' => 'Йой!',
'other' => 'Other', 'other' => 'Інше',
'readMore' => 'Read more', 'readMore' => 'Докладніше',
'success' => 'Success', 'success' => 'Успіх',
'proceed' => 'Продовжити',
'next' => 'Далі',
'close' => 'Закрити',
'clickHere' => 'натисніть тут',
'sensitive' => 'Sensitive', 'sensitive' => 'Чутливе',
'sensitiveContent' => 'Sensitive Content', 'sensitiveContent' => 'Чутливий вміст',
'sensitiveContentWarning' => 'This post may contain sensitive content', 'sensitiveContentWarning' => 'Цей допис може містити чутливий вміст',
], ],
'site' => [ 'site' => [
'terms' => 'Terms of Use', 'terms' => 'Умови використання',
'privacy' => 'Privacy Policy', 'privacy' => 'Політика приватності',
], ],
'navmenu' => [ 'navmenu' => [
'search' => 'Search', 'search' => 'Пошук',
'admin' => 'Admin Dashboard', 'admin' => 'Адмінпанель',
// Timelines // Timelines
'homeFeed' => 'Home Feed', 'homeFeed' => 'Домашня стрічка',
'localFeed' => 'Local Feed', 'localFeed' => 'Місцева стрічка',
'globalFeed' => 'Global Feed', 'globalFeed' => 'Світова стрічка',
// Core features // Core features
'discover' => 'Discover', 'discover' => 'Цікаве',
'directMessages' => 'Direct Messages', 'directMessages' => 'Прямі листи',
'notifications' => 'Notifications', 'notifications' => 'Сповіщення',
'groups' => 'Groups', 'groups' => 'Групи',
'stories' => 'Stories', 'stories' => 'Сторі',
// Self links // Self links
'profile' => 'Profile', 'profile' => 'Профіль',
'drive' => 'Drive', 'drive' => 'Сховище',
'settings' => 'Settings', 'settings' => 'Параметри',
'compose' => 'Create New', 'compose' => 'Створити',
'logout' => 'Logout', 'logout' => 'Вийти',
// Nav footer // Nav footer
'about' => 'About', 'about' => 'Про застосунок',
'help' => 'Help', 'help' => 'Довідка',
'language' => 'Language', 'language' => 'Мова',
'privacy' => 'Privacy', 'privacy' => 'Приватність',
'terms' => 'Terms', 'terms' => 'Умови',
// Temporary links // Temporary links
'backToPreviousDesign' => 'Go back to previous design' 'backToPreviousDesign' => 'Повернути минулий дизайн'
], ],
'directMessages' => [ 'directMessages' => [
'inbox' => 'Inbox', 'inbox' => 'Вхідні',
'sent' => 'Sent', 'sent' => 'Надіслані',
'requests' => 'Requests' 'requests' => 'Запити'
], ],
'notifications' => [ 'notifications' => [
'liked' => 'liked your', 'liked' => 'ставить уподобання під ваш',
'commented' => 'commented on your', 'commented' => 'коментує ваш',
'reacted' => 'reacted to your', 'reacted' => 'реагує на ваш',
'shared' => 'shared your', 'shared' => 'поширює ваш',
'tagged' => 'tagged you in a', 'tagged' => 'позначає вас через',
'updatedA' => 'updated a', 'updatedA' => 'оновлює',
'sentA' => 'sent a', 'sentA' => 'надсилає',
'followed' => 'followed', 'followed' => 'відстежує',
'mentioned' => 'mentioned', 'mentioned' => 'згадує',
'you' => 'you', 'you' => 'вас',
'yourApplication' => 'Your application to join', 'yourApplication' => 'Вашу реєстраційну заявку',
'applicationApproved' => 'was approved!', 'applicationApproved' => 'підтверджено!',
'applicationRejected' => 'was rejected. You can re-apply to join in 6 months.', 'applicationRejected' => 'відхилено. Можете повторити спробу через 6 місяців.',
'dm' => 'dm', 'dm' => 'лист',
'groupPost' => 'group post', 'groupPost' => 'допис у групі',
'modlog' => 'modlog', 'modlog' => 'моджурнал',
'post' => 'post', 'post' => 'допис',
'story' => 'story', 'story' => 'сторі',
'noneFound' => 'Сповіщень не знайдено',
], ],
'post' => [ 'post' => [
'shareToFollowers' => 'Share to followers', 'shareToFollowers' => 'Поширити авдиторії',
'shareToOther' => 'Share to other', 'shareToOther' => 'Поширити іншим',
'noLikes' => 'No likes yet', 'noLikes' => 'Вподобань поки нема',
'uploading' => 'Uploading', 'uploading' => 'Вивантаження',
], ],
'profile' => [ 'profile' => [
'posts' => 'Posts', 'posts' => 'Дописи',
'followers' => 'Followers', 'followers' => 'Авдиторія',
'following' => 'Following', 'following' => 'Підписки',
'admin' => 'Admin', 'admin' => 'Адміністрація',
'collections' => 'Collections', 'collections' => 'Збірки',
'follow' => 'Follow', 'follow' => 'Стежити',
'unfollow' => 'Unfollow', 'unfollow' => 'Не стежити',
'editProfile' => 'Edit Profile', 'editProfile' => 'Редагувати профіль',
'followRequested' => 'Follow Requested', 'followRequested' => 'Запит на стеження',
'joined' => 'Joined', 'joined' => 'Долучається',
'emptyCollections' => 'We can\'t seem to find any collections', 'emptyCollections' => 'Збірок у вас поки нема',
'emptyPosts' => 'We can\'t seem to find any posts', 'emptyPosts' => 'Дописів у вас поки нема',
], ],
'menu' => [ 'menu' => [
'viewPost' => 'View Post', 'viewPost' => 'Переглянути допис',
'viewProfile' => 'View Profile', 'viewProfile' => 'Переглянути профіль',
'moderationTools' => 'Moderation Tools', 'moderationTools' => 'Засоби модерування',
'report' => 'Report', 'report' => 'Скарга',
'archive' => 'Archive', 'archive' => 'Архівувати',
'unarchive' => 'Unarchive', 'unarchive' => 'Розархівувати',
'embed' => 'Embed', 'embed' => 'Експорт',
'selectOneOption' => 'Select one of the following options', 'selectOneOption' => 'Оберіть один із наступних варіантів',
'unlistFromTimelines' => 'Unlist from Timelines', 'unlistFromTimelines' => 'Сховати зі стрічок',
'addCW' => 'Add Content Warning', 'addCW' => 'Застерегти про вміст',
'removeCW' => 'Remove Content Warning', 'removeCW' => 'Вилучити застереження',
'markAsSpammer' => 'Mark as Spammer', 'markAsSpammer' => 'Позначити як спам',
'markAsSpammerText' => 'Unlist + CW existing and future posts', 'markAsSpammerText' => 'Сховати цей і майбутні дописи, додаючи застереження',
'spam' => 'Spam', 'spam' => 'Спам',
'sensitive' => 'Sensitive Content', 'sensitive' => 'Чутливий вміст',
'abusive' => 'Abusive or Harmful', 'abusive' => 'Ображає чи шкодить',
'underageAccount' => 'Underage Account', 'underageAccount' => 'Недостатній вік',
'copyrightInfringement' => 'Copyright Infringement', 'copyrightInfringement' => 'Порушує авторські права',
'impersonation' => 'Impersonation', 'impersonation' => 'Вдає когось',
'scamOrFraud' => 'Scam or Fraud', 'scamOrFraud' => 'Шахрайство',
'confirmReport' => 'Confirm Report', 'confirmReport' => 'Підтвердити скаргу',
'confirmReportText' => 'Are you sure you want to report this post?', 'confirmReportText' => 'Точно поскаржитись на допис?',
'reportSent' => 'Report Sent!', 'reportSent' => 'Скаргу надіслано!',
'reportSentText' => 'We have successfully received your report.', 'reportSentText' => 'Ми успішно отримали вашу скаргу.',
'reportSentError' => 'There was an issue reporting this post.', 'reportSentError' => 'Виникла помилка при надсиланні скарги.',
'modAddCWConfirm' => 'Are you sure you want to add a content warning to this post?', 'modAddCWConfirm' => 'Точно додати застереження про вміст цьому допису?',
'modCWSuccess' => 'Successfully added content warning', 'modCWSuccess' => 'Застереження про вміст успішно додано',
'modRemoveCWConfirm' => 'Are you sure you want to remove the content warning on this post?', 'modRemoveCWConfirm' => 'Точно вилучити застереження про вміст із цього допису?',
'modRemoveCWSuccess' => 'Successfully removed content warning', 'modRemoveCWSuccess' => 'Застереження про вміст успішно вилучено',
'modUnlistConfirm' => 'Are you sure you want to unlist this post?', 'modUnlistConfirm' => 'Точно сховати цей допис?',
'modUnlistSuccess' => 'Successfully unlisted post', 'modUnlistSuccess' => 'Допис успішно сховано',
'modMarkAsSpammerConfirm' => 'Are you sure you want to mark this user as a spammer? All existing and future posts will be unlisted on timelines and a content warning will be applied.', 'modMarkAsSpammerConfirm' => 'Точно позначити цей обліковий запис як спам? Усі наявні й майбутні дописи буде сховано зі стрічок, і їм буде додано застереження про вміст.',
'modMarkAsSpammerSuccess' => 'Successfully marked account as spammer', 'modMarkAsSpammerSuccess' => 'Обліковий запис успішно позначено як спам',
'toFollowers' => 'to Followers', 'toFollowers' => 'до авдиторії',
'showCaption' => 'Show Caption', 'showCaption' => 'Показати підпис',
'showLikes' => 'Show Likes', 'showLikes' => 'Показати вподобання',
'compactMode' => 'Compact Mode', 'compactMode' => 'Компактний режим',
'embedConfirmText' => 'By using this embed, you agree to our', 'embedConfirmText' => 'Експортуючи кудись допис, ви погоджуєте наші',
'deletePostConfirm' => 'Are you sure you want to delete this post?', 'deletePostConfirm' => 'Точно видалити допис?',
'archivePostConfirm' => 'Are you sure you want to archive this post?', 'archivePostConfirm' => 'Точно архівувати допис?',
'unarchivePostConfirm' => 'Are you sure you want to unarchive this post?', 'unarchivePostConfirm' => 'Точно розархівувати допис?',
], ],
'story' => [ 'story' => [
'add' => 'Add Story' 'add' => 'Додати сторі'
], ],
'timeline' => [ 'timeline' => [
'peopleYouMayKnow' => 'People you may know' 'peopleYouMayKnow' => 'Ймовірні знайомі',
'onboarding' => [
'welcome' => 'Вітаємо',
'thisIsYourHomeFeed' => 'Це ваша домашня стрічка — тут будуть дописи від облікових записів, за якими ви стежите, в порядку додання.',
'letUsHelpYouFind' => 'Можемо допомогти вам знайти цікавих людей, за якими варто стежити',
'refreshFeed' => 'Оновити мою стрічку',
],
], ],
'hashtags' => [ 'hashtags' => [
'emptyFeed' => 'We can\'t seem to find any posts for this hashtag' 'emptyFeed' => 'Дописів із цим хештегом поки нема'
],
'report' => [
'report' => 'Скарга',
'selectReason' => 'Оберіть підставу',
'reported' => 'Скаргу надіслано',
'sendingReport' => 'Надсилання скарги',
'thanksMsg' => 'Дякуємо за скаргу: ви допомагаєте вбезпечити нашу спільноту!',
'contactAdminMsg' => 'Якщо бажаєте сконтактувати з адміністрацією про цей допис чи скаргу',
], ],
]; ];