diff --git a/app/soapbox/__fixtures__/fedibird-account.json b/app/soapbox/__fixtures__/fedibird-account.json
new file mode 100644
index 000000000..07bbd7057
--- /dev/null
+++ b/app/soapbox/__fixtures__/fedibird-account.json
@@ -0,0 +1,35 @@
+{
+ "id": "66768",
+ "username": "alex",
+ "acct": "alex",
+ "display_name": "",
+ "locked": false,
+ "bot": false,
+ "cat": false,
+ "discoverable": false,
+ "group": false,
+ "created_at": "2020-01-27T00:00:00.000Z",
+ "note": "
",
+ "url": "https://fedibird.com/@alex",
+ "avatar": "https://fedibird.com/avatars/original/missing.png",
+ "avatar_static": "https://fedibird.com/avatars/original/missing.png",
+ "header": "https://fedibird.com/headers/original/missing.png",
+ "header_static": "https://fedibird.com/headers/original/missing.png",
+ "followers_count": 1,
+ "following_count": 1,
+ "subscribing_count": 0,
+ "statuses_count": 5,
+ "last_status_at": "2022-02-20",
+ "emojis": [],
+ "fields": [],
+ "other_settings": {
+ "birthday": "1993-07-03",
+ "location": "Texas, USA",
+ "noindex": false,
+ "hide_network": false,
+ "hide_statuses_count": false,
+ "hide_following_count": false,
+ "hide_followers_count": false,
+ "enable_reaction": true
+ }
+}
diff --git a/app/soapbox/__fixtures__/mk.json b/app/soapbox/__fixtures__/mk.json
new file mode 100644
index 000000000..a7c841f1e
--- /dev/null
+++ b/app/soapbox/__fixtures__/mk.json
@@ -0,0 +1,123 @@
+{
+ "acct": "mk",
+ "avatar": "https://media.spinster.xyz/4043b9fb3f9d468aa48a8d68294f338914d9d54b2816aa1c789f548efe6c6239.jpg",
+ "avatar_static": "https://media.spinster.xyz/4043b9fb3f9d468aa48a8d68294f338914d9d54b2816aa1c789f548efe6c6239.jpg",
+ "bot": false,
+ "created_at": "2019-08-01T22:06:30.000Z",
+ "display_name": "M. K. Fain",
+ "emojis": [
+ {
+ "shortcode": "4w",
+ "static_url": "https://spinster.xyz/emoji/custom/4w.png",
+ "url": "https://spinster.xyz/emoji/custom/4w.png",
+ "visible_in_picker": false
+ },
+ {
+ "shortcode": "spinster",
+ "static_url": "https://spinster.xyz/emoji/custom/spinster.png",
+ "url": "https://spinster.xyz/emoji/custom/spinster.png",
+ "visible_in_picker": false
+ }
+ ],
+ "fields": [
+ {
+ "name": "Website",
+ "value": "https://marykatefain.com"
+ },
+ {
+ "name": "Twitter",
+ "value": "https://twitter.com/mkay_fain"
+ },
+ {
+ "name": "Patreon",
+ "value": "https://www.patreon.com/mkfain"
+ },
+ {
+ "name": "Paypal",
+ "value": "https://www.paypal.com/donate?hosted_button_id=NYXHYFQ6CRWJJ"
+ },
+ {
+ "name": "Facebook",
+ "value": "https://www.facebook.com/M-K-Fain-102559968375112"
+ },
+ {
+ "name": "Dog Pics",
+ "value": "https://www.instagram.com/mmkaayyy92"
+ },
+ {
+ "name": "$BTC",
+ "value": "bc1q7fp347muhnuxrtu0pft6eswn0e7pldhssdg8py"
+ }
+ ],
+ "followers_count": 5687,
+ "following_count": 18017,
+ "fqn": "mk@spinster.xyz",
+ "header": "https://media.spinster.xyz/3a5f9d5ef06940d0c319f8f0135b1153a8a42cefd10eace97378875c0347da71.png",
+ "header_static": "https://media.spinster.xyz/3a5f9d5ef06940d0c319f8f0135b1153a8a42cefd10eace97378875c0347da71.png",
+ "id": "9y4BZYXEDuQ6K1zW9g",
+ "last_status_at": "2022-02-27T01:58:21",
+ "locked": false,
+ "note": ":spinster: Admin of @spinster
:4w: Editor of @4WPub
Sorry I didn't reply to you.
Boost ≠ agree. All opinions my own.",
+ "pleroma": {
+ "accepts_chat_messages": true,
+ "also_known_as": [],
+ "ap_id": "https://spinster.xyz/users/mk",
+ "background_image": null,
+ "favicon": "https://spinster.xyz/favicon.png",
+ "hide_favorites": true,
+ "hide_followers": false,
+ "hide_followers_count": false,
+ "hide_follows": false,
+ "hide_follows_count": false,
+ "is_admin": true,
+ "is_confirmed": true,
+ "is_moderator": false,
+ "is_suggested": true,
+ "relationship": {},
+ "skip_thread_containment": false,
+ "tags": [
+ "verified"
+ ]
+ },
+ "source": {
+ "fields": [
+ {
+ "name": "Website",
+ "value": "https://marykatefain.com"
+ },
+ {
+ "name": "Twitter",
+ "value": "https://twitter.com/mkay_fain"
+ },
+ {
+ "name": "Patreon",
+ "value": "https://www.patreon.com/mkfain"
+ },
+ {
+ "name": "Paypal",
+ "value": "https://www.paypal.com/donate?hosted_button_id=NYXHYFQ6CRWJJ"
+ },
+ {
+ "name": "Facebook",
+ "value": "https://www.facebook.com/M-K-Fain-102559968375112"
+ },
+ {
+ "name": "Dog Pics",
+ "value": "https://www.instagram.com/mmkaayyy92"
+ },
+ {
+ "name": "$BTC",
+ "value": "bc1q7fp347muhnuxrtu0pft6eswn0e7pldhssdg8py"
+ }
+ ],
+ "note": ":spinster: Admin of @spinster\r\n:4w: Editor of @4WPub\r\n\r\nSorry I didn't reply to you.\r\n\r\nBoost ≠ agree. All opinions my own.",
+ "pleroma": {
+ "actor_type": "Person",
+ "discoverable": false
+ },
+ "sensitive": false
+ },
+ "statuses_count": 9580,
+ "url": "https://spinster.xyz/users/mk",
+ "username": "mk"
+}
diff --git a/app/soapbox/__fixtures__/pleroma-2.2.2-account.json b/app/soapbox/__fixtures__/pleroma-2.2.2-account.json
new file mode 100644
index 000000000..7df005d65
--- /dev/null
+++ b/app/soapbox/__fixtures__/pleroma-2.2.2-account.json
@@ -0,0 +1,46 @@
+{
+ "acct": "alex",
+ "avatar": "https://freespeechextremist.com/images/avi.png",
+ "avatar_static": "https://freespeechextremist.com/images/avi.png",
+ "bot": false,
+ "created_at": "2022-02-28T01:55:05.000Z",
+ "display_name": "Alex Gleason",
+ "emojis": [],
+ "fields": [],
+ "followers_count": 0,
+ "following_count": 0,
+ "header": "https://freespeechextremist.com/images/banner.png",
+ "header_static": "https://freespeechextremist.com/images/banner.png",
+ "id": "AGv8wCadU7DqWgMqNk",
+ "locked": false,
+ "note": "I'm testing out compatibility with an older Pleroma version",
+ "pleroma": {
+ "accepts_chat_messages": true,
+ "ap_id": "https://freespeechextremist.com/users/alex",
+ "background_image": null,
+ "confirmation_pending": false,
+ "favicon": null,
+ "hide_favorites": true,
+ "hide_followers": false,
+ "hide_followers_count": false,
+ "hide_follows": false,
+ "hide_follows_count": false,
+ "is_admin": false,
+ "is_moderator": false,
+ "relationship": {},
+ "skip_thread_containment": false,
+ "tags": []
+ },
+ "source": {
+ "fields": [],
+ "note": "I'm testing out compatibility with an older Pleroma version",
+ "pleroma": {
+ "actor_type": "Person",
+ "discoverable": true
+ },
+ "sensitive": false
+ },
+ "statuses_count": 0,
+ "url": "https://freespeechextremist.com/users/alex",
+ "username": "alex"
+}
diff --git a/app/soapbox/__fixtures__/alex.json b/app/soapbox/__fixtures__/pleroma-account.json
similarity index 100%
rename from app/soapbox/__fixtures__/alex.json
rename to app/soapbox/__fixtures__/pleroma-account.json
diff --git a/app/soapbox/__fixtures__/realDonaldTrump.json b/app/soapbox/__fixtures__/realDonaldTrump.json
new file mode 100644
index 000000000..c9cf20076
--- /dev/null
+++ b/app/soapbox/__fixtures__/realDonaldTrump.json
@@ -0,0 +1,26 @@
+{
+ "id": "107780257626128497",
+ "username": "realDonaldTrump",
+ "acct": "realDonaldTrump",
+ "display_name": "Donald J. Trump",
+ "locked": false,
+ "bot": false,
+ "discoverable": null,
+ "group": false,
+ "created_at": "2022-02-11T00:00:00.000Z",
+ "note": "45th President of the United States of America
",
+ "url": "https://truthsocial.com/@realDonaldTrump",
+ "avatar": "https://static-assets.truthsocial.com/tmtg:prime-truth-social-assets/accounts/avatars/107/780/257/626/128/497/original/573cf5cc8281e7e9.jpeg",
+ "avatar_static": "https://static-assets.truthsocial.com/tmtg:prime-truth-social-assets/accounts/avatars/107/780/257/626/128/497/original/573cf5cc8281e7e9.jpeg",
+ "header": "https://static-assets.truthsocial.com/tmtg:prime-truth-social-assets/accounts/headers/107/780/257/626/128/497/original/3c1acf607b065ded.jpeg",
+ "header_static": "https://static-assets.truthsocial.com/tmtg:prime-truth-social-assets/accounts/headers/107/780/257/626/128/497/original/3c1acf607b065ded.jpeg",
+ "followers_count": 51507,
+ "following_count": 1,
+ "statuses_count": 1,
+ "last_status_at": "2022-02-14",
+ "verified": true,
+ "location": "",
+ "website": "",
+ "emojis": [],
+ "fields": []
+}
diff --git a/app/soapbox/components/display_name.js b/app/soapbox/components/display_name.js
index eca526679..87947af46 100644
--- a/app/soapbox/components/display_name.js
+++ b/app/soapbox/components/display_name.js
@@ -4,7 +4,6 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import HoverRefWrapper from 'soapbox/components/hover_ref_wrapper';
-import { isVerified } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
import { getAcct } from '../utils/accounts';
@@ -38,7 +37,7 @@ class DisplayName extends React.PureComponent {
const { account, displayFqn, others, children, withDate } = this.props;
let displayName, suffix;
- const verified = isVerified(account);
+ const verified = account.get('verified');
const createdAt = account.get('created_at');
diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js
index 19b218877..7f18e8b61 100644
--- a/app/soapbox/containers/soapbox.js
+++ b/app/soapbox/containers/soapbox.js
@@ -64,7 +64,7 @@ const mapStateToProps = (state) => {
// In demo mode, force the default brand color
const brandColor = settings.get('demo') ? '#0482d8' : soapboxConfig.get('brandColor');
- const accentColor = settings.get('demo') ? null : soapboxConfig.get('accentColor');
+ const accentColor = (settings.get('demo') || settings.get('halloween')) ? null : soapboxConfig.get('accentColor');
const singleUserMode = soapboxConfig.get('singleUserMode') && soapboxConfig.get('singleUserModeProfile');
diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js
index 8b5a5f258..4881d6b7d 100644
--- a/app/soapbox/features/account/components/header.js
+++ b/app/soapbox/features/account/components/header.js
@@ -27,7 +27,6 @@ import {
isStaff,
isAdmin,
isModerator,
- isVerified,
isLocal,
isRemote,
getDomain,
@@ -451,7 +450,7 @@ class Header extends ImmutablePureComponent {
}
}
- if (isVerified(account)) {
+ if (account.get('verified')) {
menu.push({
text: intl.formatMessage(messages.unverifyUser, { name: account.get('username') }),
action: this.props.onUnverifyUser,
diff --git a/app/soapbox/features/birthdays/account.js b/app/soapbox/features/birthdays/account.js
index d0961d0ae..e79273f89 100644
--- a/app/soapbox/features/birthdays/account.js
+++ b/app/soapbox/features/birthdays/account.js
@@ -56,7 +56,7 @@ class Account extends ImmutablePureComponent {
if (!account) return null;
- const birthday = account.getIn(['pleroma', 'birthday']);
+ const birthday = account.get('birthday');
if (!birthday) return null;
const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'short', year: 'numeric' });
diff --git a/app/soapbox/features/edit_profile/components/profile_preview.js b/app/soapbox/features/edit_profile/components/profile_preview.js
index 3b73e48f8..ad1db11ed 100644
--- a/app/soapbox/features/edit_profile/components/profile_preview.js
+++ b/app/soapbox/features/edit_profile/components/profile_preview.js
@@ -6,7 +6,7 @@ import { Link } from 'react-router-dom';
import StillImage from 'soapbox/components/still_image';
import VerificationBadge from 'soapbox/components/verification_badge';
-import { getAcct, isVerified } from 'soapbox/utils/accounts';
+import { getAcct } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
const mapStateToProps = state => ({
@@ -28,7 +28,7 @@ const ProfilePreview = ({ account, displayFqn }) => (
{account.get('display_name')}
- {isVerified(account) && }
+ {account.get('verified') && }
@{getAcct(account, displayFqn)}
diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js
index ad1197555..300d965a7 100644
--- a/app/soapbox/features/edit_profile/index.js
+++ b/app/soapbox/features/edit_profile/index.js
@@ -25,7 +25,6 @@ import {
SimpleTextarea,
} from 'soapbox/features/forms';
import { makeGetAccount } from 'soapbox/selectors';
-import { isVerified } from 'soapbox/utils/accounts';
import { getFeatures } from 'soapbox/utils/features';
import resizeImage from 'soapbox/utils/resize_image';
@@ -114,7 +113,7 @@ class EditProfile extends ImmutablePureComponent {
const strangerNotifications = account.getIn(['pleroma', 'notification_settings', 'block_from_strangers']);
const acceptsEmailList = account.getIn(['pleroma', 'accepts_email_list']);
const discoverable = account.getIn(['source', 'pleroma', 'discoverable']);
- const birthday = account.getIn(['pleroma', 'birthday']);
+ const birthday = account.get('birthday');
const showBirthday = account.getIn(['source', 'pleroma', 'show_birthday']);
const initialState = account.withMutations(map => {
@@ -263,7 +262,7 @@ class EditProfile extends ImmutablePureComponent {
render() {
const { intl, maxFields, account, verifiedCanEditName, supportsBirthdays, supportsEmailList } = this.props;
- const verified = isVerified(account);
+ const verified = account.get('verified');
const canEditName = verifiedCanEditName || !verified;
return (
diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js
index 35d12a627..72e033e1e 100644
--- a/app/soapbox/features/ui/components/profile_info_panel.js
+++ b/app/soapbox/features/ui/components/profile_info_panel.js
@@ -15,7 +15,7 @@ import Icon from 'soapbox/components/icon';
import VerificationBadge from 'soapbox/components/verification_badge';
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
import { CryptoAddress } from 'soapbox/features/ui/util/async-components';
-import { getAcct, isAdmin, isModerator, isLocal, isVerified } from 'soapbox/utils/accounts';
+import { getAcct, isAdmin, isModerator, isLocal } from 'soapbox/utils/accounts';
import { displayFqn } from 'soapbox/utils/state';
import ProfileStats from './profile_stats';
@@ -85,7 +85,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
getBirthday = () => {
const { account, intl } = this.props;
- const birthday = account.getIn(['pleroma', 'birthday']);
+ const birthday = account.get('birthday');
if (!birthday) return null;
const formattedBirthday = intl.formatDate(birthday, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' });
@@ -147,7 +147,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
const deactivated = !account.getIn(['pleroma', 'is_active'], true);
const displayNameHtml = deactivated ? { __html: intl.formatMessage(messages.deactivated) } : { __html: account.get('display_name_html') };
const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' });
- const verified = isVerified(account);
+ const verified = account.get('verified');
const badges = this.getBadges();
return (
diff --git a/app/soapbox/features/ui/components/user_panel.js b/app/soapbox/features/ui/components/user_panel.js
index 9bf52c4da..36a48ce56 100644
--- a/app/soapbox/features/ui/components/user_panel.js
+++ b/app/soapbox/features/ui/components/user_panel.js
@@ -9,7 +9,7 @@ import { Link } from 'react-router-dom';
import Avatar from 'soapbox/components/avatar';
import StillImage from 'soapbox/components/still_image';
import VerificationBadge from 'soapbox/components/verification_badge';
-import { getAcct, isVerified } from 'soapbox/utils/accounts';
+import { getAcct } from 'soapbox/utils/accounts';
import { shortNumberFormat } from 'soapbox/utils/numbers';
import { displayFqn } from 'soapbox/utils/state';
@@ -51,7 +51,7 @@ class UserPanel extends ImmutablePureComponent {
- {isVerified(account) && }
+ {account.get('verified') && }
@{getAcct(account, displayFqn)}
diff --git a/app/soapbox/locales/uk.json b/app/soapbox/locales/uk.json
index 1ab59de14..3709cd556 100644
--- a/app/soapbox/locales/uk.json
+++ b/app/soapbox/locales/uk.json
@@ -15,7 +15,7 @@
"account.direct": "Пряме повідомлення @{name}",
"account.domain_blocked": "Домен приховано",
"account.edit_profile": "Редагувати профіль",
- "account.endorse": "Feature on profile",
+ "account.endorse": "Публікувати у профілі",
"account.follow": "Підписатися",
"account.followers": "Підписники",
"account.followers.empty": "Ніхто ще не підписався на цього користувача.",
@@ -23,32 +23,32 @@
"account.follows.empty": "Цей користувач ще ні на кого не підписався.",
"account.follows_you": "Підписаний(-а) на Вас",
"account.hide_reblogs": "Сховати передмухи від @{name}",
- "account.last_status": "Last active",
+ "account.last_status": "Крайня активність",
"account.link_verified_on": "Права власності на це посилання були перевірені {date}",
"account.locked_info": "Статус конфіденційності цього облікового запису встановлено у заблокований. Власник вручну переглядає, хто може за ним стежити.",
- "account.login": "Log in",
+ "account.login": "Увійти",
"account.media": "Медіа",
- "account.member_since": "Joined {date}",
+ "account.member_since": "Долучення {date}",
"account.mention": "Згадати",
"account.moved_to": "{name} переїхав на:",
"account.mute": "Заглушити @{name}",
"account.muted": "Заглушений",
- "account.never_active": "Never",
+ "account.never_active": "Ніколи",
"account.posts": "Дмухи",
"account.posts_with_replies": "Дмухи й відповіді",
"account.profile": "Profile",
- "account.register": "Sign up",
+ "account.register": "Зареєструватися",
"account.remote_follow": "Remote follow",
"account.report": "Поскаржитися на @{name}",
"account.requested": "Очікує підтвердження. Натисніть щоб відмінити запит",
- "account.requested_small": "Awaiting approval",
+ "account.requested_small": "Очікує підтвердження",
"account.share": "Поширити профіль @{name}",
"account.show_reblogs": "Показати передмухи від @{name}",
"account.subscribe": "Subscribe to notifications from @{name}",
"account.subscribed": "Subscribed",
"account.unblock": "Розблокувати @{name}",
"account.unblock_domain": "Розблокувати {domain}",
- "account.unendorse": "Don't feature on profile",
+ "account.unendorse": "Не публікувати у профілі",
"account.unfollow": "Відписатися",
"account.unmute": "Зняти глушення з @{name}",
"account.unsubscribe": "Unsubscribe to notifications from @{name}",
@@ -67,21 +67,21 @@
"admin.dashboard.registration_mode_label": "Registrations",
"admin.dashboard.settings_saved": "Settings saved!",
"admin.dashcounters.domain_count_label": "peers",
- "admin.dashcounters.mau_label": "monthly active users",
+ "admin.dashcounters.mau_label": "активні користувачі місяця",
"admin.dashcounters.retention_label": "user retention",
"admin.dashcounters.status_count_label": "posts",
"admin.dashcounters.user_count_label": "total users",
"admin.dashwidgets.email_list_header": "Email list",
- "admin.dashwidgets.software_header": "Software",
+ "admin.dashwidgets.software_header": "Програмне забезпечення",
"admin.latest_accounts_panel.expand_message": "Click to see {count} more {count, plural, one {account} other {accounts}}",
"admin.latest_accounts_panel.title": "Latest Accounts",
"admin.moderation_log.empty_message": "You have not performed any moderation actions yet. When you do, a history will be shown here.",
- "admin.reports.actions.close": "Close",
- "admin.reports.actions.view_status": "View post",
+ "admin.reports.actions.close": "Закрити",
+ "admin.reports.actions.view_status": "Показати статус",
"admin.reports.empty_message": "There are no open reports. If a user gets reported, they will show up here.",
"admin.reports.report_closed_message": "Report on @{name} was closed",
"admin.reports.report_title": "Report on {acct}",
- "admin.statuses.actions.delete_status": "Delete post",
+ "admin.statuses.actions.delete_status": "Видалити пост",
"admin.statuses.actions.mark_status_not_sensitive": "Mark post not sensitive",
"admin.statuses.actions.mark_status_sensitive": "Mark post sensitive",
"admin.statuses.status_deleted_message": "Post by @{acct} was deleted",
@@ -89,8 +89,8 @@
"admin.statuses.status_marked_message_sensitive": "Post by @{acct} was marked sensitive",
"admin.user_index.empty": "No users found.",
"admin.user_index.search_input_placeholder": "Who are you looking for?",
- "admin.users.actions.deactivate_user": "Deactivate @{name}",
- "admin.users.actions.delete_user": "Delete @{name}",
+ "admin.users.actions.deactivate_user": "Деактивувати @{name}",
+ "admin.users.actions.delete_user": "Видалити @{name}",
"admin.users.actions.demote_to_moderator": "Demote @{name} to a moderator",
"admin.users.actions.demote_to_moderator_message": "@{acct} was demoted to a moderator",
"admin.users.actions.demote_to_user": "Demote @{name} to a regular user",
@@ -110,28 +110,28 @@
"admin.users.user_unverified_message": "@{acct} was unverified",
"admin.users.user_verified_message": "@{acct} was verified",
"admin_nav.awaiting_approval": "Awaiting Approval",
- "admin_nav.dashboard": "Dashboard",
- "admin_nav.reports": "Reports",
+ "admin_nav.dashboard": "Приборна панель",
+ "admin_nav.reports": "Скарги",
"alert.unexpected.clear_cookies": "clear cookies and browser data",
"alert.unexpected.help_text": "If the problem persists, please notify a site admin with a screenshot and information about your web browser. You may also {clear_cookies} (this will log you out).",
"alert.unexpected.message": "Трапилась неочікувана помилка.",
"alert.unexpected.return_home": "Return Home",
"alert.unexpected.title": "Ой!",
- "aliases.account.add": "Create alias",
+ "aliases.account.add": "Створити псевдонім",
"aliases.account_label": "Old account:",
"aliases.aliases_list_delete": "Unlink alias",
"aliases.search": "Search your old account",
"aliases.success.add": "Account alias created successfully",
"aliases.success.remove": "Account alias removed successfully",
- "app_create.name_label": "App name",
+ "app_create.name_label": "Назва додатку",
"app_create.name_placeholder": "e.g. 'Soapbox'",
- "app_create.redirect_uri_label": "Redirect URIs",
+ "app_create.redirect_uri_label": "URI перенаправлення",
"app_create.restart": "Create another",
"app_create.results.app_label": "App",
"app_create.results.explanation_text": "You created a new app and token! Please copy the credentials somewhere; you will not see them again after navigating away from this page.",
"app_create.results.explanation_title": "App created successfully",
"app_create.results.token_label": "OAuth token",
- "app_create.scopes_label": "Scopes",
+ "app_create.scopes_label": "Рамки",
"app_create.scopes_placeholder": "e.g. 'read write follow'",
"app_create.submit": "Create app",
"app_create.website_label": "Website",
@@ -152,7 +152,7 @@
"chat_box.actions.send": "Send",
"chat_box.input.placeholder": "Send a message…",
"chat_panels.main_window.empty": "No chats found. To start a chat, visit a user's profile.",
- "chat_panels.main_window.title": "Chats",
+ "chat_panels.main_window.title": "Чат",
"chats.actions.delete": "Delete message",
"chats.actions.more": "More",
"chats.actions.report": "Report user",
@@ -163,12 +163,12 @@
"chats.dividers.today": "Today",
"chats.search_placeholder": "Start a chat with…",
"column.admin.awaiting_approval": "Awaiting Approval",
- "column.admin.dashboard": "Dashboard",
+ "column.admin.dashboard": "Приборна панель",
"column.admin.moderation_log": "Moderation Log",
- "column.admin.reports": "Reports",
+ "column.admin.reports": "Скарги",
"column.admin.reports.menu.moderation_log": "Moderation Log",
"column.admin.users": "Users",
- "column.aliases": "Account aliases",
+ "column.aliases": "Псевдоніми облікового запису",
"column.aliases.create_error": "Error creating alias",
"column.aliases.delete": "Delete",
"column.aliases.delete_error": "Error deleting alias",
@@ -177,63 +177,63 @@
"column.app_create": "Create app",
"column.backups": "Backups",
"column.blocks": "Заблоковані користувачі",
- "column.bookmarks": "Bookmarks",
- "column.chats": "Chats",
+ "column.bookmarks": "Закладки",
+ "column.chats": "Чат",
"column.community": "Локальна стрічка",
"column.crypto_donate": "Donate Cryptocurrency",
- "column.developers": "Developers",
+ "column.developers": "Розробникам",
"column.direct": "Прямі повідомлення",
- "column.directory": "Browse profiles",
+ "column.directory": "Переглянути профілі",
"column.domain_blocks": "Приховані домени",
- "column.edit_profile": "Edit profile",
- "column.export_data": "Export data",
+ "column.edit_profile": "Редагувати профіль",
+ "column.export_data": "Експорт даних",
"column.favourited_statuses": "Liked posts",
- "column.favourites": "Likes",
+ "column.favourites": "Вподобане",
"column.federation_restrictions": "Federation Restrictions",
- "column.filters": "Muted words",
- "column.filters.add_new": "Add New Filter",
- "column.filters.conversations": "Conversations",
+ "column.filters": "Приховані слова",
+ "column.filters.add_new": "Додати фільтр",
+ "column.filters.conversations": "Повідомлення",
"column.filters.create_error": "Error adding filter",
- "column.filters.delete": "Delete",
+ "column.filters.delete": "Видалити",
"column.filters.delete_error": "Error deleting filter",
- "column.filters.drop_header": "Drop instead of hide",
- "column.filters.drop_hint": "Filtered posts will disappear irreversibly, even if filter is later removed",
- "column.filters.expires": "Expire after",
+ "column.filters.drop_header": "Видалити назавжди, а не просто сховати",
+ "column.filters.drop_hint": "Відсіяні дмухи зникнуть назавжди, навіть якщо фільтр потім буде знято",
+ "column.filters.expires": "Закінчується після",
"column.filters.expires_hint": "Expiration dates are not currently supported",
- "column.filters.home_timeline": "Home timeline",
- "column.filters.keyword": "Keyword or phrase",
- "column.filters.notifications": "Notifications",
- "column.filters.public_timeline": "Public timeline",
- "column.filters.subheading_add_new": "Add New Filter",
+ "column.filters.home_timeline": "Ваша стрічка",
+ "column.filters.keyword": "Ключове слово або фраза",
+ "column.filters.notifications": "Сповіщення",
+ "column.filters.public_timeline": "Глобальні стрічки",
+ "column.filters.subheading_add_new": "Додати фільтр",
"column.filters.subheading_filters": "Current Filters",
- "column.filters.whole_word_header": "Whole word",
- "column.filters.whole_word_hint": "When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word",
+ "column.filters.whole_word_header": "Ціле слово",
+ "column.filters.whole_word_hint": "Якщо пошукове слово або фраза містить лише літери та цифри, воно має збігатися цілком",
"column.follow_requests": "Запити на підписку",
- "column.followers": "Followers",
- "column.following": "Following",
+ "column.followers": "Підписники",
+ "column.following": "Підписки",
"column.groups": "Groups",
"column.home": "Головна",
- "column.import_data": "Import data",
+ "column.import_data": "Імпорт даних",
"column.info": "Server information",
"column.lists": "Списки",
"column.mentions": "Mentions",
- "column.mfa": "Multi-Factor Authentication",
- "column.mfa_cancel": "Cancel",
+ "column.mfa": "Двофакторна авторизація",
+ "column.mfa_cancel": "Відмінити",
"column.mfa_confirm_button": "Confirm",
"column.mfa_disable_button": "Disable",
"column.mfa_setup": "Proceed to Setup",
"column.mutes": "Заглушені користувачі",
"column.notifications": "Сповіщення",
- "column.pins": "Pinned posts",
- "column.preferences": "Preferences",
- "column.profile_directory": "Profile directory",
+ "column.pins": "Закріплені дмухи",
+ "column.preferences": "Налаштування",
+ "column.profile_directory": "Каталог профілів",
"column.public": "Глобальна стрічка",
"column.reactions": "Reactions",
- "column.reblogs": "Reposts",
+ "column.reblogs": "Передмухи",
"column.remote": "Federated timeline",
"column.scheduled_statuses": "Scheduled Posts",
- "column.search": "Search",
- "column.security": "Security",
+ "column.search": "Пошук",
+ "column.security": "Безпека",
"column.soapbox_config": "Soapbox config",
"column_back_button.label": "Назад",
"column_forbidden.body": "You do not have permission to access this page.",
@@ -257,8 +257,8 @@
"compose_form.poll.duration": "Тривалість опитування",
"compose_form.poll.option_placeholder": "Варіант {number}",
"compose_form.poll.remove_option": "Видалити цей варіант",
- "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
- "compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
+ "compose_form.poll.switch_to_multiple": "Перемкнути у режим вибору декількох відповідей",
+ "compose_form.poll.switch_to_single": "Change Перемкнути у режим вибору однієї відповіді",
"compose_form.publish": "Дмухнути",
"compose_form.publish_loud": "{publish}!",
"compose_form.schedule": "Schedule",
@@ -313,10 +313,10 @@
"developers.navigation.app_create_label": "Create an app",
"developers.navigation.intentional_error_label": "Trigger an error",
"direct.search_placeholder": "Send a message to…",
- "directory.federated": "From known fediverse",
- "directory.local": "From {domain} only",
- "directory.new_arrivals": "New arrivals",
- "directory.recently_active": "Recently active",
+ "directory.federated": "З відомого федесвіту",
+ "directory.local": "Тільки з домену {domain}",
+ "directory.new_arrivals": "Нові надходження",
+ "directory.recently_active": "Активні нещодавно",
"donate": "Donate",
"donate_crypto": "Donate cryptocurrency",
"edit_federation.followers_only": "Hide posts except to followers",
@@ -328,32 +328,32 @@
"edit_federation.unlisted": "Force posts unlisted",
"edit_profile.error": "Profile update failed",
"edit_profile.fields.accepts_email_list_label": "Subscribe to newsletter",
- "edit_profile.fields.avatar_label": "Avatar",
- "edit_profile.fields.bio_label": "Bio",
+ "edit_profile.fields.avatar_label": "Аватар",
+ "edit_profile.fields.bio_label": "Про Вас",
"edit_profile.fields.bio_placeholder": "Tell us about yourself.",
- "edit_profile.fields.bot_label": "This is a bot account",
+ "edit_profile.fields.bot_label": "Це обліковий запис бота",
"edit_profile.fields.discoverable_label": "Allow account discovery",
- "edit_profile.fields.display_name_label": "Display name",
+ "edit_profile.fields.display_name_label": "Ім'я",
"edit_profile.fields.display_name_placeholder": "Name",
- "edit_profile.fields.header_label": "Header",
+ "edit_profile.fields.header_label": "Заголовок",
"edit_profile.fields.hide_network_label": "Hide network",
- "edit_profile.fields.locked_label": "Lock account",
- "edit_profile.fields.meta_fields.content_placeholder": "Content",
- "edit_profile.fields.meta_fields.label_placeholder": "Label",
- "edit_profile.fields.meta_fields_label": "Profile metadata",
+ "edit_profile.fields.locked_label": "Зробити акаунт приватним",
+ "edit_profile.fields.meta_fields.content_placeholder": "Вміст",
+ "edit_profile.fields.meta_fields.label_placeholder": "Позначка",
+ "edit_profile.fields.meta_fields_label": "Метадані профіля",
"edit_profile.fields.stranger_notifications_label": "Block notifications from strangers",
"edit_profile.fields.verified_display_name": "Verified users may not update their display name",
"edit_profile.hints.accepts_email_list": "Opt-in to news and marketing updates.",
- "edit_profile.hints.avatar": "PNG, GIF or JPG. Will be downscaled to {size}",
- "edit_profile.hints.bot": "This account mainly performs automated actions and might not be monitored",
+ "edit_profile.hints.avatar": "PNG, GIF, або JPG. Буде зменшено до {size}",
+ "edit_profile.hints.bot": "Цей акаунт виконує автоматичні дії та може не відстежуватися",
"edit_profile.hints.discoverable": "Display account in profile directory and allow indexing by external services",
- "edit_profile.hints.header": "PNG, GIF or JPG. Will be downscaled to {size}",
- "edit_profile.hints.hide_network": "Who you follow and who follows you will not be shown on your profile",
+ "edit_profile.hints.header": "PNG, GIF, або JPG. Буде зменшено до {size}",
+ "edit_profile.hints.hide_network": "У вашому профілі не буде відображено підписки та підписників",
"edit_profile.hints.locked": "Requires you to manually approve followers",
- "edit_profile.hints.meta_fields": "You can have up to {count, plural, one {# item} other {# items}} displayed as a table on your profile",
+ "edit_profile.hints.meta_fields": "До {count, plural, one {# елемента} many {# елементів}} може бути відображено як таблиця у вашому профілі",
"edit_profile.hints.stranger_notifications": "Only show notifications from people you follow",
"edit_profile.meta_fields.add": "Add new item",
- "edit_profile.save": "Save",
+ "edit_profile.save": "Зберегти",
"edit_profile.success": "Profile saved!",
"embed.instructions": "Вбудуйте цей статус до вашого вебсайту, скопіювавши код нижче.",
"embed.preview": "Ось як він виглядатиме:",
@@ -375,17 +375,17 @@
"empty_column.account_favourited_statuses": "This user doesn't have any liked posts yet.",
"empty_column.account_timeline": "Тут дмухалок немає!",
"empty_column.account_unavailable": "Профіль недоступний",
- "empty_column.aliases": "You haven't created any account alias yet.",
+ "empty_column.aliases": "У вас немає псевдонімів.",
"empty_column.aliases.suggestions": "There are no account suggestions available for the provided term.",
"empty_column.blocks": "Ви ще не заблокували жодного користувача.",
- "empty_column.bookmarks": "You don't have any bookmarks yet. When you add one, it will show up here.",
+ "empty_column.bookmarks": "У вас ще немає дмухів у закладках. Коли ви щось додасте до заклкдок, воно з'явиться тут.",
"empty_column.community": "Локальна стрічка пуста. Напишіть щось, щоб розігріти народ!",
"empty_column.direct": "У вас ще немає прямих повідомлень. Коли ви відправите чи отримаєте якесь, воно з'явиться тут.",
"empty_column.domain_blocks": "Тут поки немає прихованих доменів.",
"empty_column.favourited_statuses": "У вас ще немає вподобаних дмухів. Коли ви щось вподобаєте, воно з'явиться тут.",
"empty_column.favourites": "Ніхто ще не вподобав цього дмуху. Коли хтось це зробить, вони з'являться тут.",
"empty_column.filters": "You haven't created any muted words yet.",
- "empty_column.follow_recommendations": "Looks like no suggestions could be generated for you. You can try using search to look for people you might know or explore trending hashtags.",
+ "empty_column.follow_recommendations": "Схоже, для вас не буде створено жодної пропозиції. Ви можете спробувати скористатися пошуком людей, яких ви можете знати або переглянути популярні хештеґи.",
"empty_column.follow_requests": "У вас ще немає запитів на підписку. Коли ви їх отримаєте, вони з'являться тут.",
"empty_column.group": "There is nothing in this group yet. When members of this group make new posts, they will appear here.",
"empty_column.hashtag": "Дописів з цим хештегом поки не існує.",
@@ -401,16 +401,16 @@
"empty_column.search.accounts": "There are no people results for \"{term}\"",
"empty_column.search.hashtags": "There are no hashtags results for \"{term}\"",
"empty_column.search.statuses": "There are no posts results for \"{term}\"",
- "export_data.actions.export": "Export",
+ "export_data.actions.export": "Експорт",
"export_data.actions.export_blocks": "Export blocks",
"export_data.actions.export_follows": "Export follows",
"export_data.actions.export_mutes": "Export mutes",
- "export_data.blocks_label": "Blocks",
- "export_data.follows_label": "Follows",
+ "export_data.blocks_label": "Список блокувань",
+ "export_data.follows_label": "Підписки",
"export_data.hints.blocks": "Get a CSV file containing a list of blocked accounts",
"export_data.hints.follows": "Get a CSV file containing a list of followed accounts",
"export_data.hints.mutes": "Get a CSV file containing a list of muted accounts",
- "export_data.mutes_label": "Mutes",
+ "export_data.mutes_label": "Список глушення",
"export_data.success.blocks": "Blocks exported successfully",
"export_data.success.followers": "Followers exported successfully",
"export_data.success.mutes": "Mutes exported successfully",
@@ -427,22 +427,22 @@
"fediverse_tab.explanation_box.explanation": "{site_title} is part of the Fediverse, a social network made up of thousands of independent social media sites (aka \"servers\"). The posts you see here are from 3rd-party servers. You have the freedom to engage with them, or to block any server you don't like. Pay attention to the full username after the second @ symbol to know which server a post is from. To see only {site_title} posts, visit {local}.",
"fediverse_tab.explanation_box.title": "What is the Fediverse?",
"filters.added": "Filter added.",
- "filters.context_header": "Filter contexts",
- "filters.context_hint": "One or multiple contexts where the filter should apply",
- "filters.filters_list_context_label": "Filter contexts:",
- "filters.filters_list_delete": "Delete",
+ "filters.context_header": "Фільтрувати контексти",
+ "filters.context_hint": "Один або кілька контекстів, до яких повинні бути застосовані фільтри",
+ "filters.filters_list_context_label": "Фільтрувати контексти:",
+ "filters.filters_list_delete": "Видалити",
"filters.filters_list_details_label": "Filter settings:",
"filters.filters_list_drop": "Drop",
"filters.filters_list_hide": "Hide",
- "filters.filters_list_phrase_label": "Keyword or phrase:",
- "filters.filters_list_whole-word": "Whole word",
+ "filters.filters_list_phrase_label": "Ключове слово або фраза:",
+ "filters.filters_list_whole-word": "Ціле слово",
"filters.removed": "Filter deleted.",
- "follow_recommendations.done": "Done",
- "follow_recommendations.heading": "Follow people you'd like to see posts from! Here are some suggestions.",
- "follow_recommendations.lead": "Posts from people you follow will show up in chronological order on your home feed. Don't be afraid to make mistakes, you can unfollow people just as easily any time!",
+ "follow_recommendations.done": "Готово",
+ "follow_recommendations.heading": "Підпишіться на людей, чиї дописи ви хочете бачити! Ось деякі пропозиції.",
+ "follow_recommendations.lead": "Дописи від людей, за якими ви стежите, з'являться в хронологічному порядку у вашій домашній стрічці. Не бійся помилятися, ви можете відписатися від людей так само легко в будь-який час!",
"follow_request.authorize": "Авторизувати",
"follow_request.reject": "Відмовити",
- "forms.copy": "Copy",
+ "forms.copy": "Копіювати",
"forms.hide_password": "Hide password",
"forms.show_password": "Show password",
"getting_started.open_source_notice": "{code_name} — програма з відкритим сирцевим кодом. Ви можете допомогти проекту, або повідомити про проблеми на GitLab за адресою {code_link} (v{code_version}).",
@@ -477,21 +477,21 @@
"hashtag.column_header.tag_mode.any": "або {additional}",
"hashtag.column_header.tag_mode.none": "без {additional}",
"header.about.label": "About",
- "header.back_to.label": "Back to {siteTitle}",
- "header.home.label": "Home",
- "header.login.label": "Log in",
+ "header.back_to.label": "Назад до {siteTitle}",
+ "header.home.label": "Головна",
+ "header.login.label": "Увійти",
"home.column_settings.show_direct": "Show direct messages",
"home.column_settings.show_reblogs": "Показувати передмухи",
"home.column_settings.show_replies": "Показувати відповіді",
"home.column_settings.title": "Home settings",
- "home_column.lists": "Lists",
+ "home_column.lists": "Списки",
"home_column_header.all": "All",
"home_column_header.fediverse": "Fediverse",
"home_column_header.home": "Головна",
"icon_button.icons": "Icons",
"icon_button.label": "Select icon",
"icon_button.not_found": "No icons!! (╯°□°)╯︵ ┻━┻",
- "import_data.actions.import": "Import",
+ "import_data.actions.import": "Імпорт",
"import_data.actions.import_blocks": "Import blocks",
"import_data.actions.import_follows": "Import follows",
"import_data.actions.import_mutes": "Import mutes",
@@ -508,7 +508,7 @@
"intervals.full.hours": "{number, plural, one {# година} few {# години} other {# годин}}",
"intervals.full.minutes": "{number, plural, one {# хвилина} few {# хвилини} other {# хвилин}}",
"introduction.federation.action": "Next",
- "introduction.federation.home.headline": "Home",
+ "introduction.federation.home.headline": "Головна",
"introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
"introduction.interactions.action": "Finish tutorial!",
"introduction.interactions.favourite.headline": "Favorite",
@@ -536,7 +536,7 @@
"keyboard_shortcuts.muted": "відкрити список заглушених користувачів",
"keyboard_shortcuts.my_profile": "відкрити ваш профіль",
"keyboard_shortcuts.notifications": "відкрити колонку сповіщень",
- "keyboard_shortcuts.open_media": "to open media",
+ "keyboard_shortcuts.open_media": "відкрити медіа",
"keyboard_shortcuts.pinned": "відкрити список закріплених дмухів",
"keyboard_shortcuts.profile": "відкрити профіль автора",
"keyboard_shortcuts.react": "to react",
@@ -571,9 +571,9 @@
"login.fields.instance_placeholder": "example.com",
"login.fields.otp_code_hint": "Enter the two-factor code generated by your phone app or use one of your recovery codes",
"login.fields.otp_code_label": "Two-factor code:",
- "login.fields.password_placeholder": "Password",
+ "login.fields.password_placeholder": "Пароль",
"login.fields.username_placeholder": "Username",
- "login.log_in": "Log in",
+ "login.log_in": "Увійти",
"login.otp_log_in": "OTP Login",
"login.otp_log_in.fail": "Invalid code, please try again.",
"login.reset_password_hint": "Trouble logging in?",
@@ -593,7 +593,7 @@
"mfa.setup_otp_title": "OTP Disabled",
"mfa.setup_recoverycodes": "Recovery codes",
"mfa.setup_warning": "Write these codes down or save them somewhere secure - otherwise you won't see them again. If you lose access to your 2FA app and recovery codes you'll be locked out of your account.",
- "missing_description_modal.cancel": "Cancel",
+ "missing_description_modal.cancel": "Відмінити",
"missing_description_modal.continue": "Post",
"missing_description_modal.text": "You have not entered a description for all attachments. Continue anyway?",
"missing_indicator.label": "Не знайдено",
@@ -601,18 +601,18 @@
"morefollows.followers_label": "…and {count} more {count, plural, one {follower} other {followers}} on remote sites.",
"morefollows.following_label": "…and {count} more {count, plural, one {follow} other {follows}} on remote sites.",
"mute_modal.hide_notifications": "Приховати сповіщення від користувача?",
- "navigation.chats": "Chats",
+ "navigation.chats": "Чат",
"navigation.dashboard": "Dashboard",
- "navigation.developers": "Developers",
- "navigation.direct_messages": "Messages",
- "navigation.home": "Home",
+ "navigation.developers": "Розробникам",
+ "navigation.direct_messages": "Прямі повідомлення",
+ "navigation.home": "Головна",
"navigation.invites": "Invites",
- "navigation.notifications": "Notifications",
- "navigation.search": "Search",
- "navigation_bar.account_aliases": "Account aliases",
+ "navigation.notifications": "Сповіщення",
+ "navigation.search": "Пошук",
+ "navigation_bar.account_aliases": "Псевдоніми облікового запису",
"navigation_bar.admin_settings": "Admin settings",
"navigation_bar.blocks": "Заблоковані користувачі",
- "navigation_bar.bookmarks": "Bookmarks",
+ "navigation_bar.bookmarks": "Закладки",
"navigation_bar.compose": "Написати новий дмух",
"navigation_bar.compose_direct": "Direct message",
"navigation_bar.compose_reply": "Reply to post",
@@ -626,19 +626,19 @@
"navigation_bar.info": "Про сайт",
"navigation_bar.invites": "Invites",
"navigation_bar.keyboard_shortcuts": "Гарячі клавіші",
- "navigation_bar.lists": "Lists",
+ "navigation_bar.lists": "Списки",
"navigation_bar.logout": "Вийти",
"navigation_bar.messages": "Messages",
"navigation_bar.mutes": "Заглушені користувачі",
"navigation_bar.pins": "Закріплені дмухи",
"navigation_bar.preferences": "Налаштування",
- "navigation_bar.profile_directory": "Profile directory",
+ "navigation_bar.profile_directory": "Переглянути профілі",
"navigation_bar.security": "Безпека",
"navigation_bar.soapbox_config": "Soapbox config",
"notification.chat_mention": "{name} sent you a message",
"notification.favourite": "{name} вподобав(-ла) ваш допис",
"notification.follow": "{name} підписався(-лась) на Вас",
- "notification.follow_request": "{name} has requested to follow you",
+ "notification.follow_request": "{name} відправив(-ла) запит на підписку",
"notification.mention": "{name} згадав(-ла) Вас",
"notification.move": "{name} moved to {targetName}",
"notification.pleroma:emoji_reaction": "{name} reacted to your post",
@@ -653,7 +653,7 @@
"notifications.column_settings.filter_bar.category": "Панель швидкого фільтру",
"notifications.column_settings.filter_bar.show": "Показати",
"notifications.column_settings.follow": "Нові підписники:",
- "notifications.column_settings.follow_request": "New follow requests:",
+ "notifications.column_settings.follow_request": "Нові запити на підписку:",
"notifications.column_settings.mention": "Згадки:",
"notifications.column_settings.move": "Moves:",
"notifications.column_settings.poll": "Результати опитування:",
@@ -682,8 +682,8 @@
"poll.refresh": "Оновити",
"poll.total_votes": "{count, plural, one {# голос} few {# голоси} many {# голосів} other {# голосів}}",
"poll.vote": "Проголосувати",
- "poll.voted": "You voted for this answer",
- "poll.votes": "{votes, plural, one {# vote} other {# votes}}",
+ "poll.voted": "Ви голосували за цю відповідь",
+ "poll.votes": "{votes, plural, one {# голос} few {# голоси} many {# голосів} other {# голоса}}",
"poll_button.add_poll": "Додати опитування",
"poll_button.remove_poll": "Видалити опитування",
"preferences.fields.auto_play_gif_label": "Auto-play animated GIFs",
@@ -743,7 +743,7 @@
"registration.confirmation_modal.close": "Close",
"registration.fields.confirm_placeholder": "Password (again)",
"registration.fields.email_placeholder": "E-Mail address",
- "registration.fields.password_placeholder": "Password",
+ "registration.fields.password_placeholder": "Пароль",
"registration.fields.username_hint": "Only letters, numbers, and underscores are allowed.",
"registration.fields.username_placeholder": "Username",
"registration.lead": "With an account on {instance} you'll be able to follow people on any server in the fediverse.",
@@ -764,7 +764,7 @@
"remote_instance.federation_panel.no_restrictions_message": "{siteTitle} has placed no restrictions on {host}.",
"remote_instance.federation_panel.restricted_message": "{siteTitle} blocks all activities from {host}.",
"remote_instance.federation_panel.some_restrictions_message": "{siteTitle} has placed some restrictions on {host}.",
- "remote_instance.pin_host": "Pin {host}",
+ "remote_instance.pin_host": "Відкріпити {host}",
"remote_instance.unpin_host": "Unpin {host}",
"remote_interaction.account_placeholder": "Enter your username@domain you want to act from",
"remote_interaction.divider": "or",
@@ -798,7 +798,7 @@
"schedule.remove": "Remove schedule",
"schedule_button.add_schedule": "Schedule post for later",
"schedule_button.remove_schedule": "Post immediately",
- "scheduled_status.cancel": "Cancel",
+ "scheduled_status.cancel": "Відмінити",
"search.action": "Search for “{query}”",
"search.placeholder": "Пошук",
"search_results.accounts": "Люди",
@@ -874,7 +874,7 @@
"status.admin_account": "Відкрити інтерфейс модерації для @{name}",
"status.admin_status": "Відкрити цей статус в інтерфейсі модерації",
"status.block": "Заблокувати @{name}",
- "status.bookmark": "Bookmark",
+ "status.bookmark": "Додати в закладки",
"status.bookmarked": "Bookmark added.",
"status.cancel_reblog_private": "Відмінити передмухання",
"status.cannot_reblog": "Цей допис не може бути передмухнутий",
@@ -923,7 +923,7 @@
"status.show_thread": "Показати ланцюжок",
"status.title": "Post",
"status.title_direct": "Direct message",
- "status.unbookmark": "Remove bookmark",
+ "status.unbookmark": "Видалити закладку",
"status.unbookmarked": "Bookmark removed.",
"status.unmute_conversation": "Зняти глушення з діалогу",
"status.unpin": "Відкріпити від профілю",
@@ -932,7 +932,7 @@
"suggestions.dismiss": "Відхилити пропозицію",
"tabs_bar.all": "All",
"tabs_bar.apps": "Apps",
- "tabs_bar.chats": "Chats",
+ "tabs_bar.chats": "Чат",
"tabs_bar.dashboard": "Dashboard",
"tabs_bar.fediverse": "Fediverse",
"tabs_bar.header": "Account Info",
@@ -949,7 +949,7 @@
"time_remaining.moments": "Moments remaining",
"time_remaining.seconds": "{number, plural, one {# секунда} few {# секунди} other {# секунд}}",
"trends.count_by_accounts": "{count} {rawCount, plural, one {людина} few {людини} many {людей} other {людей}} обговорюють це",
- "trends.title": "Trends",
+ "trends.title": "Актуальні",
"ui.beforeunload": "Вашу чернетку буде втрачено, якщо ви покинете Soapbox FE.",
"unauthorized_modal.footer": "Already have an account? {login}.",
"unauthorized_modal.text": "You need to be logged in to do that.",
@@ -963,7 +963,7 @@
"upload_form.undo": "Видалити",
"upload_progress.label": "Завантаження...",
"video.close": "Закрити відео",
- "video.download": "Download file",
+ "video.download": "Завантаження файла",
"video.exit_fullscreen": "Вийти з повноекранного режиму",
"video.expand": "Розширити відео",
"video.fullscreen": "На весь екран",
diff --git a/app/soapbox/normalizers/__tests__/account-test.js b/app/soapbox/normalizers/__tests__/account-test.js
new file mode 100644
index 000000000..f00dd57c5
--- /dev/null
+++ b/app/soapbox/normalizers/__tests__/account-test.js
@@ -0,0 +1,57 @@
+import { fromJS } from 'immutable';
+
+import { normalizeAccount } from '../account';
+
+describe('normalizeAccount()', () => {
+ it('normalizes Fedibird birthday', () => {
+ const account = fromJS(require('soapbox/__fixtures__/fedibird-account.json'));
+ const result = normalizeAccount(account);
+
+ expect(result.get('birthday')).toEqual('1993-07-03');
+ });
+
+ it('normalizes Pleroma birthday', () => {
+ const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json'));
+ const result = normalizeAccount(account);
+
+ expect(result.get('birthday')).toEqual('1993-07-03');
+ });
+
+ it('normalizes Pleroma legacy fields', () => {
+ const account = fromJS(require('soapbox/__fixtures__/pleroma-2.2.2-account.json'));
+ const result = normalizeAccount(account);
+
+ expect(result.getIn(['pleroma', 'is_active'])).toBe(true);
+ expect(result.getIn(['pleroma', 'is_confirmed'])).toBe(true);
+ expect(result.getIn(['pleroma', 'is_approved'])).toBe(true);
+
+ expect(result.hasIn(['pleroma', 'confirmation_pending'])).toBe(false);
+ });
+
+ it('prefers new Pleroma fields', () => {
+ const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json'));
+ const result = normalizeAccount(account);
+
+ expect(result.getIn(['pleroma', 'is_active'])).toBe(true);
+ expect(result.getIn(['pleroma', 'is_confirmed'])).toBe(true);
+ expect(result.getIn(['pleroma', 'is_approved'])).toBe(true);
+ });
+
+ it('normalizes a verified Pleroma user', () => {
+ const account = fromJS(require('soapbox/__fixtures__/mk.json'));
+ const result = normalizeAccount(account);
+ expect(result.get('verified')).toBe(true);
+ });
+
+ it('normalizes an unverified Pleroma user', () => {
+ const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json'));
+ const result = normalizeAccount(account);
+ expect(result.get('verified')).toBe(false);
+ });
+
+ it('normalizes a verified Truth Social user', () => {
+ const account = fromJS(require('soapbox/__fixtures__/realDonaldTrump.json'));
+ const result = normalizeAccount(account);
+ expect(result.get('verified')).toBe(true);
+ });
+});
diff --git a/app/soapbox/normalizers/account.js b/app/soapbox/normalizers/account.js
new file mode 100644
index 000000000..aa49f647f
--- /dev/null
+++ b/app/soapbox/normalizers/account.js
@@ -0,0 +1,47 @@
+import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
+
+import { mergeDefined } from 'soapbox/utils/normalizers';
+
+// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/549
+const normalizePleromaLegacyFields = account => {
+ return account.update('pleroma', ImmutableMap(), pleroma => {
+ return pleroma.withMutations(pleroma => {
+ const legacy = ImmutableMap({
+ is_active: !pleroma.get('deactivated'),
+ is_confirmed: !pleroma.get('confirmation_pending'),
+ is_approved: !pleroma.get('approval_pending'),
+ });
+
+ pleroma.mergeWith(mergeDefined, legacy);
+ pleroma.deleteAll(['deactivated', 'confirmation_pending', 'approval_pending']);
+ });
+ });
+};
+
+// Normalize Pleroma/Fedibird birthday
+const normalizeBirthday = account => {
+ const birthday = [
+ account.getIn(['pleroma', 'birthday']),
+ account.getIn(['other_settings', 'birthday']),
+ ].find(Boolean);
+
+ return account.set('birthday', birthday);
+};
+
+// Normalize Truth Social/Pleroma verified
+const normalizeVerified = account => {
+ return account.update('verified', verified => {
+ return [
+ verified === true,
+ account.getIn(['pleroma', 'tags'], ImmutableList()).includes('verified'),
+ ].some(Boolean);
+ });
+};
+
+export const normalizeAccount = account => {
+ return account.withMutations(account => {
+ normalizePleromaLegacyFields(account);
+ normalizeVerified(account);
+ normalizeBirthday(account);
+ });
+};
diff --git a/app/soapbox/normalizers/instance.js b/app/soapbox/normalizers/instance.js
index d95990670..155f6c8ae 100644
--- a/app/soapbox/normalizers/instance.js
+++ b/app/soapbox/normalizers/instance.js
@@ -1,6 +1,7 @@
import { Map as ImmutableMap } from 'immutable';
import { parseVersion, PLEROMA } from 'soapbox/utils/features';
+import { mergeDefined } from 'soapbox/utils/normalizers';
import { isNumber } from 'soapbox/utils/numbers';
// Use Mastodon defaults
@@ -36,9 +37,6 @@ const pleromaToMastodonConfig = instance => {
});
};
-// Use new value only if old value is undefined
-const mergeDefined = (oldVal, newVal) => oldVal === undefined ? newVal : oldVal;
-
// Get the software's default attachment limit
const getAttachmentLimit = software => software === PLEROMA ? Infinity : 4;
diff --git a/app/soapbox/normalizers/status.js b/app/soapbox/normalizers/status.js
index 8927546e8..ab6ce6312 100644
--- a/app/soapbox/normalizers/status.js
+++ b/app/soapbox/normalizers/status.js
@@ -1,6 +1,7 @@
import { Map as ImmutableMap, List as ImmutableList } from 'immutable';
import { accountToMention } from 'soapbox/utils/accounts';
+import { mergeDefined } from 'soapbox/utils/normalizers';
// Some backends can return null, or omit these required fields
const baseStatus = ImmutableMap({
@@ -40,9 +41,6 @@ const basePoll = ImmutableMap({
votes_count: 0,
});
-// Merger function for only overriding undefined values
-const mergeDefined = (oldVal, newVal) => oldVal === undefined ? newVal : oldVal;
-
// Merge base status
const mergeBase = status => {
return status.mergeDeepWith(mergeDefined, baseStatus);
diff --git a/app/soapbox/reducers/accounts.js b/app/soapbox/reducers/accounts.js
index c8b52dd37..c3cbcb9d6 100644
--- a/app/soapbox/reducers/accounts.js
+++ b/app/soapbox/reducers/accounts.js
@@ -30,7 +30,7 @@ import {
import { CHATS_FETCH_SUCCESS, CHATS_EXPAND_SUCCESS, CHAT_FETCH_SUCCESS } from 'soapbox/actions/chats';
import { normalizeAccount as normalizeAccount2 } from 'soapbox/actions/importer/normalizer';
import { STREAMING_CHAT_UPDATE } from 'soapbox/actions/streaming';
-import { normalizePleromaUserFields } from 'soapbox/utils/pleroma';
+import { normalizeAccount } from 'soapbox/normalizers/account';
import {
ACCOUNT_IMPORT,
@@ -40,27 +40,23 @@ import {
const initialState = ImmutableMap();
-const normalizePleroma = account => {
- if (!account.pleroma) return account;
- account.pleroma = normalizePleromaUserFields(account.pleroma);
- delete account.pleroma.chat_token;
- return account;
-};
-
-const normalizeAccount = (state, account) => {
- const normalized = fromJS(normalizePleroma(account)).deleteAll([
+const minifyAccount = account => {
+ return account.deleteAll([
'followers_count',
'following_count',
'statuses_count',
'source',
]);
+};
+const fixAccount = (state, account) => {
+ const normalized = minifyAccount(normalizeAccount(fromJS(account)));
return state.set(account.id, normalized);
};
const normalizeAccounts = (state, accounts) => {
accounts.forEach(account => {
- state = normalizeAccount(state, account);
+ state = fixAccount(state, account);
});
return state;
@@ -68,7 +64,7 @@ const normalizeAccounts = (state, accounts) => {
const importAccountFromChat = (state, chat) =>
// TODO: Fix this monstrosity
- normalizeAccount(state, normalizeAccount2(chat.account));
+ fixAccount(state, normalizeAccount2(chat.account));
const importAccountsFromChats = (state, chats) =>
state.withMutations(mutable =>
@@ -202,7 +198,7 @@ const setSuggested = (state, accountIds, isSuggested) => {
export default function accounts(state = initialState, action) {
switch(action.type) {
case ACCOUNT_IMPORT:
- return normalizeAccount(state, action.account);
+ return fixAccount(state, action.account);
case ACCOUNTS_IMPORT:
return normalizeAccounts(state, action.accounts);
case ACCOUNT_FETCH_FAIL_FOR_USERNAME_LOOKUP:
diff --git a/app/soapbox/utils/__tests__/accounts-test.js b/app/soapbox/utils/__tests__/accounts-test.js
index d3fd6f9ba..a9a77ffe1 100644
--- a/app/soapbox/utils/__tests__/accounts-test.js
+++ b/app/soapbox/utils/__tests__/accounts-test.js
@@ -119,7 +119,7 @@ describe('isModerator', () => {
describe('accountToMention', () => {
it('converts the account to a mention', () => {
- const account = fromJS(require('soapbox/__fixtures__/alex.json'));
+ const account = fromJS(require('soapbox/__fixtures__/pleroma-account.json'));
const expected = fromJS({
id: '9v5bmRalQvjOy0ECcC',
diff --git a/app/soapbox/utils/accounts.ts b/app/soapbox/utils/accounts.ts
index a6d418968..2300b4363 100644
--- a/app/soapbox/utils/accounts.ts
+++ b/app/soapbox/utils/accounts.ts
@@ -1,8 +1,4 @@
-import {
- Map as ImmutableMap,
- List as ImmutableList,
- OrderedSet as ImmutableOrderedSet,
-} from 'immutable';
+import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
const getDomainFromURL = (account: ImmutableMap): string => {
try {
@@ -67,11 +63,6 @@ export const isLocal = (account: ImmutableMap): boolean => {
export const isRemote = (account: ImmutableMap): boolean => !isLocal(account);
-export const isVerified = (account: ImmutableMap): boolean => {
- const tags: any = account.getIn(['pleroma', 'tags'], ImmutableList());
- return tags.includes('verified');
-};
-
export const accountToMention = (account: ImmutableMap): ImmutableMap => {
return ImmutableMap({
id: account.get('id'),
diff --git a/app/soapbox/utils/normalizers.js b/app/soapbox/utils/normalizers.js
new file mode 100644
index 000000000..7d205f21c
--- /dev/null
+++ b/app/soapbox/utils/normalizers.js
@@ -0,0 +1,2 @@
+// Use new value only if old value is undefined
+export const mergeDefined = (oldVal, newVal) => oldVal === undefined ? newVal : oldVal;
diff --git a/app/soapbox/utils/pleroma.js b/app/soapbox/utils/pleroma.js
deleted file mode 100644
index dd8937938..000000000
--- a/app/soapbox/utils/pleroma.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// https://gitlab.com/soapbox-pub/soapbox-fe/-/issues/549
-export const normalizePleromaUserFields = obj => {
- obj.is_active = obj.is_active === undefined ? !obj.deactivated : obj.is_active;
- obj.is_confirmed = obj.is_confirmed === undefined ? !obj.confirmation_pending : obj.is_confirmed;
- obj.is_approved = obj.is_approved === undefined ? !obj.approval_pending : obj.is_approved;
- delete obj.deactivated;
- delete obj.confirmation_pending;
- delete obj.approval_pending;
- return obj;
-};