From fc3b9d62a6baac2a902a9e5ebef7c28e945bcca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 30 Dec 2021 16:13:45 +0100 Subject: [PATCH 01/33] Support account subscriptions on Mastodon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/accounts.js | 4 ++-- .../features/account/components/header.js | 20 ++++++++++++++++--- .../account_timeline/components/header.js | 5 +++++ .../containers/header_container.js | 12 +++++++++-- .../ui/components/subscription_button.js | 17 +++++++++++++--- app/soapbox/utils/features.js | 4 ++++ 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index 0aabbb42b..f0db19a5e 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -203,7 +203,7 @@ export function fetchAccountFail(id, error) { }; } -export function followAccount(id, reblogs = true) { +export function followAccount(id, options = { reblogs: true }) { return (dispatch, getState) => { if (!isLoggedIn(getState)) return; @@ -212,7 +212,7 @@ export function followAccount(id, reblogs = true) { dispatch(followAccountRequest(id, locked)); - api(getState).post(`/api/v1/accounts/${id}/follow`, { reblogs }).then(response => { + api(getState).post(`/api/v1/accounts/${id}/follow`, options).then(response => { dispatch(followAccountSuccess(response.data, alreadyFollowing)); }).catch(error => { dispatch(followAccountFail(error, locked)); diff --git a/app/soapbox/features/account/components/header.js b/app/soapbox/features/account/components/header.js index a27271888..cc99b2689 100644 --- a/app/soapbox/features/account/components/header.js +++ b/app/soapbox/features/account/components/header.js @@ -256,7 +256,21 @@ class Header extends ImmutablePureComponent { }); } - if (features.accountSubscriptions) { + if (features.accountNotifies) { + if (account.getIn(['relationship', 'notifying'])) { + menu.push({ + text: intl.formatMessage(messages.unsubscribe, { name: account.get('username') }), + action: this.props.onNotifyToggle, + icon: require('@tabler/icons/icons/bell.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.subscribe, { name: account.get('username') }), + action: this.props.onNotifyToggle, + icon: require('@tabler/icons/icons/bell-off.svg'), + }); + } + } else if (features.accountSubscriptions) { if (account.getIn(['relationship', 'subscribing'])) { menu.push({ text: intl.formatMessage(messages.unsubscribe, { name: account.get('username') }), @@ -550,8 +564,8 @@ class Header extends ImmutablePureComponent { } - {features.accountSubscriptions &&
- + {(features.accountNotifies || features.accountSubscriptions) &&
+
}
diff --git a/app/soapbox/features/account_timeline/components/header.js b/app/soapbox/features/account_timeline/components/header.js index e2b9d3207..c81c31538 100644 --- a/app/soapbox/features/account_timeline/components/header.js +++ b/app/soapbox/features/account_timeline/components/header.js @@ -57,6 +57,10 @@ export default class Header extends ImmutablePureComponent { this.props.onSubscriptionToggle(this.props.account); } + handleNotifyToggle = () => { + this.props.onNotifyToggle(this.props.account); + } + handleMute = () => { this.props.onMute(this.props.account); } @@ -143,6 +147,7 @@ export default class Header extends ImmutablePureComponent { onChat={this.handleChat} onReblogToggle={this.handleReblogToggle} onSubscriptionToggle={this.handleSubscriptionToggle} + onNotifyToggle={this.handleNotifyToggle} onReport={this.handleReport} onMute={this.handleMute} onBlockDomain={this.handleBlockDomain} diff --git a/app/soapbox/features/account_timeline/containers/header_container.js b/app/soapbox/features/account_timeline/containers/header_container.js index 7513232cd..4030822bd 100644 --- a/app/soapbox/features/account_timeline/containers/header_container.js +++ b/app/soapbox/features/account_timeline/containers/header_container.js @@ -112,9 +112,9 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ onReblogToggle(account) { if (account.getIn(['relationship', 'showing_reblogs'])) { - dispatch(followAccount(account.get('id'), false)); + dispatch(followAccount(account.get('id'), { reblogs: false })); } else { - dispatch(followAccount(account.get('id'), true)); + dispatch(followAccount(account.get('id'), { reblogs: true })); } }, @@ -126,6 +126,14 @@ const mapDispatchToProps = (dispatch, { intl }) => ({ } }, + onNotifyToggle(account) { + if (account.getIn(['relationship', 'notifying'])) { + dispatch(followAccount(account.get('id'), { notify: false })); + } else { + dispatch(followAccount(account.get('id'), { notify: true })); + } + }, + // onEndorseToggle(account) { // if (account.getIn(['relationship', 'endorsed'])) { // dispatch(unpinAccount(account.get('id'))); diff --git a/app/soapbox/features/ui/components/subscription_button.js b/app/soapbox/features/ui/components/subscription_button.js index 131f55b9a..137742022 100644 --- a/app/soapbox/features/ui/components/subscription_button.js +++ b/app/soapbox/features/ui/components/subscription_button.js @@ -1,5 +1,6 @@ import React from 'react'; import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { defineMessages, injectIntl } from 'react-intl'; import classNames from 'classnames'; @@ -7,6 +8,7 @@ import Button from 'soapbox/components/button'; import Icon from 'soapbox/components/icon'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { + followAccount, subscribeAccount, unsubscribeAccount, } from 'soapbox/actions/accounts'; @@ -32,6 +34,13 @@ const mapDispatchToProps = (dispatch) => ({ dispatch(subscribeAccount(account.get('id'))); } }, + onNotifyToggle(account) { + if (account.getIn(['relationship', 'notifying'])) { + dispatch(followAccount(account.get('id'), { notify: false })); + } else { + dispatch(followAccount(account.get('id'), { notify: true })); + } + }, }); export default @connect(mapStateToProps, mapDispatchToProps) @@ -40,15 +49,17 @@ class SubscriptionButton extends ImmutablePureComponent { static propTypes = { account: ImmutablePropTypes.map, + features: PropTypes.object.isRequired, }; handleSubscriptionToggle = () => { - this.props.onSubscriptionToggle(this.props.account); + if (this.props.features.accountNotifies) this.props.onNotifyToggle(this.props.account); + else this.props.onSubscriptionToggle(this.props.account); } render() { - const { account, intl } = this.props; - const subscribing = account.getIn(['relationship', 'subscribing']); + const { account, intl, features } = this.props; + const subscribing = features.accountNotifies ? account.getIn(['relationship', 'notifying']) : account.getIn(['relationship', 'subscribing']); const following = account.getIn(['relationship', 'following']); const requested = account.getIn(['relationship', 'requested']); diff --git a/app/soapbox/utils/features.js b/app/soapbox/utils/features.js index 6447f53f7..3c2e15346 100644 --- a/app/soapbox/utils/features.js +++ b/app/soapbox/utils/features.js @@ -64,6 +64,10 @@ export const getFeatures = createSelector([ resetPasswordAPI: v.software === PLEROMA, exposableReactions: features.includes('exposable_reactions'), accountSubscriptions: v.software === PLEROMA && gte(v.version, '1.0.0'), + accountNotifies: any([ + v.software === MASTODON && gte(v.compatVersion, '3.3.0'), + v.software === PLEROMA && gte(v.version, '2.4.50'), + ]), unrestrictedLists: v.software === PLEROMA, accountByUsername: v.software === PLEROMA, profileDirectory: any([ From c89fcb80d24ed35a4a8e487b830da3a6e27554cc Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 14 Jan 2022 21:35:28 +0000 Subject: [PATCH 02/33] Revert "Merge branch 'revert-db7c7b36' into 'develop'" This reverts merge request !989 --- .../features/ui/components/pending_status.js | 54 +++++++++++++++++++ .../ui/util/pending_status_builder.js | 20 ++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/app/soapbox/features/ui/components/pending_status.js b/app/soapbox/features/ui/components/pending_status.js index 847869457..f21bfe010 100644 --- a/app/soapbox/features/ui/components/pending_status.js +++ b/app/soapbox/features/ui/components/pending_status.js @@ -1,6 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import ImmutablePureComponent from 'react-immutable-pure-component'; +import { FormattedMessage, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import { Link, NavLink } from 'react-router-dom'; @@ -29,6 +30,7 @@ const mapStateToProps = (state, props) => { }; export default @connect(mapStateToProps) +@injectIntl class PendingStatus extends ImmutablePureComponent { renderMedia = () => { @@ -47,6 +49,56 @@ class PendingStatus extends ImmutablePureComponent { } } + renderReplyMentions = () => { + const { status } = this.props; + + if (!status.get('in_reply_to_id')) { + return null; + } + + const to = status.get('mentions', []); + + if (to.size === 0) { + if (status.get('in_reply_to_account_id') === status.getIn(['account', 'id'])) { + return ( +
+ @{status.getIn(['account', 'username'])}, + more: false, + }} + /> +
+ ); + } else { + return ( +
+ +
+ ); + } + } + + + return ( +
+ (<> + @{account.username} + {' '} + )), + more: to.size > 2 && , + }} + /> +
+ ); + } + render() { const { status, className } = this.props; if (!status) return null; @@ -84,6 +136,8 @@ class PendingStatus extends ImmutablePureComponent { + {this.renderReplyMentions()} + { const getAccount = makeGetAccount(); + const getStatus = makeGetStatus(); const me = state.get('me'); const account = getAccount(state, me); + let replyToSelf = false; + if (pendingStatus.get('in_reply_to_id')) { + const inReplyTo = getStatus(state, { id: pendingStatus.get('in_reply_to_id') }); + + if (inReplyTo.getIn(['account', 'id']) === me) + replyToSelf = true; + } + const status = normalizeStatus({ account, application: null, @@ -24,7 +34,13 @@ export const buildStatus = (state, pendingStatus, idempotencyKey) => { in_reply_to_id: pendingStatus.get('in_reply_to_id'), language: null, media_attachments: pendingStatus.get('media_ids').map(id => ({ id })), - mentions: [], + mentions: ( + replyToSelf + ? ImmutableOrderedSet([account.get('acct')]).union(pendingStatus.get('to')) + : pendingStatus.get('to') + ).map(mention => ({ + username: mention.split('@')[0], + })), muted: false, pinned: false, poll: pendingStatus.get('poll', null), From 0647394f5f4175687512a78d9f241ee65aac3bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 15 Jan 2022 14:29:32 +0100 Subject: [PATCH 03/33] Fix crash in pending_status_builder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- .../ui/util/pending_status_builder.js | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/app/soapbox/features/ui/util/pending_status_builder.js b/app/soapbox/features/ui/util/pending_status_builder.js index ea3cb92ca..912e19015 100644 --- a/app/soapbox/features/ui/util/pending_status_builder.js +++ b/app/soapbox/features/ui/util/pending_status_builder.js @@ -11,12 +11,19 @@ export const buildStatus = (state, pendingStatus, idempotencyKey) => { const me = state.get('me'); const account = getAccount(state, me); - let replyToSelf = false; + let mentions; if (pendingStatus.get('in_reply_to_id')) { const inReplyTo = getStatus(state, { id: pendingStatus.get('in_reply_to_id') }); - if (inReplyTo.getIn(['account', 'id']) === me) - replyToSelf = true; + if (inReplyTo.getIn(['account', 'id']) === me) { + mentions = ImmutableOrderedSet([account.get('acct')]).union(pendingStatus.get('to', [])); + } else { + mentions = pendingStatus.get('to', []); + } + + mentions = mentions.map(mention => ({ + username: mention.split('@')[0], + })); } const status = normalizeStatus({ @@ -34,13 +41,7 @@ export const buildStatus = (state, pendingStatus, idempotencyKey) => { in_reply_to_id: pendingStatus.get('in_reply_to_id'), language: null, media_attachments: pendingStatus.get('media_ids').map(id => ({ id })), - mentions: ( - replyToSelf - ? ImmutableOrderedSet([account.get('acct')]).union(pendingStatus.get('to')) - : pendingStatus.get('to') - ).map(mention => ({ - username: mention.split('@')[0], - })), + mentions, muted: false, pinned: false, poll: pendingStatus.get('poll', null), From 5e76b5afca3fb3ffa308b766b855a84a29a19811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 19 Jan 2022 21:43:03 +0100 Subject: [PATCH 04/33] Birth dates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/features/edit_profile/index.js | 46 ++++++++++++++++++- .../ui/components/profile_info_panel.js | 10 ++++ app/soapbox/utils/features.js | 1 + app/styles/components/profile-info-panel.scss | 3 +- app/styles/forms.scss | 37 +++++++++++++++ package.json | 2 +- yarn.lock | 8 ++-- 7 files changed, 99 insertions(+), 8 deletions(-) diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index f38197653..0a3dad66b 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -5,10 +5,12 @@ import { import { unescape } from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; +import DatePicker from 'react-datepicker'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; +import 'react-datepicker/dist/react-datepicker.css'; import { updateNotificationSettings } from 'soapbox/actions/accounts'; import { patchMe } from 'soapbox/actions/me'; @@ -49,6 +51,7 @@ const messages = defineMessages({ error: { id: 'edit_profile.error', defaultMessage: 'Profile update failed' }, bioPlaceholder: { id: 'edit_profile.fields.bio_placeholder', defaultMessage: 'Tell us about yourself.' }, displayNamePlaceholder: { id: 'edit_profile.fields.display_name_placeholder', defaultMessage: 'Name' }, + birthDatePlaceholder: { id: 'edit_profile.fields.birth_date_placeholder', defaultMessage: 'Your birth date' }, }); const makeMapStateToProps = () => { @@ -58,12 +61,15 @@ const makeMapStateToProps = () => { const me = state.get('me'); const account = getAccount(state, me); const soapbox = getSoapboxConfig(state); + const features = getFeatures(state.get('instance')); return { account, maxFields: state.getIn(['instance', 'pleroma', 'metadata', 'fields_limits', 'max_fields'], 4), verifiedCanEditName: soapbox.get('verifiedCanEditName'), - supportsEmailList: getFeatures(state.get('instance')).emailList, + supportsEmailList: features.emailList, + supportsBirthDates: features.birthDates, + minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_min_age']), }; }; @@ -94,6 +100,9 @@ class EditProfile extends ImmutablePureComponent { account: ImmutablePropTypes.map, maxFields: PropTypes.number, verifiedCanEditName: PropTypes.bool, + supportsEmailList: PropTypes.bool, + supportsBirthDates: PropTypes.bool, + minAge: PropTypes.number, }; state = { @@ -107,6 +116,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 birthDate = account.getIn(['pleroma', 'birth_date']); const initialState = account.withMutations(map => { map.merge(map.get('source')); @@ -116,6 +126,7 @@ class EditProfile extends ImmutablePureComponent { map.set('accepts_email_list', acceptsEmailList); map.set('hide_network', hidesNetwork(account)); map.set('discoverable', discoverable); + if (birthDate) map.set('birthDate', new Date(birthDate)); unescapeParams(map, ['display_name', 'bio']); }); @@ -156,6 +167,7 @@ class EditProfile extends ImmutablePureComponent { hide_follows: state.hide_network, hide_followers_count: state.hide_network, hide_follows_count: state.hide_network, + birth_date: state.birthDate?.toISOString().slice(0, 10), }, this.getFieldParams().toJS()); } @@ -223,6 +235,12 @@ class EditProfile extends ImmutablePureComponent { }; } + handleBirthDateChange = (birthDate) => { + this.setState({ + birthDate, + }); + } + handleAddField = () => { this.setState({ fields: this.state.fields.push(ImmutableMap({ name: '', value: '' })), @@ -237,8 +255,15 @@ class EditProfile extends ImmutablePureComponent { }; } + isDateValid = date => { + const { minAge } = this.props; + const allowedDate = new Date(); + allowedDate.setDate(allowedDate.getDate() - minAge); + return date && allowedDate.setHours(0, 0, 0, 0) >= new Date(date).setHours(0, 0, 0, 0); + } + render() { - const { intl, maxFields, account, verifiedCanEditName, supportsEmailList } = this.props; + const { intl, maxFields, account, verifiedCanEditName, supportsEmailList, supportsBirthDates } = this.props; const verified = isVerified(account); const canEditName = verifiedCanEditName || !verified; @@ -267,6 +292,23 @@ class EditProfile extends ImmutablePureComponent { onChange={this.handleTextChange} rows={3} /> + {supportsBirthDates && ( +
+
+ +
+
+ +
+
+ )}
diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index 74dd9a187..f2af515f5 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -103,6 +103,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 birthDate = account.getIn(['pleroma', 'birth_date']) && intl.formatDate(account.getIn(['pleroma', 'birth_date']), { day: 'numeric', month: 'long', year: 'numeric' }); const verified = isVerified(account); const badges = this.getBadges(); @@ -150,6 +151,15 @@ class ProfileInfoPanel extends ImmutablePureComponent { />
} + {birthDate &&
+ + +
} + Date: Wed, 19 Jan 2022 23:59:10 +0100 Subject: [PATCH 05/33] Show birth date field on registration page when required MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birth_date_input.js | 71 +++++++++++++++++++ .../components/registration_form.js | 24 ++++++- app/soapbox/features/edit_profile/index.js | 48 +++++-------- app/styles/forms.scss | 1 + package.json | 2 +- yarn.lock | 28 ++++---- 6 files changed, 127 insertions(+), 47 deletions(-) create mode 100644 app/soapbox/components/birth_date_input.js diff --git a/app/soapbox/components/birth_date_input.js b/app/soapbox/components/birth_date_input.js new file mode 100644 index 000000000..5183973d6 --- /dev/null +++ b/app/soapbox/components/birth_date_input.js @@ -0,0 +1,71 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import DatePicker from 'react-datepicker'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl } from 'react-intl'; +import { connect } from 'react-redux'; +import 'react-datepicker/dist/react-datepicker.css'; + +import { getFeatures } from 'soapbox/utils/features'; + +const messages = defineMessages({ + birthDatePlaceholder: { id: 'edit_profile.fields.birth_date_placeholder', defaultMessage: 'Your birth date' }, +}); + +const mapStateToProps = state => { + const features = getFeatures(state.get('instance')); + + return { + supportsBirthDates: features.birthDates, + minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_min_age']), + }; +}; + +export default @connect(mapStateToProps) +@injectIntl +class EditProfile extends ImmutablePureComponent { + + static propTypes = { + hint: PropTypes.node, + required: PropTypes.bool, + supportsBirthDates: PropTypes.bool, + minAge: PropTypes.number, + onChange: PropTypes.func.isRequired, + value: PropTypes.instanceOf(Date), + }; + + isDateValid = date => { + const { minAge } = this.props; + const allowedDate = new Date(); + allowedDate.setDate(allowedDate.getDate() - minAge); + return date && allowedDate.setHours(0, 0, 0, 0) >= new Date(date).setHours(0, 0, 0, 0); + } + + render() { + const { intl, value, onChange, supportsBirthDates, hint, required } = this.props; + + if (!supportsBirthDates) return null; + + return ( +
+ {hint && ( +
+ {hint} +
+ )} +
+ +
+
+ ); + } + +} \ No newline at end of file diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index d9226f505..8b6ceb3a9 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -14,6 +14,7 @@ import { accountLookup } from 'soapbox/actions/accounts'; import { register, verifyCredentials } from 'soapbox/actions/auth'; import { openModal } from 'soapbox/actions/modal'; import { getSettings } from 'soapbox/actions/settings'; +import BirthDateInput from 'soapbox/components/birth_date_input'; import ShowablePassword from 'soapbox/components/showable_password'; import CaptchaField from 'soapbox/features/auth_login/components/captcha'; import { @@ -46,6 +47,7 @@ const mapStateToProps = (state, props) => ({ needsApproval: state.getIn(['instance', 'approval_required']), supportsEmailList: getFeatures(state.get('instance')).emailList, supportsAccountLookup: getFeatures(state.get('instance')).accountLookup, + birthDateRequired: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_required']), }); export default @connect(mapStateToProps) @@ -61,6 +63,7 @@ class RegistrationForm extends ImmutablePureComponent { supportsEmailList: PropTypes.bool, supportsAccountLookup: PropTypes.bool, inviteToken: PropTypes.string, + birthDateRequired: PropTypes.bool, } static contextTypes = { @@ -129,6 +132,12 @@ class RegistrationForm extends ImmutablePureComponent { this.setState({ passwordMismatch: !this.passwordsMatch() }); } + onBirthDateChange = birthDate => { + this.setState({ + birthDate, + }); + } + launchModal = () => { const { dispatch, intl, needsConfirmation, needsApproval } = this.props; @@ -197,6 +206,7 @@ class RegistrationForm extends ImmutablePureComponent { onSubmit = e => { const { dispatch, inviteToken } = this.props; + const { birthDate } = this.state; if (!this.passwordsMatch()) { this.setState({ passwordMismatch: true }); @@ -211,6 +221,10 @@ class RegistrationForm extends ImmutablePureComponent { if (inviteToken) { params.set('token', inviteToken); } + + if (birthDate) { + params.set('birth_date', birthDate.toISOString().slice(0, 10)); + } }); this.setState({ submissionLoading: true }); @@ -245,8 +259,8 @@ class RegistrationForm extends ImmutablePureComponent { } render() { - const { instance, intl, supportsEmailList } = this.props; - const { params, usernameUnavailable, passwordConfirmation, passwordMismatch } = this.state; + const { instance, intl, supportsEmailList, birthDateRequired } = this.props; + const { params, usernameUnavailable, passwordConfirmation, passwordMismatch, birthDate } = this.state; const isLoading = this.state.captchaLoading || this.state.submissionLoading; return ( @@ -311,6 +325,12 @@ class RegistrationForm extends ImmutablePureComponent { error={passwordMismatch === true} required /> + {!birthDateRequired && + } {instance.get('approval_required') && } diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index 0a3dad66b..f055d601e 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -5,17 +5,16 @@ import { import { unescape } from 'lodash'; import PropTypes from 'prop-types'; import React from 'react'; -import DatePicker from 'react-datepicker'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import { connect } from 'react-redux'; -import 'react-datepicker/dist/react-datepicker.css'; import { updateNotificationSettings } from 'soapbox/actions/accounts'; import { patchMe } from 'soapbox/actions/me'; import snackbar from 'soapbox/actions/snackbar'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; +import BirthDateInput from 'soapbox/components/birth_date_input'; import Icon from 'soapbox/components/icon'; import { SimpleForm, @@ -69,7 +68,6 @@ const makeMapStateToProps = () => { verifiedCanEditName: soapbox.get('verifiedCanEditName'), supportsEmailList: features.emailList, supportsBirthDates: features.birthDates, - minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_min_age']), }; }; @@ -102,7 +100,6 @@ class EditProfile extends ImmutablePureComponent { verifiedCanEditName: PropTypes.bool, supportsEmailList: PropTypes.bool, supportsBirthDates: PropTypes.bool, - minAge: PropTypes.number, }; state = { @@ -117,6 +114,7 @@ class EditProfile extends ImmutablePureComponent { const acceptsEmailList = account.getIn(['pleroma', 'accepts_email_list']); const discoverable = account.getIn(['source', 'pleroma', 'discoverable']); const birthDate = account.getIn(['pleroma', 'birth_date']); + const hideBirthDate = account.getIn(['pleroma', 'hide_birth_date']); const initialState = account.withMutations(map => { map.merge(map.get('source')); @@ -126,6 +124,7 @@ class EditProfile extends ImmutablePureComponent { map.set('accepts_email_list', acceptsEmailList); map.set('hide_network', hidesNetwork(account)); map.set('discoverable', discoverable); + map.set('hide_birth_date', hideBirthDate); if (birthDate) map.set('birthDate', new Date(birthDate)); unescapeParams(map, ['display_name', 'bio']); }); @@ -168,6 +167,7 @@ class EditProfile extends ImmutablePureComponent { hide_followers_count: state.hide_network, hide_follows_count: state.hide_network, birth_date: state.birthDate?.toISOString().slice(0, 10), + hide_birth_date: state.hide_birth_date, }, this.getFieldParams().toJS()); } @@ -235,7 +235,7 @@ class EditProfile extends ImmutablePureComponent { }; } - handleBirthDateChange = (birthDate) => { + handleBirthDateChange = birthDate => { this.setState({ birthDate, }); @@ -255,15 +255,8 @@ class EditProfile extends ImmutablePureComponent { }; } - isDateValid = date => { - const { minAge } = this.props; - const allowedDate = new Date(); - allowedDate.setDate(allowedDate.getDate() - minAge); - return date && allowedDate.setHours(0, 0, 0, 0) >= new Date(date).setHours(0, 0, 0, 0); - } - render() { - const { intl, maxFields, account, verifiedCanEditName, supportsEmailList, supportsBirthDates } = this.props; + const { intl, maxFields, account, verifiedCanEditName, supportsBirthDates, supportsEmailList } = this.props; const verified = isVerified(account); const canEditName = verifiedCanEditName || !verified; @@ -292,23 +285,11 @@ class EditProfile extends ImmutablePureComponent { onChange={this.handleTextChange} rows={3} /> - {supportsBirthDates && ( -
-
- -
-
- -
-
- )} + } + value={this.state.birthDate} + onChange={this.handleBirthDateChange} + />
@@ -363,6 +344,13 @@ class EditProfile extends ImmutablePureComponent { checked={this.state.discoverable} onChange={this.handleCheckboxChange} /> + {supportsBirthDates && } + hint={} + name='hide_birth_date' + checked={this.state.hide_birth_date} + onChange={this.handleCheckboxChange} + />} {supportsEmailList && } hint={} diff --git a/app/styles/forms.scss b/app/styles/forms.scss index 55daca384..9c46a965f 100644 --- a/app/styles/forms.scss +++ b/app/styles/forms.scss @@ -638,6 +638,7 @@ code { .datepicker { padding: 0; margin-bottom: 8px; + border: none; &__hint { padding-bottom: 0; diff --git a/package.json b/package.json index 72ad7dfb5..2706765e6 100644 --- a/package.json +++ b/package.json @@ -118,7 +118,7 @@ "qrcode.react": "^1.0.0", "react": "^16.13.1", "react-color": "^2.18.1", - "react-datepicker": "^4.1.1", + "react-datepicker": "^4.6.0", "react-dom": "^16.13.1", "react-helmet": "^6.0.0", "react-hotkeys": "^1.1.4", diff --git a/yarn.lock b/yarn.lock index 48f6a651c..53ae2f599 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3292,10 +3292,10 @@ data-urls@^2.0.0: whatwg-mimetype "^2.3.0" whatwg-url "^8.0.0" -date-fns@^2.0.1: - version "2.23.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9" - integrity sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA== +date-fns@^2.24.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" + integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== debug@2.6.9, debug@^2.6.9: version "2.6.9" @@ -7820,16 +7820,16 @@ react-color@^2.18.1: reactcss "^1.2.0" tinycolor2 "^1.4.1" -react-datepicker@^4.1.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.2.1.tgz#72caf5055bc7c4eb0279c1f6d7624ded053edc4c" - integrity sha512-0gcvHMnX8rS1fV90PjjsB7MQdsWNU77JeVHf6bbwK9HnFxgwjVflTx40ebKmHV+leqe+f+FgUP9Nvqbe5RGyfA== +react-datepicker@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.6.0.tgz#10fc7c5b9c72df5c3e29712d559cb3fe73fd9f62" + integrity sha512-JGSQnQSQYUkS7zvSaZuyHv5lxp3wMrN7GXV0VA0E9Ax9fL3Bb6E1pSXjL6C3WoeuV8dt/mItQfRkPpRGCrl/OA== dependencies: "@popperjs/core" "^2.9.2" classnames "^2.2.6" - date-fns "^2.0.1" + date-fns "^2.24.0" prop-types "^15.7.2" - react-onclickoutside "^6.10.0" + react-onclickoutside "^6.12.0" react-popper "^2.2.5" react-dom@^16.13.1: @@ -7959,10 +7959,10 @@ react-notification@^6.8.4: dependencies: prop-types "^15.6.2" -react-onclickoutside@^6.10.0: - version "6.12.0" - resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.0.tgz#c63db2e3c2c852b288160cdb6cff443604e28db4" - integrity sha512-oPlOTYcISLHfpMog2lUZMFSbqOs4LFcA4+vo7fpfevB5v9Z0D5VBDBkfeO5lv+hpEcGoaGk67braLT+QT+eICA== +react-onclickoutside@^6.12.0: + version "6.12.1" + resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz#92dddd28f55e483a1838c5c2930e051168c1e96b" + integrity sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q== react-overlays@^0.9.0: version "0.9.3" From d6f0023cc90a237bf06cda9ef8b71f2128217cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 20 Jan 2022 22:28:49 +0100 Subject: [PATCH 06/33] Add birthday reminder notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/accounts.js | 27 ++++ app/soapbox/actions/settings.js | 4 + app/soapbox/components/birthday_reminders.js | 118 ++++++++++++++++++ .../components/column_settings.js | 15 ++- .../containers/column_settings_container.js | 1 + app/soapbox/features/notifications/index.js | 30 +++-- .../features/ui/components/birthdays_modal.js | 97 ++++++++++++++ .../features/ui/components/modal_root.js | 2 + .../features/ui/util/async-components.js | 4 + app/soapbox/reducers/user_lists.js | 4 + app/styles/components/notification.scss | 15 +++ docs/store.md | 3 + 12 files changed, 310 insertions(+), 10 deletions(-) create mode 100644 app/soapbox/components/birthday_reminders.js create mode 100644 app/soapbox/features/ui/components/birthdays_modal.js diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index aacdcd106..e0bcbd46c 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -109,6 +109,10 @@ export const NOTIFICATION_SETTINGS_REQUEST = 'NOTIFICATION_SETTINGS_REQUEST'; export const NOTIFICATION_SETTINGS_SUCCESS = 'NOTIFICATION_SETTINGS_SUCCESS'; export const NOTIFICATION_SETTINGS_FAIL = 'NOTIFICATION_SETTINGS_FAIL'; +export const BIRTHDAY_REMINDERS_FETCH_REQUEST = 'BIRTHDAY_REMINDERS_FETCH_REQUEST'; +export const BIRTHDAY_REMINDERS_FETCH_SUCCESS = 'BIRTHDAY_REMINDERS_FETCH_SUCCESS'; +export const BIRTHDAY_REMINDERS_FETCH_FAIL = 'BIRTHDAY_REMINDERS_FETCH_FAIL'; + export function createAccount(params) { return (dispatch, getState) => { dispatch({ type: ACCOUNT_CREATE_REQUEST, params }); @@ -1030,3 +1034,26 @@ export function accountLookup(acct, cancelToken) { }); }; } + +export function fetchBirthdayReminders(day, month) { + return (dispatch, getState) => { + if (!isLoggedIn(getState)) return; + + const me = getState().get('me'); + + dispatch({ type: BIRTHDAY_REMINDERS_FETCH_REQUEST, day, month, id: me }); + + api(getState).get('/api/v1/pleroma/birthday_reminders', { params: { day, month } }).then(response => { + dispatch(importFetchedAccounts(response.data)); + dispatch({ + type: BIRTHDAY_REMINDERS_FETCH_SUCCESS, + accounts: response.data, + day, + month, + id: me, + }); + }).catch(error => { + dispatch({ type: BIRTHDAY_REMINDERS_FETCH_FAIL, day, month, id: me }); + }); + }; +} diff --git a/app/soapbox/actions/settings.js b/app/soapbox/actions/settings.js index 4a50909fa..418c41292 100644 --- a/app/soapbox/actions/settings.js +++ b/app/soapbox/actions/settings.js @@ -100,6 +100,10 @@ export const defaultSettings = ImmutableMap({ move: false, 'pleroma:emoji_reaction': false, }), + + birthdays: ImmutableMap({ + show: true, + }), }), community: ImmutableMap({ diff --git a/app/soapbox/components/birthday_reminders.js b/app/soapbox/components/birthday_reminders.js new file mode 100644 index 000000000..a00a1ba33 --- /dev/null +++ b/app/soapbox/components/birthday_reminders.js @@ -0,0 +1,118 @@ + +import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { injectIntl, FormattedMessage } from 'react-intl'; +import { connect } from 'react-redux'; +import { Link } from 'react-router-dom'; + +import { fetchBirthdayReminders } from 'soapbox/actions/accounts'; +import { openModal } from 'soapbox/actions/modal'; +import Icon from 'soapbox/components/icon'; +import { makeGetAccount } from 'soapbox/selectors'; + +const mapStateToProps = (state, props) => { + const me = state.get('me'); + const getAccount = makeGetAccount(); + + const birthdays = state.getIn(['user_lists', 'birthday_reminders', me]); + + if (birthdays && birthdays.size > 0) { + return { + birthdays, + account: getAccount(state, birthdays.first()), + }; + } + + return { + birthdays, + }; +}; + +export default @connect(mapStateToProps) +@injectIntl +class BirthdayReminders extends ImmutablePureComponent { + + static propTypes = { + birthdays: ImmutablePropTypes.orderedSet, + intl: PropTypes.object.isRequired, + dispatch: PropTypes.func.isRequired, + }; + + componentDidMount() { + const { dispatch } = this.props; + + const date = new Date(); + + const day = date.getDate(); + const month = date.getMonth() + 1; + + dispatch(fetchBirthdayReminders(day, month)); + } + + handleOpenBirthdaysModal = () => { + const { dispatch } = this.props; + + dispatch(openModal('BIRTHDAYS')); + } + + renderMessage() { + const { birthdays, account } = this.props; + + const link = ( + + + + ); + + if (birthdays.size === 1) { + return ; + } + + return ( + + + + ), + }} + /> + ); + } + + render() { + const { birthdays } = this.props; + + if (!birthdays || birthdays.size === 0) return null; + + return ( +
+
+
+ +
+ + + {this.renderMessage()} + +
+
+ ); + } + +} \ No newline at end of file diff --git a/app/soapbox/features/notifications/components/column_settings.js b/app/soapbox/features/notifications/components/column_settings.js index e033eb6be..39dd79836 100644 --- a/app/soapbox/features/notifications/components/column_settings.js +++ b/app/soapbox/features/notifications/components/column_settings.js @@ -24,6 +24,7 @@ class ColumnSettings extends React.PureComponent { onClear: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, supportsEmojiReacts: PropTypes.bool, + supportsBirthDates: PropTypes.bool, }; onPushChange = (path, checked) => { @@ -39,7 +40,7 @@ class ColumnSettings extends React.PureComponent { } render() { - const { intl, settings, pushSettings, onChange, onClear, onClose, supportsEmojiReacts } = this.props; + const { intl, settings, pushSettings, onChange, onClear, onClose, supportsEmojiReacts, supportsBirthDates } = this.props; const filterShowStr = ; const filterAdvancedStr = ; @@ -50,6 +51,7 @@ class ColumnSettings extends React.PureComponent { const soundSettings = [['sounds', 'follow'], ['sounds', 'favourite'], ['sounds', 'pleroma:emoji_reaction'], ['sounds', 'mention'], ['sounds', 'reblog'], ['sounds', 'poll'], ['sounds', 'move']]; const showPushSettings = pushSettings.get('browserSupport') && pushSettings.get('isSubscribed'); const pushStr = showPushSettings && ; + const birthdaysStr = ; return (
@@ -84,6 +86,17 @@ class ColumnSettings extends React.PureComponent {
+ {supportsBirthDates && +
+ + + +
+ +
+
+ } +
diff --git a/app/soapbox/features/notifications/containers/column_settings_container.js b/app/soapbox/features/notifications/containers/column_settings_container.js index da37f306f..05dc1f0eb 100644 --- a/app/soapbox/features/notifications/containers/column_settings_container.js +++ b/app/soapbox/features/notifications/containers/column_settings_container.js @@ -24,6 +24,7 @@ const mapStateToProps = state => { settings: getSettings(state).get('notifications'), pushSettings: state.get('push_notifications'), supportsEmojiReacts: features.emojiReacts, + supportsBirthDates: features.birthDates, }; }; diff --git a/app/soapbox/features/notifications/index.js b/app/soapbox/features/notifications/index.js index b174d776e..57edf8315 100644 --- a/app/soapbox/features/notifications/index.js +++ b/app/soapbox/features/notifications/index.js @@ -8,8 +8,10 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { getSettings } from 'soapbox/actions/settings'; +import BirthdayReminders from 'soapbox/components/birthday_reminders'; import SubNavigation from 'soapbox/components/sub_navigation'; import PlaceholderNotification from 'soapbox/features/placeholder/components/placeholder_notification'; +import { getFeatures } from 'soapbox/utils/features'; import { expandNotifications, @@ -45,14 +47,21 @@ const getNotifications = createSelector([ return notifications.filter(item => item !== null && allowedType === item.get('type')); }); -const mapStateToProps = state => ({ - showFilterBar: getSettings(state).getIn(['notifications', 'quickFilter', 'show']), - notifications: getNotifications(state), - isLoading: state.getIn(['notifications', 'isLoading'], true), - isUnread: state.getIn(['notifications', 'unread']) > 0, - hasMore: state.getIn(['notifications', 'hasMore']), - totalQueuedNotificationsCount: state.getIn(['notifications', 'totalQueuedNotificationsCount'], 0), -}); +const mapStateToProps = state => { + const settings = getSettings(state); + const instance = state.get('instance'); + const features = getFeatures(instance); + + return { + showFilterBar: settings.getIn(['notifications', 'quickFilter', 'show']), + notifications: getNotifications(state), + isLoading: state.getIn(['notifications', 'isLoading'], true), + isUnread: state.getIn(['notifications', 'unread']) > 0, + hasMore: state.getIn(['notifications', 'hasMore']), + totalQueuedNotificationsCount: state.getIn(['notifications', 'totalQueuedNotificationsCount'], 0), + showBirthdayReminders: settings.getIn(['notifications', 'birthdays', 'show']) && settings.getIn(['notifications', 'quickFilter', 'active']) === 'all' && features.birthDates, + }; +}; export default @connect(mapStateToProps) @injectIntl @@ -68,6 +77,7 @@ class Notifications extends React.PureComponent { hasMore: PropTypes.bool, dequeueNotifications: PropTypes.func, totalQueuedNotificationsCount: PropTypes.number, + showBirthdayReminders: PropTypes.bool, }; componentWillUnmount() { @@ -137,7 +147,7 @@ class Notifications extends React.PureComponent { } render() { - const { intl, notifications, isLoading, hasMore, showFilterBar, totalQueuedNotificationsCount } = this.props; + const { intl, notifications, isLoading, hasMore, showFilterBar, totalQueuedNotificationsCount, showBirthdayReminders } = this.props; const emptyMessage = ; let scrollableContent = null; @@ -164,6 +174,8 @@ class Notifications extends React.PureComponent { onMoveDown={this.handleMoveDown} /> )); + + if (showBirthdayReminders) scrollableContent = scrollableContent.unshift(); } else { scrollableContent = null; } diff --git a/app/soapbox/features/ui/components/birthdays_modal.js b/app/soapbox/features/ui/components/birthdays_modal.js new file mode 100644 index 000000000..995ad5cc5 --- /dev/null +++ b/app/soapbox/features/ui/components/birthdays_modal.js @@ -0,0 +1,97 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import { injectIntl, FormattedMessage, defineMessages } from 'react-intl'; +import { connect } from 'react-redux'; + +import IconButton from 'soapbox/components/icon_button'; +import LoadingIndicator from 'soapbox/components/loading_indicator'; +import ScrollableList from 'soapbox/components/scrollable_list'; +import AccountContainer from 'soapbox/containers/account_container'; + +const messages = defineMessages({ + close: { id: 'lightbox.close', defaultMessage: 'Close' }, +}); + +const mapStateToProps = (state) => { + const me = state.get('me'); + + return { + accountIds: state.getIn(['user_lists', 'birthday_reminders', me]), + }; +}; + +export default @connect(mapStateToProps) +@injectIntl +class BirthdaysModal extends React.PureComponent { + + static contextTypes = { + router: PropTypes.object, + }; + + static propTypes = { + onClose: PropTypes.func.isRequired, + intl: PropTypes.object.isRequired, + accountIds: ImmutablePropTypes.orderedSet, + }; + + componentDidMount() { + this.unlistenHistory = this.context.router.history.listen((_, action) => { + if (action === 'PUSH') { + this.onClickClose(null, true); + } + }); + } + + componentWillUnmount() { + if (this.unlistenHistory) { + this.unlistenHistory(); + } + } + + onClickClose = (_, noPop) => { + this.props.onClose('BIRTHDAYS', noPop); + }; + + render() { + const { intl, accountIds } = this.props; + + let body; + + if (!accountIds) { + body = ; + } else { + const emptyMessage = ; + + body = ( + + {accountIds.map(id => + , + )} + + ); + } + + + return ( +
+
+

+ +

+ +
+ {body} +
+ ); + } + +} diff --git a/app/soapbox/features/ui/components/modal_root.js b/app/soapbox/features/ui/components/modal_root.js index 5425cf5eb..1cc6304c6 100644 --- a/app/soapbox/features/ui/components/modal_root.js +++ b/app/soapbox/features/ui/components/modal_root.js @@ -26,6 +26,7 @@ import { FavouritesModal, ReblogsModal, MentionsModal, + BirthdaysModal, } from '../../../features/ui/util/async-components'; import BundleContainer from '../containers/bundle_container'; @@ -57,6 +58,7 @@ const MODAL_COMPONENTS = { 'FAVOURITES': FavouritesModal, 'REACTIONS': ReactionsModal, 'MENTIONS': MentionsModal, + 'BIRTHDAYS': BirthdaysModal, }; export default class ModalRoot extends React.PureComponent { diff --git a/app/soapbox/features/ui/util/async-components.js b/app/soapbox/features/ui/util/async-components.js index 08a223f90..7111a43c5 100644 --- a/app/soapbox/features/ui/util/async-components.js +++ b/app/soapbox/features/ui/util/async-components.js @@ -214,6 +214,10 @@ export function MentionsModal() { return import(/* webpackChunkName: "features/ui" */'../components/mentions_modal'); } +export function BirthdaysModal() { + return import(/* webpackChunkName: "features/ui" */'../components/birthdays_modal'); +} + export function ListEditor() { return import(/* webpackChunkName: "features/list_editor" */'../../list_editor'); } diff --git a/app/soapbox/reducers/user_lists.js b/app/soapbox/reducers/user_lists.js index 2b9feaaa2..076144f75 100644 --- a/app/soapbox/reducers/user_lists.js +++ b/app/soapbox/reducers/user_lists.js @@ -10,6 +10,7 @@ import { FOLLOW_REQUEST_AUTHORIZE_SUCCESS, FOLLOW_REQUEST_REJECT_SUCCESS, PINNED_ACCOUNTS_FETCH_SUCCESS, + BIRTHDAY_REMINDERS_FETCH_SUCCESS, } from '../actions/accounts'; import { BLOCKS_FETCH_SUCCESS, @@ -55,6 +56,7 @@ const initialState = ImmutableMap({ groups: ImmutableMap(), groups_removed_accounts: ImmutableMap(), pinned: ImmutableMap(), + birthday_reminders: ImmutableMap(), }); const normalizeList = (state, type, id, accounts, next) => { @@ -131,6 +133,8 @@ export default function userLists(state = initialState, action) { return state.updateIn(['groups_removed_accounts', action.groupId, 'items'], list => list.filterNot(item => item === action.id)); case PINNED_ACCOUNTS_FETCH_SUCCESS: return normalizeList(state, 'pinned', action.id, action.accounts, action.next); + case BIRTHDAY_REMINDERS_FETCH_SUCCESS: + return state.setIn(['birthday_reminders', action.id], ImmutableOrderedSet(action.accounts.map(item => item.id))); default: return state; } diff --git a/app/styles/components/notification.scss b/app/styles/components/notification.scss index 0a1e58a09..1bcbb937c 100644 --- a/app/styles/components/notification.scss +++ b/app/styles/components/notification.scss @@ -89,3 +89,18 @@ padding-bottom: 8px !important; } } + +.notification-birthday span[type="button"] { + &:focus, + &:hover, + &:active { + text-decoration: underline; + cursor: pointer; + } +} + +.columns-area .notification-birthday { + .notification__message { + padding-top: 0; + } +} diff --git a/docs/store.md b/docs/store.md index 34088ab8c..7f866bacb 100644 --- a/docs/store.md +++ b/docs/store.md @@ -391,6 +391,9 @@ If it's not documented, it's because I inherited it from Mastodon and I don't kn mention: true, poll: true, reblog: true + }, + birthdays: { + show: true } }, theme: 'azure', From 97d09317aeea4a7591d326dd30a9c926cd9dc0d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 21 Jan 2022 23:40:39 +0100 Subject: [PATCH 07/33] Modal improvements, profile information MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birthday_reminders.js | 27 ++++-- app/soapbox/features/birthdays/account.js | 88 +++++++++++++++++++ .../features/ui/components/birthdays_modal.js | 4 +- .../ui/components/profile_info_panel.js | 45 ++++++++-- .../reducers/__tests__/user_lists-test.js | 1 + app/styles/accounts.scss | 6 ++ docs/store.md | 3 +- 7 files changed, 153 insertions(+), 21 deletions(-) create mode 100644 app/soapbox/features/birthdays/account.js diff --git a/app/soapbox/components/birthday_reminders.js b/app/soapbox/components/birthday_reminders.js index a00a1ba33..8c1896bf7 100644 --- a/app/soapbox/components/birthday_reminders.js +++ b/app/soapbox/components/birthday_reminders.js @@ -1,6 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { HotKeys } from 'react-hotkeys'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; import { injectIntl, FormattedMessage } from 'react-intl'; @@ -51,6 +52,12 @@ class BirthdayReminders extends ImmutablePureComponent { dispatch(fetchBirthdayReminders(day, month)); } + getHandlers() { + return { + open: this.handleOpenBirthdaysModal, + }; + } + handleOpenBirthdaysModal = () => { const { dispatch } = this.props; @@ -101,17 +108,19 @@ class BirthdayReminders extends ImmutablePureComponent { if (!birthdays || birthdays.size === 0) return null; return ( -
-
-
- -
+ +
+
+
+ +
- - {this.renderMessage()} - + + {this.renderMessage()} + +
-
+ ); } diff --git a/app/soapbox/features/birthdays/account.js b/app/soapbox/features/birthdays/account.js new file mode 100644 index 000000000..141fd7b8e --- /dev/null +++ b/app/soapbox/features/birthdays/account.js @@ -0,0 +1,88 @@ +import PropTypes from 'prop-types'; +import React from 'react'; +import ImmutablePropTypes from 'react-immutable-proptypes'; +import ImmutablePureComponent from 'react-immutable-pure-component'; +import { defineMessages, injectIntl } from 'react-intl'; +import { connect } from 'react-redux'; + +import Avatar from 'soapbox/components/avatar'; +import DisplayName from 'soapbox/components/display_name'; +import Icon from 'soapbox/components/icon'; +import Permalink from 'soapbox/components/permalink'; +import { makeGetAccount } from 'soapbox/selectors'; + +const messages = defineMessages({ + birthDate: { id: 'account.birth_date', defaultMessage: 'Birth date: {date}' }, +}); + +const makeMapStateToProps = () => { + const getAccount = makeGetAccount(); + + const mapStateToProps = (state, { accountId }) => { + const account = getAccount(state, accountId); + + return { + account, + }; + }; + + return mapStateToProps; +}; + +export default @connect(makeMapStateToProps) +@injectIntl +class Account extends ImmutablePureComponent { + + static propTypes = { + accountId: PropTypes.string.isRequired, + intl: PropTypes.object.isRequired, + account: ImmutablePropTypes.map, + }; + + static defaultProps = { + added: false, + }; + + componentDidMount() { + const { account, accountId } = this.props; + + if (accountId && !account) { + this.props.fetchAccount(accountId); + } + } + + render() { + const { account, intl } = this.props; + + if (!account) return null; + + const birthDate = account.getIn(['pleroma', 'birth_date']); + if (!birthDate) return null; + + const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'short', year: 'numeric' }); + + return ( +
+
+ +
+
+ + +
+
+
+ + {formattedBirthDate} +
+
+
+ ); + } + +} diff --git a/app/soapbox/features/ui/components/birthdays_modal.js b/app/soapbox/features/ui/components/birthdays_modal.js index 995ad5cc5..9a0744ba7 100644 --- a/app/soapbox/features/ui/components/birthdays_modal.js +++ b/app/soapbox/features/ui/components/birthdays_modal.js @@ -7,7 +7,7 @@ import { connect } from 'react-redux'; import IconButton from 'soapbox/components/icon_button'; import LoadingIndicator from 'soapbox/components/loading_indicator'; import ScrollableList from 'soapbox/components/scrollable_list'; -import AccountContainer from 'soapbox/containers/account_container'; +import Account from 'soapbox/features/birthdays/account'; const messages = defineMessages({ close: { id: 'lightbox.close', defaultMessage: 'Close' }, @@ -69,7 +69,7 @@ class BirthdaysModal extends React.PureComponent { emptyMessage={emptyMessage} > {accountIds.map(id => - , + , )} ); diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index f2af515f5..98abf8d86 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -80,6 +80,41 @@ class ProfileInfoPanel extends ImmutablePureComponent { return badges; } + getBirthDate = () => { + const { account, intl } = this.props; + + const birthDate = account.getIn(['pleroma', 'birth_date']); + if (!birthDate) return null; + + const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'long', year: 'numeric' }); + + const date = new Date(birthDate); + const today = new Date(); + + const hasBirthday = date.getDate() === today.getDate() && date.getMonth() === today.getMonth(); + + if (hasBirthday) { + return ( +
+ + +
+ ); + } + return ( +
+ + +
+ ); + } + render() { const { account, displayFqn, intl, identity_proofs, username } = this.props; @@ -103,7 +138,6 @@ 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 birthDate = account.getIn(['pleroma', 'birth_date']) && intl.formatDate(account.getIn(['pleroma', 'birth_date']), { day: 'numeric', month: 'long', year: 'numeric' }); const verified = isVerified(account); const badges = this.getBadges(); @@ -151,14 +185,7 @@ class ProfileInfoPanel extends ImmutablePureComponent { />
} - {birthDate &&
- - -
} + {this.getBirthDate()} { groups: ImmutableMap(), groups_removed_accounts: ImmutableMap(), pinned: ImmutableMap(), + birthday_reminders: ImmutableMap(), })); }); }); diff --git a/app/styles/accounts.scss b/app/styles/accounts.scss index 7b0a53fe9..21579f647 100644 --- a/app/styles/accounts.scss +++ b/app/styles/accounts.scss @@ -554,3 +554,9 @@ a .account__avatar { padding-right: 3px; } } + +.account__birth-date { + display: flex; + align-items: center; + white-space: nowrap; +} diff --git a/docs/store.md b/docs/store.md index 7f866bacb..7c0bff506 100644 --- a/docs/store.md +++ b/docs/store.md @@ -126,7 +126,8 @@ If it's not documented, it's because I inherited it from Mastodon and I don't kn groups: {}, followers: {}, mutes: {}, - favourited_by: {} + favourited_by: {}, + birthday_reminders: {} } ``` From bae4455f8cb7f98a72208062913fc932cbdf566d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 23 Jan 2022 12:53:48 +0100 Subject: [PATCH 08/33] birth_date -> birthday, hide_birth_date -> show_birthday MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birth_date_input.js | 4 ++-- .../components/registration_form.js | 4 ++-- app/soapbox/features/birthdays/account.js | 2 +- app/soapbox/features/edit_profile/index.js | 22 +++++++++---------- .../ui/components/profile_info_panel.js | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/soapbox/components/birth_date_input.js b/app/soapbox/components/birth_date_input.js index 5183973d6..3147c317e 100644 --- a/app/soapbox/components/birth_date_input.js +++ b/app/soapbox/components/birth_date_input.js @@ -9,7 +9,7 @@ import 'react-datepicker/dist/react-datepicker.css'; import { getFeatures } from 'soapbox/utils/features'; const messages = defineMessages({ - birthDatePlaceholder: { id: 'edit_profile.fields.birth_date_placeholder', defaultMessage: 'Your birth date' }, + birthDatePlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, }); const mapStateToProps = state => { @@ -17,7 +17,7 @@ const mapStateToProps = state => { return { supportsBirthDates: features.birthDates, - minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_min_age']), + minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_min_age']), }; }; diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index 8b6ceb3a9..0bc68be30 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -47,7 +47,7 @@ const mapStateToProps = (state, props) => ({ needsApproval: state.getIn(['instance', 'approval_required']), supportsEmailList: getFeatures(state.get('instance')).emailList, supportsAccountLookup: getFeatures(state.get('instance')).accountLookup, - birthDateRequired: state.getIn(['instance', 'pleroma', 'metadata', 'birth_date_required']), + birthDateRequired: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_required']), }); export default @connect(mapStateToProps) @@ -223,7 +223,7 @@ class RegistrationForm extends ImmutablePureComponent { } if (birthDate) { - params.set('birth_date', birthDate.toISOString().slice(0, 10)); + params.set('birthday', birthDate.toISOString().slice(0, 10)); } }); diff --git a/app/soapbox/features/birthdays/account.js b/app/soapbox/features/birthdays/account.js index 141fd7b8e..4a266cd8f 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 birthDate = account.getIn(['pleroma', 'birth_date']); + const birthDate = account.getIn(['pleroma', 'birthday']); if (!birthDate) return null; const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'short', year: 'numeric' }); diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index f055d601e..426af2a39 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -50,7 +50,7 @@ const messages = defineMessages({ error: { id: 'edit_profile.error', defaultMessage: 'Profile update failed' }, bioPlaceholder: { id: 'edit_profile.fields.bio_placeholder', defaultMessage: 'Tell us about yourself.' }, displayNamePlaceholder: { id: 'edit_profile.fields.display_name_placeholder', defaultMessage: 'Name' }, - birthDatePlaceholder: { id: 'edit_profile.fields.birth_date_placeholder', defaultMessage: 'Your birth date' }, + birthDatePlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, }); const makeMapStateToProps = () => { @@ -113,8 +113,8 @@ 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 birthDate = account.getIn(['pleroma', 'birth_date']); - const hideBirthDate = account.getIn(['pleroma', 'hide_birth_date']); + const birthDate = account.getIn(['pleroma', 'birthday']); + const showBirthDate = account.getIn(['source', 'pleroma', 'show_birthday']); const initialState = account.withMutations(map => { map.merge(map.get('source')); @@ -124,7 +124,7 @@ class EditProfile extends ImmutablePureComponent { map.set('accepts_email_list', acceptsEmailList); map.set('hide_network', hidesNetwork(account)); map.set('discoverable', discoverable); - map.set('hide_birth_date', hideBirthDate); + map.set('show_birthday', showBirthDate); if (birthDate) map.set('birthDate', new Date(birthDate)); unescapeParams(map, ['display_name', 'bio']); }); @@ -166,8 +166,8 @@ class EditProfile extends ImmutablePureComponent { hide_follows: state.hide_network, hide_followers_count: state.hide_network, hide_follows_count: state.hide_network, - birth_date: state.birthDate?.toISOString().slice(0, 10), - hide_birth_date: state.hide_birth_date, + birthday: state.birthDate?.toISOString().slice(0, 10), + show_birthday: state.show_birthday, }, this.getFieldParams().toJS()); } @@ -286,7 +286,7 @@ class EditProfile extends ImmutablePureComponent { rows={3} /> } + hint={} value={this.state.birthDate} onChange={this.handleBirthDateChange} /> @@ -345,10 +345,10 @@ class EditProfile extends ImmutablePureComponent { onChange={this.handleCheckboxChange} /> {supportsBirthDates && } - hint={} - name='hide_birth_date' - checked={this.state.hide_birth_date} + label={} + hint={} + name='show_birthday' + checked={this.state.show_birthday} onChange={this.handleCheckboxChange} />} {supportsEmailList && { const { account, intl } = this.props; - const birthDate = account.getIn(['pleroma', 'birth_date']); + const birthDate = account.getIn(['pleroma', 'birthday']); if (!birthDate) return null; const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'long', year: 'numeric' }); From bcc0e0983b76835143a489642eab53f5e73c4a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Mon, 24 Jan 2022 23:33:16 +0100 Subject: [PATCH 09/33] Birthdays: use the new route MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/accounts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index e0bcbd46c..2d12fe06f 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -1043,7 +1043,7 @@ export function fetchBirthdayReminders(day, month) { dispatch({ type: BIRTHDAY_REMINDERS_FETCH_REQUEST, day, month, id: me }); - api(getState).get('/api/v1/pleroma/birthday_reminders', { params: { day, month } }).then(response => { + api(getState).get('/api/v1/pleroma/birthdays', { params: { day, month } }).then(response => { dispatch(importFetchedAccounts(response.data)); dispatch({ type: BIRTHDAY_REMINDERS_FETCH_SUCCESS, From e0d7f2dd8772a688ad7038edb9975da7538d5897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Mon, 24 Jan 2022 23:51:22 +0100 Subject: [PATCH 10/33] Birthdays: Accessibility improvements/fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birthday_reminders.js | 29 +++++++++++++++++++- app/soapbox/features/notifications/index.js | 27 +++++++++++++++--- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/app/soapbox/components/birthday_reminders.js b/app/soapbox/components/birthday_reminders.js index 8c1896bf7..9a14f1f55 100644 --- a/app/soapbox/components/birthday_reminders.js +++ b/app/soapbox/components/birthday_reminders.js @@ -39,6 +39,7 @@ class BirthdayReminders extends ImmutablePureComponent { birthdays: ImmutablePropTypes.orderedSet, intl: PropTypes.object.isRequired, dispatch: PropTypes.func.isRequired, + onMoveDown: PropTypes.func, }; componentDidMount() { @@ -55,6 +56,7 @@ class BirthdayReminders extends ImmutablePureComponent { getHandlers() { return { open: this.handleOpenBirthdaysModal, + moveDown: this.props.onMoveDown, }; } @@ -102,6 +104,31 @@ class BirthdayReminders extends ImmutablePureComponent { ); } + renderMessageForScreenReader = () => { + const { intl, birthdays, account } = this.props; + + if (birthdays.size === 1) { + return intl.formatMessage({ id: 'notification.birthday', defaultMessage: '{name} has birthday today' }, { name: account.get('display_name') }); + } + + return intl.formatMessage( + { + id: 'notification.birthday_plural', + defaultMessage: '{name} and {more} have birthday today', + }, + { + name: account.get('display_name'), + more: intl.formatMessage( + { + id: 'notification.birthday.more', + defaultMessage: '{count} more {count, plural, one {friend} other {friends}}', + }, + { count: birthdays.size - 1 }, + ), + }, + ); + } + render() { const { birthdays } = this.props; @@ -109,7 +136,7 @@ class BirthdayReminders extends ImmutablePureComponent { return ( -
+
diff --git a/app/soapbox/features/notifications/index.js b/app/soapbox/features/notifications/index.js index 57edf8315..29434fa65 100644 --- a/app/soapbox/features/notifications/index.js +++ b/app/soapbox/features/notifications/index.js @@ -51,6 +51,8 @@ const mapStateToProps = state => { const settings = getSettings(state); const instance = state.get('instance'); const features = getFeatures(instance); + const showBirthdayReminders = settings.getIn(['notifications', 'birthdays', 'show']) && settings.getIn(['notifications', 'quickFilter', 'active']) === 'all' && features.birthDates; + const birthdays = showBirthdayReminders && state.getIn(['user_lists', 'birthday_reminders', state.get('me')]); return { showFilterBar: settings.getIn(['notifications', 'quickFilter', 'show']), @@ -59,7 +61,8 @@ const mapStateToProps = state => { isUnread: state.getIn(['notifications', 'unread']) > 0, hasMore: state.getIn(['notifications', 'hasMore']), totalQueuedNotificationsCount: state.getIn(['notifications', 'totalQueuedNotificationsCount'], 0), - showBirthdayReminders: settings.getIn(['notifications', 'birthdays', 'show']) && settings.getIn(['notifications', 'quickFilter', 'active']) === 'all' && features.birthDates, + showBirthdayReminders, + hasBirthdays: !!birthdays, }; }; @@ -78,6 +81,7 @@ class Notifications extends React.PureComponent { dequeueNotifications: PropTypes.func, totalQueuedNotificationsCount: PropTypes.number, showBirthdayReminders: PropTypes.bool, + hasBirthdays: PropTypes.bool, }; componentWillUnmount() { @@ -114,15 +118,25 @@ class Notifications extends React.PureComponent { } handleMoveUp = id => { - const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1; + const { hasBirthdays } = this.props; + + let elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) - 1; + if (hasBirthdays) elementIndex++; this._selectChild(elementIndex, true); } handleMoveDown = id => { - const elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1; + const { hasBirthdays } = this.props; + + let elementIndex = this.props.notifications.findIndex(item => item !== null && item.get('id') === id) + 1; + if (hasBirthdays) elementIndex++; this._selectChild(elementIndex, false); } + handleMoveBelowBirthdays = () => { + this._selectChild(1, false); + } + _selectChild(index, align_top) { const container = this.column.node; const element = container.querySelector(`article:nth-of-type(${index + 1}) .focusable`); @@ -175,7 +189,12 @@ class Notifications extends React.PureComponent { /> )); - if (showBirthdayReminders) scrollableContent = scrollableContent.unshift(); + if (showBirthdayReminders) scrollableContent = scrollableContent.unshift( + , + ); } else { scrollableContent = null; } From 980f5f8ae3455026971f0ad5678cb594e83a46df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 25 Jan 2022 16:51:15 +0100 Subject: [PATCH 11/33] Birthdays: use maxDate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birth_date_input.js | 14 +++++--------- .../auth_login/components/registration_form.js | 2 +- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/app/soapbox/components/birth_date_input.js b/app/soapbox/components/birth_date_input.js index 3147c317e..b07c54515 100644 --- a/app/soapbox/components/birth_date_input.js +++ b/app/soapbox/components/birth_date_input.js @@ -34,18 +34,14 @@ class EditProfile extends ImmutablePureComponent { value: PropTypes.instanceOf(Date), }; - isDateValid = date => { - const { minAge } = this.props; - const allowedDate = new Date(); - allowedDate.setDate(allowedDate.getDate() - minAge); - return date && allowedDate.setHours(0, 0, 0, 0) >= new Date(date).setHours(0, 0, 0, 0); - } - render() { - const { intl, value, onChange, supportsBirthDates, hint, required } = this.props; + const { intl, value, onChange, supportsBirthDates, hint, required, minAge } = this.props; if (!supportsBirthDates) return null; + const maxDate = new Date(); + maxDate.setDate(maxDate.getDate() - minAge); + return (
{hint && ( @@ -60,7 +56,7 @@ class EditProfile extends ImmutablePureComponent { wrapperClassName='react-datepicker-wrapper' onChange={onChange} placeholderText={intl.formatMessage(messages.birthDatePlaceholder)} - filterDate={this.isDateValid} + maxDate={maxDate} required={required} />
diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index 0bc68be30..52272f1f9 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -325,7 +325,7 @@ class RegistrationForm extends ImmutablePureComponent { error={passwordMismatch === true} required /> - {!birthDateRequired && + {birthDateRequired && Date: Tue, 25 Jan 2022 21:09:30 +0100 Subject: [PATCH 12/33] Birthdays: renames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- ...{birth_date_input.js => birthday_input.js} | 12 +++---- .../components/registration_form.js | 28 ++++++++-------- app/soapbox/features/birthdays/account.js | 12 +++---- app/soapbox/features/edit_profile/index.js | 32 +++++++++---------- .../components/column_settings.js | 6 ++-- .../containers/column_settings_container.js | 2 +- app/soapbox/features/notifications/index.js | 2 +- .../ui/components/profile_info_panel.js | 18 +++++------ app/soapbox/utils/features.js | 2 +- app/styles/accounts.scss | 2 +- app/styles/components/profile-info-panel.scss | 2 +- 11 files changed, 59 insertions(+), 59 deletions(-) rename app/soapbox/components/{birth_date_input.js => birthday_input.js} (78%) diff --git a/app/soapbox/components/birth_date_input.js b/app/soapbox/components/birthday_input.js similarity index 78% rename from app/soapbox/components/birth_date_input.js rename to app/soapbox/components/birthday_input.js index b07c54515..cb1408d51 100644 --- a/app/soapbox/components/birth_date_input.js +++ b/app/soapbox/components/birthday_input.js @@ -9,14 +9,14 @@ import 'react-datepicker/dist/react-datepicker.css'; import { getFeatures } from 'soapbox/utils/features'; const messages = defineMessages({ - birthDatePlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, + birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, }); const mapStateToProps = state => { const features = getFeatures(state.get('instance')); return { - supportsBirthDates: features.birthDates, + supportsBirthdays: features.birthdays, minAge: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_min_age']), }; }; @@ -28,16 +28,16 @@ class EditProfile extends ImmutablePureComponent { static propTypes = { hint: PropTypes.node, required: PropTypes.bool, - supportsBirthDates: PropTypes.bool, + supportsBirthdays: PropTypes.bool, minAge: PropTypes.number, onChange: PropTypes.func.isRequired, value: PropTypes.instanceOf(Date), }; render() { - const { intl, value, onChange, supportsBirthDates, hint, required, minAge } = this.props; + const { intl, value, onChange, supportsBirthdays, hint, required, minAge } = this.props; - if (!supportsBirthDates) return null; + if (!supportsBirthdays) return null; const maxDate = new Date(); maxDate.setDate(maxDate.getDate() - minAge); @@ -55,7 +55,7 @@ class EditProfile extends ImmutablePureComponent { dateFormat='d MMMM yyyy' wrapperClassName='react-datepicker-wrapper' onChange={onChange} - placeholderText={intl.formatMessage(messages.birthDatePlaceholder)} + placeholderText={intl.formatMessage(messages.birthdayPlaceholder)} maxDate={maxDate} required={required} /> diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index 52272f1f9..127916a19 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -14,7 +14,7 @@ import { accountLookup } from 'soapbox/actions/accounts'; import { register, verifyCredentials } from 'soapbox/actions/auth'; import { openModal } from 'soapbox/actions/modal'; import { getSettings } from 'soapbox/actions/settings'; -import BirthDateInput from 'soapbox/components/birth_date_input'; +import BirthdayInput from 'soapbox/components/birthday_input'; import ShowablePassword from 'soapbox/components/showable_password'; import CaptchaField from 'soapbox/features/auth_login/components/captcha'; import { @@ -47,7 +47,7 @@ const mapStateToProps = (state, props) => ({ needsApproval: state.getIn(['instance', 'approval_required']), supportsEmailList: getFeatures(state.get('instance')).emailList, supportsAccountLookup: getFeatures(state.get('instance')).accountLookup, - birthDateRequired: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_required']), + birthdayRequired: state.getIn(['instance', 'pleroma', 'metadata', 'birthday_required']), }); export default @connect(mapStateToProps) @@ -63,7 +63,7 @@ class RegistrationForm extends ImmutablePureComponent { supportsEmailList: PropTypes.bool, supportsAccountLookup: PropTypes.bool, inviteToken: PropTypes.string, - birthDateRequired: PropTypes.bool, + birthdayRequired: PropTypes.bool, } static contextTypes = { @@ -132,9 +132,9 @@ class RegistrationForm extends ImmutablePureComponent { this.setState({ passwordMismatch: !this.passwordsMatch() }); } - onBirthDateChange = birthDate => { + onBirthdayChange = birthday => { this.setState({ - birthDate, + birthday, }); } @@ -206,7 +206,7 @@ class RegistrationForm extends ImmutablePureComponent { onSubmit = e => { const { dispatch, inviteToken } = this.props; - const { birthDate } = this.state; + const { birthday } = this.state; if (!this.passwordsMatch()) { this.setState({ passwordMismatch: true }); @@ -222,8 +222,8 @@ class RegistrationForm extends ImmutablePureComponent { params.set('token', inviteToken); } - if (birthDate) { - params.set('birthday', birthDate.toISOString().slice(0, 10)); + if (birthday) { + params.set('birthday', birthday.toISOString().slice(0, 10)); } }); @@ -259,8 +259,8 @@ class RegistrationForm extends ImmutablePureComponent { } render() { - const { instance, intl, supportsEmailList, birthDateRequired } = this.props; - const { params, usernameUnavailable, passwordConfirmation, passwordMismatch, birthDate } = this.state; + const { instance, intl, supportsEmailList, birthdayRequired } = this.props; + const { params, usernameUnavailable, passwordConfirmation, passwordMismatch, birthday } = this.state; const isLoading = this.state.captchaLoading || this.state.submissionLoading; return ( @@ -325,10 +325,10 @@ class RegistrationForm extends ImmutablePureComponent { error={passwordMismatch === true} required /> - {birthDateRequired && - } {instance.get('approval_required') && diff --git a/app/soapbox/features/birthdays/account.js b/app/soapbox/features/birthdays/account.js index 4a266cd8f..847e28de2 100644 --- a/app/soapbox/features/birthdays/account.js +++ b/app/soapbox/features/birthdays/account.js @@ -56,10 +56,10 @@ class Account extends ImmutablePureComponent { if (!account) return null; - const birthDate = account.getIn(['pleroma', 'birthday']); - if (!birthDate) return null; + const birthday = account.getIn(['pleroma', 'birthday']); + if (!birthday) return null; - const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'short', year: 'numeric' }); + const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'short', year: 'numeric' }); return (
@@ -72,13 +72,13 @@ class Account extends ImmutablePureComponent {
- {formattedBirthDate} + {formattedBirthday}
diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index 426af2a39..cf73ddbc4 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -14,7 +14,7 @@ import { updateNotificationSettings } from 'soapbox/actions/accounts'; import { patchMe } from 'soapbox/actions/me'; import snackbar from 'soapbox/actions/snackbar'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; -import BirthDateInput from 'soapbox/components/birth_date_input'; +import BirthdayInput from 'soapbox/components/birthday_input'; import Icon from 'soapbox/components/icon'; import { SimpleForm, @@ -50,7 +50,7 @@ const messages = defineMessages({ error: { id: 'edit_profile.error', defaultMessage: 'Profile update failed' }, bioPlaceholder: { id: 'edit_profile.fields.bio_placeholder', defaultMessage: 'Tell us about yourself.' }, displayNamePlaceholder: { id: 'edit_profile.fields.display_name_placeholder', defaultMessage: 'Name' }, - birthDatePlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, + birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, }); const makeMapStateToProps = () => { @@ -67,7 +67,7 @@ const makeMapStateToProps = () => { maxFields: state.getIn(['instance', 'pleroma', 'metadata', 'fields_limits', 'max_fields'], 4), verifiedCanEditName: soapbox.get('verifiedCanEditName'), supportsEmailList: features.emailList, - supportsBirthDates: features.birthDates, + supportsBirthdays: features.birthdays, }; }; @@ -99,7 +99,7 @@ class EditProfile extends ImmutablePureComponent { maxFields: PropTypes.number, verifiedCanEditName: PropTypes.bool, supportsEmailList: PropTypes.bool, - supportsBirthDates: PropTypes.bool, + supportsBirthdays: PropTypes.bool, }; state = { @@ -113,8 +113,8 @@ 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 birthDate = account.getIn(['pleroma', 'birthday']); - const showBirthDate = account.getIn(['source', 'pleroma', 'show_birthday']); + const birthday = account.getIn(['pleroma', 'birthday']); + const showBirthday = account.getIn(['source', 'pleroma', 'show_birthday']); const initialState = account.withMutations(map => { map.merge(map.get('source')); @@ -124,8 +124,8 @@ class EditProfile extends ImmutablePureComponent { map.set('accepts_email_list', acceptsEmailList); map.set('hide_network', hidesNetwork(account)); map.set('discoverable', discoverable); - map.set('show_birthday', showBirthDate); - if (birthDate) map.set('birthDate', new Date(birthDate)); + map.set('show_birthday', showBirthday); + if (birthday) map.set('birthday', new Date(birthday)); unescapeParams(map, ['display_name', 'bio']); }); @@ -166,7 +166,7 @@ class EditProfile extends ImmutablePureComponent { hide_follows: state.hide_network, hide_followers_count: state.hide_network, hide_follows_count: state.hide_network, - birthday: state.birthDate?.toISOString().slice(0, 10), + birthday: state.birthday?.toISOString().slice(0, 10), show_birthday: state.show_birthday, }, this.getFieldParams().toJS()); } @@ -235,9 +235,9 @@ class EditProfile extends ImmutablePureComponent { }; } - handleBirthDateChange = birthDate => { + handleBirthdayChange = birthday => { this.setState({ - birthDate, + birthday, }); } @@ -256,7 +256,7 @@ class EditProfile extends ImmutablePureComponent { } render() { - const { intl, maxFields, account, verifiedCanEditName, supportsBirthDates, supportsEmailList } = this.props; + const { intl, maxFields, account, verifiedCanEditName, supportsBirthdays, supportsEmailList } = this.props; const verified = isVerified(account); const canEditName = verifiedCanEditName || !verified; @@ -285,10 +285,10 @@ class EditProfile extends ImmutablePureComponent { onChange={this.handleTextChange} rows={3} /> - } - value={this.state.birthDate} - onChange={this.handleBirthDateChange} + value={this.state.birthday} + onChange={this.handleBirthdayChange} />
@@ -344,7 +344,7 @@ class EditProfile extends ImmutablePureComponent { checked={this.state.discoverable} onChange={this.handleCheckboxChange} /> - {supportsBirthDates && } hint={} name='show_birthday' diff --git a/app/soapbox/features/notifications/components/column_settings.js b/app/soapbox/features/notifications/components/column_settings.js index 39dd79836..63093ec78 100644 --- a/app/soapbox/features/notifications/components/column_settings.js +++ b/app/soapbox/features/notifications/components/column_settings.js @@ -24,7 +24,7 @@ class ColumnSettings extends React.PureComponent { onClear: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, supportsEmojiReacts: PropTypes.bool, - supportsBirthDates: PropTypes.bool, + supportsBirthdays: PropTypes.bool, }; onPushChange = (path, checked) => { @@ -40,7 +40,7 @@ class ColumnSettings extends React.PureComponent { } render() { - const { intl, settings, pushSettings, onChange, onClear, onClose, supportsEmojiReacts, supportsBirthDates } = this.props; + const { intl, settings, pushSettings, onChange, onClear, onClose, supportsEmojiReacts, supportsBirthdays } = this.props; const filterShowStr = ; const filterAdvancedStr = ; @@ -86,7 +86,7 @@ class ColumnSettings extends React.PureComponent {
- {supportsBirthDates && + {supportsBirthdays &&
diff --git a/app/soapbox/features/notifications/containers/column_settings_container.js b/app/soapbox/features/notifications/containers/column_settings_container.js index 05dc1f0eb..292c08961 100644 --- a/app/soapbox/features/notifications/containers/column_settings_container.js +++ b/app/soapbox/features/notifications/containers/column_settings_container.js @@ -24,7 +24,7 @@ const mapStateToProps = state => { settings: getSettings(state).get('notifications'), pushSettings: state.get('push_notifications'), supportsEmojiReacts: features.emojiReacts, - supportsBirthDates: features.birthDates, + supportsBirthdays: features.birthdays, }; }; diff --git a/app/soapbox/features/notifications/index.js b/app/soapbox/features/notifications/index.js index 29434fa65..b3afd7c2f 100644 --- a/app/soapbox/features/notifications/index.js +++ b/app/soapbox/features/notifications/index.js @@ -51,7 +51,7 @@ const mapStateToProps = state => { const settings = getSettings(state); const instance = state.get('instance'); const features = getFeatures(instance); - const showBirthdayReminders = settings.getIn(['notifications', 'birthdays', 'show']) && settings.getIn(['notifications', 'quickFilter', 'active']) === 'all' && features.birthDates; + const showBirthdayReminders = settings.getIn(['notifications', 'birthdays', 'show']) && settings.getIn(['notifications', 'quickFilter', 'active']) === 'all' && features.birthdays; const birthdays = showBirthdayReminders && state.getIn(['user_lists', 'birthday_reminders', state.get('me')]); return { diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index adf092155..f90cac95d 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -80,22 +80,22 @@ class ProfileInfoPanel extends ImmutablePureComponent { return badges; } - getBirthDate = () => { + getBirthday = () => { const { account, intl } = this.props; - const birthDate = account.getIn(['pleroma', 'birthday']); - if (!birthDate) return null; + const birthday = account.getIn(['pleroma', 'birthday']); + if (!birthday) return null; - const formattedBirthDate = intl.formatDate(birthDate, { day: 'numeric', month: 'long', year: 'numeric' }); + const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'long', year: 'numeric' }); - const date = new Date(birthDate); + const date = new Date(birthday); const today = new Date(); const hasBirthday = date.getDate() === today.getDate() && date.getMonth() === today.getMonth(); if (hasBirthday) { return ( -
+
+
@@ -185,7 +185,7 @@ class ProfileInfoPanel extends ImmutablePureComponent { />
} - {this.getBirthDate()} + {this.getBirthday()} Date: Tue, 25 Jan 2022 17:08:20 -0600 Subject: [PATCH 13/33] "birth date" --> "birthday", move the toggle next to the picker --- app/soapbox/components/birthday_input.js | 5 ++-- app/soapbox/features/birthdays/account.js | 4 +-- app/soapbox/features/edit_profile/index.js | 30 +++++++++++-------- .../ui/components/profile_info_panel.js | 4 +-- 4 files changed, 23 insertions(+), 20 deletions(-) diff --git a/app/soapbox/components/birthday_input.js b/app/soapbox/components/birthday_input.js index cb1408d51..ad6e561ea 100644 --- a/app/soapbox/components/birthday_input.js +++ b/app/soapbox/components/birthday_input.js @@ -9,7 +9,7 @@ import 'react-datepicker/dist/react-datepicker.css'; import { getFeatures } from 'soapbox/utils/features'; const messages = defineMessages({ - birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, + birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' }, }); const mapStateToProps = state => { @@ -52,7 +52,6 @@ class EditProfile extends ImmutablePureComponent {
{ @@ -73,7 +73,7 @@ class Account extends ImmutablePureComponent {
diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index cf73ddbc4..9a425768b 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -50,7 +50,7 @@ const messages = defineMessages({ error: { id: 'edit_profile.error', defaultMessage: 'Profile update failed' }, bioPlaceholder: { id: 'edit_profile.fields.bio_placeholder', defaultMessage: 'Tell us about yourself.' }, displayNamePlaceholder: { id: 'edit_profile.fields.display_name_placeholder', defaultMessage: 'Name' }, - birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, + birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birthday' }, }); const makeMapStateToProps = () => { @@ -285,11 +285,22 @@ class EditProfile extends ImmutablePureComponent { onChange={this.handleTextChange} rows={3} /> - } - value={this.state.birthday} - onChange={this.handleBirthdayChange} - /> + {supportsBirthdays && ( + <> + } + value={this.state.birthday} + onChange={this.handleBirthdayChange} + /> + } + hint={} + name='show_birthday' + checked={this.state.show_birthday} + onChange={this.handleCheckboxChange} + /> + + )}
@@ -344,13 +355,6 @@ class EditProfile extends ImmutablePureComponent { checked={this.state.discoverable} onChange={this.handleCheckboxChange} /> - {supportsBirthdays && } - hint={} - name='show_birthday' - checked={this.state.show_birthday} - onChange={this.handleCheckboxChange} - />} {supportsEmailList && } hint={} diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index f90cac95d..6b35c601e 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -98,7 +98,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
); @@ -107,7 +107,7 @@ class ProfileInfoPanel extends ImmutablePureComponent {
From 741e80d9ab16fecedc2585f6813da86987da2292 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Tue, 25 Jan 2022 23:37:40 -0800 Subject: [PATCH 14/33] Birthdays: Try to fix timezones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birthday_input.js | 5 +++-- .../features/auth_login/components/registration_form.js | 2 +- app/soapbox/features/edit_profile/index.js | 9 +++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/soapbox/components/birthday_input.js b/app/soapbox/components/birthday_input.js index cb1408d51..36473dac8 100644 --- a/app/soapbox/components/birthday_input.js +++ b/app/soapbox/components/birthday_input.js @@ -39,8 +39,8 @@ class EditProfile extends ImmutablePureComponent { if (!supportsBirthdays) return null; - const maxDate = new Date(); - maxDate.setDate(maxDate.getDate() - minAge); + let maxDate = new Date(); + maxDate = new Date(maxDate.getTime() - minAge * 1000 * 60 * 60 * 24 + maxDate.getTimezoneOffset() * 1000 * 60); return (
@@ -56,6 +56,7 @@ class EditProfile extends ImmutablePureComponent { wrapperClassName='react-datepicker-wrapper' onChange={onChange} placeholderText={intl.formatMessage(messages.birthdayPlaceholder)} + minDate={new Date('1900-01-01')} maxDate={maxDate} required={required} /> diff --git a/app/soapbox/features/auth_login/components/registration_form.js b/app/soapbox/features/auth_login/components/registration_form.js index 127916a19..dbda945a8 100644 --- a/app/soapbox/features/auth_login/components/registration_form.js +++ b/app/soapbox/features/auth_login/components/registration_form.js @@ -223,7 +223,7 @@ class RegistrationForm extends ImmutablePureComponent { } if (birthday) { - params.set('birthday', birthday.toISOString().slice(0, 10)); + params.set('birthday', new Date(birthday.getTime() - (birthday.getTimezoneOffset() * 60000)).toISOString().slice(0, 10)); } }); diff --git a/app/soapbox/features/edit_profile/index.js b/app/soapbox/features/edit_profile/index.js index cf73ddbc4..8fe4ddd2b 100644 --- a/app/soapbox/features/edit_profile/index.js +++ b/app/soapbox/features/edit_profile/index.js @@ -125,7 +125,10 @@ class EditProfile extends ImmutablePureComponent { map.set('hide_network', hidesNetwork(account)); map.set('discoverable', discoverable); map.set('show_birthday', showBirthday); - if (birthday) map.set('birthday', new Date(birthday)); + if (birthday) { + const date = new Date(birthday); + map.set('birthday', new Date(date.getTime() + (date.getTimezoneOffset() * 60000))); + } unescapeParams(map, ['display_name', 'bio']); }); @@ -166,7 +169,9 @@ class EditProfile extends ImmutablePureComponent { hide_follows: state.hide_network, hide_followers_count: state.hide_network, hide_follows_count: state.hide_network, - birthday: state.birthday?.toISOString().slice(0, 10), + birthday: state.birthday + ? new Date(state.birthday.getTime() - (state.birthday.getTimezoneOffset() * 60000)).toISOString().slice(0, 10) + : undefined, show_birthday: state.show_birthday, }, this.getFieldParams().toJS()); } From b1bc544a018ec004ec769c2db6e439d193ada244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 26 Jan 2022 18:43:00 +0100 Subject: [PATCH 15/33] Birthdays: Use custom header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/birthday_input.js | 63 ++++++++++++++++++++++++ app/styles/components/datepicker.scss | 1 + app/styles/forms.scss | 43 +++++++++++----- 3 files changed, 94 insertions(+), 13 deletions(-) diff --git a/app/soapbox/components/birthday_input.js b/app/soapbox/components/birthday_input.js index 36473dac8..d94700926 100644 --- a/app/soapbox/components/birthday_input.js +++ b/app/soapbox/components/birthday_input.js @@ -6,10 +6,15 @@ import { defineMessages, injectIntl } from 'react-intl'; import { connect } from 'react-redux'; import 'react-datepicker/dist/react-datepicker.css'; +import IconButton from 'soapbox/components/icon_button'; import { getFeatures } from 'soapbox/utils/features'; const messages = defineMessages({ birthdayPlaceholder: { id: 'edit_profile.fields.birthday_placeholder', defaultMessage: 'Your birth date' }, + previousMonth: { id: 'datepicker.previous_month', defaultMessage: 'Previous month' }, + nextMonth: { id: 'datepicker.next_month', defaultMessage: 'Next month' }, + previousYear: { id: 'datepicker.previous_year', defaultMessage: 'Previous year' }, + nextYear: { id: 'datepicker.next_year', defaultMessage: 'Next year' }, }); const mapStateToProps = state => { @@ -34,6 +39,63 @@ class EditProfile extends ImmutablePureComponent { value: PropTypes.instanceOf(Date), }; + renderHeader = ({ + decreaseMonth, + increaseMonth, + prevMonthButtonDisabled, + nextMonthButtonDisabled, + decreaseYear, + increaseYear, + prevYearButtonDisabled, + nextYearButtonDisabled, + date, + }) => { + const { intl } = this.props; + + return ( +
+
+ + {intl.formatDate(date, { month: 'long' })} + +
+
+ + {intl.formatDate(date, { year: 'numeric' })} + +
+
+ ); + } + render() { const { intl, value, onChange, supportsBirthdays, hint, required, minAge } = this.props; @@ -59,6 +121,7 @@ class EditProfile extends ImmutablePureComponent { minDate={new Date('1900-01-01')} maxDate={maxDate} required={required} + renderCustomHeader={this.renderHeader} />
diff --git a/app/styles/components/datepicker.scss b/app/styles/components/datepicker.scss index 76996ffda..dd74db173 100644 --- a/app/styles/components/datepicker.scss +++ b/app/styles/components/datepicker.scss @@ -33,6 +33,7 @@ .datepicker .react-datepicker { box-shadow: 0 0 6px 0 rgb(0 0 0 / 30%); + font-family: inherit; font-size: 12px; border: 0; border-radius: 10px; diff --git a/app/styles/forms.scss b/app/styles/forms.scss index 9c46a965f..64ab2fb4d 100644 --- a/app/styles/forms.scss +++ b/app/styles/forms.scss @@ -648,19 +648,8 @@ code { } .react-datepicker { - &__navigation { - display: flex; - height: 32px; - width: 32px; - margin: 0; - background: none; - line-height: 24px; - - &:hover, - &:active, - &:focus { - background: none; - } + &__header { + padding-top: 4px; } &__input-container { @@ -671,6 +660,34 @@ code { } } } + + &__years, + &__months { + display: flex; + justify-content: space-between; + align-items: center; + margin: 0 4px; + font-size: 16px; + } + + &__button { + width: 28px; + margin: 0; + padding: 4px; + background: transparent; + color: var(--primary-text-color); + + &:hover, + &:active, + &:focus { + background: none; + } + + .svg-icon { + height: 20px; + width: 20px; + } + } } } From 7c790a53eb1188f22bd0f6964a1c44d3f25f4d27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 26 Jan 2022 19:28:01 +0100 Subject: [PATCH 16/33] Add quotes for pending statuses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/features/ui/components/pending_status.js | 5 ++++- app/soapbox/features/ui/util/pending_status_builder.js | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/soapbox/features/ui/components/pending_status.js b/app/soapbox/features/ui/components/pending_status.js index 847869457..31e836cd9 100644 --- a/app/soapbox/features/ui/components/pending_status.js +++ b/app/soapbox/features/ui/components/pending_status.js @@ -9,9 +9,10 @@ import DisplayName from 'soapbox/components/display_name'; import RelativeTimestamp from 'soapbox/components/relative_timestamp'; import StatusContent from 'soapbox/components/status_content'; import PlaceholderCard from 'soapbox/features/placeholder/components/placeholder_card'; +import PlaceholderMediaGallery from 'soapbox/features/placeholder/components/placeholder_media_gallery'; +import QuotedStatus from 'soapbox/features/status/containers/quoted_status_container'; import { getDomain } from 'soapbox/utils/accounts'; -import PlaceholderMediaGallery from '../../placeholder/components/placeholder_media_gallery'; import { buildStatus } from '../util/pending_status_builder'; import PollPreview from './poll_preview'; @@ -93,6 +94,8 @@ class PendingStatus extends ImmutablePureComponent { {this.renderMedia()} {status.get('poll') && } + {status.get('quote') && } + {/* TODO */} {/* */}
diff --git a/app/soapbox/features/ui/util/pending_status_builder.js b/app/soapbox/features/ui/util/pending_status_builder.js index 1c6f33517..ee94ade62 100644 --- a/app/soapbox/features/ui/util/pending_status_builder.js +++ b/app/soapbox/features/ui/util/pending_status_builder.js @@ -28,6 +28,7 @@ export const buildStatus = (state, pendingStatus, idempotencyKey) => { muted: false, pinned: false, poll: pendingStatus.get('poll', null), + quote: pendingStatus.get('quote_id', null), reblog: null, reblogged: false, reblogs_count: 0, From 22b3986178d551a1134914eda8918e41b9b0010e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Wed, 26 Jan 2022 19:49:04 +0100 Subject: [PATCH 17/33] PendingStatus: Do not display PlaceholderCard if it has a quote MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/features/ui/components/pending_status.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/features/ui/components/pending_status.js b/app/soapbox/features/ui/components/pending_status.js index 31e836cd9..35bbfcc31 100644 --- a/app/soapbox/features/ui/components/pending_status.js +++ b/app/soapbox/features/ui/components/pending_status.js @@ -41,7 +41,7 @@ class PendingStatus extends ImmutablePureComponent { media={status.get('media_attachments')} /> ); - } else if (shouldHaveCard(status)) { + } else if (!status.get('quote') && shouldHaveCard(status)) { return ; } else { return null; From 0964fc1f4df267ad6bbd7e82506d708fffe1ef67 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Wed, 26 Jan 2022 19:37:32 -0600 Subject: [PATCH 18/33] Add "demo" mode for taking screenshots --- app/images/soapbox-logo.svg | 1 + app/soapbox/containers/soapbox.js | 7 +++++-- app/soapbox/features/ui/components/tabs_bar.js | 7 ++++++- 3 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 app/images/soapbox-logo.svg diff --git a/app/images/soapbox-logo.svg b/app/images/soapbox-logo.svg new file mode 100644 index 000000000..270b7b810 --- /dev/null +++ b/app/images/soapbox-logo.svg @@ -0,0 +1 @@ + diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js index 651ddb703..40b4e10b6 100644 --- a/app/soapbox/containers/soapbox.js +++ b/app/soapbox/containers/soapbox.js @@ -54,6 +54,9 @@ const mapStateToProps = (state) => { const soapboxConfig = getSoapboxConfig(state); const locale = settings.get('locale'); + // In demo mode, force the default brand color + const brandColor = settings.get('demo') ? '#0482d8' : soapboxConfig.get('brandColor'); + return { showIntroduction, me, @@ -63,11 +66,11 @@ const mapStateToProps = (state) => { dyslexicFont: settings.get('dyslexicFont'), demetricator: settings.get('demetricator'), locale: validLocale(locale) ? locale : 'en', - themeCss: generateThemeCss(soapboxConfig.get('brandColor')), + themeCss: generateThemeCss(brandColor), brandColor: soapboxConfig.get('brandColor'), themeMode: settings.get('themeMode'), halloween: settings.get('halloween'), - customCss: soapboxConfig.get('customCss'), + customCss: settings.get('demo') ? null : soapboxConfig.get('customCss'), }; }; diff --git a/app/soapbox/features/ui/components/tabs_bar.js b/app/soapbox/features/ui/components/tabs_bar.js index b6ca8f420..8e833334a 100644 --- a/app/soapbox/features/ui/components/tabs_bar.js +++ b/app/soapbox/features/ui/components/tabs_bar.js @@ -6,6 +6,7 @@ import { FormattedMessage, injectIntl, defineMessages } from 'react-intl'; import { connect } from 'react-redux'; import { Link, NavLink, withRouter } from 'react-router-dom'; +import { getSettings } from 'soapbox/actions/settings'; import { getSoapboxConfig } from 'soapbox/actions/soapbox'; import Icon from 'soapbox/components/icon'; import IconWithCounter from 'soapbox/components/icon_with_counter'; @@ -168,10 +169,14 @@ const mapStateToProps = state => { const reportsCount = state.getIn(['admin', 'openReports']).count(); const approvalCount = state.getIn(['admin', 'awaitingApproval']).count(); const instance = state.get('instance'); + const settings = getSettings(state); + + // In demo mode, use the Soapbox logo + const logo = settings.get('demo') ? require('images/soapbox-logo.svg') : getSoapboxConfig(state).get('logo'); return { account: state.getIn(['accounts', me]), - logo: getSoapboxConfig(state).get('logo'), + logo, features: getFeatures(instance), notificationCount: state.getIn(['notifications', 'unread']), chatsCount: state.getIn(['chats', 'items']).reduce((acc, curr) => acc + Math.min(curr.get('unread', 0), 1), 0), From ae7f2f86a019ad2ac2098dd3392e0be3beb7b897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Thu, 27 Jan 2022 17:26:39 +0100 Subject: [PATCH 19/33] Add quoted status tombstone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/components/status.js | 10 +++++++++- .../features/status/components/detailed_status.js | 12 ++++++++++-- app/styles/components/status.scss | 10 ++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/soapbox/components/status.js b/app/soapbox/components/status.js index fe23bae02..5bacc10c1 100644 --- a/app/soapbox/components/status.js +++ b/app/soapbox/components/status.js @@ -477,7 +477,15 @@ class Status extends ImmutablePureComponent { let quote; if (status.get('quote')) { - quote = ; + if (status.getIn(['pleroma', 'quote_visible'], true) === false) { + quote = ( +
+

+
+ ); + } else { + quote = ; + } } if (otherAccounts && otherAccounts.size > 1) { diff --git a/app/soapbox/features/status/components/detailed_status.js b/app/soapbox/features/status/components/detailed_status.js index a54c9bda5..b0e1b6a6c 100644 --- a/app/soapbox/features/status/components/detailed_status.js +++ b/app/soapbox/features/status/components/detailed_status.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import React from 'react'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { injectIntl } from 'react-intl'; +import { FormattedMessage, injectIntl } from 'react-intl'; import { FormattedDate } from 'react-intl'; import { Link, NavLink } from 'react-router-dom'; @@ -164,7 +164,15 @@ class DetailedStatus extends ImmutablePureComponent { let quote; if (status.get('quote')) { - quote = ; + if (status.getIn(['pleroma', 'quote_visible'], true) === false) { + quote = ( +
+

+
+ ); + } else { + quote = ; + } } if (status.get('visibility') === 'direct') { diff --git a/app/styles/components/status.scss b/app/styles/components/status.scss index 9633ae100..eca5fd091 100644 --- a/app/styles/components/status.scss +++ b/app/styles/components/status.scss @@ -820,4 +820,14 @@ a.status-card.compact:hover { .attachment-thumbs .media-gallery { margin-top: 5px !important; } + + &-tombstone { + margin-top: 14px; + padding: 12px; + border: 1px solid var(--brand-color--med); + border-radius: 10px; + color: var(--primary-text-color--faint); + font-size: 14px; + text-align: center; + } } From e5e4105a03908e4d65a82c16714d1651c5887ced Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 28 Jan 2022 10:17:38 -0600 Subject: [PATCH 20/33] Fix quote_visible for nested quote --- app/soapbox/reducers/statuses.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/soapbox/reducers/statuses.js b/app/soapbox/reducers/statuses.js index 9c1f61109..f0f3da3ec 100644 --- a/app/soapbox/reducers/statuses.js +++ b/app/soapbox/reducers/statuses.js @@ -52,7 +52,9 @@ const fixQuote = (state, status) => { const oldStatus = state.get(status.get('id')); if (oldStatus && !status.get('quote') && isQuote(status)) { - return status.set('quote', oldStatus.get('quote')); + return status + .set('quote', oldStatus.get('quote')) + .updateIn(['pleroma', 'quote_visible'], visible => visible || oldStatus.getIn(['pleroma', 'quote_visible'])); } else { return status; } From 309981a2949f5e7ac1c75e3d6e9b4f4b9cb5d8b9 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 28 Jan 2022 11:52:41 -0600 Subject: [PATCH 21/33] sw.js: Fix display of RT line in push notifications --- app/soapbox/service_worker/web_push_notifications.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/service_worker/web_push_notifications.js b/app/soapbox/service_worker/web_push_notifications.js index a43fec6d8..b73dabf42 100644 --- a/app/soapbox/service_worker/web_push_notifications.js +++ b/app/soapbox/service_worker/web_push_notifications.js @@ -73,7 +73,7 @@ const formatMessage = (messageId, locale, values = {}) => (new IntlMessageFormat(locales[locale][messageId], locale)).format(values); const htmlToPlainText = html => - unescape(html.replace(//g, '\n').replace(/<\/p>

/g, '\n\n').replace(/<[^>]*>/g, '')); + unescape(html.replace(//g, '\n').replace(/<\/p><[^>]*>/g, '\n\n').replace(/<[^>]*>/g, '')); const handlePush = (event) => { const { access_token, notification_id, preferred_locale, title, body, icon } = event.data.json(); From 65a71b76534b5bcbae45074ae7b545fe72fc88ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Fri, 28 Jan 2022 21:11:03 +0100 Subject: [PATCH 22/33] Add line-clamp to quoted post content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/styles/components/status.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/styles/components/status.scss b/app/styles/components/status.scss index eca5fd091..cc5cf8cdf 100644 --- a/app/styles/components/status.scss +++ b/app/styles/components/status.scss @@ -804,6 +804,11 @@ a.status-card.compact:hover { } &__content { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: 6; + -webkit-box-orient: vertical; margin-top: 5px; font-size: 14px; From cac8b5026e5e7c4e56dd6be9b6db69d2d6aaf677 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 28 Jan 2022 14:52:22 -0600 Subject: [PATCH 23/33] Fix RT spacing in the other place --- app/soapbox/utils/html.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/utils/html.js b/app/soapbox/utils/html.js index fec437c03..f303ba8e8 100644 --- a/app/soapbox/utils/html.js +++ b/app/soapbox/utils/html.js @@ -1,7 +1,7 @@ // NB: This function can still return unsafe HTML export const unescapeHTML = (html) => { const wrapper = document.createElement('div'); - wrapper.innerHTML = html.replace(//g, '\n').replace(/<\/p>

/g, '\n\n').replace(/<[^>]*>/g, ''); + wrapper.innerHTML = html.replace(//g, '\n').replace(/<\/p><[^>]*>/g, '\n\n').replace(/<[^>]*>/g, ''); return wrapper.textContent; }; From 630f583c2ff2201547a55360daeaca888aadd897 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sun, 30 Jan 2022 09:47:31 -0600 Subject: [PATCH 24/33] Strip all instances of compat features from statuses --- app/soapbox/utils/html.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/soapbox/utils/html.js b/app/soapbox/utils/html.js index f303ba8e8..9eddcf876 100644 --- a/app/soapbox/utils/html.js +++ b/app/soapbox/utils/html.js @@ -14,12 +14,11 @@ export const stripCompatibilityFeatures = html => { '.recipients-inline', ]; + // Remove all instances of all selectors selectors.forEach(selector => { - const elem = node.querySelector(selector); - - if (elem) { + node.querySelectorAll(selector).forEach(elem => { elem.remove(); - } + }); }); return node.innerHTML; From a0af3310b1bdd3ed2223c88af82ab70dc8646192 Mon Sep 17 00:00:00 2001 From: Isabell Deinschnitzel <6174132-iss_dein_schnitzel@users.noreply.gitlab.com> Date: Sun, 30 Jan 2022 22:01:23 +0000 Subject: [PATCH 25/33] Update de.json --- app/soapbox/locales/de.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/locales/de.json b/app/soapbox/locales/de.json index 866cfcd22..d4bf70722 100644 --- a/app/soapbox/locales/de.json +++ b/app/soapbox/locales/de.json @@ -783,7 +783,7 @@ "reply_indicator.cancel": "Abbrechen", "reply_mentions.account.add": "Add to mentions", "reply_mentions.account.remove": "Remove from mentions", - "reply_mentions.more": "und {count, plural, one {einen weiteren Nutzer} other {# weitere Nutzer}}.", + "reply_mentions.more": "und {count, plural, one {einen weiteren Nutzer} other {# weitere Nutzer}}", "reply_mentions.reply": "Antwort an {accounts}{more}", "reply_mentions.reply_empty": "Antwort auf einen Beitrag", "report.block": "{target} blockieren.", From 0166dd40ffb0d66a9eb1d20ed10e24359d6f3a05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 30 Jan 2022 23:17:55 +0100 Subject: [PATCH 26/33] Fix quoted status content with multiple paragraphs on Firefox MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/styles/components/status.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/styles/components/status.scss b/app/styles/components/status.scss index cc5cf8cdf..ba06c5039 100644 --- a/app/styles/components/status.scss +++ b/app/styles/components/status.scss @@ -809,6 +809,7 @@ a.status-card.compact:hover { text-overflow: ellipsis; -webkit-line-clamp: 6; -webkit-box-orient: vertical; + max-height: 114px; margin-top: 5px; font-size: 14px; From 7e7ca52cca8e3cdbb630f26e0b5ab0611578a620 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Jan 2022 10:49:51 -0600 Subject: [PATCH 27/33] Delay rendering until instance has loaded or failed (for feature detection) --- app/soapbox/containers/soapbox.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js index 40b4e10b6..23c0a84bd 100644 --- a/app/soapbox/containers/soapbox.js +++ b/app/soapbox/containers/soapbox.js @@ -31,6 +31,14 @@ import configureStore from '../store/configureStore'; const validLocale = locale => Object.keys(messages).includes(locale); +// Delay rendering until instance has loaded or failed (for feature detection) +const isInstanceLoaded = state => { + const v = state.getIn(['instance', 'version']); + const fetchFailed = state.getIn(['meta', 'instance_fetch_failed'], false); + + return v !== '0.0.0' || fetchFailed; +}; + export const store = configureStore(); // Configure global functions for developers @@ -60,6 +68,7 @@ const mapStateToProps = (state) => { return { showIntroduction, me, + instanceLoaded: isInstanceLoaded(state), reduceMotion: settings.get('reduceMotion'), underlineLinks: settings.get('underlineLinks'), systemFont: settings.get('systemFont'), @@ -80,6 +89,7 @@ class SoapboxMount extends React.PureComponent { static propTypes = { showIntroduction: PropTypes.bool, me: SoapboxPropTypes.me, + instanceLoaded: PropTypes.bool, reduceMotion: PropTypes.bool, underlineLinks: PropTypes.bool, systemFont: PropTypes.bool, @@ -124,8 +134,9 @@ class SoapboxMount extends React.PureComponent { } render() { - const { me, themeCss, locale, customCss } = this.props; + const { me, instanceLoaded, themeCss, locale, customCss } = this.props; if (me === null) return null; + if (!instanceLoaded) return null; if (this.state.localeLoading) return null; // Disabling introduction for launch From 6e889c7a4f3ca17c03a5049e5ad13798ab98f60d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Jan 2022 11:18:44 -0600 Subject: [PATCH 28/33] Mastodon: fall back to account lookup API --- app/soapbox/actions/accounts.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index aacdcd106..fe0f5519a 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -156,14 +156,7 @@ export function fetchAccountByUsername(username) { const features = getFeatures(instance); const me = state.get('me'); - if (!me && features.accountLookup) { - dispatch(accountLookup(username)).then(account => { - dispatch(fetchAccountSuccess(account)); - }).catch(error => { - dispatch(fetchAccountFail(null, error)); - dispatch(importErrorWhileFetchingAccountByUsername(username)); - }); - } else if (features.accountByUsername) { + if (features.accountByUsername && (me || !features.accountLookup)) { api(getState).get(`/api/v1/accounts/${username}`).then(response => { dispatch(fetchRelationships([response.data.id])); dispatch(importFetchedAccount(response.data)); @@ -172,6 +165,13 @@ export function fetchAccountByUsername(username) { dispatch(fetchAccountFail(null, error)); dispatch(importErrorWhileFetchingAccountByUsername(username)); }); + } else if (features.accountLookup) { + dispatch(accountLookup(username)).then(account => { + dispatch(fetchAccountSuccess(account)); + }).catch(error => { + dispatch(fetchAccountFail(null, error)); + dispatch(importErrorWhileFetchingAccountByUsername(username)); + }); } else { dispatch(accountSearch({ q: username, From 0d000bf4e00818c8a4277e1e8eb1ec8b864cc868 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Jan 2022 11:23:39 -0600 Subject: [PATCH 29/33] Set instance version default, just in case... --- app/soapbox/containers/soapbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/containers/soapbox.js b/app/soapbox/containers/soapbox.js index 23c0a84bd..301de4c01 100644 --- a/app/soapbox/containers/soapbox.js +++ b/app/soapbox/containers/soapbox.js @@ -33,7 +33,7 @@ const validLocale = locale => Object.keys(messages).includes(locale); // Delay rendering until instance has loaded or failed (for feature detection) const isInstanceLoaded = state => { - const v = state.getIn(['instance', 'version']); + const v = state.getIn(['instance', 'version'], '0.0.0'); const fetchFailed = state.getIn(['meta', 'instance_fetch_failed'], false); return v !== '0.0.0' || fetchFailed; From b665891659b79e1999bca8e2f252712ceaf490f7 Mon Sep 17 00:00:00 2001 From: t t Date: Tue, 1 Feb 2022 01:00:32 +0000 Subject: [PATCH 30/33] Shavian transliteration --- app/soapbox/features/preferences/index.js | 1 + app/soapbox/locales/en-Shaw.json | 975 ++++++++++++++++++++++ app/soapbox/locales/messages.js | 1 + 3 files changed, 977 insertions(+) create mode 100644 app/soapbox/locales/en-Shaw.json diff --git a/app/soapbox/features/preferences/index.js b/app/soapbox/features/preferences/index.js index 4cf74d702..77b59b4b5 100644 --- a/app/soapbox/features/preferences/index.js +++ b/app/soapbox/features/preferences/index.js @@ -32,6 +32,7 @@ export const languages = { da: 'Dansk', de: 'Deutsch', el: 'Ελληνικά', + 'en-Shaw': '𐑖𐑱𐑝𐑾𐑯', eo: 'Esperanto', es: 'Español', eu: 'Euskara', diff --git a/app/soapbox/locales/en-Shaw.json b/app/soapbox/locales/en-Shaw.json new file mode 100644 index 000000000..ae0b73eb2 --- /dev/null +++ b/app/soapbox/locales/en-Shaw.json @@ -0,0 +1,975 @@ +{ + "about.also_available": "𐑩𐑝𐑱𐑤𐑩𐑚𐑩𐑤 𐑦𐑯:", + "accordion.collapse": "𐑒𐑩𐑤𐑨𐑐𐑕", + "accordion.expand": "𐑦𐑒𐑕𐑐𐑨𐑯𐑛", + "account.add_or_remove_from_list": "𐑨𐑛 𐑹 𐑮𐑦𐑥𐑵𐑝 𐑮𐑦𐑥𐑵𐑝 𐑤𐑦𐑕𐑑𐑕", + "account.badges.bot": "𐑚𐑪𐑑", + "account.block": "𐑚𐑤𐑪𐑒 @{name}", + "account.block_domain": "𐑣𐑲𐑛 𐑧𐑝𐑮𐑦𐑔𐑦𐑙 𐑓𐑮𐑪𐑥 {domain}", + "account.blocked": "𐑚𐑤𐑪𐑒𐑑", + "account.chat": "𐑗𐑨𐑑 𐑢𐑦𐑞 @{name}", + "account.column_settings.description": "𐑞𐑰𐑟 𐑕𐑧𐑑𐑦𐑙𐑟 𐑩𐑐𐑤𐑲 𐑑 𐑷𐑤 𐑩𐑒𐑬𐑯𐑑 𐑑𐑲𐑥𐑤𐑲𐑯𐑟.", + "account.column_settings.title": "𐑩𐑒𐑬𐑯𐑑 𐑑𐑲𐑥𐑤𐑲𐑯 𐑕𐑧𐑑𐑦𐑙𐑟", + "account.deactivated": "𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑𐑩𐑛", + "account.deactivated_description": "𐑞𐑦𐑕 𐑩𐑒𐑬𐑯𐑑 𐑣𐑨𐑟 𐑚𐑰𐑯 𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑𐑩𐑛.", + "account.direct": "𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡 @{name}", + "account.domain_blocked": "𐑛𐑴𐑥𐑱𐑯 𐑣𐑦𐑛𐑩𐑯", + "account.edit_profile": "𐑧𐑛𐑦𐑑 𐑐𐑮𐑴𐑓𐑲𐑤", + "account.endorse": "𐑓𐑰𐑗𐑼 𐑪𐑯 𐑐𐑮𐑴𐑓𐑲𐑤", + "account.follow": "𐑓𐑪𐑤𐑴", + "account.followers": "𐑓𐑪𐑤𐑴𐑼𐑟", + "account.followers.empty": "𐑯𐑴 𐑢𐑳𐑯 𐑓𐑪𐑤𐑴𐑟 𐑞𐑦𐑕 𐑿𐑟𐑼 𐑘𐑧𐑑.", + "account.follows": "𐑓𐑪𐑤𐑴𐑟", + "account.follows.empty": "𐑞𐑦𐑕 𐑿𐑟𐑼 𐑛𐑳𐑟𐑩𐑯𐑑 𐑓𐑪𐑤𐑴 𐑧𐑯𐑦𐑢𐑳𐑯 𐑘𐑧𐑑.", + "account.follows_you": "𐑓𐑪𐑤𐑴𐑟 𐑿", + "account.hide_reblogs": "𐑣𐑲𐑛 𐑮𐑰𐑐𐑴𐑕𐑑𐑕 𐑓𐑮𐑪𐑥 @{name}", + "account.last_status": "𐑤𐑭𐑕𐑑 𐑨𐑒𐑑𐑦𐑝", + "account.link_verified_on": "𐑴𐑯𐑼𐑖𐑦𐑐 𐑝 𐑞𐑦𐑕 𐑤𐑦𐑙𐑒 𐑢𐑪𐑟 𐑗𐑧𐑒𐑑 𐑪𐑯 {date}", + "account.locked_info": "𐑞𐑦𐑕 𐑩𐑒𐑬𐑯𐑑 𐑐𐑮𐑦𐑝𐑩𐑕𐑦 𐑕𐑑𐑱𐑑𐑩𐑕 𐑦𐑟 𐑕𐑧𐑑 𐑑 𐑤𐑪𐑒𐑑. 𐑞 𐑴𐑯𐑼 𐑥𐑨𐑯𐑘𐑫𐑩𐑤𐑦 𐑮𐑦𐑝𐑿𐑟 𐑣𐑵 𐑒𐑨𐑯 𐑓𐑪𐑤𐑴 𐑞𐑧𐑥.", + "account.login": "𐑤𐑪𐑜 𐑦𐑯", + "account.media": "𐑥𐑰𐑛𐑾", + "account.member_since": "𐑡𐑶𐑯𐑛 {date}", + "account.mention": "𐑥𐑧𐑯𐑖𐑩𐑯", + "account.moved_to": "{name} 𐑣𐑨𐑟 𐑥𐑵𐑝𐑛 𐑑:", + "account.mute": "𐑥𐑿𐑑 @{name}", + "account.muted": "𐑥𐑿𐑑𐑩𐑛", + "account.never_active": "𐑯𐑧𐑝𐑼", + "account.posts": "𐑐𐑴𐑕𐑑𐑕", + "account.posts_with_replies": "𐑐𐑴𐑕𐑑𐑕 𐑯 𐑮𐑦𐑐𐑤𐑲𐑟", + "account.profile": "𐑐𐑮𐑴𐑓𐑲𐑤", + "account.register": "𐑕𐑲𐑯 𐑳𐑐", + "account.remote_follow": "𐑮𐑦𐑥𐑴𐑑 𐑓𐑪𐑤𐑴", + "account.report": "𐑮𐑦𐑐𐑹𐑑 @{name}", + "account.requested": "𐑩𐑢𐑱𐑑𐑦𐑙 𐑩𐑐𐑮𐑵𐑝𐑩𐑤. 𐑒𐑤𐑦𐑒 𐑑 𐑒𐑨𐑯𐑕𐑩𐑤 𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑", + "account.requested_small": "𐑩𐑢𐑱𐑑𐑦𐑙 𐑩𐑐𐑮𐑵𐑝𐑩𐑤", + "account.share": "𐑖𐑺 @{name}'s 𐑐𐑮𐑴𐑓𐑲𐑤", + "account.show_reblogs": "𐑖𐑴 𐑮𐑰𐑐𐑴𐑕𐑑𐑕 𐑓𐑮𐑪𐑥 @{name}", + "account.subscribe": "𐑕𐑩𐑚𐑕𐑒𐑮𐑲𐑚 𐑑 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑓𐑮𐑪𐑥 @{name}", + "account.subscribed": "𐑕𐑩𐑚𐑕𐑒𐑮𐑲𐑚𐑛", + "account.unblock": "𐑳𐑯𐑚𐑤𐑪𐑒 @{name}", + "account.unblock_domain": "𐑳𐑯𐑣𐑲𐑛 {domain}", + "account.unendorse": "𐑛𐑴𐑯𐑑 𐑓𐑰𐑗𐑼 𐑪𐑯 𐑐𐑮𐑴𐑓𐑲𐑤", + "account.unfollow": "𐑳𐑯𐑓𐑪𐑤𐑴", + "account.unmute": "𐑳𐑯𐑥𐑿𐑑 @{name}", + "account.unsubscribe": "𐑳𐑯𐑕𐑩𐑚𐑕𐑒𐑮𐑲𐑚 𐑑 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑓𐑮𐑪𐑥 @{name}", + "account_gallery.none": "𐑯𐑴 𐑥𐑰𐑛𐑾 𐑑 𐑖𐑴.", + "account_search.placeholder": "𐑕𐑻𐑗 𐑓 𐑩𐑯 𐑩𐑒𐑬𐑯𐑑", + "account_timeline.column_settings.show_pinned": "𐑖𐑴 𐑐𐑦𐑯𐑛 𐑐𐑴𐑕𐑑𐑕", + "admin.awaiting_approval.approved_message": "{acct} 𐑢𐑪𐑟 𐑩𐑐𐑮𐑵𐑝𐑛!", + "admin.awaiting_approval.empty_message": "𐑞𐑺 𐑦𐑟 𐑯𐑴𐑚𐑪𐑛𐑦 𐑢𐑱𐑑𐑦𐑙 𐑓 𐑩𐑐𐑮𐑵𐑝𐑩𐑤. 𐑢𐑧𐑯 𐑩 𐑯𐑿 𐑿𐑟𐑼 𐑕𐑲𐑯𐑟 𐑳𐑐, 𐑿 𐑒𐑨𐑯 𐑮𐑦𐑝𐑿 𐑞𐑧𐑥 𐑣𐑽.", + "admin.awaiting_approval.rejected_message": "{acct} 𐑢𐑪𐑟 𐑮𐑦𐑡𐑧𐑒𐑑𐑩𐑛.", + "admin.dashboard.registration_mode.approval_hint": "𐑿𐑟𐑼𐑟 𐑒𐑨𐑯 𐑕𐑲𐑯 𐑳𐑐, 𐑚𐑳𐑑 𐑞𐑺 𐑩𐑒𐑬𐑯𐑑 𐑴𐑯𐑤𐑦 𐑜𐑧𐑑𐑕 𐑨𐑒𐑑𐑦𐑝𐑱𐑑𐑩𐑛 𐑢𐑧𐑯 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯 𐑩𐑐𐑮𐑵𐑝𐑟 𐑦𐑑.", + "admin.dashboard.registration_mode.approval_label": "𐑩𐑐𐑮𐑵𐑝𐑩𐑤 𐑮𐑦𐑒𐑢𐑲𐑼𐑛", + "admin.dashboard.registration_mode.closed_hint": "𐑯𐑴𐑚𐑪𐑛𐑦 𐑒𐑨𐑯 𐑕𐑲𐑯 𐑳𐑐. 𐑿 𐑒𐑨𐑯 𐑕𐑑𐑦𐑤 𐑦𐑯𐑝𐑲𐑑 𐑐𐑰𐑐𐑩𐑤.", + "admin.dashboard.registration_mode.closed_label": "𐑒𐑤𐑴𐑟𐑛", + "admin.dashboard.registration_mode.open_hint": "𐑧𐑯𐑦𐑢𐑳𐑯 𐑒𐑨𐑯 𐑡𐑶𐑯.", + "admin.dashboard.registration_mode.open_label": "𐑴𐑐𐑩𐑯", + "admin.dashboard.registration_mode_label": "𐑮𐑧𐑡𐑦𐑕𐑑𐑮𐑱𐑖𐑩𐑯𐑟", + "admin.dashboard.settings_saved": "𐑕𐑧𐑑𐑦𐑙𐑟 𐑕𐑱𐑝𐑛!", + "admin.dashcounters.domain_count_label": "𐑐𐑽𐑟", + "admin.dashcounters.mau_label": "𐑥𐑳𐑯𐑔𐑤𐑦 𐑨𐑒𐑑𐑦𐑝 𐑿𐑟𐑼𐑟", + "admin.dashcounters.retention_label": "𐑿𐑟𐑼 𐑮𐑦𐑑𐑧𐑯𐑖𐑩𐑯", + "admin.dashcounters.status_count_label": "𐑐𐑴𐑕𐑑𐑕", + "admin.dashcounters.user_count_label": "𐑑𐑴𐑑𐑩𐑤 𐑿𐑟𐑼𐑟", + "admin.dashwidgets.email_list_header": "𐑰𐑥𐑱𐑤 𐑤𐑦𐑕𐑑", + "admin.dashwidgets.software_header": "𐑕𐑪𐑓𐑑𐑢𐑺", + "admin.latest_accounts_panel.expand_message": "𐑒𐑤𐑦𐑒 𐑑 𐑕𐑰 {count} 𐑥𐑹 {count, plural, one {account} other {accounts}}", + "admin.latest_accounts_panel.title": "𐑤𐑱𐑑𐑩𐑕𐑑 𐑩𐑒𐑬𐑯𐑑𐑕", + "admin.moderation_log.empty_message": "𐑿 𐑣𐑨𐑝 𐑯𐑪𐑑 𐑐𐑼𐑓𐑹𐑥𐑛 𐑧𐑯𐑦 𐑥𐑪𐑛𐑼𐑱𐑖𐑩𐑯 𐑨𐑒𐑖𐑩𐑯𐑟 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 do, 𐑩 𐑣𐑦𐑕𐑑𐑼𐑦 𐑢𐑦𐑤 𐑚𐑰 𐑖𐑴𐑯 𐑣𐑽.", + "admin.reports.actions.close": "𐑒𐑤𐑴𐑟", + "admin.reports.actions.view_status": "𐑝𐑿 𐑐𐑴𐑕𐑑", + "admin.reports.empty_message": "𐑞𐑺 𐑸 𐑯𐑴 𐑴𐑐𐑩𐑯 𐑮𐑦𐑐𐑹𐑑𐑕. 𐑦𐑓 𐑩 𐑿𐑟𐑼 𐑜𐑧𐑑𐑕 𐑮𐑦𐑐𐑹𐑑𐑩𐑛, 𐑞𐑱 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "admin.reports.report_closed_message": "𐑮𐑦𐑐𐑹𐑑 𐑪𐑯 @{name} 𐑢𐑪𐑟 𐑒𐑤𐑴𐑟𐑛", + "admin.reports.report_title": "𐑮𐑦𐑐𐑹𐑑 𐑪𐑯 {acct}", + "admin.statuses.actions.delete_status": "𐑛𐑦𐑤𐑰𐑑 𐑐𐑴𐑕𐑑", + "admin.statuses.actions.mark_status_not_sensitive": "𐑥𐑸𐑒 𐑐𐑴𐑕𐑑 𐑯𐑪𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "admin.statuses.actions.mark_status_sensitive": "𐑥𐑸𐑒 𐑐𐑴𐑕𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "admin.statuses.status_deleted_message": "𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct} 𐑢𐑪𐑟 𐑛𐑦𐑤𐑰𐑑𐑩𐑛", + "admin.statuses.status_marked_message_not_sensitive": "𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct} 𐑢𐑪𐑟 𐑥𐑸𐑒𐑑 𐑯𐑪𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "admin.statuses.status_marked_message_sensitive": "𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct} 𐑢𐑪𐑟 𐑥𐑸𐑒𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "admin.user_index.empty": "𐑯𐑴 𐑿𐑟𐑼𐑟 𐑓𐑬𐑯𐑛.", + "admin.user_index.search_input_placeholder": "𐑣𐑵 𐑸 𐑿 𐑤𐑫𐑒𐑦𐑙 for?", + "admin.users.actions.deactivate_user": "𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑 @{name}", + "admin.users.actions.delete_user": "𐑛𐑦𐑤𐑰𐑑 @{name}", + "admin.users.actions.demote_to_moderator": "𐑛𐑦𐑥𐑴𐑑 @{name} 𐑑 𐑩 𐑥𐑪𐑛𐑼𐑱𐑑𐑼", + "admin.users.actions.demote_to_moderator_message": "@{acct} 𐑢𐑪𐑟 𐑛𐑦𐑥𐑴𐑑𐑩𐑛 𐑑 𐑩 𐑥𐑪𐑛𐑼𐑱𐑑𐑼", + "admin.users.actions.demote_to_user": "𐑛𐑦𐑥𐑴𐑑 @{name} 𐑑 𐑩 𐑮𐑧𐑜𐑘𐑩𐑤𐑼 𐑿𐑟𐑼", + "admin.users.actions.demote_to_user_message": "@{acct} 𐑢𐑪𐑟 𐑛𐑦𐑥𐑴𐑑𐑩𐑛 𐑑 𐑩 𐑮𐑧𐑜𐑘𐑩𐑤𐑼 𐑿𐑟𐑼", + "admin.users.actions.promote_to_admin": "𐑐𐑮𐑩𐑥𐑴𐑑 @{name} 𐑑 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯", + "admin.users.actions.promote_to_admin_message": "@{acct} 𐑢𐑪𐑟 𐑐𐑮𐑩𐑥𐑴𐑑𐑩𐑛 𐑑 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯", + "admin.users.actions.promote_to_moderator": "𐑐𐑮𐑩𐑥𐑴𐑑 @{name} 𐑑 𐑩 𐑥𐑪𐑛𐑼𐑱𐑑𐑼", + "admin.users.actions.promote_to_moderator_message": "@{acct} 𐑢𐑪𐑟 𐑐𐑮𐑩𐑥𐑴𐑑𐑩𐑛 𐑑 𐑩 𐑥𐑪𐑛𐑼𐑱𐑑𐑼", + "admin.users.actions.suggest_user": "𐑕𐑩𐑡𐑧𐑕𐑑 @{name}", + "admin.users.actions.unsuggest_user": "𐑳𐑯𐑕𐑩𐑡𐑧𐑕𐑑 @{name}", + "admin.users.actions.unverify_user": "𐑳𐑯𐑝𐑧𐑮𐑦𐑓𐑲 @{name}", + "admin.users.actions.verify_user": "𐑝𐑧𐑮𐑦𐑓𐑲 @{name}", + "admin.users.user_deactivated_message": "@{acct} 𐑢𐑪𐑟 𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑𐑩𐑛", + "admin.users.user_deleted_message": "@{acct} 𐑢𐑪𐑟 𐑛𐑦𐑤𐑰𐑑𐑩𐑛", + "admin.users.user_suggested_message": "@{acct} 𐑢𐑪𐑟 𐑕𐑩𐑡𐑧𐑕𐑑𐑩𐑛", + "admin.users.user_unsuggested_message": "@{acct} 𐑢𐑪𐑟 𐑳𐑯𐑕𐑩𐑡𐑧𐑕𐑑𐑩𐑛", + "admin.users.user_unverified_message": "@{acct} 𐑢𐑪𐑟 𐑳𐑯𐑝𐑧𐑮𐑦𐑓𐑲𐑛", + "admin.users.user_verified_message": "@{acct} 𐑢𐑪𐑟 𐑝𐑧𐑮𐑦𐑓𐑲𐑛", + "admin_nav.awaiting_approval": "𐑩𐑢𐑱𐑑𐑦𐑙 𐑩𐑐𐑮𐑵𐑝𐑩𐑤", + "admin_nav.dashboard": "𐑛𐑨𐑖𐑚𐑹𐑛", + "admin_nav.reports": "𐑮𐑦𐑐𐑹𐑑𐑕", + "alert.unexpected.clear_cookies": "𐑒𐑤𐑽 𐑒𐑫𐑒𐑦𐑟 𐑯 𐑚𐑮𐑬𐑟𐑼 𐑛𐑱𐑑𐑩", + "alert.unexpected.help_text": "𐑦𐑓 𐑞 𐑐𐑮𐑪𐑚𐑤𐑩𐑥 𐑐𐑼𐑕𐑦𐑕𐑑𐑕, 𐑐𐑤𐑰𐑟 𐑯𐑴𐑑𐑦𐑓𐑲 𐑩 𐑕𐑲𐑑 𐑨𐑛𐑥𐑦𐑯 𐑢𐑦𐑞 𐑩 𐑕𐑒𐑮𐑰𐑯𐑖𐑪𐑑 𐑯 𐑦𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑩𐑚𐑬𐑑 𐑘𐑹 𐑢𐑧𐑚 𐑚𐑮𐑬𐑟𐑼. 𐑿 𐑥𐑱 𐑷𐑤𐑕𐑴 {clear_cookies} (𐑞𐑦𐑕 𐑢𐑦𐑤 𐑤𐑪𐑜 𐑿 𐑬𐑑).", + "alert.unexpected.message": "𐑩𐑯 𐑳𐑯𐑦𐑒𐑕𐑐𐑧𐑒𐑑𐑩𐑛 𐑧𐑮𐑼 occurred.", + "alert.unexpected.return_home": "𐑮𐑦𐑑𐑻𐑯 𐑣𐑴𐑥", + "alert.unexpected.title": "𐑵𐑐𐑕!", + "aliases.account.add": "𐑒𐑮𐑦𐑱𐑑 𐑱𐑤𐑾𐑕", + "aliases.account_label": "𐑴𐑤𐑛 𐑩𐑒𐑬𐑯𐑑:", + "aliases.aliases_list_delete": "𐑳𐑯𐑤𐑦𐑙𐑒 𐑱𐑤𐑾𐑕", + "aliases.search": "𐑕𐑻𐑗 𐑘𐑹 𐑴𐑤𐑛 𐑩𐑒𐑬𐑯𐑑", + "aliases.success.add": "𐑩𐑒𐑬𐑯𐑑 𐑱𐑤𐑾𐑕 𐑒𐑮𐑦𐑱𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "aliases.success.remove": "𐑩𐑒𐑬𐑯𐑑 𐑱𐑤𐑾𐑕 𐑮𐑦𐑥𐑵𐑝𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "app_create.name_label": "𐑨𐑐 𐑯𐑱𐑥", + "app_create.name_placeholder": "e.g. 'Soapbox'", + "app_create.redirect_uri_label": "𐑮𐑰𐑛𐑦𐑮𐑧𐑒𐑑 URIs", + "app_create.restart": "𐑒𐑮𐑦𐑱𐑑 𐑩𐑯𐑳𐑞𐑼", + "app_create.results.app_label": "𐑨𐑐", + "app_create.results.explanation_text": "𐑿 𐑒𐑮𐑦𐑱𐑑𐑩𐑛 𐑩 𐑯𐑿 𐑨𐑐 𐑯 𐑑𐑴𐑒𐑩𐑯! 𐑐𐑤𐑰𐑟 𐑒𐑪𐑐𐑦 𐑞 𐑒𐑮𐑦𐑛𐑧𐑯𐑖𐑩𐑤𐑟 𐑕𐑳𐑥𐑢𐑺; 𐑿 𐑢𐑦𐑤 𐑯𐑪𐑑 𐑕𐑰 𐑞𐑧𐑥 𐑩𐑜𐑱𐑯 𐑭𐑓𐑑𐑼 𐑯𐑨𐑝𐑦𐑜𐑱𐑑𐑦𐑙 𐑩𐑢𐑱 𐑓𐑮𐑪𐑥 𐑞𐑦𐑕 𐑐𐑱𐑡.", + "app_create.results.explanation_title": "𐑨𐑐 𐑒𐑮𐑦𐑱𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "app_create.results.token_label": "OAuth 𐑑𐑴𐑒𐑩𐑯", + "app_create.scopes_label": "𐑕𐑒𐑴𐑐𐑕", + "app_create.scopes_placeholder": "e.g. 'read write follow'", + "app_create.submit": "𐑒𐑮𐑦𐑱𐑑 𐑨𐑐", + "app_create.website_label": "𐑢𐑧𐑚𐑕𐑲𐑑", + "auth.invalid_credentials": "𐑮𐑪𐑙 𐑿𐑟𐑼𐑯𐑱𐑥 𐑹 𐑐𐑭𐑕𐑢𐑻𐑛", + "auth.logged_out": "𐑤𐑪𐑜𐑛 𐑬𐑑.", + "backups.actions.create": "𐑒𐑮𐑦𐑱𐑑 𐑚𐑨𐑒𐑳𐑐", + "backups.empty_message": "𐑯𐑴 𐑚𐑨𐑒𐑳𐑐𐑕 𐑓𐑬𐑯𐑛. {action}", + "backups.empty_message.action": "𐑒𐑮𐑦𐑱𐑑 𐑢𐑳𐑯 𐑯𐑬?", + "backups.pending": "𐑐𐑧𐑯𐑛𐑦𐑙", + "boost_modal.combo": "𐑿 𐑒𐑨𐑯 𐑐𐑮𐑧𐑕 {combo} 𐑑 𐑕𐑒𐑦𐑐 𐑞𐑦𐑕 𐑯𐑧𐑒𐑕𐑑 𐑑𐑲𐑥", + "bundle_column_error.body": "𐑕𐑳𐑥𐑔𐑦𐑙 𐑢𐑧𐑯𐑑 𐑮𐑪𐑙 𐑢𐑲𐑤 𐑤𐑴𐑛𐑦𐑙 𐑞𐑦𐑕 𐑒𐑩𐑥𐑐𐑴𐑯𐑩𐑯𐑑.", + "bundle_column_error.retry": "𐑑𐑮𐑲 𐑩𐑜𐑱𐑯", + "bundle_column_error.title": "𐑯𐑧𐑑𐑢𐑻𐑒 𐑧𐑮𐑼", + "bundle_modal_error.close": "𐑒𐑤𐑴𐑟", + "bundle_modal_error.message": "𐑕𐑳𐑥𐑔𐑦𐑙 𐑢𐑧𐑯𐑑 𐑮𐑪𐑙 𐑢𐑲𐑤 𐑤𐑴𐑛𐑦𐑙 𐑞𐑦𐑕 𐑒𐑩𐑥𐑐𐑴𐑯𐑩𐑯𐑑.", + "bundle_modal_error.retry": "𐑑𐑮𐑲 𐑩𐑜𐑱𐑯", + "chat_box.actions.close": "𐑒𐑤𐑴𐑟 𐑗𐑨𐑑", + "chat_box.actions.send": "𐑕𐑧𐑯𐑛", + "chat_box.input.placeholder": "𐑕𐑧𐑯𐑛 𐑩 𐑥𐑧𐑕𐑦𐑡…", + "chat_panels.main_window.empty": "𐑯𐑴 𐑗𐑨𐑑𐑕 𐑓𐑬𐑯𐑛. 𐑑 𐑕𐑑𐑸𐑑 𐑩 𐑗𐑨𐑑, 𐑝𐑦𐑟𐑦𐑑 𐑩 𐑿𐑟𐑼𐑟 𐑐𐑮𐑴𐑓𐑲𐑤.", + "chat_panels.main_window.title": "𐑗𐑨𐑑𐑕", + "chats.actions.delete": "𐑛𐑦𐑤𐑰𐑑 𐑥𐑧𐑕𐑦𐑡", + "chats.actions.more": "𐑥𐑹", + "chats.actions.report": "𐑮𐑦𐑐𐑹𐑑 𐑿𐑟𐑼", + "chats.attachment": "𐑩𐑑𐑨𐑗𐑥𐑩𐑯𐑑", + "chats.attachment_image": "𐑦𐑥𐑦𐑡", + "chats.audio_toggle_off": "𐑷𐑛𐑦𐑴 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯 𐑪𐑓", + "chats.audio_toggle_on": "𐑷𐑛𐑦𐑴 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯 on", + "chats.dividers.today": "𐑑𐑩𐑛𐑱", + "chats.search_placeholder": "𐑕𐑑𐑸𐑑 𐑩 𐑗𐑨𐑑 𐑢𐑦𐑞…", + "column.admin.awaiting_approval": "𐑩𐑢𐑱𐑑𐑦𐑙 𐑩𐑐𐑮𐑵𐑝𐑩𐑤", + "column.admin.dashboard": "𐑛𐑨𐑖𐑚𐑹𐑛", + "column.admin.moderation_log": "𐑥𐑪𐑛𐑼𐑱𐑖𐑩𐑯 𐑤𐑪𐑜", + "column.admin.reports": "𐑮𐑦𐑐𐑹𐑑𐑕", + "column.admin.reports.menu.moderation_log": "𐑥𐑪𐑛𐑼𐑱𐑖𐑩𐑯 𐑤𐑪𐑜", + "column.admin.users": "𐑿𐑟𐑼𐑟", + "column.aliases": "𐑩𐑒𐑬𐑯𐑑 𐑱𐑤𐑾𐑕𐑩𐑟", + "column.aliases.create_error": "𐑧𐑮𐑼 𐑒𐑮𐑦𐑱𐑑𐑦𐑙 𐑱𐑤𐑾𐑕", + "column.aliases.delete": "𐑛𐑦𐑤𐑰𐑑", + "column.aliases.delete_error": "𐑧𐑮𐑼 𐑛𐑦𐑤𐑰𐑑𐑦𐑙 𐑱𐑤𐑾𐑕", + "column.aliases.subheading_add_new": "𐑨𐑛 𐑯𐑿 𐑱𐑤𐑾𐑕", + "column.aliases.subheading_aliases": "𐑒𐑳𐑮𐑩𐑯𐑑 𐑱𐑤𐑾𐑕𐑩𐑟", + "column.app_create": "𐑒𐑮𐑦𐑱𐑑 𐑨𐑐", + "column.backups": "𐑚𐑨𐑒𐑳𐑐𐑕", + "column.blocks": "𐑚𐑤𐑪𐑒𐑑 𐑿𐑟𐑼𐑟", + "column.bookmarks": "𐑚𐑫𐑒𐑥𐑸𐑒𐑕", + "column.chats": "𐑗𐑨𐑑𐑕", + "column.community": "𐑤𐑴𐑒𐑩𐑤 𐑑𐑲𐑥𐑤𐑲𐑯", + "column.crypto_donate": "𐑛𐑴𐑯𐑱𐑑 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦", + "column.developers": "𐑛𐑦𐑝𐑧𐑤𐑩𐑐𐑼𐑟", + "column.direct": "𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡𐑩𐑟", + "column.directory": "𐑚𐑮𐑬𐑟 𐑐𐑮𐑴𐑓𐑲𐑤s", + "column.domain_blocks": "𐑣𐑦𐑛𐑩𐑯 𐑛𐑴𐑥𐑱𐑯𐑟", + "column.edit_profile": "𐑧𐑛𐑦𐑑 𐑐𐑮𐑴𐑓𐑲𐑤", + "column.export_data": "𐑦𐑒𐑕𐑐𐑹𐑑 𐑛𐑱𐑑𐑩", + "column.favourited_statuses": "𐑤𐑲𐑒𐑑 𐑐𐑴𐑕𐑑𐑕", + "column.favourites": "𐑤𐑲𐑒𐑕", + "column.federation_restrictions": "𐑓𐑧𐑛𐑼𐑱𐑖𐑩𐑯 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟", + "column.filters": "𐑥𐑿𐑑𐑩𐑛 𐑢𐑻𐑛𐑟", + "column.filters.add_new": "𐑨𐑛 𐑯𐑿 𐑓𐑦𐑤𐑑𐑼", + "column.filters.conversations": "𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯𐑟", + "column.filters.create_error": "𐑧𐑮𐑼 𐑨𐑛𐑦𐑙 𐑓𐑦𐑤𐑑𐑼", + "column.filters.delete": "𐑛𐑦𐑤𐑰𐑑", + "column.filters.delete_error": "𐑧𐑮𐑼 𐑛𐑦𐑤𐑰𐑑𐑦𐑙 𐑓𐑦𐑤𐑑𐑼", + "column.filters.drop_header": "𐑛𐑮𐑪𐑐 𐑦𐑯𐑕𐑑𐑧𐑛 𐑝 𐑣𐑲𐑛", + "column.filters.drop_hint": "𐑓𐑦𐑤𐑑𐑼𐑛 𐑐𐑴𐑕𐑑𐑕 𐑢𐑦𐑤 𐑛𐑦𐑕𐑩𐑐𐑽 𐑦𐑮𐑦𐑝𐑻𐑕𐑩𐑚𐑤𐑦, 𐑰𐑝𐑩𐑯 𐑦𐑓 𐑓𐑦𐑤𐑑𐑼 𐑦𐑟 𐑤𐑱𐑑𐑼 𐑮𐑦𐑥𐑵𐑝𐑛", + "column.filters.expires": "𐑦𐑒𐑕𐑐𐑲𐑼 𐑭𐑓𐑑𐑼", + "column.filters.expires_hint": "𐑧𐑒𐑕𐑐𐑦𐑮𐑱𐑖𐑩𐑯 𐑛𐑱𐑑𐑕 𐑸 𐑯𐑪𐑑 𐑒𐑳𐑮𐑩𐑯𐑑𐑤𐑦 𐑕𐑩𐑐𐑹𐑑𐑩𐑛", + "column.filters.home_timeline": "𐑣𐑴𐑥 𐑑𐑲𐑥𐑤𐑲𐑯", + "column.filters.keyword": "𐑒𐑰𐑢𐑻𐑛 𐑹 𐑓𐑮𐑱𐑟", + "column.filters.notifications": "𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "column.filters.public_timeline": "𐑐𐑳𐑚𐑤𐑦𐑒 𐑑𐑲𐑥𐑤𐑲𐑯", + "column.filters.subheading_add_new": "𐑨𐑛 𐑯𐑿 𐑓𐑦𐑤𐑑𐑼", + "column.filters.subheading_filters": "𐑒𐑳𐑮𐑩𐑯𐑑 𐑓𐑦𐑤𐑑𐑼𐑟", + "column.filters.whole_word_header": "𐑣𐑴𐑤 𐑢𐑻𐑛", + "column.filters.whole_word_hint": "𐑢𐑧𐑯 𐑞 𐑒𐑰𐑢𐑻𐑛 𐑹 𐑓𐑮𐑱𐑟 𐑦𐑟 𐑨𐑤𐑓𐑩𐑯𐑿𐑥𐑧𐑮𐑦𐑒 𐑴𐑯𐑤𐑦, 𐑦𐑑 𐑢𐑦𐑤 𐑴𐑯𐑤𐑦 𐑚𐑰 𐑩𐑐𐑤𐑲𐑛 𐑦𐑓 𐑦𐑑 𐑥𐑨𐑗𐑩𐑟 𐑞 𐑣𐑴𐑤 𐑢𐑻𐑛", + "column.follow_requests": "𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑕", + "column.followers": "𐑓𐑪𐑤𐑴𐑼𐑟", + "column.following": "𐑓𐑪𐑤𐑴𐑦𐑙", + "column.groups": "𐑜𐑮𐑵𐑐𐑕", + "column.home": "𐑣𐑴𐑥", + "column.import_data": "𐑦𐑥𐑐𐑹𐑑 𐑛𐑱𐑑𐑩", + "column.info": "𐑕𐑻𐑝𐑼 𐑦𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯", + "column.lists": "𐑤𐑦𐑕𐑑𐑕", + "column.mentions": "𐑥𐑧𐑯𐑖𐑩𐑯𐑟", + "column.mfa": "𐑥𐑳𐑤𐑑𐑦-𐑓𐑨𐑒𐑑𐑼 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯", + "column.mfa_cancel": "𐑒𐑨𐑯𐑕𐑩𐑤", + "column.mfa_confirm_button": "𐑒𐑩𐑯𐑓𐑻𐑥", + "column.mfa_disable_button": "𐑛𐑦𐑕𐑱𐑚𐑩𐑤", + "column.mfa_setup": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑕𐑧𐑑𐑳𐑐", + "column.mutes": "𐑥𐑿𐑑𐑩𐑛 𐑿𐑟𐑼𐑟", + "column.notifications": "𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "column.pins": "𐑐𐑦𐑯𐑛 𐑐𐑴𐑕𐑑𐑕", + "column.preferences": "𐑐𐑮𐑧𐑓𐑼𐑩𐑯𐑕𐑩𐑟", + "column.profile_directory": "𐑐𐑮𐑴𐑓𐑲𐑤 𐑛𐑦𐑮𐑧𐑒𐑑𐑼𐑦", + "column.public": "𐑓𐑧𐑛𐑼𐑱𐑑𐑩𐑛 𐑑𐑲𐑥𐑤𐑲𐑯", + "column.reactions": "𐑮𐑦𐑨𐑒𐑖𐑩𐑯𐑟", + "column.reblogs": "𐑮𐑰𐑐𐑴𐑕𐑑𐑕", + "column.remote": "𐑓𐑧𐑛𐑼𐑱𐑑𐑩𐑛 𐑑𐑲𐑥𐑤𐑲𐑯", + "column.scheduled_statuses": "𐑖𐑧𐑡𐑵𐑤𐑛 𐑐𐑴𐑕𐑑𐑕", + "column.search": "𐑕𐑻𐑗", + "column.security": "𐑕𐑦𐑒𐑘𐑫𐑼𐑦𐑑𐑦", + "column.soapbox_config": "·𐑕𐑴𐑐𐑚𐑪𐑒𐑕 𐑒𐑩𐑯𐑓𐑦𐑜", + "column_back_button.label": "𐑚𐑨𐑒", + "column_forbidden.body": "𐑿 𐑛𐑵 𐑯𐑪𐑑 𐑣𐑨𐑝 𐑐𐑼𐑥𐑦𐑖𐑩𐑯 𐑑 𐑨𐑒𐑕𐑧𐑕 𐑞𐑦𐑕 𐑐𐑱𐑡.", + "column_forbidden.title": "𐑓𐑼𐑚𐑦𐑛𐑩𐑯", + "column_header.hide_settings": "𐑣𐑲𐑛 𐑕𐑧𐑑𐑦𐑙𐑟", + "column_header.show_settings": "𐑖𐑴 𐑕𐑧𐑑𐑦𐑙𐑟", + "community.column_settings.media_only": "𐑥𐑰𐑛𐑾 𐑴𐑯𐑤𐑦", + "community.column_settings.title": "𐑤𐑴𐑒𐑩𐑤 𐑑𐑲𐑥𐑤𐑲𐑯 𐑕𐑧𐑑𐑦𐑙𐑟", + "compose.character_counter.title": "𐑿𐑟𐑛 {chars} 𐑬𐑑 𐑝 {maxChars} 𐑒𐑨𐑮𐑩𐑒𐑑𐑼𐑟", + "compose.invalid_schedule": "𐑿 𐑥𐑳𐑕𐑑 𐑖𐑧𐑡𐑵𐑤 𐑩 𐑐𐑴𐑕𐑑 𐑨𐑑 𐑤𐑰𐑕𐑑 5 𐑥𐑦𐑯𐑦𐑑𐑕 𐑬𐑑.", + "compose.submit_success": "𐑘𐑹 𐑐𐑴𐑕𐑑 𐑢𐑪𐑟 𐑕𐑧𐑯𐑑", + "compose_form.direct_message_warning": "𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑢𐑦𐑤 𐑴𐑯𐑤𐑦 𐑚𐑰 𐑕𐑧𐑯𐑑 𐑑 𐑞 𐑥𐑧𐑯𐑖𐑩𐑯𐑛 𐑿𐑟𐑼𐑟.", + "compose_form.hashtag_warning": "𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑢𐑴𐑯𐑑 𐑚𐑰 𐑤𐑦𐑕𐑑𐑩𐑛 𐑳𐑯𐑛𐑼 𐑧𐑯𐑦 𐑣𐑨𐑖𐑑𐑨𐑜 𐑨𐑟 𐑦𐑑 𐑦𐑟 𐑳𐑯𐑤𐑦𐑕𐑑𐑩𐑛. 𐑴𐑯𐑤𐑦 𐑐𐑳𐑚𐑤𐑦𐑒 𐑐𐑴𐑕𐑑𐑕 𐑒𐑨𐑯 𐑚𐑰 𐑕𐑻𐑗𐑑 𐑚𐑲 𐑣𐑨𐑖𐑑𐑨𐑜.", + "compose_form.lock_disclaimer": "𐑘𐑹 𐑩𐑒𐑬𐑯𐑑 𐑦𐑟 𐑯𐑪𐑑 {locked}. 𐑧𐑯𐑦𐑢𐑳𐑯 𐑒𐑨𐑯 𐑓𐑪𐑤𐑴 𐑿 𐑑 𐑝𐑿 𐑘𐑹 𐑓𐑪𐑤𐑴𐑼-𐑴𐑯𐑤𐑦 𐑐𐑴𐑕𐑑𐑕.", + "compose_form.lock_disclaimer.lock": "𐑤𐑪𐑒𐑑", + "compose_form.markdown.marked": "𐑐𐑴𐑕𐑑 𐑥𐑸𐑒𐑛𐑬𐑯 𐑦𐑯𐑱𐑚𐑩𐑤𐑛", + "compose_form.markdown.unmarked": "𐑐𐑴𐑕𐑑 𐑥𐑸𐑒𐑛𐑬𐑯 𐑛𐑦𐑕𐑱𐑚𐑩𐑤𐑛", + "compose_form.message": "𐑥𐑧𐑕𐑦𐑡", + "compose_form.placeholder": "𐑢𐑪𐑑𐑕 𐑪𐑯 𐑘𐑹 𐑥𐑲𐑯𐑛?", + "compose_form.poll.add_option": "𐑨𐑛 𐑩 𐑗𐑶𐑕", + "compose_form.poll.duration": "𐑐𐑴𐑤 𐑛𐑘𐑫𐑼𐑱𐑖𐑩𐑯", + "compose_form.poll.option_placeholder": "𐑗𐑶𐑕 {number}", + "compose_form.poll.remove_option": "𐑮𐑦𐑥𐑵𐑝 𐑞𐑦𐑕 𐑗𐑶𐑕", + "compose_form.poll.switch_to_multiple": "𐑗𐑱𐑯𐑡 𐑐𐑴𐑤 𐑑 𐑩𐑤𐑬 𐑥𐑳𐑤𐑑𐑦𐑐𐑩𐑤 𐑗𐑶𐑕𐑩𐑟", + "compose_form.poll.switch_to_single": "𐑗𐑱𐑯𐑡 𐑐𐑴𐑤 𐑑 𐑩𐑤𐑬 𐑓 𐑩 𐑕𐑦𐑙𐑜𐑩𐑤 𐑗𐑶𐑕", + "compose_form.publish": "𐑐𐑳𐑚𐑤𐑦𐑖", + "compose_form.publish_loud": "{publish}!", + "compose_form.schedule": "𐑖𐑧𐑡𐑵𐑤", + "compose_form.scheduled_statuses.click_here": "𐑒𐑤𐑦𐑒 𐑣𐑽", + "compose_form.scheduled_statuses.message": "𐑿 𐑣𐑨𐑝 𐑖𐑧𐑡𐑵𐑤𐑛 𐑐𐑴𐑕𐑑𐑕. {click_here} 𐑑 𐑕𐑰 𐑞𐑧𐑥.", + "compose_form.sensitive.hide": "𐑥𐑸𐑒 𐑥𐑰𐑛𐑾 𐑨𐑟 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "compose_form.sensitive.marked": "𐑥𐑰𐑛𐑾 𐑦𐑟 𐑥𐑸𐑒𐑑 𐑨𐑟 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "compose_form.sensitive.unmarked": "𐑥𐑰𐑛𐑾 𐑦𐑟 𐑯𐑪𐑑 𐑥𐑸𐑒𐑑 𐑨𐑟 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "compose_form.spoiler.marked": "𐑑𐑧𐑒𐑕𐑑 𐑦𐑟 𐑣𐑦𐑛𐑩𐑯 behind 𐑢𐑹𐑯𐑦𐑙", + "compose_form.spoiler.unmarked": "𐑑𐑧𐑒𐑕𐑑 𐑦𐑟 𐑯𐑪𐑑 𐑣𐑦𐑛𐑩𐑯", + "compose_form.spoiler_placeholder": "𐑮𐑲𐑑 𐑘𐑹 𐑢𐑹𐑯𐑦𐑙 𐑣𐑽", + "confirmation_modal.cancel": "𐑒𐑨𐑯𐑕𐑩𐑤", + "confirmations.admin.deactivate_user.confirm": "𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑 @{name}", + "confirmations.admin.deactivate_user.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑 @{acct}. 𐑛𐑰𐑨𐑒𐑑𐑦𐑝𐑱𐑑𐑦𐑙 𐑩 𐑿𐑟𐑼 𐑦𐑟 𐑩 𐑮𐑦𐑝𐑻𐑕𐑩𐑚𐑩𐑤 𐑨𐑒𐑖𐑩𐑯.", + "confirmations.admin.delete_local_user.checkbox": "𐑲 𐑳𐑯𐑛𐑼𐑕𐑑𐑨𐑯𐑛 𐑞𐑨𐑑 𐑲 𐑨𐑥 𐑩𐑚𐑬𐑑 𐑑 𐑛𐑦𐑤𐑰𐑑 𐑩 𐑤𐑴𐑒𐑩𐑤 𐑿𐑟𐑼.", + "confirmations.admin.delete_status.confirm": "𐑛𐑦𐑤𐑰𐑑 𐑐𐑴𐑕𐑑", + "confirmations.admin.delete_status.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑛𐑦𐑤𐑰𐑑 𐑩 𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct}. 𐑞𐑦𐑕 𐑨𐑒𐑖𐑩𐑯 𐑒𐑨𐑯𐑪𐑑 𐑚𐑰 𐑳𐑯𐑛𐑳𐑯.", + "confirmations.admin.delete_user.confirm": "𐑛𐑦𐑤𐑰𐑑 @{name}", + "confirmations.admin.delete_user.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑛𐑦𐑤𐑰𐑑 @{acct}. ¡𐑞𐑦𐑕 𐑦𐑟 𐑩 𐑛𐑦𐑕𐑑𐑮𐑳𐑒𐑑𐑦𐑝 𐑨𐑒𐑖𐑩𐑯 𐑞𐑨𐑑 𐑒𐑨𐑯𐑪𐑑 𐑚𐑰 𐑳𐑯𐑛𐑳𐑯!", + "confirmations.admin.mark_status_not_sensitive.confirm": "𐑥𐑸𐑒 𐑐𐑴𐑕𐑑 𐑯𐑪𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "confirmations.admin.mark_status_not_sensitive.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑥𐑸𐑒 𐑩 𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct} 𐑯𐑪𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝.", + "confirmations.admin.mark_status_sensitive.confirm": "𐑥𐑸𐑒 𐑐𐑴𐑕𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "confirmations.admin.mark_status_sensitive.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑥𐑸𐑒 𐑩 𐑐𐑴𐑕𐑑 𐑚𐑲 @{acct} 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝.", + "confirmations.admin.reject_user.confirm": "𐑮𐑦𐑡𐑧𐑒𐑑 @{name}", + "confirmations.admin.reject_user.message": "𐑿 𐑸 𐑩𐑚𐑬𐑑 𐑑 𐑮𐑦𐑡𐑧𐑒𐑑 @{acct} 𐑮𐑧𐑡𐑦𐑕𐑑𐑮𐑱𐑖𐑩𐑯 𐑮𐑦𐑒𐑢𐑧𐑕𐑑. 𐑞𐑦𐑕 𐑨𐑒𐑖𐑩𐑯 𐑒𐑨𐑯𐑪𐑑 𐑚𐑰 𐑳𐑯𐑛𐑳𐑯.", + "confirmations.block.block_and_report": "𐑚𐑤𐑪𐑒 𐑯 𐑮𐑦𐑐𐑹𐑑", + "confirmations.block.confirm": "𐑚𐑤𐑪𐑒", + "confirmations.block.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑚𐑤𐑪𐑒 {name}?", + "confirmations.delete.confirm": "𐑛𐑦𐑤𐑰𐑑", + "confirmations.delete.heading": "𐑛𐑦𐑤𐑰𐑑 𐑐𐑴𐑕𐑑", + "confirmations.delete.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑛𐑦𐑤𐑰𐑑 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑?", + "confirmations.delete_list.confirm": "𐑛𐑦𐑤𐑰𐑑", + "confirmations.delete_list.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑐𐑻𐑥𐑩𐑯𐑩𐑯𐑑𐑤𐑦 𐑛𐑦𐑤𐑰𐑑 𐑞𐑦𐑕 list?", + "confirmations.domain_block.confirm": "𐑣𐑲𐑛 𐑦𐑯𐑑𐑲𐑼 𐑛𐑴𐑥𐑱𐑯", + "confirmations.domain_block.message": "𐑸 𐑿 𐑮𐑾𐑤𐑦, 𐑮𐑾𐑤𐑦 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑚𐑤𐑪𐑒 𐑞 𐑦𐑯𐑑𐑲𐑼 {domain}? 𐑦𐑯 𐑥𐑴𐑕𐑑 𐑒𐑱𐑕𐑩𐑟 𐑩 𐑓𐑿 𐑑𐑸𐑜𐑩𐑑𐑩𐑛 𐑚𐑤𐑪𐑒𐑕 𐑹 𐑥𐑿𐑑𐑕 𐑸 𐑕𐑩𐑓𐑦𐑖𐑩𐑯𐑑 𐑯 𐑐𐑮𐑧𐑓𐑼𐑩𐑚𐑩𐑤. 𐑿 𐑢𐑦𐑤 𐑯𐑪𐑑 𐑕𐑰 𐑒𐑪𐑯𐑑𐑧𐑯𐑑 𐑓𐑮𐑪𐑥 𐑞𐑨𐑑 𐑛𐑴𐑥𐑱𐑯 𐑦𐑯 𐑧𐑯𐑦 𐑐𐑳𐑚𐑤𐑦𐑒 𐑑𐑲𐑥𐑤𐑲𐑯𐑟 𐑹 𐑘𐑹 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟.", + "confirmations.mute.confirm": "𐑥𐑿𐑑", + "confirmations.mute.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑥𐑿𐑑 {name}?", + "confirmations.redraft.confirm": "𐑛𐑦𐑤𐑰𐑑 𐑯 𐑮𐑰𐑛𐑮𐑭𐑓𐑑", + "confirmations.redraft.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑛𐑦𐑤𐑰𐑑 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑯 𐑮𐑰𐑛𐑮𐑭𐑓𐑑 𐑦𐑑? 𐑓𐑱𐑝𐑼𐑦𐑑𐑕 𐑯 𐑮𐑰𐑐𐑴𐑕𐑑𐑕 𐑢𐑦𐑤 𐑚𐑰 𐑤𐑪𐑕𐑑, 𐑯 𐑮𐑦𐑐𐑤𐑲𐑟 𐑑 𐑞 𐑼𐑦𐑡𐑦𐑯𐑩𐑤 𐑐𐑴𐑕𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑹𐑓𐑩𐑯𐑛.", + "confirmations.register.needs_approval": "𐑘𐑹 𐑩𐑒𐑬𐑯𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑥𐑨𐑯𐑘𐑫𐑩𐑤𐑦 𐑩𐑐𐑮𐑵𐑝𐑛 𐑚𐑲 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯. 𐑐𐑤𐑰𐑟 𐑚𐑰 𐑐𐑱𐑖𐑩𐑯𐑑 𐑢𐑲𐑤 𐑢𐑰 𐑮𐑦𐑝𐑿 𐑘𐑹 𐑛𐑰𐑑𐑱𐑤𐑟.", + "confirmations.register.needs_confirmation": "𐑐𐑤𐑰𐑟 𐑗𐑧𐑒 𐑘𐑹 𐑦𐑯𐑚𐑪𐑒𐑕 𐑨𐑑 {email} 𐑓 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑦𐑯𐑕𐑑𐑮𐑳𐑒𐑖𐑩𐑯𐑟. 𐑿 𐑢𐑦𐑤 𐑯𐑰𐑛 𐑑 𐑝𐑧𐑮𐑦𐑓𐑲 𐑘𐑹 𐑰𐑥𐑱𐑤 𐑩𐑛𐑮𐑧𐑕 𐑑 𐑒𐑩𐑯𐑑𐑦𐑯𐑿.", + "confirmations.reply.confirm": "𐑮𐑦𐑐𐑤𐑲", + "confirmations.reply.message": "𐑮𐑦𐑐𐑤𐑲𐑦𐑙 𐑯𐑬 𐑢𐑦𐑤 𐑴𐑝𐑼𐑲𐑑 𐑞 𐑥𐑧𐑕𐑦𐑡 𐑿 𐑸 𐑒𐑳𐑮𐑩𐑯𐑑𐑤𐑦 𐑒𐑩𐑥𐑐𐑴𐑟𐑦𐑙. 𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑐𐑮𐑩𐑕𐑰𐑛?", + "confirmations.unfollow.confirm": "𐑳𐑯𐑓𐑪𐑤𐑴", + "confirmations.unfollow.message": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑳𐑯𐑓𐑪𐑤𐑴 {name}?", + "crypto_donate.explanation_box.message": "{siteTitle} 𐑩𐑒𐑕𐑧𐑐𐑑𐑕 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦 𐑛𐑴𐑯𐑱𐑖𐑩𐑯𐑟. 𐑿 𐑥𐑱 𐑕𐑧𐑯𐑛 𐑩 𐑛𐑴𐑯𐑱𐑖𐑩𐑯 𐑑 𐑧𐑯𐑦 𐑝 𐑞 𐑩𐑛𐑮𐑧𐑕𐑩𐑟 𐑚𐑦𐑤𐑴. 𐑔𐑨𐑙𐑒 𐑿 𐑓 𐑘𐑹 𐑕𐑩𐑐𐑹𐑑!", + "crypto_donate.explanation_box.title": "𐑕𐑧𐑯𐑛𐑦𐑙 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦 𐑛𐑴𐑯𐑱𐑖𐑩𐑯𐑟", + "crypto_donate_panel.actions.more": "𐑒𐑤𐑦𐑒 𐑑 𐑕𐑰 {count} 𐑥𐑹 {count, plural, one {wallet} other {wallets}}", + "crypto_donate_panel.heading": "𐑛𐑴𐑯𐑱𐑑 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦", + "crypto_donate_panel.intro.message": "{siteTitle} 𐑩𐑒𐑕𐑧𐑐𐑑𐑕 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦 𐑛𐑴𐑯𐑱𐑖𐑩𐑯𐑟 𐑑 fund our 𐑕𐑻𐑝𐑦𐑕. 𐑔𐑨𐑙𐑒 𐑿 𐑓 𐑘𐑹 𐑕𐑩𐑐𐑹𐑑!", + "datepicker.hint": "𐑖𐑧𐑡𐑵𐑤𐑛 𐑑 𐑐𐑴𐑕𐑑 𐑨𐑑…", + "developers.navigation.app_create_label": "𐑒𐑮𐑦𐑱𐑑 𐑩𐑯 𐑨𐑐", + "developers.navigation.intentional_error_label": "𐑑𐑮𐑦𐑜𐑼 𐑩𐑯 𐑧𐑮𐑼", + "direct.search_placeholder": "𐑕𐑧𐑯𐑛 𐑩 𐑥𐑧𐑕𐑦𐑡 to…", + "directory.federated": "𐑓𐑮𐑪𐑥 𐑯𐑴𐑯 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕", + "directory.local": "𐑓𐑮𐑪𐑥 {domain} 𐑴𐑯𐑤𐑦", + "directory.new_arrivals": "𐑯𐑿 𐑼𐑲𐑝𐑩𐑤𐑟", + "directory.recently_active": "𐑮𐑰𐑕𐑩𐑯𐑑𐑤𐑦 𐑨𐑒𐑑𐑦𐑝", + "donate": "𐑛𐑴𐑯𐑱𐑑", + "donate_crypto": "𐑛𐑴𐑯𐑱𐑑 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦", + "edit_federation.followers_only": "𐑣𐑲𐑛 𐑐𐑴𐑕𐑑𐑕 𐑦𐑒𐑕𐑧𐑐𐑑 𐑑 𐑓𐑪𐑤𐑴𐑼𐑟", + "edit_federation.force_nsfw": "𐑓𐑹𐑕 𐑩𐑑𐑨𐑗𐑥𐑩𐑯𐑑𐑕 𐑑 𐑚𐑰 𐑥𐑸𐑒𐑑 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "edit_federation.media_removal": "𐑕𐑑𐑮𐑦𐑐 𐑥𐑰𐑛𐑾", + "edit_federation.reject": "𐑮𐑦𐑡𐑧𐑒𐑑 𐑷𐑤 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟", + "edit_federation.save": "𐑕𐑱𐑝", + "edit_federation.success": "{host} 𐑓𐑧𐑛𐑼𐑱𐑖𐑩𐑯 𐑢𐑪𐑟 𐑳𐑐𐑛𐑱𐑑𐑩𐑛", + "edit_federation.unlisted": "𐑓𐑹𐑕 𐑐𐑴𐑕𐑑𐑕 𐑳𐑯𐑤𐑦𐑕𐑑𐑩𐑛", + "edit_profile.error": "𐑐𐑮𐑴𐑓𐑲𐑤 𐑳𐑐𐑛𐑱𐑑 𐑓𐑱𐑤𐑛", + "edit_profile.fields.accepts_email_list_label": "𐑕𐑩𐑚𐑕𐑒𐑮𐑲𐑚 𐑑 𐑯𐑿𐑟𐑤𐑧𐑑𐑼", + "edit_profile.fields.avatar_label": "𐑨𐑝𐑩𐑑𐑸", + "edit_profile.fields.bio_label": "𐑚𐑲𐑴", + "edit_profile.fields.bio_placeholder": "𐑑𐑧𐑤 𐑳𐑕 𐑩𐑚𐑬𐑑 𐑘𐑹𐑕𐑧𐑤𐑓.", + "edit_profile.fields.bot_label": "𐑞𐑦𐑕 𐑦𐑟 𐑩 𐑚𐑪𐑑 𐑩𐑒𐑬𐑯𐑑", + "edit_profile.fields.discoverable_label": "𐑩𐑤𐑬 𐑩𐑒𐑬𐑯𐑑 𐑛𐑦𐑕𐑒𐑳𐑝𐑼𐑦", + "edit_profile.fields.display_name_label": "𐑛𐑦𐑕𐑐𐑤𐑱 𐑯𐑱𐑥", + "edit_profile.fields.display_name_placeholder": "𐑯𐑱𐑥", + "edit_profile.fields.header_label": "𐑣𐑧𐑛𐑼", + "edit_profile.fields.hide_network_label": "𐑣𐑲𐑛 𐑯𐑧𐑑𐑢𐑻𐑒", + "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": "𐑚𐑤𐑪𐑒 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑓𐑮𐑪𐑥 strangers", + "edit_profile.fields.verified_display_name": "𐑝𐑧𐑮𐑦𐑓𐑲𐑛 𐑿𐑟𐑼𐑟 𐑥𐑱 𐑯𐑪𐑑 𐑳𐑐𐑛𐑱𐑑 𐑞𐑺 𐑛𐑦𐑕𐑐𐑤𐑱 𐑯𐑱𐑥", + "edit_profile.hints.accepts_email_list": "𐑪𐑐𐑑-𐑦𐑯 𐑑 𐑯𐑿𐑟 𐑯 𐑥𐑸𐑒𐑩𐑑𐑦𐑙 𐑳𐑐𐑛𐑱𐑑𐑕.", + "edit_profile.hints.avatar": "PNG, GIF 𐑹 JPG. 𐑢𐑦𐑤 𐑚𐑰 downscaled 𐑑 {size}", + "edit_profile.hints.bot": "𐑞𐑦𐑕 𐑩𐑒𐑬𐑯𐑑 𐑥𐑱𐑯𐑤𐑦 𐑐𐑼𐑓𐑹𐑥𐑟 𐑷𐑑𐑩𐑥𐑱𐑑𐑩𐑛 𐑨𐑒𐑖𐑩𐑯𐑟 𐑯 𐑥𐑲𐑑 𐑯𐑪𐑑 𐑚𐑰 𐑥𐑪𐑯𐑦𐑑𐑼𐑛", + "edit_profile.hints.discoverable": "𐑛𐑦𐑕𐑐𐑤𐑱 𐑩𐑒𐑬𐑯𐑑 𐑦𐑯 𐑐𐑮𐑴𐑓𐑲𐑤 𐑛𐑦𐑮𐑧𐑒𐑑𐑼𐑦 𐑯 𐑩𐑤𐑬 𐑦𐑯𐑛𐑧𐑒𐑕𐑦𐑙 𐑚𐑲 𐑦𐑒𐑕𐑑𐑻𐑯𐑩𐑤 𐑕𐑻𐑝𐑦𐑕𐑩𐑟", + "edit_profile.hints.header": "PNG, GIF 𐑹 JPG. 𐑢𐑦𐑤 𐑚𐑰 downscaled 𐑑 {size}", + "edit_profile.hints.hide_network": "𐑣𐑵 𐑿 𐑓𐑪𐑤𐑴 𐑯 𐑣𐑵 𐑓𐑪𐑤𐑴𐑟 𐑿 𐑢𐑦𐑤 𐑯𐑪𐑑 𐑚𐑰 𐑖𐑴𐑯 𐑪𐑯 𐑘𐑹 𐑐𐑮𐑴𐑓𐑲𐑤", + "edit_profile.hints.locked": "𐑮𐑦𐑒𐑢𐑲𐑼𐑟 𐑿 𐑑 𐑥𐑨𐑯𐑘𐑫𐑩𐑤𐑦 𐑩𐑐𐑮𐑵𐑝 𐑓𐑪𐑤𐑴𐑼𐑟", + "edit_profile.hints.meta_fields": "𐑿 𐑒𐑨𐑯 𐑣𐑨𐑝 𐑳𐑐 𐑑 {count, plural, one {# item} other {# items}} 𐑛𐑦𐑕𐑐𐑤𐑱𐑛 𐑨𐑟 𐑩 𐑑𐑱𐑚𐑩𐑤 𐑪𐑯 𐑘𐑹 𐑐𐑮𐑴𐑓𐑲𐑤", + "edit_profile.hints.stranger_notifications": "𐑴𐑯𐑤𐑦 𐑖𐑴 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑓𐑮𐑪𐑥 𐑐𐑰𐑐𐑩𐑤 𐑿 𐑓𐑪𐑤𐑴", + "edit_profile.meta_fields.add": "𐑨𐑛 𐑯𐑿 𐑲𐑑𐑩𐑥", + "edit_profile.save": "𐑕𐑱𐑝", + "edit_profile.success": "𐑐𐑮𐑴𐑓𐑲𐑤 𐑕𐑱𐑝𐑛!", + "embed.instructions": " 𐑦𐑥𐑚𐑧𐑛 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑪𐑯 𐑘𐑹 𐑢𐑧𐑚𐑕𐑲𐑑 𐑚𐑲 𐑒𐑪𐑐𐑦𐑦𐑙 𐑞 𐑒𐑴𐑛 𐑚𐑦𐑤𐑴.", + "embed.preview": "𐑣𐑽 𐑦𐑟 𐑢𐑪𐑑 𐑦𐑑 𐑢𐑦𐑤 𐑤𐑫𐑒 𐑤𐑲𐑒:", + "emoji_button.activity": "𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦", + "emoji_button.custom": "𐑒𐑳𐑕𐑑𐑩𐑥", + "emoji_button.flags": "𐑓𐑤𐑨𐑜𐑟", + "emoji_button.food": "𐑓𐑵𐑛 𐑯 𐑛𐑮𐑦𐑙𐑒", + "emoji_button.label": "𐑦𐑯𐑕𐑻𐑑 𐑦𐑥𐑴𐑡𐑦", + "emoji_button.nature": "𐑯𐑱𐑗𐑼", + "emoji_button.not_found": "𐑯𐑴 𐑦𐑥𐑴𐑡𐑦𐑟!! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "𐑪𐑚𐑡𐑧𐑒𐑑𐑕", + "emoji_button.people": "𐑐𐑰𐑐𐑩𐑤", + "emoji_button.recent": "𐑓𐑮𐑰𐑒𐑢𐑩𐑯𐑑𐑤𐑦 𐑿𐑟𐑛", + "emoji_button.search": "𐑕𐑻𐑗...", + "emoji_button.search_results": "𐑕𐑻𐑗 𐑮𐑦𐑟𐑳𐑤𐑑𐑕", + "emoji_button.symbols": "𐑕𐑦𐑥𐑚𐑩𐑤𐑟", + "emoji_button.travel": "𐑑𐑮𐑨𐑝𐑩𐑤 𐑯 𐑐𐑤𐑱𐑕𐑩𐑟", + "empty_column.account_blocked": "𐑿 𐑸 𐑚𐑤𐑪𐑒𐑑 𐑚𐑲 @{accountUsername}.", + "empty_column.account_favourited_statuses": "𐑞𐑦𐑕 𐑿𐑟𐑼 𐑛𐑳𐑟𐑩𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑤𐑲𐑒𐑑 𐑐𐑴𐑕𐑑𐑕 𐑘𐑧𐑑.", + "empty_column.account_timeline": "𐑯𐑴 𐑐𐑴𐑕𐑑𐑕 𐑣𐑽!", + "empty_column.account_unavailable": "𐑐𐑮𐑴𐑓𐑲𐑤 𐑳𐑯𐑩𐑝𐑱𐑤𐑩𐑚𐑩𐑤", + "empty_column.aliases": "𐑿 𐑣𐑨𐑝𐑩𐑯𐑑 𐑒𐑮𐑦𐑱𐑑𐑩𐑛 𐑧𐑯𐑦 𐑩𐑒𐑬𐑯𐑑 𐑱𐑤𐑾𐑕 𐑘𐑧𐑑.", + "empty_column.aliases.suggestions": "𐑞𐑺 𐑸 𐑯𐑴 𐑩𐑒𐑬𐑯𐑑 𐑕𐑩𐑡𐑧𐑕𐑗𐑩𐑯𐑟 available 𐑓 𐑞 𐑐𐑮𐑩𐑝𐑲𐑛𐑩𐑛 term.", + "empty_column.blocks": "𐑿 𐑣𐑨𐑝𐑩𐑯𐑑 𐑚𐑤𐑪𐑒𐑑 𐑧𐑯𐑦 𐑿𐑟𐑼𐑟 𐑘𐑧𐑑.", + "empty_column.bookmarks": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑚𐑫𐑒𐑥𐑸𐑒𐑕 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑨𐑛 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.community": "𐑞 𐑤𐑴𐑒𐑩𐑤 𐑑𐑲𐑥𐑤𐑲𐑯 𐑦𐑟 𐑧𐑥𐑐𐑑𐑦. 𐑮𐑲𐑑 𐑕𐑳𐑥𐑔𐑦𐑙 𐑐𐑳𐑚𐑤𐑦𐑒𐑤𐑦 𐑑 𐑜𐑧𐑑 𐑞 𐑚𐑷𐑤 𐑮𐑴𐑤𐑦𐑙!", + "empty_column.direct": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡𐑩𐑟 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑕𐑧𐑯𐑛 𐑹 𐑮𐑦𐑕𐑰𐑝 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.domain_blocks": "𐑞𐑺 𐑸 𐑯𐑴 𐑣𐑦𐑛𐑩𐑯 𐑛𐑴𐑥𐑱𐑯𐑟 𐑘𐑧𐑑.", + "empty_column.favourited_statuses": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑤𐑲𐑒𐑑 𐑐𐑴𐑕𐑑𐑕 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑤𐑲𐑒 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.favourites": "𐑯𐑴 𐑢𐑳𐑯 𐑣𐑨𐑟 𐑤𐑲𐑒𐑑 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑕𐑳𐑥𐑢𐑳𐑯 𐑛𐑳𐑟, 𐑞𐑱 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.filters": "𐑿 𐑣𐑨𐑝𐑩𐑯𐑑 𐑒𐑮𐑦𐑱𐑑𐑩𐑛 𐑧𐑯𐑦 𐑥𐑿𐑑𐑩𐑛 𐑢𐑻𐑛𐑟 𐑘𐑧𐑑.", + "empty_column.follow_recommendations": "𐑤𐑫𐑒𐑕 𐑤𐑲𐑒 𐑯𐑴 𐑕𐑩𐑡𐑧𐑕𐑗𐑩𐑯𐑟 𐑒𐑫𐑛 𐑚𐑰 𐑡𐑧𐑯𐑼𐑱𐑑𐑩𐑛 𐑓 𐑿. 𐑿 𐑒𐑨𐑯 𐑑𐑮𐑲 𐑿𐑟𐑦𐑙 𐑕𐑻𐑗 𐑑 𐑤𐑫𐑒 𐑓 𐑐𐑰𐑐𐑩𐑤 𐑿 𐑥𐑲𐑑 𐑯𐑴 𐑹 𐑦𐑒𐑕𐑐𐑤𐑹 𐑑𐑮𐑧𐑯𐑛𐑦𐑙 𐑣𐑨𐑖𐑑𐑨𐑜𐑟.", + "empty_column.follow_requests": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑕 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑮𐑦𐑕𐑰𐑝 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.group": "𐑞𐑺 𐑦𐑟 𐑯𐑳𐑔𐑦𐑙 𐑦𐑯 𐑞𐑦𐑕 𐑜𐑮𐑵𐑐 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑥𐑧𐑥𐑚𐑼𐑟 𐑝 𐑞𐑦𐑕 𐑜𐑮𐑵𐑐 𐑥𐑱𐑒 𐑯𐑿 𐑐𐑴𐑕𐑑𐑕, 𐑞𐑱 𐑢𐑦𐑤 𐑩𐑐𐑽 𐑣𐑽.", + "empty_column.hashtag": "𐑞𐑺 𐑦𐑟 𐑯𐑳𐑔𐑦𐑙 𐑦𐑯 𐑞𐑦𐑕 𐑣𐑨𐑖𐑑𐑨𐑜 𐑘𐑧𐑑.", + "empty_column.home": "𐑘𐑹 𐑣𐑴𐑥 𐑑𐑲𐑥𐑤𐑲𐑯 𐑦𐑟 𐑧𐑥𐑐𐑑𐑦! 𐑝𐑦𐑟𐑦𐑑 {public} 𐑑 𐑜𐑧𐑑 𐑕𐑑𐑸𐑑𐑩𐑛 𐑯 𐑥𐑰𐑑 𐑳𐑞𐑼 𐑿𐑟𐑼𐑟.", + "empty_column.home.local_tab": "𐑞 {site_title} tab", + "empty_column.list": "𐑞𐑺 𐑦𐑟 𐑯𐑳𐑔𐑦𐑙 𐑦𐑯 𐑞𐑦𐑕 𐑤𐑦𐑕𐑑 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑥𐑧𐑥𐑚𐑼𐑟 𐑝 𐑞𐑦𐑕 𐑤𐑦𐑕𐑑 𐑒𐑮𐑦𐑱𐑑 𐑯𐑿 𐑐𐑴𐑕𐑑𐑕, 𐑞𐑱 𐑢𐑦𐑤 𐑩𐑐𐑽 𐑣𐑽.", + "empty_column.lists": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑤𐑦𐑕𐑑𐑕 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑒𐑮𐑦𐑱𐑑 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.mutes": "𐑿 𐑣𐑨𐑝𐑩𐑯𐑑 𐑥𐑿𐑑𐑩𐑛 𐑧𐑯𐑦 𐑿𐑟𐑼𐑟 𐑘𐑧𐑑.", + "empty_column.notifications": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑘𐑧𐑑. 𐑦𐑯𐑑𐑼𐑨𐑒𐑑 𐑢𐑦𐑞 𐑳𐑞𐑼𐑟 𐑑 𐑕𐑑𐑸𐑑 𐑞 𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯.", + "empty_column.public": "𐑞𐑺 𐑦𐑟 𐑯𐑳𐑔𐑦𐑙 𐑣𐑽! 𐑮𐑲𐑑 𐑕𐑳𐑥𐑔𐑦𐑙 𐑐𐑳𐑚𐑤𐑦𐑒𐑤𐑦, 𐑹 𐑥𐑨𐑯𐑘𐑫𐑩𐑤𐑦 𐑓𐑪𐑤𐑴 𐑿𐑟𐑼𐑟 𐑓𐑮𐑪𐑥 𐑳𐑞𐑼 𐑕𐑻𐑝𐑼𐑟 𐑑 𐑓𐑦𐑤 𐑦𐑑 𐑳𐑐", + "empty_column.remote": "𐑞𐑺 𐑦𐑟 𐑯𐑳𐑔𐑦𐑙 𐑣𐑽! 𐑥𐑨𐑯𐑘𐑫𐑩𐑤𐑦 𐑓𐑪𐑤𐑴 𐑿𐑟𐑼𐑟 𐑓𐑮𐑪𐑥 {instance} 𐑑 𐑓𐑦𐑤 𐑦𐑑 𐑳𐑐.", + "empty_column.scheduled_statuses": "𐑿 𐑛𐑴𐑯𐑑 𐑣𐑨𐑝 𐑧𐑯𐑦 𐑖𐑧𐑡𐑵𐑤𐑛 𐑕𐑑𐑱𐑑𐑩𐑕𐑩𐑟 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑿 𐑨𐑛 𐑢𐑳𐑯, 𐑦𐑑 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "empty_column.search.accounts": "𐑞𐑺 𐑸 𐑯𐑴 𐑐𐑰𐑐𐑩𐑤 𐑮𐑦𐑟𐑳𐑤𐑑𐑕 𐑓 \"{term}\"", + "empty_column.search.hashtags": "𐑞𐑺 𐑸 𐑯𐑴 𐑣𐑨𐑖𐑑𐑨𐑜𐑟 𐑮𐑦𐑟𐑳𐑤𐑑𐑕 𐑓 \"{term}\"", + "empty_column.search.statuses": "𐑞𐑺 𐑸 𐑯𐑴 𐑐𐑴𐑕𐑑𐑕 𐑮𐑦𐑟𐑳𐑤𐑑𐑕 𐑓 \"{term}\"", + "export_data.actions.export": "𐑦𐑒𐑕𐑐𐑹𐑑", + "export_data.actions.export_blocks": "𐑦𐑒𐑕𐑐𐑹𐑑 𐑚𐑤𐑪𐑒𐑕", + "export_data.actions.export_follows": "𐑦𐑒𐑕𐑐𐑹𐑑 𐑓𐑪𐑤𐑴𐑟", + "export_data.actions.export_mutes": "𐑦𐑒𐑕𐑐𐑹𐑑 𐑥𐑿𐑑𐑕", + "export_data.blocks_label": "𐑚𐑤𐑪𐑒𐑕", + "export_data.follows_label": "𐑓𐑪𐑤𐑴𐑟", + "export_data.hints.blocks": "𐑜𐑧𐑑 𐑩 CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑚𐑤𐑪𐑒𐑑 𐑩𐑒𐑬𐑯𐑑𐑕", + "export_data.hints.follows": "𐑜𐑧𐑑 𐑩 CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑓𐑪𐑤𐑴𐑛 𐑩𐑒𐑬𐑯𐑑𐑕", + "export_data.hints.mutes": "𐑜𐑧𐑑 𐑩 CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑥𐑿𐑑𐑩𐑛 𐑩𐑒𐑬𐑯𐑑𐑕", + "export_data.mutes_label": "𐑥𐑿𐑑𐑕", + "export_data.success.blocks": "𐑚𐑤𐑪𐑒𐑕 𐑦𐑒𐑕𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "export_data.success.followers": "𐑓𐑪𐑤𐑴𐑼𐑟 𐑦𐑒𐑕𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "export_data.success.mutes": "𐑥𐑿𐑑𐑕 𐑦𐑒𐑕𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "federation_restriction.federated_timeline_removal": "·𐑓𐑧𐑛𐑦𐑝𐑻𐑕 𐑑𐑲𐑥𐑤𐑲𐑯 𐑮𐑦𐑥𐑵𐑝𐑩𐑤", + "federation_restriction.followers_only": "𐑣𐑦𐑛𐑩𐑯 𐑦𐑒𐑕𐑧𐑐𐑑 𐑑 𐑓𐑪𐑤𐑴𐑼𐑟", + "federation_restriction.full_media_removal": "𐑓𐑫𐑤 𐑥𐑰𐑛𐑾 𐑮𐑦𐑥𐑵𐑝𐑩𐑤", + "federation_restriction.media_nsfw": "𐑩𐑑𐑨𐑗𐑥𐑩𐑯𐑑𐑕 𐑥𐑸𐑒𐑑 ⸰𐑯𐑕𐑓𐑢", + "federation_restriction.partial_media_removal": "𐑐𐑸𐑖𐑩𐑤 𐑥𐑰𐑛𐑾 𐑮𐑦𐑥𐑵𐑝𐑩𐑤", + "federation_restrictions.empty_message": "{siteTitle} 𐑣𐑨𐑟 𐑯𐑪𐑑 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑑𐑩𐑛 𐑧𐑯𐑦 𐑦𐑯𐑕𐑑𐑩𐑯𐑕𐑩𐑟.", + "federation_restrictions.explanation_box.message": "𐑯𐑹𐑥𐑩𐑤𐑦 𐑕𐑻𐑝𐑼𐑟 𐑪𐑯 𐑞 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕 𐑒𐑨𐑯 𐑒𐑩𐑥𐑿𐑯𐑦𐑒𐑱𐑑 𐑓𐑮𐑰𐑤𐑦. {siteTitle} 𐑣𐑨𐑟 𐑦𐑥𐑐𐑴𐑟𐑛 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟 𐑪𐑯 𐑞 𐑓𐑪𐑤𐑴𐑦𐑙 𐑕𐑻𐑝𐑼𐑟.", + "federation_restrictions.explanation_box.title": "𐑦𐑯𐑕𐑑𐑩𐑯𐑕-specific policies", + "federation_restrictions.not_disclosed_message": "{siteTitle} 𐑛𐑳𐑟 𐑯𐑪𐑑 𐑛𐑦𐑕𐑒𐑤𐑴𐑟 𐑓𐑧𐑛𐑼𐑱𐑖𐑩𐑯 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟 𐑔𐑮𐑵 𐑞 API.", + "fediverse_tab.explanation_box.dismiss": "𐑛𐑴𐑯𐑑 𐑖𐑴 𐑩𐑜𐑱𐑯", + "fediverse_tab.explanation_box.explanation": "{site_title} 𐑦𐑟 𐑐𐑸𐑑 𐑝 𐑞 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕, 𐑩 𐑕𐑴𐑖𐑩𐑤 𐑯𐑧𐑑𐑢𐑻𐑒 𐑥𐑱𐑛 𐑳𐑐 𐑝 𐑔𐑬𐑟𐑩𐑯𐑛𐑟 𐑝 𐑦𐑯𐑛𐑦𐑐𐑧𐑯𐑛𐑩𐑯𐑑 𐑕𐑴𐑖𐑩𐑤 𐑥𐑰𐑛𐑾 𐑕𐑲𐑑𐑕 (aka \"𐑕𐑻𐑝𐑼𐑟\"). 𐑞 𐑐𐑴𐑕𐑑𐑕 𐑿 𐑕𐑰 𐑣𐑽 𐑸 𐑓𐑮𐑪𐑥 3rd-𐑐𐑸𐑑𐑦 𐑕𐑻𐑝𐑼𐑟. 𐑿 𐑣𐑨𐑝 𐑞 𐑓𐑮𐑰𐑛𐑩𐑥 𐑑 𐑦𐑯𐑜𐑱𐑡 𐑢𐑦𐑞 𐑞𐑧𐑥, 𐑹 𐑑 𐑚𐑤𐑪𐑒 𐑧𐑯𐑦 𐑕𐑻𐑝𐑼 𐑿 𐑛𐑴𐑯𐑑 𐑤𐑲𐑒. 𐑐𐑱 𐑩𐑑𐑧𐑯𐑖𐑩𐑯 𐑑 𐑞 𐑓𐑫𐑤 𐑿𐑟𐑼𐑯𐑱𐑥 𐑭𐑓𐑑𐑼 𐑞 𐑕𐑧𐑒𐑩𐑯𐑛 @ 𐑕𐑦𐑥𐑚𐑩𐑤 𐑑 𐑯𐑴 𐑢𐑦𐑗 𐑕𐑻𐑝𐑼 𐑩 𐑐𐑴𐑕𐑑 𐑦𐑟 𐑓𐑮𐑪𐑥. 𐑑 𐑕𐑰 𐑴𐑯𐑤𐑦 {site_title} 𐑐𐑴𐑕𐑑𐑕, 𐑝𐑦𐑟𐑦𐑑 {local}.", + "fediverse_tab.explanation_box.title": "𐑢𐑪𐑑 𐑦𐑟 𐑞 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕?", + "filters.added": "𐑓𐑦𐑤𐑑𐑼 𐑨𐑛𐑩𐑛.", + "filters.context_header": "𐑓𐑦𐑤𐑑𐑼 𐑒𐑪𐑯𐑑𐑧𐑒𐑕𐑑𐑕", + "filters.context_hint": "𐑢𐑳𐑯 𐑹 𐑥𐑳𐑤𐑑𐑦𐑐𐑩𐑤 𐑒𐑪𐑯𐑑𐑧𐑒𐑕𐑑𐑕 𐑢𐑺 𐑞 𐑓𐑦𐑤𐑑𐑼 𐑖𐑫𐑛 𐑩𐑐𐑤𐑲", + "filters.filters_list_context_label": "𐑓𐑦𐑤𐑑𐑼 𐑒𐑪𐑯𐑑𐑧𐑒𐑕𐑑𐑕:", + "filters.filters_list_delete": "𐑛𐑦𐑤𐑰𐑑", + "filters.filters_list_details_label": "𐑓𐑦𐑤𐑑𐑼 𐑕𐑧𐑑𐑦𐑙𐑟:", + "filters.filters_list_drop": "𐑛𐑮𐑪𐑐", + "filters.filters_list_hide": "𐑣𐑲𐑛", + "filters.filters_list_phrase_label": "𐑒𐑰𐑢𐑻𐑛 𐑹 𐑓𐑮𐑱𐑟:", + "filters.filters_list_whole-word": "𐑣𐑴𐑤 𐑢𐑻𐑛", + "filters.removed": "𐑓𐑦𐑤𐑑𐑼 𐑛𐑦𐑤𐑰𐑑𐑩𐑛.", + "follow_recommendations.done": "𐑛𐑳𐑯", + "follow_recommendations.heading": "𐑓𐑪𐑤𐑴 𐑐𐑰𐑐𐑩𐑤 𐑿𐑛 𐑤𐑲𐑒 𐑑 𐑕𐑰 𐑐𐑴𐑕𐑑𐑕 𐑓𐑮𐑪𐑥! 𐑣𐑽 𐑸 𐑕𐑳𐑥 𐑕𐑩𐑡𐑧𐑕𐑗𐑩𐑯𐑟.", + "follow_recommendations.lead": "𐑐𐑴𐑕𐑑𐑕 𐑓𐑮𐑪𐑥 𐑐𐑰𐑐𐑩𐑤 𐑿 𐑓𐑪𐑤𐑴 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑦𐑯 𐑒𐑮𐑪𐑯𐑩𐑤𐑪𐑡𐑦𐑒𐑩𐑤 𐑹𐑛𐑼 𐑪𐑯 𐑘𐑹 𐑣𐑴𐑥 𐑓𐑰𐑛. 𐑛𐑴𐑯𐑑 𐑚𐑰 𐑩𐑓𐑮𐑱𐑛 𐑑 𐑥𐑱𐑒 𐑥𐑦𐑕𐑑𐑱𐑒𐑕, 𐑿 𐑒𐑨𐑯 𐑳𐑯𐑓𐑪𐑤𐑴 𐑐𐑰𐑐𐑩𐑤 𐑡𐑳𐑕𐑑 𐑨𐑟 𐑰𐑟𐑦𐑤𐑦 𐑧𐑯𐑦 𐑑𐑲𐑥!", + "follow_request.authorize": "𐑷𐑔𐑼𐑲𐑟", + "follow_request.reject": "𐑮𐑦𐑡𐑧𐑒𐑑", + "forms.copy": "𐑒𐑪𐑐𐑦", + "forms.hide_password": "𐑣𐑲𐑛 𐑐𐑭𐑕𐑢𐑻𐑛", + "forms.show_password": "𐑖𐑴 𐑐𐑭𐑕𐑢𐑻𐑛", + "getting_started.open_source_notice": "{code_name} 𐑦𐑟 𐑴𐑐𐑩𐑯 𐑕𐑹𐑕 𐑕𐑪𐑓𐑑𐑢𐑺. 𐑿 𐑒𐑨𐑯 𐑒𐑩𐑯𐑑𐑮𐑦𐑚𐑿𐑑 𐑹 𐑮𐑦𐑐𐑹𐑑 𐑦𐑖𐑵𐑟 𐑨𐑑 {code_link} (v{code_version}).", + "group.detail.archived_group": "𐑸𐑒𐑲𐑝𐑛 𐑜𐑮𐑵𐑐", + "group.members.empty": "𐑞𐑦𐑕 𐑜𐑮𐑵𐑐 𐑛𐑳𐑟 𐑯𐑪𐑑 𐑣𐑨𐑟 𐑧𐑯𐑦 𐑥𐑧𐑥𐑚𐑼𐑟.", + "group.removed_accounts.empty": "𐑞𐑦𐑕 𐑜𐑮𐑵𐑐 𐑛𐑳𐑟 𐑯𐑪𐑑 𐑣𐑨𐑟 𐑧𐑯𐑦 𐑮𐑦𐑥𐑵𐑝𐑛 𐑩𐑒𐑬𐑯𐑑𐑕.", + "groups.card.join": "𐑡𐑶𐑯", + "groups.card.members": "𐑥𐑧𐑥𐑚𐑼𐑟", + "groups.card.roles.admin": "𐑘𐑫𐑼 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯", + "groups.card.roles.member": "𐑘𐑫𐑼 𐑩 𐑥𐑧𐑥𐑚𐑼", + "groups.card.view": "𐑝𐑿", + "groups.create": "𐑒𐑮𐑦𐑱𐑑 𐑜𐑮𐑵𐑐", + "groups.detail.role_admin": "𐑘𐑫𐑼 𐑩𐑯 𐑨𐑛𐑥𐑦𐑯", + "groups.edit": "𐑧𐑛𐑦𐑑", + "groups.form.coverImage": "𐑳𐑐𐑤𐑴𐑛 𐑯𐑿 𐑚𐑨𐑯𐑼 𐑦𐑥𐑦𐑡 (𐑪𐑐𐑖𐑩𐑯𐑩𐑤)", + "groups.form.coverImageChange": "𐑚𐑨𐑯𐑼 𐑦𐑥𐑦𐑡 𐑕𐑦𐑤𐑧𐑒𐑑𐑩𐑛", + "groups.form.create": "𐑒𐑮𐑦𐑱𐑑 𐑜𐑮𐑵𐑐", + "groups.form.description": "𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯", + "groups.form.title": "𐑑𐑲𐑑𐑩𐑤", + "groups.form.update": "𐑳𐑐𐑛𐑱𐑑 𐑜𐑮𐑵𐑐", + "groups.join": "𐑡𐑶𐑯 𐑜𐑮𐑵𐑐", + "groups.leave": "𐑤𐑰𐑝 𐑜𐑮𐑵𐑐", + "groups.removed_accounts": "𐑮𐑦𐑥𐑵𐑝𐑛 𐑩𐑒𐑬𐑯𐑑𐑕", + "groups.sidebar-panel.item.no_recent_activity": "𐑯𐑴 𐑮𐑰𐑕𐑩𐑯𐑑 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦", + "groups.sidebar-panel.item.view": "𐑯𐑿 𐑐𐑴𐑕𐑑𐑕", + "groups.sidebar-panel.show_all": "𐑖𐑴 𐑷𐑤", + "groups.sidebar-panel.title": "𐑜𐑮𐑵𐑐𐑕 𐑘𐑫𐑼 𐑦𐑯", + "groups.tab_admin": "𐑥𐑨𐑯𐑦𐑡", + "groups.tab_featured": "𐑓𐑰𐑗𐑼𐑛", + "groups.tab_member": "𐑥𐑧𐑥𐑚𐑼", + "hashtag.column_header.tag_mode.all": "𐑯 {additional}", + "hashtag.column_header.tag_mode.any": "𐑹 {additional}", + "hashtag.column_header.tag_mode.none": "𐑢𐑦𐑞𐑬𐑑 {additional}", + "header.about.label": "𐑩𐑚𐑬𐑑", + "header.back_to.label": "𐑚𐑨𐑒 𐑑 {siteTitle}", + "header.home.label": "𐑣𐑴𐑥", + "header.login.label": "𐑤𐑪𐑜 𐑦𐑯", + "home.column_settings.show_direct": "𐑖𐑴 𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡𐑩𐑟", + "home.column_settings.show_reblogs": "𐑖𐑴 𐑮𐑰𐑐𐑴𐑕𐑑𐑕", + "home.column_settings.show_replies": "𐑖𐑴 𐑮𐑦𐑐𐑤𐑲𐑟", + "home.column_settings.title": "𐑣𐑴𐑥 𐑕𐑧𐑑𐑦𐑙𐑟", + "home_column.lists": "𐑤𐑦𐑕𐑑𐑕", + "home_column_header.all": "𐑷𐑤", + "home_column_header.fediverse": "·𐑓𐑧𐑛𐑦𐑝𐑻𐑕", + "home_column_header.home": "𐑣𐑴𐑥", + "icon_button.icons": "𐑲𐑒𐑪𐑯𐑟", + "icon_button.label": "𐑕𐑦𐑤𐑧𐑒𐑑 𐑲𐑒𐑪𐑯", + "icon_button.not_found": "𐑯𐑴 𐑲𐑒𐑪𐑯𐑟!! (╯°□°)╯︵ ┻━┻", + "import_data.actions.import": "𐑦𐑥𐑐𐑹𐑑", + "import_data.actions.import_blocks": "𐑦𐑥𐑐𐑹𐑑 𐑚𐑤𐑪𐑒𐑕", + "import_data.actions.import_follows": "𐑦𐑥𐑐𐑹𐑑 𐑓𐑪𐑤𐑴𐑟", + "import_data.actions.import_mutes": "𐑦𐑥𐑐𐑹𐑑 𐑥𐑿𐑑𐑕", + "import_data.blocks_label": "𐑚𐑤𐑪𐑒𐑕", + "import_data.follows_label": "𐑓𐑪𐑤𐑴𐑟", + "import_data.hints.blocks": "CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑚𐑤𐑪𐑒𐑑 𐑩𐑒𐑬𐑯𐑑𐑕", + "import_data.hints.follows": "CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑓𐑪𐑤𐑴𐑛 𐑩𐑒𐑬𐑯𐑑𐑕", + "import_data.hints.mutes": "CSV 𐑓𐑲𐑤 𐑒𐑩𐑯𐑑𐑱𐑯𐑦𐑙 𐑩 𐑤𐑦𐑕𐑑 𐑝 𐑥𐑿𐑑𐑩𐑛 𐑩𐑒𐑬𐑯𐑑𐑕", + "import_data.mutes_label": "𐑥𐑿𐑑𐑕", + "import_data.success.blocks": "𐑚𐑤𐑪𐑒𐑕 𐑦𐑥𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "import_data.success.followers": "𐑓𐑪𐑤𐑴𐑼𐑟 𐑦𐑥𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "import_data.success.mutes": "𐑥𐑿𐑑𐑕 𐑦𐑥𐑐𐑹𐑑𐑩𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦", + "intervals.full.days": "{number, plural, one {# day} other {# days}}", + "intervals.full.hours": "{number, plural, one {# hour} other {# hours}}", + "intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}", + "introduction.federation.action": "𐑯𐑧𐑒𐑕𐑑", + "introduction.federation.home.headline": "𐑣𐑴𐑥", + "introduction.federation.home.text": "𐑐𐑴𐑕𐑑𐑕 𐑓𐑮𐑪𐑥 𐑐𐑰𐑐𐑩𐑤 𐑿 𐑓𐑪𐑤𐑴 𐑢𐑦𐑤 𐑩𐑐𐑽 𐑦𐑯 𐑘𐑹 𐑣𐑴𐑥 𐑓𐑰𐑛. 𐑿 𐑒𐑨𐑯 𐑓𐑪𐑤𐑴 𐑧𐑯𐑦𐑢𐑳𐑯 𐑪𐑯 𐑧𐑯𐑦 𐑕𐑻𐑝𐑼!", + "introduction.interactions.action": "Finish tutorial!", + "introduction.interactions.favourite.headline": "𐑓𐑱𐑝𐑼𐑦𐑑", + "introduction.interactions.favourite.text": "𐑿 𐑒𐑨𐑯 𐑕𐑱𐑝 𐑩 𐑐𐑴𐑕𐑑 𐑓 𐑤𐑱𐑑𐑼, 𐑯 let 𐑞 𐑷𐑔𐑼 𐑯𐑴 𐑞𐑨𐑑 𐑿 𐑤𐑲𐑒𐑑 𐑦𐑑, 𐑚𐑲 𐑓𐑱𐑝𐑼𐑦𐑑𐑦𐑙 𐑦𐑑.", + "introduction.interactions.reblog.headline": "𐑮𐑰𐑐𐑴𐑕𐑑", + "introduction.interactions.reblog.text": "𐑿 𐑒𐑨𐑯 𐑖𐑺 𐑳𐑞𐑼 𐑐𐑰𐑐𐑩𐑤𐑟 𐑐𐑴𐑕𐑑𐑕 𐑢𐑦𐑞 𐑘𐑹 𐑓𐑪𐑤𐑴𐑼𐑟 𐑚𐑲 𐑮𐑰𐑐𐑴𐑕𐑑𐑦𐑙 𐑞𐑧𐑥.", + "introduction.interactions.reply.headline": "𐑮𐑦𐑐𐑤𐑲", + "introduction.interactions.reply.text": "𐑿 𐑒𐑨𐑯 𐑮𐑦𐑐𐑤𐑲 𐑑 𐑳𐑞𐑼 𐑐𐑰𐑐𐑩𐑤𐑟 𐑯 𐑘𐑹 𐑴𐑯 𐑐𐑴𐑕𐑑𐑕, 𐑢𐑦𐑗 𐑢𐑦𐑤 chain 𐑞𐑧𐑥 𐑑𐑩𐑜𐑧𐑞𐑼 𐑦𐑯 𐑩 𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯.", + "introduction.welcome.action": "𐑤𐑧𐑑𐑕 𐑜𐑴!", + "introduction.welcome.headline": "𐑓𐑻𐑕𐑑 𐑕𐑑𐑧𐑐𐑕", + "introduction.welcome.text": "𐑢𐑧𐑤𐑒𐑩𐑥 𐑑 𐑞 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕! 𐑦𐑯 𐑩 𐑓𐑿 𐑥𐑴𐑥𐑩𐑯𐑑𐑕, 𐑿𐑤 𐑚𐑰 𐑱𐑚𐑩𐑤 𐑑 𐑚𐑮𐑷𐑛𐑒𐑭𐑕𐑑 𐑥𐑧𐑕𐑦𐑡𐑩𐑟 𐑯 𐑑𐑷𐑒 𐑑 𐑘𐑹 𐑓𐑮𐑧𐑯𐑛𐑟 𐑩𐑒𐑮𐑪𐑕 𐑩 𐑢𐑲𐑛 𐑝𐑼𐑲𐑩𐑑𐑦 𐑝 𐑕𐑻𐑝𐑼𐑟. 𐑚𐑳𐑑 𐑞𐑦𐑕 𐑕𐑻𐑝𐑼, {domain}, 𐑦𐑟 special—it 𐑣𐑴𐑕𐑑𐑕 𐑘𐑹 𐑐𐑮𐑴𐑓𐑲𐑤, so 𐑮𐑦𐑥𐑧𐑥𐑚𐑼 𐑦𐑑𐑕 𐑯𐑱𐑥.", + "keyboard_shortcuts.back": "𐑑 𐑯𐑨𐑝𐑦𐑜𐑱𐑑 𐑚𐑨𐑒", + "keyboard_shortcuts.blocked": "𐑑 𐑴𐑐𐑩𐑯 𐑚𐑤𐑪𐑒𐑑 𐑿𐑟𐑼𐑟 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.boost": "𐑑 𐑮𐑰𐑐𐑴𐑕𐑑", + "keyboard_shortcuts.compose": "𐑑 𐑓𐑴𐑒𐑩𐑕 𐑞 𐑒𐑩𐑥𐑐𐑴𐑟 𐑑𐑧𐑒𐑕𐑑𐑺𐑾", + "keyboard_shortcuts.down": "𐑑 𐑥𐑵𐑝 𐑛𐑬𐑯 𐑦𐑯 𐑞 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.enter": "𐑑 𐑴𐑐𐑩𐑯 𐑐𐑴𐑕𐑑", + "keyboard_shortcuts.favourite": "𐑑 𐑤𐑲𐑒", + "keyboard_shortcuts.favourites": "𐑑 𐑴𐑐𐑩𐑯 𐑤𐑲𐑒𐑕 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.heading": "𐑒𐑰𐑚𐑹𐑛 𐑖𐑹𐑑𐑒𐑳𐑑𐑕", + "keyboard_shortcuts.home": "𐑑 𐑴𐑐𐑩𐑯 𐑣𐑴𐑥 𐑑𐑲𐑥𐑤𐑲𐑯", + "keyboard_shortcuts.hotkey": "Hotkey", + "keyboard_shortcuts.legend": "𐑑 𐑛𐑦𐑕𐑐𐑤𐑱 𐑞𐑦𐑕 legend", + "keyboard_shortcuts.mention": "𐑑 𐑥𐑧𐑯𐑖𐑩𐑯 𐑷𐑔𐑼", + "keyboard_shortcuts.muted": "𐑑 𐑴𐑐𐑩𐑯 𐑥𐑿𐑑𐑩𐑛 𐑿𐑟𐑼𐑟 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.my_profile": "𐑑 𐑴𐑐𐑩𐑯 𐑘𐑹 𐑐𐑮𐑴𐑓𐑲𐑤", + "keyboard_shortcuts.notifications": "𐑑 𐑴𐑐𐑩𐑯 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑒𐑪𐑤𐑩𐑥", + "keyboard_shortcuts.open_media": "𐑑 𐑴𐑐𐑩𐑯 𐑥𐑰𐑛𐑾", + "keyboard_shortcuts.pinned": "𐑑 𐑴𐑐𐑩𐑯 𐑐𐑦𐑯𐑛 𐑐𐑴𐑕𐑑𐑕 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.profile": "𐑑 𐑴𐑐𐑩𐑯 𐑷𐑔𐑼𐑟 𐑐𐑮𐑴𐑓𐑲𐑤", + "keyboard_shortcuts.react": "𐑑 𐑮𐑦𐑨𐑒𐑑", + "keyboard_shortcuts.reply": "𐑑 𐑮𐑦𐑐𐑤𐑲", + "keyboard_shortcuts.requests": "𐑑 𐑴𐑐𐑩𐑯 𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑕 𐑤𐑦𐑕𐑑", + "keyboard_shortcuts.search": "𐑑 𐑓𐑴𐑒𐑩𐑕 𐑕𐑻𐑗", + "keyboard_shortcuts.toggle_hidden": "𐑑 𐑖𐑴/𐑣𐑲𐑛 𐑑𐑧𐑒𐑕𐑑 behind CW", + "keyboard_shortcuts.toggle_sensitivity": "𐑑 𐑖𐑴/𐑣𐑲𐑛 𐑥𐑰𐑛𐑾", + "keyboard_shortcuts.toot": "𐑑 𐑕𐑑𐑸𐑑 𐑩 𐑯𐑿 𐑐𐑴𐑕𐑑", + "keyboard_shortcuts.unfocus": "𐑑 𐑳𐑯-𐑓𐑴𐑒𐑩𐑕 𐑒𐑩𐑥𐑐𐑴𐑟 𐑑𐑧𐑒𐑕𐑑𐑺𐑾/𐑕𐑻𐑗", + "keyboard_shortcuts.up": "𐑑 𐑥𐑵𐑝 𐑳𐑐 𐑦𐑯 𐑞 𐑤𐑦𐑕𐑑", + "lightbox.close": "𐑒𐑤𐑴𐑟", + "lightbox.next": "𐑯𐑧𐑒𐑕𐑑", + "lightbox.previous": "𐑐𐑮𐑰𐑝𐑾𐑕", + "lightbox.view_context": "𐑝𐑿 𐑒𐑪𐑯𐑑𐑧𐑒𐑕𐑑", + "list.click_to_add": "𐑒𐑤𐑦𐑒 𐑣𐑽 𐑑 𐑨𐑛 𐑐𐑰𐑐𐑩𐑤", + "list.label": "𐑕𐑦𐑤𐑧𐑒𐑑 𐑤𐑦𐑕𐑑…", + "list.select": "𐑕𐑦𐑤𐑧𐑒𐑑 𐑤𐑦𐑕𐑑", + "list_adder.header_title": "𐑨𐑛 𐑹 𐑮𐑦𐑥𐑵𐑝 𐑓𐑮𐑪𐑥 𐑤𐑦𐑕𐑑𐑕", + "lists.account.add": "𐑨𐑛 𐑑 𐑤𐑦𐑕𐑑", + "lists.account.remove": "𐑮𐑦𐑥𐑵𐑝 𐑓𐑮𐑪𐑥 𐑤𐑦𐑕𐑑", + "lists.edit": "𐑧𐑛𐑦𐑑 𐑤𐑦𐑕𐑑", + "lists.edit.submit": "𐑗𐑱𐑯𐑡 𐑑𐑲𐑑𐑩𐑤", + "lists.new.create": "𐑨𐑛 𐑤𐑦𐑕𐑑", + "lists.new.create_title": "𐑒𐑮𐑦𐑱𐑑", + "lists.new.save_title": "𐑕𐑱𐑝 𐑑𐑲𐑑𐑩𐑤", + "lists.new.title_placeholder": "𐑯𐑿 𐑤𐑦𐑕𐑑 𐑑𐑲𐑑𐑩𐑤", + "lists.search": "𐑕𐑻𐑗 𐑩𐑥𐑳𐑙 𐑐𐑰𐑐𐑩𐑤 𐑿 𐑓𐑪𐑤𐑴", + "lists.subheading": "𐑘𐑹 𐑤𐑦𐑕𐑑𐑕", + "loading_indicator.label": "𐑤𐑴𐑛𐑦𐑙...", + "login.fields.instance_label": "𐑦𐑯𐑕𐑑𐑩𐑯𐑕", + "login.fields.instance_placeholder": "example.com", + "login.fields.otp_code_hint": "𐑧𐑯𐑑𐑼 𐑞 two-factor 𐑒𐑴𐑛 𐑡𐑧𐑯𐑼𐑱𐑑𐑩𐑛 𐑚𐑲 𐑘𐑹 𐑓𐑴𐑯 𐑨𐑐 𐑹 𐑿𐑕 𐑢𐑳𐑯 𐑝 𐑘𐑹 𐑮𐑦𐑒𐑳𐑝𐑼𐑦 𐑒𐑴𐑛𐑟", + "login.fields.otp_code_label": "Two-factor 𐑒𐑴𐑛:", + "login.fields.password_placeholder": "𐑐𐑭𐑕𐑢𐑻𐑛", + "login.fields.username_placeholder": "𐑿𐑟𐑼𐑯𐑱𐑥", + "login.log_in": "𐑤𐑪𐑜 𐑦𐑯", + "login.otp_log_in": "OTP 𐑤𐑪𐑜𐑦𐑯", + "login.otp_log_in.fail": "𐑦𐑯𐑝𐑨𐑤𐑦𐑛 𐑒𐑴𐑛, 𐑐𐑤𐑰𐑟 𐑑𐑮𐑲 𐑩𐑜𐑱𐑯.", + "login.reset_password_hint": "𐑑𐑮𐑳𐑚𐑩𐑤 𐑤𐑪𐑜𐑦𐑙 𐑦𐑯?", + "media_gallery.toggle_visible": "𐑑𐑪𐑜𐑩𐑤 𐑝𐑦𐑟𐑩𐑚𐑦𐑤𐑦𐑑𐑦", + "media_panel.empty_message": "𐑯𐑴 𐑥𐑰𐑛𐑾 𐑓𐑬𐑯𐑛.", + "media_panel.title": "𐑥𐑰𐑛𐑾", + "mfa.mfa_disable_enter_password": "𐑧𐑯𐑑𐑼 𐑘𐑹 𐑒𐑳𐑮𐑩𐑯𐑑 𐑐𐑭𐑕𐑢𐑻𐑛 𐑑 𐑛𐑦𐑕𐑱𐑚𐑩𐑤 two-factor auth.", + "mfa.mfa_setup_enter_password": "𐑧𐑯𐑑𐑼 𐑘𐑹 𐑒𐑳𐑮𐑩𐑯𐑑 𐑐𐑭𐑕𐑢𐑻𐑛 𐑑 𐑒𐑩𐑯𐑓𐑻𐑥 𐑘𐑹 𐑲𐑛𐑧𐑯𐑑𐑦𐑑𐑦", + "mfa.mfa_setup_scan_description": "𐑿𐑟𐑦𐑙 𐑘𐑹 two-factor 𐑨𐑐, 𐑕𐑒𐑨𐑯 𐑞𐑦𐑕 QR 𐑒𐑴𐑛 𐑹 𐑧𐑯𐑑𐑼 𐑞 𐑑𐑧𐑒𐑕𐑑 𐑒𐑰.", + "mfa.mfa_setup_scan_key": "𐑒𐑰:", + "mfa.mfa_setup_scan_title": "𐑕𐑒𐑨𐑯", + "mfa.mfa_setup_verify_description": "𐑑 𐑦𐑯𐑱𐑚𐑩𐑤 two-factor 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯, 𐑧𐑯𐑑𐑼 𐑞 𐑒𐑴𐑛 𐑓𐑮𐑪𐑥 𐑘𐑹 two-factor 𐑨𐑐", + "mfa.mfa_setup_verify_title": "𐑝𐑧𐑮𐑦𐑓𐑲", + "mfa.otp_enabled_description": "𐑿 𐑣𐑨𐑝 𐑦𐑯𐑱𐑚𐑩𐑤𐑛 two-factor 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯 via OTP.", + "mfa.otp_enabled_title": "OTP 𐑦𐑯𐑱𐑚𐑩𐑤𐑛", + "mfa.setup_hint": "𐑓𐑪𐑤𐑴 𐑞𐑰𐑟 𐑕𐑑𐑧𐑐𐑕 𐑑 𐑕𐑧𐑑 𐑳𐑐 𐑥𐑳𐑤𐑑𐑦-𐑓𐑨𐑒𐑑𐑼 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯 𐑪𐑯 𐑘𐑹 𐑩𐑒𐑬𐑯𐑑 𐑢𐑦𐑞 OTP", + "mfa.setup_otp_title": "OTP 𐑛𐑦𐑕𐑱𐑚𐑩𐑤𐑛", + "mfa.setup_recoverycodes": "𐑮𐑦𐑒𐑳𐑝𐑼𐑦 𐑒𐑴𐑛𐑟", + "mfa.setup_warning": "𐑮𐑲𐑑 𐑞𐑰𐑟 𐑒𐑴𐑛𐑟 𐑛𐑬𐑯 𐑹 𐑕𐑱𐑝 𐑞𐑧𐑥 𐑕𐑳𐑥𐑢𐑺 𐑕𐑦𐑒𐑘𐑫𐑼 - 𐑳𐑞𐑼𐑢𐑲𐑟 𐑿 𐑢𐑴𐑯𐑑 𐑕𐑰 𐑞𐑧𐑥 𐑩𐑜𐑱𐑯. 𐑦𐑓 𐑿 𐑤𐑵𐑟 𐑨𐑒𐑕𐑧𐑕 𐑑 𐑘𐑹 2FA 𐑨𐑐 𐑯 𐑮𐑦𐑒𐑳𐑝𐑼𐑦 𐑒𐑴𐑛𐑟 𐑿𐑤 𐑚𐑰 𐑤𐑪𐑒𐑑 𐑬𐑑 𐑝 𐑘𐑹 𐑩𐑒𐑬𐑯𐑑.", + "missing_description_modal.cancel": "𐑒𐑨𐑯𐑕𐑩𐑤", + "missing_description_modal.continue": "𐑐𐑴𐑕𐑑", + "missing_description_modal.text": "𐑿 𐑣𐑨𐑝 𐑯𐑪𐑑 𐑧𐑯𐑑𐑼𐑛 𐑩 𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯 𐑓 𐑷𐑤 𐑩𐑑𐑨𐑗𐑥𐑩𐑯𐑑𐑕. 𐑒𐑩𐑯𐑑𐑦𐑯𐑿 𐑧𐑯𐑦𐑢𐑱?", + "missing_indicator.label": "𐑯𐑪𐑑 𐑓𐑬𐑯𐑛", + "missing_indicator.sublabel": "𐑞𐑦𐑕 𐑮𐑦𐑟𐑹𐑕 𐑒𐑫𐑛 𐑯𐑪𐑑 𐑚𐑰 𐑓𐑬𐑯𐑛", + "morefollows.followers_label": "…𐑯 {count} 𐑥𐑹 {count, plural, one {follower} other {followers}} 𐑪𐑯 𐑮𐑦𐑥𐑴𐑑 𐑕𐑲𐑑𐑕.", + "morefollows.following_label": "…𐑯 {count} 𐑥𐑹 {count, plural, one {follow} other {follows}} 𐑪𐑯 𐑮𐑦𐑥𐑴𐑑 𐑕𐑲𐑑𐑕.", + "mute_modal.hide_notifications": "𐑣𐑲𐑛 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟 𐑓𐑮𐑪𐑥 𐑞𐑦𐑕 𐑿𐑟𐑼?", + "navigation.chats": "𐑗𐑨𐑑𐑕", + "navigation.dashboard": "𐑛𐑨𐑖𐑚𐑹𐑛", + "navigation.developers": "𐑛𐑦𐑝𐑧𐑤𐑩𐑐𐑼𐑟", + "navigation.direct_messages": "𐑥𐑧𐑕𐑦𐑡𐑩𐑟", + "navigation.home": "𐑣𐑴𐑥", + "navigation.invites": "𐑦𐑯𐑝𐑲𐑑𐑕", + "navigation.notifications": "𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "navigation.search": "𐑕𐑻𐑗", + "navigation_bar.account_aliases": "𐑩𐑒𐑬𐑯𐑑 𐑱𐑤𐑾𐑕𐑩𐑟", + "navigation_bar.admin_settings": "AdminFE", + "navigation_bar.blocks": "𐑚𐑤𐑪𐑒𐑕", + "navigation_bar.bookmarks": "𐑚𐑫𐑒𐑥𐑸𐑒𐑕", + "navigation_bar.compose": "𐑒𐑩𐑥𐑐𐑴𐑟 𐑯𐑿 𐑐𐑴𐑕𐑑", + "navigation_bar.compose_direct": "𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡", + "navigation_bar.compose_reply": "𐑮𐑦𐑐𐑤𐑲 𐑑 𐑐𐑴𐑕𐑑", + "navigation_bar.domain_blocks": "𐑛𐑴𐑥𐑱𐑯 𐑚𐑤𐑪𐑒𐑕", + "navigation_bar.export_data": "𐑦𐑒𐑕𐑐𐑹𐑑 𐑛𐑱𐑑𐑩", + "navigation_bar.favourites": "𐑤𐑲𐑒𐑕", + "navigation_bar.filters": "𐑓𐑦𐑤𐑑𐑼𐑟", + "navigation_bar.follow_requests": "𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑕", + "navigation_bar.import_data": "𐑦𐑥𐑐𐑹𐑑 𐑛𐑱𐑑𐑩", + "navigation_bar.in_reply_to": "In 𐑮𐑦𐑐𐑤𐑲 to", + "navigation_bar.info": "𐑩𐑚𐑬𐑑 𐑞𐑦𐑕 𐑕𐑻𐑝𐑼", + "navigation_bar.invites": "𐑦𐑯𐑝𐑲𐑑𐑕", + "navigation_bar.keyboard_shortcuts": "𐑣𐑪𐑑𐑒𐑰𐑟", + "navigation_bar.lists": "𐑤𐑦𐑕𐑑𐑕", + "navigation_bar.logout": " 𐑤𐑪𐑜𐑬𐑑", + "navigation_bar.messages": "𐑥𐑧𐑕𐑦𐑡𐑩𐑟", + "navigation_bar.mutes": "𐑥𐑿𐑑𐑕", + "navigation_bar.pins": "𐑐𐑦𐑯𐑛 𐑐𐑴𐑕𐑑𐑕", + "navigation_bar.preferences": "𐑐𐑮𐑧𐑓𐑼𐑩𐑯𐑕𐑩𐑟", + "navigation_bar.profile_directory": "𐑐𐑮𐑴𐑓𐑲𐑤 𐑛𐑦𐑮𐑧𐑒𐑑𐑼𐑦", + "navigation_bar.security": "𐑕𐑦𐑒𐑘𐑫𐑼𐑦𐑑𐑦", + "navigation_bar.soapbox_config": "·𐑕𐑴𐑐𐑚𐑪𐑒𐑕 𐑒𐑩𐑯𐑓𐑦𐑜", + "notification.chat_mention": "{name} 𐑕𐑧𐑯𐑑 𐑿 𐑩 𐑥𐑧𐑕𐑦𐑡", + "notification.favourite": "{name} 𐑤𐑲𐑒𐑑 𐑘𐑹 𐑐𐑴𐑕𐑑", + "notification.follow": "{name} 𐑓𐑪𐑤𐑴𐑛 𐑿", + "notification.follow_request": "{name} 𐑣𐑨𐑟 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑩𐑛 𐑑 𐑓𐑪𐑤𐑴 𐑿", + "notification.mention": "{name} 𐑥𐑧𐑯𐑖𐑩𐑯𐑛 𐑿", + "notification.move": "{name} 𐑥𐑵𐑝𐑛 𐑑 {targetName}", + "notification.pleroma:emoji_reaction": "{name} 𐑮𐑦𐑨𐑒𐑑𐑩𐑛 𐑑 𐑘𐑹 𐑐𐑴𐑕𐑑", + "notification.poll": "A 𐑐𐑴𐑤 𐑿 𐑣𐑨𐑝 𐑝𐑴𐑑𐑩𐑛 𐑦𐑯 𐑣𐑨𐑟 𐑧𐑯𐑛𐑩𐑛", + "notification.reblog": "{name} 𐑮𐑰𐑐𐑴𐑕𐑑𐑩𐑛 𐑘𐑹 𐑐𐑴𐑕𐑑", + "notifications.clear": "𐑒𐑤𐑽 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "notifications.clear_confirmation": "𐑸 𐑿 𐑖𐑫𐑼 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑐𐑻𐑥𐑩𐑯𐑩𐑯𐑑𐑤𐑦 𐑒𐑤𐑽 𐑷𐑤 𐑘𐑹 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟?", + "notifications.column_settings.alert": "𐑛𐑧𐑕𐑒𐑑𐑪𐑐 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "notifications.column_settings.emoji_react": "𐑦𐑥𐑴𐑡𐑦 𐑮𐑦𐑨𐑒𐑑𐑕:", + "notifications.column_settings.favourite": "𐑤𐑲𐑒𐑕:", + "notifications.column_settings.filter_bar.advanced": "𐑛𐑦𐑕𐑐𐑤𐑱 𐑷𐑤 𐑒𐑨𐑑𐑩𐑜𐑼𐑦𐑟", + "notifications.column_settings.filter_bar.category": "𐑒𐑢𐑦𐑒 𐑓𐑦𐑤𐑑𐑼 𐑚𐑸", + "notifications.column_settings.filter_bar.show": "𐑖𐑴", + "notifications.column_settings.follow": "𐑯𐑿 𐑓𐑪𐑤𐑴𐑼𐑟:", + "notifications.column_settings.follow_request": "𐑯𐑿 𐑓𐑪𐑤𐑴 𐑮𐑦𐑒𐑢𐑧𐑕𐑑𐑕:", + "notifications.column_settings.mention": "𐑥𐑧𐑯𐑖𐑩𐑯𐑟:", + "notifications.column_settings.move": "𐑥𐑵𐑝𐑟:", + "notifications.column_settings.poll": "𐑐𐑴𐑤 𐑮𐑦𐑟𐑳𐑤𐑑𐑕:", + "notifications.column_settings.push": "𐑐𐑫𐑖 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "notifications.column_settings.reblog": "𐑮𐑰𐑐𐑴𐑕𐑑𐑕:", + "notifications.column_settings.show": "𐑖𐑴 𐑦𐑯 𐑒𐑪𐑤𐑩𐑥", + "notifications.column_settings.sound": "𐑐𐑤𐑱 𐑕𐑬𐑯𐑛", + "notifications.column_settings.sounds": "𐑕𐑬𐑯𐑛𐑟", + "notifications.column_settings.sounds.all_sounds": "𐑐𐑤𐑱 𐑕𐑬𐑯𐑛 𐑓 𐑷𐑤 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "notifications.column_settings.title": "𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯 𐑕𐑧𐑑𐑦𐑙𐑟", + "notifications.filter.all": "𐑷𐑤", + "notifications.filter.boosts": "𐑮𐑰𐑐𐑴𐑕𐑑𐑕", + "notifications.filter.emoji_reacts": "𐑦𐑥𐑴𐑡𐑦 𐑮𐑦𐑨𐑒𐑑𐑕", + "notifications.filter.favourites": "𐑤𐑲𐑒𐑕", + "notifications.filter.follows": "𐑓𐑪𐑤𐑴𐑟", + "notifications.filter.mentions": "𐑥𐑧𐑯𐑖𐑩𐑯𐑟", + "notifications.filter.moves": "𐑥𐑵𐑝𐑟", + "notifications.filter.polls": "𐑐𐑴𐑤 𐑮𐑦𐑟𐑳𐑤𐑑𐑕", + "notifications.group": "{count} 𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "notifications.queue_label": "𐑒𐑤𐑦𐑒 𐑑 𐑕𐑰 {count} 𐑯𐑿 {count, plural, one {notification} other {notifications}}", + "password_reset.confirmation": "𐑗𐑧𐑒 𐑘𐑹 𐑰𐑥𐑱𐑤 𐑓 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯.", + "password_reset.fields.username_placeholder": "𐑰𐑥𐑱𐑤 𐑹 𐑿𐑟𐑼𐑯𐑱𐑥", + "password_reset.reset": "𐑮𐑰𐑕𐑧𐑑 𐑐𐑭𐑕𐑢𐑻𐑛", + "pinned_statuses.none": "𐑯𐑴 𐑐𐑦𐑯𐑟 𐑑 𐑖𐑴.", + "poll.closed": "𐑒𐑤𐑴𐑟𐑛", + "poll.refresh": "𐑮𐑦𐑓𐑮𐑧𐑖", + "poll.total_votes": "{count, plural, one {# vote} other {# votes}}", + "poll.vote": "𐑝𐑴𐑑", + "poll.voted": "𐑿 𐑝𐑴𐑑𐑩𐑛 𐑓 𐑞𐑦𐑕 answer", + "poll.votes": "{votes, plural, one {# vote} other {# votes}}", + "poll_button.add_poll": "𐑨𐑛 𐑩 𐑐𐑴𐑤", + "poll_button.remove_poll": "𐑮𐑦𐑥𐑵𐑝 𐑐𐑴𐑤", + "preferences.fields.auto_play_gif_label": "𐑷𐑑𐑴-𐑐𐑤𐑱 𐑨𐑯𐑦𐑥𐑱𐑑𐑩𐑛 GIFs", + "preferences.fields.autoload_more_label": "𐑷𐑑𐑩𐑥𐑨𐑑𐑦𐑒𐑤𐑦 𐑤𐑴𐑛 𐑥𐑹 𐑲𐑑𐑩𐑥𐑟 𐑢𐑧𐑯 scrolled 𐑑 𐑞 𐑚𐑪𐑑𐑩𐑥 𐑝 𐑞 𐑐𐑱𐑡", + "preferences.fields.autoload_timelines_label": "𐑷𐑑𐑩𐑥𐑨𐑑𐑦𐑒𐑤𐑦 𐑤𐑴𐑛 𐑯𐑿 𐑐𐑴𐑕𐑑𐑕 𐑢𐑧𐑯 scrolled 𐑑 𐑞 𐑑𐑪𐑐 𐑝 𐑞 𐑐𐑱𐑡", + "preferences.fields.boost_modal_label": "𐑖𐑴 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑛𐑲𐑩𐑤𐑪𐑜 𐑚𐑦𐑓𐑹 𐑮𐑰𐑐𐑴𐑕𐑑𐑦𐑙", + "preferences.fields.content_type_label": "𐑐𐑴𐑕𐑑 format", + "preferences.fields.delete_modal_label": "𐑖𐑴 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑛𐑲𐑩𐑤𐑪𐑜 𐑚𐑦𐑓𐑹 𐑛𐑦𐑤𐑰𐑑𐑦𐑙 𐑩 𐑐𐑴𐑕𐑑", + "preferences.fields.demetricator_label": "𐑿𐑕 Demetricator", + "preferences.fields.developer_label": "𐑛𐑦𐑝𐑧𐑤𐑩𐑐𐑼 𐑑𐑵𐑤𐑟", + "preferences.fields.display_media.default": "𐑣𐑲𐑛 𐑥𐑰𐑛𐑾 𐑥𐑸𐑒𐑑 𐑨𐑟 𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝", + "preferences.fields.display_media.hide_all": "𐑷𐑤𐑢𐑱𐑟 𐑣𐑲𐑛 𐑥𐑰𐑛𐑾", + "preferences.fields.display_media.show_all": "𐑷𐑤𐑢𐑱𐑟 𐑖𐑴 𐑥𐑰𐑛𐑾", + "preferences.fields.dyslexic_font_label": "Dyslexic 𐑥𐑴𐑛", + "preferences.fields.expand_spoilers_label": "𐑷𐑤𐑢𐑱𐑟 𐑦𐑒𐑕𐑐𐑨𐑯𐑛 𐑐𐑴𐑕𐑑𐑕 𐑥𐑸𐑒𐑑 𐑢𐑦𐑞 𐑒𐑪𐑯𐑑𐑧𐑯𐑑 𐑢𐑹𐑯𐑦𐑙𐑟", + "preferences.fields.halloween_label": "Halloween 𐑥𐑴𐑛", + "preferences.fields.language_label": "𐑤𐑨𐑙𐑜𐑢𐑦𐑡", + "preferences.fields.media_display_label": "𐑥𐑰𐑛𐑾 𐑛𐑦𐑕𐑐𐑤𐑱", + "preferences.fields.missing_description_modal_label": "𐑖𐑴 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑛𐑲𐑩𐑤𐑪𐑜 𐑚𐑦𐑓𐑹 𐑕𐑧𐑯𐑛𐑦𐑙 𐑩 𐑐𐑴𐑕𐑑 𐑢𐑦𐑞𐑬𐑑 𐑥𐑰𐑛𐑾 𐑛𐑦𐑕𐑒𐑮𐑦𐑐𐑖𐑩𐑯𐑟", + "preferences.fields.privacy_label": "𐑐𐑴𐑕𐑑 𐑐𐑮𐑦𐑝𐑩𐑕𐑦", + "preferences.fields.reduce_motion_label": "𐑮𐑦𐑛𐑿𐑕 𐑥𐑴𐑖𐑩𐑯 𐑦𐑯 𐑨𐑯𐑦𐑥𐑱𐑖𐑩𐑯𐑟", + "preferences.fields.system_font_label": "𐑿𐑕 𐑕𐑦𐑕𐑑𐑩𐑥𐑟 𐑛𐑦𐑓𐑷𐑤𐑑 𐑓𐑪𐑯𐑑", + "preferences.fields.underline_links_label": "𐑷𐑤𐑢𐑱𐑟 𐑳𐑯𐑛𐑼𐑤𐑲𐑯 𐑤𐑦𐑙𐑒𐑕 𐑦𐑯 𐑐𐑴𐑕𐑑𐑕", + "preferences.fields.unfollow_modal_label": "𐑖𐑴 𐑒𐑪𐑯𐑓𐑼𐑥𐑱𐑖𐑩𐑯 𐑛𐑲𐑩𐑤𐑪𐑜 𐑚𐑦𐑓𐑹 𐑳𐑯𐑓𐑪𐑤𐑴𐑦𐑙 𐑕𐑳𐑥𐑢𐑳𐑯", + "preferences.hints.content_type_markdown": "𐑢𐑹𐑯𐑦𐑙: 𐑦𐑒𐑕𐑐𐑧𐑮𐑦𐑥𐑧𐑯𐑑𐑩𐑤!", + "preferences.hints.demetricator": "𐑛𐑦𐑒𐑮𐑰𐑕 𐑕𐑴𐑖𐑩𐑤 𐑥𐑰𐑛𐑾 𐑨𐑙𐑟𐑲𐑩𐑑𐑦 𐑚𐑲 𐑣𐑲𐑛𐑦𐑙 𐑷𐑤 𐑯𐑳𐑥𐑚𐑼𐑟 𐑓𐑮𐑪𐑥 𐑞 𐑕𐑲𐑑.", + "preferences.hints.halloween": "𐑚𐑦𐑢𐑺: SPOOKY! 𐑕𐑩𐑐𐑹𐑑𐑕 𐑤𐑲𐑑/𐑛𐑸𐑒 𐑑𐑪𐑜𐑩𐑤.", + "preferences.hints.privacy_followers_only": "𐑴𐑯𐑤𐑦 𐑖𐑴 𐑑 𐑓𐑪𐑤𐑴𐑼𐑟", + "preferences.hints.privacy_public": "𐑧𐑝𐑮𐑦𐑢𐑳𐑯 𐑒𐑨𐑯 𐑕𐑰", + "preferences.hints.privacy_unlisted": "𐑧𐑝𐑮𐑦𐑢𐑳𐑯 𐑒𐑨𐑯 𐑕𐑰, 𐑚𐑳𐑑 𐑯𐑪𐑑 𐑤𐑦𐑕𐑑𐑩𐑛 𐑪𐑯 𐑐𐑳𐑚𐑤𐑦𐑒 𐑑𐑲𐑥𐑤𐑲𐑯𐑟", + "preferences.options.content_type_markdown": "𐑥𐑸𐑒𐑛𐑬𐑯", + "preferences.options.content_type_plaintext": "𐑐𐑤𐑱𐑯 𐑑𐑧𐑒𐑕𐑑", + "preferences.options.privacy_followers_only": "𐑓𐑪𐑤𐑴𐑼𐑟-𐑴𐑯𐑤𐑦", + "preferences.options.privacy_public": "𐑐𐑳𐑚𐑤𐑦𐑒", + "preferences.options.privacy_unlisted": "𐑳𐑯𐑤𐑦𐑕𐑑𐑩𐑛", + "privacy.change": "𐑩𐑡𐑳𐑕𐑑 𐑐𐑴𐑕𐑑 𐑐𐑮𐑦𐑝𐑩𐑕𐑦", + "privacy.direct.long": "𐑐𐑴𐑕𐑑 𐑑 𐑥𐑧𐑯𐑖𐑩𐑯𐑛 𐑿𐑟𐑼𐑟 𐑴𐑯𐑤𐑦", + "privacy.direct.short": "𐑛𐑦𐑮𐑧𐑒𐑑", + "privacy.private.long": "𐑐𐑴𐑕𐑑 𐑑 𐑓𐑪𐑤𐑴𐑼𐑟 𐑴𐑯𐑤𐑦", + "privacy.private.short": "𐑓𐑪𐑤𐑴𐑼𐑟-𐑴𐑯𐑤𐑦", + "privacy.public.long": "𐑐𐑴𐑕𐑑 𐑑 𐑐𐑳𐑚𐑤𐑦𐑒 𐑑𐑲𐑥𐑤𐑲𐑯𐑟", + "privacy.public.short": "𐑐𐑳𐑚𐑤𐑦𐑒", + "privacy.unlisted.long": "𐑛𐑵 𐑯𐑪𐑑 𐑐𐑴𐑕𐑑 𐑑 𐑐𐑳𐑚𐑤𐑦𐑒 𐑑𐑲𐑥𐑤𐑲𐑯𐑟", + "privacy.unlisted.short": "𐑳𐑯𐑤𐑦𐑕𐑑𐑩𐑛", + "profile_dropdown.add_account": "𐑨𐑛 𐑩𐑯 𐑦𐑜𐑟𐑦𐑕𐑑𐑦𐑙 𐑩𐑒𐑬𐑯𐑑", + "profile_dropdown.logout": "𐑤𐑪𐑜 𐑬𐑑 @{acct}", + "public.column_settings.title": "·𐑓𐑧𐑛𐑦𐑝𐑻𐑕 𐑑𐑲𐑥𐑤𐑲𐑯 𐑕𐑧𐑑𐑦𐑙𐑟", + "reactions.all": "𐑷𐑤", + "regeneration_indicator.label": "𐑤𐑴𐑛𐑦𐑙…", + "regeneration_indicator.sublabel": "𐑘𐑹 𐑣𐑴𐑥 𐑓𐑰𐑛 𐑦𐑟 𐑚𐑰𐑦𐑙 𐑐𐑮𐑦𐑐𐑺𐑛!", + "register_invite.lead": "𐑒𐑩𐑥𐑐𐑤𐑰𐑑 𐑞 𐑓𐑹𐑥 𐑚𐑦𐑤𐑴 𐑑 𐑒𐑮𐑦𐑱𐑑 𐑩𐑯 𐑩𐑒𐑬𐑯𐑑.", + "register_invite.title": "𐑿𐑝 𐑚𐑰𐑯 𐑦𐑯𐑝𐑲𐑑𐑩𐑛 𐑑 𐑡𐑶𐑯 {siteTitle}!", + "registration.agreement": "𐑲 𐑩𐑜𐑮𐑰 𐑑 𐑞 {tos}.", + "registration.captcha.hint": "𐑒𐑤𐑦𐑒 𐑞 𐑦𐑥𐑦𐑡 𐑑 𐑜𐑧𐑑 𐑩 𐑯𐑿 ·𐑒𐑨𐑐𐑗𐑩", + "registration.closed_message": "{instance} 𐑦𐑟 𐑯𐑪𐑑 𐑩𐑒𐑕𐑧𐑐𐑑𐑦𐑙 𐑯𐑿 𐑥𐑧𐑥𐑚𐑼𐑟", + "registration.closed_title": "𐑮𐑧𐑡𐑦𐑕𐑑𐑮𐑱𐑖𐑩𐑯𐑟 𐑒𐑤𐑴𐑟𐑛", + "registration.confirmation_modal.close": "𐑒𐑤𐑴𐑟", + "registration.fields.confirm_placeholder": "𐑐𐑭𐑕𐑢𐑻𐑛 (𐑩𐑜𐑱𐑯)", + "registration.fields.email_placeholder": "𐑰𐑥𐑱𐑤 𐑩𐑛𐑮𐑧𐑕", + "registration.fields.password_placeholder": "𐑐𐑭𐑕𐑢𐑻𐑛", + "registration.fields.username_hint": "𐑴𐑯𐑤𐑦 𐑤𐑧𐑑𐑼𐑟, 𐑯𐑳𐑥𐑚𐑼𐑟, 𐑯 𐑳𐑯𐑛𐑼𐑕𐑒𐑹𐑟 𐑸 𐑩𐑤𐑬𐑛.", + "registration.fields.username_placeholder": "𐑿𐑟𐑼𐑯𐑱𐑥", + "registration.lead": "𐑢𐑦𐑞 𐑩𐑯 𐑩𐑒𐑬𐑯𐑑 𐑪𐑯 {instance} 𐑿𐑤 𐑚𐑰 𐑱𐑚𐑩𐑤 𐑑 𐑓𐑪𐑤𐑴 𐑐𐑰𐑐𐑩𐑤 𐑪𐑯 𐑧𐑯𐑦 𐑕𐑻𐑝𐑼 𐑦𐑯 𐑞 ·𐑓𐑧𐑛𐑦𐑝𐑻𐑕.", + "registration.newsletter": "𐑕𐑩𐑚𐑕𐑒𐑮𐑲𐑚 𐑑 𐑯𐑿𐑟𐑤𐑧𐑑𐑼.", + "registration.password_mismatch": "𐑐𐑭𐑕𐑢𐑻𐑛𐑟 𐑛𐑴𐑯𐑑 match.", + "registration.reason": "𐑢𐑲 𐑛𐑵 𐑿 𐑢𐑪𐑯𐑑 𐑑 𐑡𐑶𐑯?", + "registration.reason_hint": "𐑞𐑦𐑕 𐑢𐑦𐑤 help 𐑳𐑕 𐑮𐑦𐑝𐑿 𐑘𐑹 𐑨𐑐𐑤𐑦𐑒𐑱𐑖𐑩𐑯", + "registration.sign_up": "𐑕𐑲𐑯 𐑳𐑐", + "registration.tos": "Terms 𐑝 𐑕𐑻𐑝𐑦𐑕", + "registration.username_unavailable": "𐑿𐑟𐑼𐑯𐑱𐑥 𐑦𐑟 𐑷𐑤𐑮𐑧𐑛𐑦 𐑑𐑱𐑒𐑩𐑯.", + "relative_time.days": "{number}d", + "relative_time.hours": "{number}h", + "relative_time.just_now": "𐑯𐑬", + "relative_time.minutes": "{number}m", + "relative_time.seconds": "{number}s", + "remote_instance.edit_federation": "𐑧𐑛𐑦𐑑 𐑓𐑧𐑛𐑼𐑱𐑖𐑩𐑯", + "remote_instance.federation_panel.heading": "𐑓𐑧𐑛𐑼𐑱𐑖𐑩𐑯 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟", + "remote_instance.federation_panel.no_restrictions_message": "{siteTitle} 𐑣𐑨𐑟 𐑐𐑤𐑱𐑕𐑑 𐑯𐑴 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟 𐑪𐑯 {host}.", + "remote_instance.federation_panel.restricted_message": "{siteTitle} 𐑚𐑤𐑪𐑒𐑕 𐑷𐑤 𐑨𐑒𐑑𐑦𐑝𐑦𐑑𐑦𐑟 𐑓𐑮𐑪𐑥 {host}.", + "remote_instance.federation_panel.some_restrictions_message": "{siteTitle} 𐑣𐑨𐑟 𐑐𐑤𐑱𐑕𐑑 𐑕𐑳𐑥 𐑮𐑦𐑕𐑑𐑮𐑦𐑒𐑖𐑩𐑯𐑟 𐑪𐑯 {host}.", + "remote_instance.pin_host": "𐑐𐑦𐑯 {host}", + "remote_instance.unpin_host": "𐑳𐑯𐑐𐑦𐑯 {host}", + "remote_interaction.account_placeholder": "𐑧𐑯𐑑𐑼 𐑘𐑹 username@domain 𐑿 𐑢𐑪𐑯𐑑 𐑑 act 𐑓𐑮𐑪𐑥", + "remote_interaction.divider": "or", + "remote_interaction.favourite": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑤𐑲𐑒", + "remote_interaction.favourite_title": "𐑤𐑲𐑒 𐑩 𐑐𐑴𐑕𐑑 𐑮𐑦𐑥𐑴𐑑𐑤𐑦", + "remote_interaction.follow": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑓𐑪𐑤𐑴", + "remote_interaction.follow_title": "𐑓𐑪𐑤𐑴 {user} 𐑮𐑦𐑥𐑴𐑑𐑤𐑦", + "remote_interaction.poll_vote": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑝𐑴𐑑", + "remote_interaction.poll_vote_title": "𐑝𐑴𐑑 𐑦𐑯 𐑩 𐑐𐑴𐑤 𐑮𐑦𐑥𐑴𐑑𐑤𐑦", + "remote_interaction.reblog": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑮𐑰𐑐𐑴𐑕𐑑", + "remote_interaction.reblog_title": "𐑮𐑰𐑚𐑤𐑪𐑜 𐑩 𐑐𐑴𐑕𐑑 𐑮𐑦𐑥𐑴𐑑𐑤𐑦", + "remote_interaction.reply": "𐑐𐑮𐑩𐑕𐑰𐑛 𐑑 𐑮𐑦𐑐𐑤𐑲", + "remote_interaction.reply_title": "𐑮𐑦𐑐𐑤𐑲 𐑑 𐑩 𐑐𐑴𐑕𐑑 𐑮𐑦𐑥𐑴𐑑𐑤𐑦", + "remote_interaction.user_not_found_error": "𐑒𐑫𐑛𐑩𐑯𐑑 find given 𐑿𐑟𐑼", + "remote_timeline.filter_message": "𐑿 𐑸 𐑝𐑿𐑦𐑙 𐑞 𐑑𐑲𐑥𐑤𐑲𐑯 𐑝 {instance}.", + "reply_indicator.cancel": "𐑒𐑨𐑯𐑕𐑩𐑤", + "reply_mentions.account.add": "𐑨𐑛 𐑑 𐑥𐑧𐑯𐑖𐑩𐑯𐑟", + "reply_mentions.account.remove": "𐑮𐑦𐑥𐑵𐑝 𐑓𐑮𐑪𐑥 𐑥𐑧𐑯𐑖𐑩𐑯𐑟", + "reply_mentions.more": "𐑯 {count} 𐑥𐑹", + "reply_mentions.reply": "𐑮𐑦𐑐𐑤𐑲𐑦𐑙 𐑑 {accounts}{more}", + "reply_mentions.reply_empty": "𐑮𐑦𐑐𐑤𐑲𐑦𐑙 𐑑 𐑐𐑴𐑕𐑑", + "report.block": "𐑚𐑤𐑪𐑒 {target}", + "report.block_hint": "𐑛𐑵 𐑿 𐑷𐑤𐑕𐑴 𐑢𐑪𐑯𐑑 𐑑 𐑚𐑤𐑪𐑒 𐑞𐑦𐑕 𐑩𐑒𐑬𐑯𐑑?", + "report.forward": "𐑓𐑹𐑢𐑼𐑛 𐑑 {target}", + "report.forward_hint": "𐑞 𐑩𐑒𐑬𐑯𐑑 𐑦𐑟 𐑓𐑮𐑪𐑥 𐑩𐑯𐑳𐑞𐑼 𐑕𐑻𐑝𐑼. 𐑕𐑧𐑯𐑛 𐑩 𐑒𐑪𐑐𐑦 𐑝 𐑞 𐑮𐑦𐑐𐑹𐑑 𐑞𐑺 𐑨𐑟 𐑢𐑧𐑤?", + "report.hint": "𐑞 𐑮𐑦𐑐𐑹𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑕𐑧𐑯𐑑 𐑑 𐑘𐑹 𐑕𐑻𐑝𐑼 𐑥𐑪𐑛𐑼𐑱𐑑𐑼𐑟. 𐑿 𐑒𐑨𐑯 𐑐𐑮𐑩𐑝𐑲𐑛 𐑩𐑯 𐑧𐑒𐑕𐑐𐑤𐑩𐑯𐑱𐑖𐑩𐑯 𐑝 𐑢𐑲 𐑿 𐑸 𐑮𐑦𐑐𐑹𐑑𐑦𐑙 𐑞𐑦𐑕 𐑩𐑒𐑬𐑯𐑑 𐑚𐑦𐑤𐑴:", + "report.placeholder": "𐑩𐑛𐑦𐑖𐑩𐑯𐑩𐑤 𐑒𐑪𐑥𐑧𐑯𐑑𐑕", + "report.submit": "𐑕𐑩𐑚𐑥𐑦𐑑", + "report.target": "𐑮𐑦𐑐𐑹𐑑𐑦𐑙 {target}", + "schedule.post_time": "𐑐𐑴𐑕𐑑 𐑛𐑱𐑑/𐑑𐑲𐑥", + "schedule.remove": "𐑮𐑦𐑥𐑵𐑝 𐑖𐑧𐑡𐑵𐑤", + "schedule_button.add_schedule": "𐑖𐑧𐑡𐑵𐑤 𐑐𐑴𐑕𐑑 𐑓 𐑤𐑱𐑑𐑼", + "schedule_button.remove_schedule": "𐑐𐑴𐑕𐑑 𐑦𐑥𐑰𐑛𐑾𐑑𐑤𐑦", + "scheduled_status.cancel": "𐑒𐑨𐑯𐑕𐑩𐑤", + "search.action": "𐑕𐑻𐑗 𐑓 “{query}”", + "search.placeholder": "𐑕𐑻𐑗", + "search_results.accounts": "𐑐𐑰𐑐𐑩𐑤", + "search_results.hashtags": "𐑣𐑨𐑖𐑑𐑨𐑜𐑟", + "search_results.statuses": "𐑐𐑴𐑕𐑑𐑕", + "search_results.top": "𐑑𐑪𐑐", + "security.codes.fail": "𐑓𐑱𐑤𐑛 𐑑 𐑓𐑧𐑗 𐑚𐑨𐑒𐑳𐑐 𐑒𐑴𐑛𐑟", + "security.confirm.fail": "𐑦𐑯𐑒𐑼𐑧𐑒𐑑 𐑒𐑴𐑛 𐑹 𐑐𐑭𐑕𐑢𐑻𐑛. 𐑑𐑮𐑲 𐑩𐑜𐑱𐑯.", + "security.delete_account.fail": "𐑩𐑒𐑬𐑯𐑑 𐑛𐑦𐑤𐑰𐑖𐑩𐑯 𐑓𐑱𐑤𐑛.", + "security.delete_account.success": "𐑩𐑒𐑬𐑯𐑑 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦 𐑛𐑦𐑤𐑰𐑑𐑩𐑛.", + "security.disable.fail": "𐑦𐑯𐑒𐑼𐑧𐑒𐑑 𐑐𐑭𐑕𐑢𐑻𐑛. 𐑑𐑮𐑲 𐑩𐑜𐑱𐑯.", + "security.disable_mfa": "𐑛𐑦𐑕𐑱𐑚𐑩𐑤", + "security.fields.email.label": "𐑰𐑥𐑱𐑤 𐑩𐑛𐑮𐑧𐑕", + "security.fields.new_password.label": "𐑯𐑿 𐑐𐑭𐑕𐑢𐑻𐑛", + "security.fields.old_password.label": "𐑒𐑳𐑮𐑩𐑯𐑑 𐑐𐑭𐑕𐑢𐑻𐑛", + "security.fields.password.label": "𐑐𐑭𐑕𐑢𐑻𐑛", + "security.fields.password_confirmation.label": "𐑯𐑿 𐑐𐑭𐑕𐑢𐑻𐑛 (𐑩𐑜𐑱𐑯)", + "security.headers.delete": "𐑛𐑦𐑤𐑰𐑑 𐑩𐑒𐑬𐑯𐑑", + "security.headers.tokens": "𐑕𐑧𐑖𐑩𐑯𐑟", + "security.headers.update_email": "𐑗𐑱𐑯𐑡 𐑰𐑥𐑱𐑤", + "security.headers.update_password": "𐑗𐑱𐑯𐑡 𐑐𐑭𐑕𐑢𐑻𐑛", + "security.mfa": "𐑕𐑧𐑑 𐑳𐑐 2-Factor Auth", + "security.mfa_enabled": "𐑿 𐑣𐑨𐑝 𐑥𐑳𐑤𐑑𐑦-𐑓𐑨𐑒𐑑𐑼 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯 𐑕𐑧𐑑 𐑳𐑐 𐑢𐑦𐑞 OTP.", + "security.mfa_header": "𐑷𐑔𐑼𐑲𐑟𐑱𐑖𐑩𐑯 𐑥𐑧𐑔𐑩𐑛𐑟", + "security.mfa_setup_hint": "𐑒𐑩𐑯𐑓𐑦𐑜𐑼 𐑥𐑳𐑤𐑑𐑦-𐑓𐑨𐑒𐑑𐑼 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯 𐑢𐑦𐑞 OTP", + "security.qr.fail": "𐑓𐑱𐑤𐑛 𐑑 𐑓𐑧𐑗 𐑕𐑧𐑑𐑳𐑐 key", + "security.submit": "𐑕𐑱𐑝 𐑗𐑱𐑯𐑡𐑩𐑟", + "security.submit.delete": "𐑛𐑦𐑤𐑰𐑑 𐑩𐑒𐑬𐑯𐑑", + "security.text.delete": "𐑑 𐑛𐑦𐑤𐑰𐑑 𐑘𐑹 𐑩𐑒𐑬𐑯𐑑, 𐑧𐑯𐑑𐑼 𐑘𐑹 𐑐𐑭𐑕𐑢𐑻𐑛 𐑞𐑧𐑯 𐑒𐑤𐑦𐑒 𐑛𐑦𐑤𐑰𐑑 𐑩𐑒𐑬𐑯𐑑. 𐑞𐑦𐑕 𐑦𐑟 𐑩 𐑐𐑻𐑥𐑩𐑯𐑩𐑯𐑑 𐑨𐑒𐑖𐑩𐑯 𐑞𐑨𐑑 𐑒𐑨𐑯𐑪𐑑 𐑚𐑰 𐑳𐑯𐑛𐑳𐑯. 𐑘𐑹 𐑩𐑒𐑬𐑯𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑛𐑦𐑕𐑑𐑮𐑶𐑛 𐑓𐑮𐑪𐑥 𐑞𐑦𐑕 𐑕𐑻𐑝𐑼, 𐑯 𐑩 𐑛𐑦𐑤𐑰𐑖𐑩𐑯 𐑮𐑦𐑒𐑢𐑧𐑕𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑕𐑧𐑯𐑑 𐑑 𐑳𐑞𐑼 𐑕𐑻𐑝𐑼𐑟. 𐑦𐑑𐑕 𐑯𐑪𐑑 𐑜𐑨𐑮𐑩𐑯𐑑𐑰𐑛 𐑞𐑨𐑑 𐑷𐑤 𐑕𐑻𐑝𐑼𐑟 𐑢𐑦𐑤 𐑐𐑻𐑡 𐑘𐑹 𐑩𐑒𐑬𐑯𐑑.", + "security.tokens.revoke": "𐑮𐑦𐑝𐑴𐑒", + "security.update_email.fail": "𐑳𐑐𐑛𐑱𐑑 𐑰𐑥𐑱𐑤 𐑓𐑱𐑤𐑛.", + "security.update_email.success": "𐑰𐑥𐑱𐑤 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦 𐑳𐑐𐑛𐑱𐑑𐑩𐑛.", + "security.update_password.fail": "𐑳𐑐𐑛𐑱𐑑 𐑐𐑭𐑕𐑢𐑻𐑛 𐑓𐑱𐑤𐑛.", + "security.update_password.success": "𐑐𐑭𐑕𐑢𐑻𐑛 𐑕𐑩𐑒𐑕𐑧𐑕𐑓𐑩𐑤𐑦 𐑳𐑐𐑛𐑱𐑑𐑩𐑛.", + "signup_panel.subtitle": "𐑕𐑲𐑯 𐑳𐑐 𐑯𐑬 𐑑 𐑛𐑦𐑕𐑒𐑳𐑕.", + "signup_panel.title": "𐑯𐑿 𐑑 {site_title}?", + "soapbox_config.authenticated_profile_hint": "𐑿𐑟𐑼𐑟 𐑥𐑳𐑕𐑑 𐑚𐑰 𐑤𐑪𐑜𐑛-𐑦𐑯 𐑑 𐑝𐑿 𐑮𐑦𐑐𐑤𐑲𐑟 𐑯 𐑥𐑰𐑛𐑾 𐑪𐑯 𐑿𐑟𐑼 𐑐𐑮𐑴𐑓𐑲𐑤𐑟.", + "soapbox_config.authenticated_profile_label": "𐑐𐑮𐑴𐑓𐑲𐑤𐑟 𐑮𐑦𐑒𐑢𐑲𐑼 𐑷𐑔𐑧𐑯𐑑𐑦𐑒𐑱𐑖𐑩𐑯", + "soapbox_config.copyright_footer.meta_fields.label_placeholder": "Copyright footer", + "soapbox_config.crypto_address.meta_fields.address_placeholder": "𐑩𐑛𐑮𐑧𐑕", + "soapbox_config.crypto_address.meta_fields.note_placeholder": "𐑯𐑴𐑑 (𐑪𐑐𐑖𐑩𐑯𐑩𐑤)", + "soapbox_config.crypto_address.meta_fields.ticker_placeholder": "𐑑𐑦𐑒𐑼", + "soapbox_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "𐑯𐑳𐑥𐑚𐑼 𐑝 𐑲𐑑𐑩𐑥𐑟 𐑑 𐑛𐑦𐑕𐑐𐑤𐑱 𐑦𐑯 𐑞 𐑒𐑮𐑦𐑐𐑑𐑴 𐑣𐑴𐑥𐑐𐑱𐑡 widget", + "soapbox_config.custom_css.meta_fields.url_placeholder": "URL", + "soapbox_config.display_fqn_label": "𐑛𐑦𐑕𐑐𐑤𐑱 𐑛𐑴𐑥𐑱𐑯 (eg @user@domain) 𐑓 𐑤𐑴𐑒𐑩𐑤 𐑩𐑒𐑬𐑯𐑑𐑕.", + "soapbox_config.fields.brand_color_label": "𐑚𐑮𐑨𐑯𐑛 𐑒𐑳𐑤𐑼", + "soapbox_config.fields.crypto_address.add": "𐑨𐑛 𐑯𐑿 𐑒𐑮𐑦𐑐𐑑𐑴 𐑩𐑛𐑮𐑧𐑕", + "soapbox_config.fields.crypto_addresses_label": "𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦 𐑩𐑛𐑮𐑧𐑕𐑩𐑟", + "soapbox_config.fields.home_footer.add": "𐑨𐑛 𐑯𐑿 𐑣𐑴𐑥 𐑓𐑫𐑑𐑼 𐑲𐑑𐑩𐑥", + "soapbox_config.fields.home_footer_fields_label": "𐑣𐑴𐑥 𐑓𐑫𐑑𐑼 𐑲𐑑𐑩𐑥𐑟", + "soapbox_config.fields.logo_label": "Logo", + "soapbox_config.fields.promo_panel.add": "𐑨𐑛 𐑯𐑿 Promo panel 𐑲𐑑𐑩𐑥", + "soapbox_config.fields.promo_panel_fields_label": "Promo panel 𐑲𐑑𐑩𐑥𐑟", + "soapbox_config.fields.theme_label": "𐑛𐑦𐑓𐑷𐑤𐑑 𐑔𐑰𐑥", + "soapbox_config.greentext_label": "𐑦𐑯𐑱𐑚𐑩𐑤 𐑜𐑮𐑰𐑯𐑑𐑧𐑒𐑕𐑑 𐑕𐑩𐑐𐑹𐑑", + "soapbox_config.hints.crypto_addresses": "𐑨𐑛 𐑒𐑮𐑦𐑐𐑑𐑴𐑒𐑳𐑮𐑩𐑯𐑕𐑦 𐑩𐑛𐑮𐑧𐑕𐑩𐑟 so 𐑿𐑟𐑼𐑟 𐑝 𐑘𐑹 𐑕𐑲𐑑 𐑒𐑨𐑯 𐑛𐑴𐑯𐑱𐑑 𐑑 𐑿. 𐑹𐑛𐑼 matters, 𐑯 𐑿 𐑥𐑳𐑕𐑑 𐑿𐑕 lowercase 𐑑𐑦𐑒𐑼 values.", + "soapbox_config.hints.home_footer_fields": "𐑿 𐑒𐑨𐑯 𐑣𐑨𐑝 custom defined 𐑤𐑦𐑙𐑒𐑕 𐑛𐑦𐑕𐑐𐑤𐑱𐑛 𐑪𐑯 𐑞 𐑓𐑫𐑑𐑼 𐑝 𐑘𐑹 static 𐑐𐑱𐑡𐑩𐑟", + "soapbox_config.hints.logo": "SVG. 𐑨𐑑 𐑥𐑴𐑕𐑑 2 MB. 𐑢𐑦𐑤 𐑚𐑰 𐑛𐑦𐑕𐑐𐑤𐑱𐑛 𐑑 50px height, maintaining aspect ratio", + "soapbox_config.hints.promo_panel_fields": "𐑿 𐑒𐑨𐑯 𐑣𐑨𐑝 custom defined 𐑤𐑦𐑙𐑒𐑕 𐑛𐑦𐑕𐑐𐑤𐑱𐑛 𐑪𐑯 𐑞 right panel 𐑝 𐑞 𐑑𐑲𐑥𐑤𐑲𐑯𐑟 𐑐𐑱𐑡.", + "soapbox_config.hints.promo_panel_icons": "{ link }", + "soapbox_config.hints.promo_panel_icons.link": "·𐑕𐑴𐑐𐑚𐑪𐑒𐑕 𐑲𐑒𐑪𐑯𐑟 List", + "soapbox_config.home_footer.meta_fields.label_placeholder": "Label", + "soapbox_config.home_footer.meta_fields.url_placeholder": "URL", + "soapbox_config.promo_panel.meta_fields.icon_placeholder": "𐑲𐑒𐑪𐑯", + "soapbox_config.promo_panel.meta_fields.label_placeholder": "Label", + "soapbox_config.promo_panel.meta_fields.url_placeholder": "URL", + "soapbox_config.raw_json_hint": "𐑧𐑛𐑦𐑑 𐑞 𐑕𐑧𐑑𐑦𐑙𐑟 𐑛𐑱𐑑𐑩 𐑛𐑦𐑮𐑧𐑒𐑑𐑤𐑦. 𐑗𐑱𐑯𐑡𐑩𐑟 𐑥𐑱𐑛 𐑛𐑦𐑮𐑧𐑒𐑑𐑤𐑦 𐑑 𐑞 JSON 𐑓𐑲𐑤 𐑢𐑦𐑤 𐑴𐑝𐑼𐑮𐑲𐑛 𐑞 𐑓𐑹𐑥 𐑓𐑰𐑤𐑛𐑟 𐑩𐑚𐑳𐑝. 𐑒𐑤𐑦𐑒 𐑕𐑱𐑝 𐑑 𐑩𐑐𐑤𐑲 𐑘𐑹 𐑗𐑱𐑯𐑡𐑩𐑟.", + "soapbox_config.raw_json_label": "𐑩𐑛𐑝𐑭𐑯𐑕𐑑: 𐑧𐑛𐑦𐑑 raw JSON 𐑛𐑱𐑑𐑩", + "soapbox_config.save": "𐑕𐑱𐑝", + "soapbox_config.saved": "·𐑕𐑴𐑐𐑚𐑪𐑒𐑕 𐑒𐑩𐑯𐑓𐑦𐑜 𐑕𐑱𐑝𐑛!", + "soapbox_config.verified_can_edit_name_label": "𐑩𐑤𐑬 𐑝𐑧𐑮𐑦𐑓𐑲𐑛 𐑿𐑟𐑼𐑟 𐑑 𐑧𐑛𐑦𐑑 𐑞𐑺 𐑴𐑯 𐑛𐑦𐑕𐑐𐑤𐑱 𐑯𐑱𐑥.", + "status.admin_account": "𐑴𐑐𐑩𐑯 𐑥𐑪𐑛𐑼𐑱𐑖𐑩𐑯 𐑦𐑯𐑑𐑼𐑓𐑱𐑕 𐑓 @{name}", + "status.admin_status": "𐑴𐑐𐑩𐑯 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑦𐑯 𐑞 𐑥𐑪𐑛𐑼𐑱𐑖𐑩𐑯 𐑦𐑯𐑑𐑼𐑓𐑱𐑕", + "status.block": "𐑚𐑤𐑪𐑒 @{name}", + "status.bookmark": "𐑚𐑫𐑒𐑥𐑸𐑒", + "status.bookmarked": "𐑚𐑫𐑒𐑥𐑸𐑒 𐑨𐑛𐑩𐑛.", + "status.cancel_reblog_private": "𐑳𐑯-𐑮𐑰𐑐𐑴𐑕𐑑", + "status.cannot_reblog": "𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑒𐑨𐑯𐑪𐑑 𐑚𐑰 𐑮𐑰𐑐𐑴𐑕𐑑𐑩𐑛", + "status.chat": "𐑗𐑨𐑑 𐑢𐑦𐑞 @{name}", + "status.copy": "𐑒𐑪𐑐𐑦 𐑤𐑦𐑙𐑒 𐑑 𐑐𐑴𐑕𐑑", + "status.delete": "𐑛𐑦𐑤𐑰𐑑", + "status.detailed_status": "𐑛𐑰𐑑𐑱𐑤𐑛 𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯 𐑝𐑿", + "status.direct": "𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡 @{name}", + "status.embed": " 𐑦𐑥𐑚𐑧𐑛", + "status.favourite": "𐑤𐑲𐑒", + "status.filtered": "𐑓𐑦𐑤𐑑𐑼𐑛", + "status.load_more": "𐑤𐑴𐑛 𐑥𐑹", + "status.media_hidden": "𐑥𐑰𐑛𐑾 𐑣𐑦𐑛𐑩𐑯", + "status.mention": "𐑥𐑧𐑯𐑖𐑩𐑯 @{name}", + "status.more": "𐑥𐑹", + "status.mute": "𐑥𐑿𐑑 @{name}", + "status.mute_conversation": "𐑥𐑿𐑑 𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯", + "status.open": "𐑦𐑒𐑕𐑐𐑨𐑯𐑛 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑", + "status.pin": "𐑐𐑦𐑯 𐑪𐑯 𐑐𐑮𐑴𐑓𐑲𐑤", + "status.pinned": "𐑐𐑦𐑯𐑛 𐑐𐑴𐑕𐑑", + "status.reactions.cry": "𐑕𐑨𐑛", + "status.reactions.empty": "𐑯𐑴 𐑢𐑳𐑯 𐑣𐑨𐑟 𐑮𐑦𐑨𐑒𐑑𐑩𐑛 𐑑 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑕𐑳𐑥𐑢𐑳𐑯 𐑛𐑳𐑟, 𐑞𐑱 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "status.reactions.heart": "𐑤𐑳𐑝", + "status.reactions.laughing": "𐑣𐑭𐑣𐑭", + "status.reactions.like": "𐑤𐑲𐑒", + "status.reactions.open_mouth": "𐑢𐑬", + "status.reactions.weary": "𐑢𐑽𐑦", + "status.reactions_expand": "𐑕𐑦𐑤𐑧𐑒𐑑 𐑦𐑥𐑴𐑡𐑦", + "status.read_more": "𐑮𐑧𐑛 𐑥𐑹", + "status.reblog": "𐑮𐑰𐑐𐑴𐑕𐑑", + "status.reblog_private": "𐑮𐑰𐑐𐑴𐑕𐑑 𐑑 𐑼𐑦𐑡𐑦𐑯𐑩𐑤 𐑷𐑛𐑾𐑯𐑕", + "status.reblogged_by": "{name} 𐑮𐑰𐑐𐑴𐑕𐑑𐑩𐑛", + "status.reblogs.empty": "𐑯𐑴 𐑢𐑳𐑯 𐑣𐑨𐑟 𐑮𐑰𐑐𐑴𐑕𐑑𐑩𐑛 𐑞𐑦𐑕 𐑐𐑴𐑕𐑑 𐑘𐑧𐑑. 𐑢𐑧𐑯 𐑕𐑳𐑥𐑢𐑳𐑯 𐑛𐑳𐑟, 𐑞𐑱 𐑢𐑦𐑤 𐑖𐑴 𐑳𐑐 𐑣𐑽.", + "status.redraft": "𐑛𐑦𐑤𐑰𐑑 𐑯 𐑮𐑰𐑛𐑮𐑭𐑓𐑑", + "status.remove_account_from_group": "𐑮𐑦𐑥𐑵𐑝 𐑩𐑒𐑬𐑯𐑑 𐑓𐑮𐑪𐑥 𐑜𐑮𐑵𐑐", + "status.remove_post_from_group": "𐑮𐑦𐑥𐑵𐑝 𐑐𐑴𐑕𐑑 𐑓𐑮𐑪𐑥 𐑜𐑮𐑵𐑐", + "status.reply": "𐑮𐑦𐑐𐑤𐑲", + "status.replyAll": "𐑮𐑦𐑐𐑤𐑲 𐑑 𐑔𐑮𐑧𐑛", + "status.report": "𐑮𐑦𐑐𐑹𐑑 @{name}", + "status.sensitive_warning": "𐑕𐑧𐑯𐑕𐑦𐑑𐑦𐑝 𐑒𐑪𐑯𐑑𐑧𐑯𐑑", + "status.share": "𐑖𐑺", + "status.show_less": "𐑖𐑴 𐑤𐑧𐑕", + "status.show_less_all": "𐑖𐑴 𐑤𐑧𐑕 𐑓 𐑷𐑤", + "status.show_more": "𐑖𐑴 𐑥𐑹", + "status.show_more_all": "𐑖𐑴 𐑥𐑹 𐑓 𐑷𐑤", + "status.show_thread": "𐑖𐑴 𐑔𐑮𐑧𐑛", + "status.title": "𐑐𐑴𐑕𐑑", + "status.title_direct": "𐑛𐑦𐑮𐑧𐑒𐑑 𐑥𐑧𐑕𐑦𐑡", + "status.unbookmark": "𐑮𐑦𐑥𐑵𐑝 𐑚𐑫𐑒𐑥𐑸𐑒", + "status.unbookmarked": "𐑚𐑫𐑒𐑥𐑸𐑒 𐑮𐑦𐑥𐑵𐑝𐑛.", + "status.unmute_conversation": "𐑳𐑯𐑥𐑿𐑑 𐑒𐑪𐑯𐑝𐑼𐑕𐑱𐑖𐑩𐑯", + "status.unpin": "𐑳𐑯𐑐𐑦𐑯 𐑓𐑮𐑪𐑥 𐑐𐑮𐑴𐑓𐑲𐑤", + "status_list.queue_label": "𐑒𐑤𐑦𐑒 𐑑 𐑕𐑰 {count} 𐑯𐑿 {count, plural, 𐑢𐑳𐑯 {post} 𐑳𐑞𐑼 {posts}}", + "statuses.tombstone": "𐑢𐑳𐑯 𐑹 𐑥𐑹 𐑐𐑴𐑕𐑑𐑕 𐑦𐑟 𐑳𐑯𐑩𐑝𐑱𐑤𐑩𐑚𐑩𐑤.", + "suggestions.dismiss": "𐑛𐑦𐑕𐑥𐑦𐑕 𐑕𐑩𐑡𐑧𐑕𐑗𐑩𐑯", + "tabs_bar.all": "𐑷𐑤", + "tabs_bar.apps": "𐑨𐑐𐑕", + "tabs_bar.chats": "𐑗𐑨𐑑𐑕", + "tabs_bar.dashboard": "𐑛𐑨𐑖𐑚𐑹𐑛", + "tabs_bar.fediverse": "·𐑓𐑧𐑛𐑦𐑝𐑻𐑕", + "tabs_bar.header": "𐑩𐑒𐑬𐑯𐑑 𐑦𐑯𐑓𐑴", + "tabs_bar.home": "𐑣𐑴𐑥", + "tabs_bar.news": "𐑯𐑿𐑟", + "tabs_bar.notifications": "𐑯𐑴𐑑𐑦𐑓𐑦𐑒𐑱𐑖𐑩𐑯𐑟", + "tabs_bar.post": "𐑐𐑴𐑕𐑑", + "tabs_bar.search": "𐑕𐑻𐑗", + "tabs_bar.theme_toggle_dark": "𐑕𐑢𐑦𐑗 𐑑 𐑛𐑸𐑒 𐑔𐑰𐑥", + "tabs_bar.theme_toggle_light": "𐑕𐑢𐑦𐑗 𐑑 𐑤𐑲𐑑 𐑔𐑰𐑥", + "time_remaining.days": "{number, plural, one {# day} other {# days}} 𐑤𐑧𐑓𐑑", + "time_remaining.hours": "{number, plural, one {# hour} other {# hours}} 𐑤𐑧𐑓𐑑", + "time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} 𐑤𐑧𐑓𐑑", + "time_remaining.moments": "𐑥𐑴𐑥𐑩𐑯𐑑𐑕 remaining", + "time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} 𐑤𐑧𐑓𐑑", + "trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people} 𐑑𐑷𐑒𐑦𐑙", + "trends.title": "𐑑𐑮𐑧𐑯𐑛𐑟", + "ui.beforeunload": "𐑘𐑹 𐑛𐑮𐑭𐑓𐑑 𐑢𐑦𐑤 𐑚𐑰 𐑤𐑪𐑕𐑑 𐑦𐑓 𐑿 𐑤𐑰𐑝.", + "unauthorized_modal.footer": "𐑷𐑤𐑮𐑧𐑛𐑦 𐑣𐑨𐑝 𐑩𐑯 𐑩𐑒𐑬𐑯𐑑? {login}.", + "unauthorized_modal.text": "𐑿 𐑯𐑰𐑛 𐑑 𐑚𐑰 𐑤𐑪𐑜𐑛 𐑦𐑯 𐑑 𐑛𐑵 𐑞𐑨𐑑.", + "unauthorized_modal.title": "𐑕𐑲𐑯 𐑳𐑐 𐑓 {site_title}", + "upload_area.title": "𐑛𐑮𐑨𐑜 𐑯 𐑛𐑮𐑪𐑐 𐑑 𐑳𐑐𐑤𐑴𐑛", + "upload_button.label": "𐑨𐑛 𐑥𐑰𐑛𐑾 𐑩𐑑𐑨𐑗𐑥𐑩𐑯𐑑", + "upload_error.limit": "𐑓𐑲𐑤 𐑳𐑐𐑤𐑴𐑛 𐑤𐑦𐑥𐑦𐑑 𐑦𐑒𐑕𐑰𐑛𐑩𐑛.", + "upload_error.poll": "𐑓𐑲𐑤 𐑳𐑐𐑤𐑴𐑛 𐑯𐑪𐑑 𐑩𐑤𐑬𐑛 𐑢𐑦𐑞 𐑐𐑴𐑤𐑟.", + "upload_form.description": "𐑛𐑦𐑕𐑒𐑮𐑲𐑚 𐑓 𐑞 𐑝𐑦𐑠𐑫𐑩𐑤𐑦 𐑦𐑥𐑐𐑺𐑛", + "upload_form.preview": "𐑐𐑮𐑰𐑝𐑿", + "upload_form.undo": "𐑛𐑦𐑤𐑰𐑑", + "upload_progress.label": "𐑳𐑐𐑤𐑴𐑛𐑦𐑙...", + "video.close": "𐑒𐑤𐑴𐑟 𐑝𐑦𐑛𐑦𐑴", + "video.download": "𐑛𐑬𐑯𐑤𐑴𐑛 𐑓𐑲𐑤", + "video.exit_fullscreen": "𐑧𐑒𐑕𐑦𐑑 𐑓𐑫𐑤 𐑕𐑒𐑮𐑰𐑯", + "video.expand": "𐑦𐑒𐑕𐑐𐑨𐑯𐑛 𐑝𐑦𐑛𐑦𐑴", + "video.fullscreen": "𐑓𐑫𐑤 𐑕𐑒𐑮𐑰𐑯", + "video.hide": "𐑣𐑲𐑛 𐑝𐑦𐑛𐑦𐑴", + "video.mute": "𐑥𐑿𐑑 𐑕𐑬𐑯𐑛", + "video.pause": "𐑐𐑷𐑟", + "video.play": "𐑐𐑤𐑱", + "video.unmute": "𐑳𐑯𐑥𐑿𐑑 𐑕𐑬𐑯𐑛", + "who_to_follow.title": "𐑣𐑵 𐑑 𐑓𐑪𐑤𐑴" +} diff --git a/app/soapbox/locales/messages.js b/app/soapbox/locales/messages.js index 4118776cd..feaf780a7 100644 --- a/app/soapbox/locales/messages.js +++ b/app/soapbox/locales/messages.js @@ -12,6 +12,7 @@ export default { 'de': () => import(/* webpackChunkName: "locale_de" */'./de.json'), 'el': () => import(/* webpackChunkName: "locale_el" */'./el.json'), 'en': () => import(/* webpackChunkName: "locale_en" */'./en.json'), + 'en-Shaw': () => import(/* webpackChunkName: "locale_en-Shaw" */'./en-Shaw.json'), 'eo': () => import(/* webpackChunkName: "locale_eo" */'./eo.json'), 'es-AR': () => import(/* webpackChunkName: "locale_es-AR" */'./es-AR.json'), 'es': () => import(/* webpackChunkName: "locale_es" */'./es.json'), From abe5b072457e0036b36dae21219aa2b4e9a07af3 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Mon, 31 Jan 2022 20:18:15 -0600 Subject: [PATCH 31/33] Format birthday as UTC --- app/soapbox/features/ui/components/profile_info_panel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js index 6b35c601e..8cd4dfb5d 100644 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ b/app/soapbox/features/ui/components/profile_info_panel.js @@ -86,7 +86,7 @@ class ProfileInfoPanel extends ImmutablePureComponent { const birthday = account.getIn(['pleroma', 'birthday']); if (!birthday) return null; - const formattedBirthday = intl.formatDate(birthday, { day: 'numeric', month: 'long', year: 'numeric' }); + const formattedBirthday = intl.formatDate(birthday, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' }); const date = new Date(birthday); const today = new Date(); From 1de9421f0dfdc69c4390fe114b44f18ee7247278 Mon Sep 17 00:00:00 2001 From: Ashdemai Date: Tue, 1 Feb 2022 02:27:01 +0000 Subject: [PATCH 32/33] Update app/soapbox/locales/he.json --- app/soapbox/locales/he.json | 212 ++++++++++++++++++------------------ 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/app/soapbox/locales/he.json b/app/soapbox/locales/he.json index e3664d0c6..f18df7257 100644 --- a/app/soapbox/locales/he.json +++ b/app/soapbox/locales/he.json @@ -1,19 +1,19 @@ { - "about.also_available": "Available in:", - "accordion.collapse": "Collapse", - "accordion.expand": "Expand", + "about.also_available": "זמין ב", + "accordion.collapse": "כווץ", + "accordion.expand": "הרחבה", "account.add_or_remove_from_list": "הוסף או הסר מהרשימות", "account.badges.bot": "בוט", "account.block": "חסימת @{name}", "account.block_domain": "להסתיר הכל מהקהילה {domain}", "account.blocked": "חסום", - "account.chat": "Chat with @{name}", - "account.column_settings.description": "These settings apply to all account timelines.", - "account.column_settings.title": "Acccount timeline settings", - "account.deactivated": "Deactivated", - "account.deactivated_description": "This account has been deactivated.", - "account.direct": "Direct Message @{name}", - "account.domain_blocked": "הדומיין חסוי", + "account.chat": "צ'אט עם @{name}", + "account.column_settings.description": ".ההגדרות האלו מיושמות על כל ציר הזמן", + "account.column_settings.title": "הגדרות ציר זמן של המשתמש", + "account.deactivated": "מושבת", + "account.deactivated_description": "החשבון הזה הושבת", + "account.direct": "הודעה ישירה @{name}", + "account.domain_blocked": "הדומיין חסום", "account.edit_profile": "עריכת פרופיל", "account.endorse": "הצג בפרופיל", "account.follow": "מעקב", @@ -23,61 +23,61 @@ "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": "This account privacy status is set to locked. The owner manually reviews who can follow them.", - "account.login": "Log in", + "account.locked_info": "החשבון הוגדר כנעול. בעל החשבון בודק ידנית מי יכול לעקוב אחריו", + "account.login": "התחברות", "account.media": "מדיה", - "account.member_since": "Joined {date}", + "account.member_since": "הצטרף {date}", "account.mention": "אזכור של", "account.moved_to": "החשבון {name} הועבר אל:", "account.mute": "להשתיק את @{name}", - "account.muted": "Muted", - "account.never_active": "Never", + "account.muted": "מושתק", + "account.never_active": "אף פעם", "account.posts": "הודעות", "account.posts_with_replies": "Toots with replies", - "account.profile": "Profile", - "account.register": "Sign up", - "account.remote_follow": "Remote follow", + "account.profile": "פרופיל", + "account.register": "הרשם", + "account.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.subscribe": "הרשם להתראות מאת @{name}", + "account.subscribed": "רשום", "account.unblock": "הסרת חסימה מעל @{name}", "account.unblock_domain": "הסר חסימה מקהילת {domain}", "account.unendorse": "לא להציג בפרופיל", "account.unfollow": "הפסקת מעקב", "account.unmute": "הפסקת השתקת @{name}", - "account.unsubscribe": "Unsubscribe to notifications from @{name}", - "account_gallery.none": "No media to show.", - "account_search.placeholder": "Search for an account", - "account_timeline.column_settings.show_pinned": "Show pinned posts", - "admin.awaiting_approval.approved_message": "{acct} was approved!", - "admin.awaiting_approval.empty_message": "There is nobody waiting for approval. When a new user signs up, you can review them here.", - "admin.awaiting_approval.rejected_message": "{acct} was rejected.", - "admin.dashboard.registration_mode.approval_hint": "Users can sign up, but their account only gets activated when an admin approves it.", - "admin.dashboard.registration_mode.approval_label": "Approval Required", - "admin.dashboard.registration_mode.closed_hint": "Nobody can sign up. You can still invite people.", - "admin.dashboard.registration_mode.closed_label": "Closed", - "admin.dashboard.registration_mode.open_hint": "Anyone can join.", - "admin.dashboard.registration_mode.open_label": "Open", - "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.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.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", + "account.unsubscribe": "בטל הרשמה מ@{name}", + "account_gallery.none": "אין מדיה להראות.", + "account_search.placeholder": "חפש משתמש", + "account_timeline.column_settings.show_pinned": "הצג הודעות מוצמדות", + "admin.awaiting_approval.approved_message": "{acct} הואשר!", + "admin.awaiting_approval.empty_message": "אף אחד לא מחכה לאישור. כאשר משתמש חדש יירשם, תוכל לבחון אותו פה.", + "admin.awaiting_approval.rejected_message": "{acct} נדחה", + "admin.dashboard.registration_mode.approval_hint": "משתמשים יכולים להרשם, אבל החשבון שלהם מופעל רק כשמנהל יאשר אותו.", + "admin.dashboard.registration_mode.approval_label": "נדרש אישור", + "admin.dashboard.registration_mode.closed_hint": "אף אחד לא יכול להרשם. אתה עדיין יכול להזמין אנשים.", + "admin.dashboard.registration_mode.closed_label": "סגור להרשמה", + "admin.dashboard.registration_mode.open_hint": "כל אחד יכול להצטרף", + "admin.dashboard.registration_mode.open_label": "פתוח", + "admin.dashboard.registration_mode_label": "הרשמות", + "admin.dashboard.settings_saved": "ההגדרות נשמרו!", + "admin.dashcounters.domain_count_label": "עמיתים", + "admin.dashcounters.mau_label": "משתמשים פעילים חודשית", + "admin.dashcounters.retention_label": "שימור משתמשים", + "admin.dashcounters.status_count_label": "פוסטים", + "admin.dashcounters.user_count_label": "סך כל המשתמשים", + "admin.dashwidgets.email_list_header": "רשימת דואר", + "admin.dashwidgets.software_header": "תוכנה", + "admin.latest_accounts_panel.expand_message": "לחץ כדי לראות {count} עוד{count, plural, one {account} אחר {accounts}}", + "admin.latest_accounts_panel.title": "חשבונות אחרונים", + "admin.moderation_log.empty_message": "לא ביצעת פעולות ניהול עדיין. כשתבצע, ההיסטוריה תהיה כאן.", + "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}", @@ -160,8 +160,8 @@ "chats.attachment_image": "Image", "chats.audio_toggle_off": "Audio notification off", "chats.audio_toggle_on": "Audio notification on", - "chats.dividers.today": "Today", - "chats.search_placeholder": "Start a chat with…", + "chats.dividers.today": "היום", + "chats.search_placeholder": "התחל בצ'אט עם", "column.admin.awaiting_approval": "Awaiting Approval", "column.admin.dashboard": "Dashboard", "column.admin.moderation_log": "Moderation Log", @@ -169,64 +169,64 @@ "column.admin.reports.menu.moderation_log": "Moderation Log", "column.admin.users": "Users", "column.aliases": "Account aliases", - "column.aliases.create_error": "Error creating alias", - "column.aliases.delete": "Delete", - "column.aliases.delete_error": "Error deleting alias", - "column.aliases.subheading_add_new": "Add New Alias", - "column.aliases.subheading_aliases": "Current aliases", - "column.app_create": "Create app", - "column.backups": "Backups", + "column.aliases.create_error": "שגיאה ביצירת כינוי", + "column.aliases.delete": "מחק כינוי", + "column.aliases.delete_error": "שגיאה במחיקת כינוי", + "column.aliases.subheading_add_new": "הוסף כינוי חדש", + "column.aliases.subheading_aliases": "כינויים נוכחיים", + "column.app_create": "צור אפליקציה", + "column.backups": "גיבויים", "column.blocks": "חסימות", - "column.bookmarks": "Bookmarks", - "column.chats": "Chats", + "column.bookmarks": "סימניות", + "column.chats": "צ'אטים", "column.community": "ציר זמן מקומי", - "column.crypto_donate": "Donate Cryptocurrency", - "column.developers": "Developers", - "column.direct": "Direct messages", - "column.directory": "Browse profiles", - "column.domain_blocks": "Hidden domains", - "column.edit_profile": "Edit profile", - "column.export_data": "Export data", - "column.favourited_statuses": "Liked posts", - "column.favourites": "Likes", - "column.federation_restrictions": "Federation Restrictions", - "column.filters": "Muted words", - "column.filters.add_new": "Add New Filter", - "column.filters.conversations": "Conversations", - "column.filters.create_error": "Error adding filter", - "column.filters.delete": "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.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.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.crypto_donate": "תרום קריפטו", + "column.developers": "מפתחים", + "column.direct": "הודעות ישירות", + "column.directory": "דפדף בין פרופילים", + "column.domain_blocks": "דומיינים מוסתרים", + "column.edit_profile": "ערוך פרופיל", + "column.export_data": "יצא נתונים", + "column.favourited_statuses": "פוסטים שאהבתי", + "column.favourites": "לייקים", + "column.federation_restrictions": "הגבלות פדרציה", + "column.filters": "מילים מושתקות", + "column.filters.add_new": "הוסף פילטר חדש", + "column.filters.conversations": "שיחות", + "column.filters.create_error": "שגיאה בהוספת פילטר", + "column.filters.delete": "מחק פילטר", + "column.filters.delete_error": "שגיאה במחיקת פילטר", + "column.filters.drop_header": "הורד במקום להסתיר", + "column.filters.drop_hint": "פוסטים מסוננים ייעלמו באופן בלתי הפיך, גם אם הפילטר יוסר מאוחר יותר", + "column.filters.expires": "פג תוקף לאחר", + "column.filters.expires_hint": "תאריכי תפוגה אינם נתמכים כעת", + "column.filters.home_timeline": "ציר זמן ביתי", + "column.filters.keyword": "מילת מפתח או ביטוי", + "column.filters.notifications": "התראות", + "column.filters.public_timeline": "ציר זמן ציבורי", + "column.filters.subheading_add_new": "הוסף פילטר חדש", + "column.filters.subheading_filters": "פילטרים נוכחיים", + "column.filters.whole_word_header": "מילה שלמה", + "column.filters.whole_word_hint": "כאשר מילת המפתח או הביטוי הם אלפאנומריים בלבד, הם יוחלו רק אם הם תואמים לכל המילה.", "column.follow_requests": "בקשות מעקב", - "column.followers": "Followers", - "column.following": "Following", - "column.groups": "Groups", - "column.home": "בבית", - "column.import_data": "Import data", - "column.info": "Server information", - "column.lists": "Lists", - "column.mentions": "Mentions", - "column.mfa": "Multi-Factor Authentication", - "column.mfa_cancel": "Cancel", - "column.mfa_confirm_button": "Confirm", - "column.mfa_disable_button": "Disable", - "column.mfa_setup": "Proceed to Setup", + "column.followers": "עוקבים", + "column.following": "עוקב אחרי", + "column.groups": "קבוצות", + "column.home": "בית", + "column.import_data": "יבא נתונים", + "column.info": "מידע על הסרבר", + "column.lists": "רשימות", + "column.mentions": "אזכורים", + "column.mfa": "אימות מרובה גורמים", + "column.mfa_cancel": "בטל", + "column.mfa_confirm_button": "אמת", + "column.mfa_disable_button": "השבת", + "column.mfa_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", @@ -237,10 +237,10 @@ "column.soapbox_config": "Soapbox config", "column_back_button.label": "חזרה", "column_forbidden.body": "You do not have permission to access this page.", - "column_forbidden.title": "Forbidden", + "column_forbidden.title": "אסור", "column_header.hide_settings": "הסתרת העדפות", "column_header.show_settings": "הצגת העדפות", - "community.column_settings.media_only": "Media only", + "community.column_settings.media_only": "רק מדיה", "community.column_settings.title": "Local timeline settings", "compose.character_counter.title": "Used {chars} out of {maxChars} characters", "compose.invalid_schedule": "You must schedule a post at least 5 minutes out.", From 1d663921508d626596f02d0cb56b98635d381326 Mon Sep 17 00:00:00 2001 From: Ashdemai Date: Tue, 1 Feb 2022 02:59:13 +0000 Subject: [PATCH 33/33] Update app/soapbox/locales/he.json --- app/soapbox/locales/he.json | 220 ++++++++++++++++++------------------ 1 file changed, 110 insertions(+), 110 deletions(-) diff --git a/app/soapbox/locales/he.json b/app/soapbox/locales/he.json index f18df7257..1c5d5b4e9 100644 --- a/app/soapbox/locales/he.json +++ b/app/soapbox/locales/he.json @@ -34,8 +34,8 @@ "account.mute": "להשתיק את @{name}", "account.muted": "מושתק", "account.never_active": "אף פעם", - "account.posts": "הודעות", - "account.posts_with_replies": "Toots with replies", + "account.posts": "פוסטים", + "account.posts_with_replies": "פוסטים עם תגובות", "account.profile": "פרופיל", "account.register": "הרשם", "account.remote_follow": "מעקב מרחוק", @@ -78,31 +78,31 @@ "admin.moderation_log.empty_message": "לא ביצעת פעולות ניהול עדיין. כשתבצע, ההיסטוריה תהיה כאן.", "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.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", - "admin.statuses.status_marked_message_not_sensitive": "Post by @{acct} was marked not sensitive", - "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.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", - "admin.users.actions.demote_to_user_message": "@{acct} was demoted to a regular user", - "admin.users.actions.promote_to_admin": "Promote @{name} to an admin", - "admin.users.actions.promote_to_admin_message": "@{acct} was promoted to an admin", - "admin.users.actions.promote_to_moderator": "Promote @{name} to a moderator", - "admin.users.actions.promote_to_moderator_message": "@{acct} was promoted to a moderator", - "admin.users.actions.suggest_user": "Suggest @{name}", - "admin.users.actions.unsuggest_user": "Unsuggest @{name}", - "admin.users.actions.unverify_user": "Unverify @{name}", - "admin.users.actions.verify_user": "Verify @{name}", + "admin.reports.empty_message": "אין דוחות פתוחים. אם משתמש יידווח, הוא יופיע כאן.", + "admin.reports.report_closed_message": "דיווח על @{name} נסגר", + "admin.reports.report_title": "דיווח על {acct}", + "admin.statuses.actions.delete_status": "מחק פוסט", + "admin.statuses.actions.mark_status_not_sensitive": "סמן פוסט כלא רגיש", + "admin.statuses.actions.mark_status_sensitive": "סמן פוסט כרגיש", + "admin.statuses.status_deleted_message": "פוסט מ@{acct} נמחק", + "admin.statuses.status_marked_message_not_sensitive": "פוסטים מ@{acct} סומנו כלא רגישים", + "admin.statuses.status_marked_message_sensitive": "פוסטים מ@{acct} סומנו כרגישים", + "admin.user_index.empty": "לא נמצאו משתמשים.", + "admin.user_index.search_input_placeholder": "את מי אתה מחפש?", + "admin.users.actions.deactivate_user": "השבת @{name}", + "admin.users.actions.delete_user": "מחק @{name}", + "admin.users.actions.demote_to_moderator": "הורד @{name} בדרגה למנהל", + "admin.users.actions.demote_to_moderator_message": "@{acct} הורד בדרגה למנהל", + "admin.users.actions.demote_to_user": "הורד @{name} בדרגה למשתמש רגיל", + "admin.users.actions.demote_to_user_message": "@{acct} הורד בדרגה למשתמש רגיל", + "admin.users.actions.promote_to_admin": "קדם @{name} לאדמין", + "admin.users.actions.promote_to_admin_message": "@{acct} קודם לאדמין", + "admin.users.actions.promote_to_moderator": "קדם @{name} למנהל", + "admin.users.actions.promote_to_moderator_message": "@{acct} קודם למנהל", + "admin.users.actions.suggest_user": "הצע @{name}", + "admin.users.actions.unsuggest_user": "הסר הצעה @{name}", + "admin.users.actions.unverify_user": "הסר אימות @{name}", + "admin.users.actions.verify_user": "אמת @{name}", "admin.users.user_deactivated_message": "@{acct} was deactivated", "admin.users.user_deleted_message": "@{acct} was deleted", "admin.users.user_suggested_message": "@{acct} was suggested", @@ -112,22 +112,22 @@ "admin_nav.awaiting_approval": "Awaiting Approval", "admin_nav.dashboard": "Dashboard", "admin_nav.reports": "Reports", - "alert.unexpected.clear_cookies": "clear cookies and browser data", + "alert.unexpected.clear_cookies": "נקה קובצי 'עוגיות' ונתוני דפדפן", "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.return_home": "חזור הביתה", "alert.unexpected.title": "אופס!", - "aliases.account.add": "Create alias", - "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_placeholder": "e.g. 'Soapbox'", - "app_create.redirect_uri_label": "Redirect URIs", - "app_create.restart": "Create another", - "app_create.results.app_label": "App", + "aliases.account.add": "צור כינוי", + "aliases.account_label": "חשבון ישן:", + "aliases.aliases_list_delete": "בטל קישור בכינוי", + "aliases.search": "חפש חשבון ישן", + "aliases.success.add": "כינוי חשבון נוצר בהצלחה", + "aliases.success.remove": "כינוי חשבון הוסר בהצלחה", + "app_create.name_label": "שם אפליקציה", + "app_create.name_placeholder": "לדוגמא 'סבוניה'", + "app_create.redirect_uri_label": "נתב URIs", + "app_create.restart": "צור עוד", + "app_create.results.app_label": "אפליקציה", "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", @@ -135,7 +135,7 @@ "app_create.scopes_placeholder": "e.g. 'read write follow'", "app_create.submit": "Create app", "app_create.website_label": "Website", - "auth.invalid_credentials": "Wrong username or password", + "auth.invalid_credentials": "Wrong username or סיסמא", "auth.logged_out": "Logged out.", "backups.actions.create": "Create backup", "backups.empty_message": "No backups found. {action}", @@ -443,8 +443,8 @@ "follow_request.authorize": "קבלה", "follow_request.reject": "דחיה", "forms.copy": "Copy", - "forms.hide_password": "Hide password", - "forms.show_password": "Show password", + "forms.hide_password": "Hide סיסמא", + "forms.show_password": "Show סיסמא", "getting_started.open_source_notice": "מסטודון היא תוכנה חופשית (בקוד פתוח). ניתן לתרום או לדווח על בעיות בגיטהאב: {code_link} (v{code_version}).", "group.detail.archived_group": "Archived group", "group.members.empty": "This group does not has any members.", @@ -580,8 +580,8 @@ "media_gallery.toggle_visible": "נראה בלתי נראה", "media_panel.empty_message": "No media found.", "media_panel.title": "Media", - "mfa.mfa_disable_enter_password": "Enter your current password to disable two-factor auth:", - "mfa.mfa_setup_enter_password": "Enter your current password to confirm your identity:", + "mfa.mfa_disable_enter_password": "Enter your current סיסמא to disable two-factor auth:", + "mfa.mfa_setup_enter_password": "Enter your current סיסמא to confirm your identity:", "mfa.mfa_setup_scan_description": "Using your two-factor app, scan this QR code or enter text key:", "mfa.mfa_setup_scan_key": "Key:", "mfa.mfa_setup_scan_title": "Scan", @@ -676,7 +676,7 @@ "notifications.queue_label": "Click to see {count} new {count, plural, one {notification} other {notifications}}", "password_reset.confirmation": "Check your email for confirmation.", "password_reset.fields.username_placeholder": "Email or username", - "password_reset.reset": "Reset password", + "password_reset.reset": "Reset סיסמא", "pinned_statuses.none": "No pins to show.", "poll.closed": "Closed", "poll.refresh": "Refresh", @@ -806,90 +806,90 @@ "search_results.statuses": "Posts", "search_results.top": "Top", "security.codes.fail": "Failed to fetch backup codes", - "security.confirm.fail": "Incorrect code or password. Try again.", + "security.confirm.fail": "Incorrect code or סיסמא. Try again.", "security.delete_account.fail": "Account deletion failed.", "security.delete_account.success": "Account successfully deleted.", - "security.disable.fail": "Incorrect password. Try again.", + "security.disable.fail": "Incorrect סיסמא. Try again.", "security.disable_mfa": "Disable", "security.fields.email.label": "Email address", - "security.fields.new_password.label": "New password", - "security.fields.old_password.label": "Current password", - "security.fields.password.label": "Password", - "security.fields.password_confirmation.label": "New password (again)", - "security.headers.delete": "Delete Account", + "security.fields.new_password.label": "סיסמא חדשה", + "security.fields.old_password.label": "סיסמא נוכחית", + "security.fields.סיסמא.label": "סיסמא", + "security.fields.password_confirmation.label": "סיסמא חדשה (שוב)", + "security.headers.delete": "מחק חשבון", "security.headers.tokens": "Sessions", - "security.headers.update_email": "Change Email", - "security.headers.update_password": "Change Password", - "security.mfa": "Set up 2-Factor Auth", - "security.mfa_enabled": "You have multi-factor authentication set up with OTP.", - "security.mfa_header": "Authorization Methods", - "security.mfa_setup_hint": "Configure multi-factor authentication with OTP", - "security.qr.fail": "Failed to fetch setup key", - "security.submit": "Save changes", - "security.submit.delete": "Delete Account", - "security.text.delete": "To delete your account, enter your password then click Delete Account. This is a permanent action that cannot be undone. Your account will be destroyed from this server, and a deletion request will be sent to other servers. It's not guaranteed that all servers will purge your account.", - "security.tokens.revoke": "Revoke", - "security.update_email.fail": "Update email failed.", - "security.update_email.success": "Email successfully updated.", - "security.update_password.fail": "Update password failed.", - "security.update_password.success": "Password successfully updated.", - "signup_panel.subtitle": "Sign up now to discuss.", - "signup_panel.title": "New to {site_title}?", - "soapbox_config.authenticated_profile_hint": "Users must be logged-in to view replies and media on user profiles.", - "soapbox_config.authenticated_profile_label": "Profiles require authentication", - "soapbox_config.copyright_footer.meta_fields.label_placeholder": "Copyright footer", - "soapbox_config.crypto_address.meta_fields.address_placeholder": "Address", - "soapbox_config.crypto_address.meta_fields.note_placeholder": "Note (optional)", - "soapbox_config.crypto_address.meta_fields.ticker_placeholder": "Ticker", - "soapbox_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "Number of items to display in the crypto homepage widget", + "security.headers.update_email": "שנה אימייל", + "security.headers.update_password": "שנה סיסמא", + "security.mfa": "הגדר אימות דו-גורמי", + "security.mfa_enabled": "הגדרת אימות מרובה גורמים עם OTP.", + "security.mfa_header": "שיטות הרשאה", + "security.mfa_setup_hint": "הגדר אימות רב-גורמי עם OTP", + "security.qr.fail": "אחזור מפתח ההגדרה נכשל", + "security.submit": "שמור שינויים", + "security.submit.delete": "מחק חשבון", + "security.text.delete": "כדי למחוק את חשבונך, הזן את הסיסמה שלך ולאחר מכן לחץ על מחק חשבון. זוהי פעולה קבועה שלא ניתן לבטלה. החשבון שלך יושמד מהשרת הזה, ובקשת מחיקה תישלח לשרתים אחרים. לא מובטח שכל השרתים ינקו את חשבונך.", + "security.tokens.revoke": "בטל", + "security.update_email.fail": "עדכון האימייל נכשל.", + "security.update_email.success": "האימייל עודכן בהצלחה.", + "security.update_password.fail": "עדכון הסיסמא נכשל.", + "security.update_password.success": "הסיסמה עודכנה בהצלחה.", + "signup_panel.subtitle": "הירשם כעת כדי לדון.", + "signup_panel.title": "חדש ל{site_title}?", + "soapbox_config.authenticated_profile_hint": "משתמשים חייבים להיות מחוברים כדי לראות תגובות ומדיה בפרופילי משתמש.", + "soapbox_config.authenticated_profile_label": "פרופילים שדורשים אימות", + "soapbox_config.copyright_footer.meta_fields.label_placeholder": "כותרת תחתונה של זכויות יוצרים", + "soapbox_config.crypto_address.meta_fields.address_placeholder": "כתובת", + "soapbox_config.crypto_address.meta_fields.note_placeholder": "הערה (אפשרי)", + "soapbox_config.crypto_address.meta_fields.ticker_placeholder": "טיקר", + "soapbox_config.crypto_donate_panel_limit.meta_fields.limit_placeholder": "מספר הפריטים להצגה בווידג'ט דף הבית של קריפטו", "soapbox_config.custom_css.meta_fields.url_placeholder": "URL", - "soapbox_config.display_fqn_label": "Display domain (eg @user@domain) for local accounts.", - "soapbox_config.fields.brand_color_label": "Brand color", - "soapbox_config.fields.crypto_address.add": "Add new crypto address", - "soapbox_config.fields.crypto_addresses_label": "Cryptocurrency addresses", + "soapbox_config.display_fqn_label": "הצג דומיין (למשל @user@domain) עבור חשבונות מקומיים.", + "soapbox_config.fields.brand_color_label": "צבע מותג", + "soapbox_config.fields.crypto_address.add": "הוסף כתובת קריפטו חדשה", + "soapbox_config.fields.crypto_addresses_label": "כתובות של מטבעות קריפטוגרפיים", "soapbox_config.fields.home_footer.add": "Add new Home Footer Item", "soapbox_config.fields.home_footer_fields_label": "Home footer items", "soapbox_config.fields.logo_label": "Logo", - "soapbox_config.fields.promo_panel.add": "Add new Promo panel item", - "soapbox_config.fields.promo_panel_fields_label": "Promo panel items", - "soapbox_config.fields.theme_label": "Default theme", - "soapbox_config.greentext_label": "Enable greentext support", - "soapbox_config.hints.crypto_addresses": "Add cryptocurrency addresses so users of your site can donate to you. Order matters, and you must use lowercase ticker values.", - "soapbox_config.hints.home_footer_fields": "You can have custom defined links displayed on the footer of your static pages", - "soapbox_config.hints.logo": "SVG. At most 2 MB. Will be displayed to 50px height, maintaining aspect ratio", - "soapbox_config.hints.promo_panel_fields": "You can have custom defined links displayed on the right panel of the timelines page.", + "soapbox_config.fields.promo_panel.add": "הוסף פריטי פאנל פרומו חדשים", + "soapbox_config.fields.promo_panel_fields_label": "פריטי פאנל לפרומו", + "soapbox_config.fields.theme_label": "ערכת נושא המוגדרת כברירת מחדל", + "soapbox_config.greentext_label": "אפשר תמיכה ב-greentext", + "soapbox_config.hints.crypto_addresses": "הוסף כתובות של מטבעות קריפטוגרפיים כדי שמשתמשי האתר שלך יוכלו לתרום לך. יש חשיבות לסדר, ועליך להשתמש בערכי טיקרים קטנים.", + "soapbox_config.hints.home_footer_fields": "אתה יכול להציג קישורים מוגדרים בהתאמה אישית בכותרת התחתונה של הדפים הסטטיים שלך", + "soapbox_config.hints.logo": "SVG. לכל היותר 2 מגה-בייט. יוצג בגובה של 50 פיקסלים, תוך שמירה על יחס רוחב-גובה", + "soapbox_config.hints.promo_panel_fields": "אתה יכול להציג קישורים מוגדרים בהתאמה אישית בחלונית לצד דף ציר הזמן.", "soapbox_config.hints.promo_panel_icons": "{ link }", - "soapbox_config.hints.promo_panel_icons.link": "Soapbox Icons List", - "soapbox_config.home_footer.meta_fields.label_placeholder": "Label", + "soapbox_config.hints.promo_panel_icons.link": "רשימת אייקוני סבוניה", + "soapbox_config.home_footer.meta_fields.label_placeholder": "תווית", "soapbox_config.home_footer.meta_fields.url_placeholder": "URL", - "soapbox_config.promo_panel.meta_fields.icon_placeholder": "Icon", - "soapbox_config.promo_panel.meta_fields.label_placeholder": "Label", + "soapbox_config.promo_panel.meta_fields.icon_placeholder": "סמל", + "soapbox_config.promo_panel.meta_fields.label_placeholder": "תווית", "soapbox_config.promo_panel.meta_fields.url_placeholder": "URL", - "soapbox_config.raw_json_hint": "Edit the settings data directly. Changes made directly to the JSON file will override the form fields above. Click Save to apply your changes.", - "soapbox_config.raw_json_label": "Advanced: Edit raw JSON data", - "soapbox_config.save": "Save", - "soapbox_config.saved": "Soapbox config saved!", - "soapbox_config.verified_can_edit_name_label": "Allow verified users to edit their own display name.", - "status.admin_account": "Open moderation interface for @{name}", - "status.admin_status": "Open this post in the moderation interface", - "status.block": "Block @{name}", - "status.bookmark": "Bookmark", - "status.bookmarked": "Bookmark added.", - "status.cancel_reblog_private": "Un-repost", + "soapbox_config.raw_json_hint": "ערוך את נתוני ההגדרות ישירות. שינויים שנעשו ישירות בקובץ JSON יעקפו את שדות הטופס שלמעלה. לחץ על שמור כדי להחיל את השינויים שלך.", + "soapbox_config.raw_json_label": "מתקדם: ערוך נתוני JSON גולמיים", + "soapbox_config.save": "שמור", + "soapbox_config.saved": "תצורת סבוניה נשמרה!", + "soapbox_config.verified_can_edit_name_label": "אפשר למשתמשים מאומתים לערוך את שם התצוגה שלהם.", + "status.admin_account": "פתח ממשק ניהול ל@{name}", + "status.admin_status": "פתח את הפוסט הזה בממשק הניהול", + "status.block": "חסום @{name}", + "status.bookmark": "סימניה", + "status.bookmarked": "סימניה נוספה.", + "status.cancel_reblog_private": "הסר הדהוד", "status.cannot_reblog": "לא ניתן להדהד הודעה זו", - "status.chat": "Chat with @{name}", - "status.copy": "Copy link to post", + "status.chat": "שוחח עם @{name}", + "status.copy": "העתק קישור לפוסט", "status.delete": "מחיקה", - "status.detailed_status": "Detailed conversation view", - "status.direct": "Direct message @{name}", + "status.detailed_status": "תצוגת שיחה מפורטת", + "status.direct": "הודעה ישירה @{name}", "status.embed": "הטמעה", "status.favourite": "חיבוב", - "status.filtered": "Filtered", + "status.filtered": "מסונן", "status.load_more": "עוד", "status.media_hidden": "מדיה מוסתרת", "status.mention": "פניה אל @{name}", "status.more": "עוד", - "status.mute": "Mute @{name}", + "status.mute": "השתק @{name}", "status.mute_conversation": "השתקת שיחה", "status.open": "הרחבת הודעה", "status.pin": "לקבע באודות",