Skip to content
Snippets Groups Projects
Commit f1ab7064 authored by Eugen Rochko's avatar Eugen Rochko Committed by GitHub
Browse files

Add buttons to block and unblock domain (#3127)

* Add buttons to block and unblock domain

* Relationship API now returns "domain_blocking" status for accounts,
rename "block entire domain" to "hide entire domain", fix unblocking domain,
do not block notifications from domain-blocked-but-followed people, do
not send Salmons to domain blocked users

* Add test

* Personal domain blocks shouldn't affect Salmon after all, since in this
direction of communication the control is very thin when it comes to
public stuff. Best stay consistent and not affect federation in this way

* Ignore followers and follow request from domain blocked folks,
ensure account domain blocks are not created for empty domain,
and avoid duplicates in validation

* Purge followers when blocking domain (without soft-blocks, since they
are useless here)

* Add tests, fix local timeline being empty when having any domain blocks
parent 1548695c
No related branches found
No related tags found
No related merge requests found
Showing
with 277 additions and 20 deletions
......@@ -71,11 +71,12 @@ class Api::V1::AccountsController < ApiController
def block
BlockService.new.call(current_user.account, @account)
@following = { @account.id => false }
@followed_by = { @account.id => false }
@blocking = { @account.id => true }
@requested = { @account.id => false }
@muting = { @account.id => current_user.account.muting?(@account.id) }
@following = { @account.id => false }
@followed_by = { @account.id => false }
@blocking = { @account.id => true }
@requested = { @account.id => false }
@muting = { @account.id => current_account.muting?(@account.id) }
@domain_blocking = { @account.id => current_account.domain_blocking?(@account.domain) }
render :relationship
end
......@@ -107,12 +108,13 @@ class Api::V1::AccountsController < ApiController
def relationships
ids = params[:id].is_a?(Enumerable) ? params[:id].map(&:to_i) : [params[:id].to_i]
@accounts = Account.where(id: ids).select('id')
@following = Account.following_map(ids, current_user.account_id)
@followed_by = Account.followed_by_map(ids, current_user.account_id)
@blocking = Account.blocking_map(ids, current_user.account_id)
@muting = Account.muting_map(ids, current_user.account_id)
@requested = Account.requested_map(ids, current_user.account_id)
@accounts = Account.where(id: ids).select('id')
@following = Account.following_map(ids, current_user.account_id)
@followed_by = Account.followed_by_map(ids, current_user.account_id)
@blocking = Account.blocking_map(ids, current_user.account_id)
@muting = Account.muting_map(ids, current_user.account_id)
@requested = Account.requested_map(ids, current_user.account_id)
@domain_blocking = Account.domain_blocking_map(ids, current_user.account_id)
end
def search
......@@ -128,11 +130,12 @@ class Api::V1::AccountsController < ApiController
end
def set_relationship
@following = Account.following_map([@account.id], current_user.account_id)
@followed_by = Account.followed_by_map([@account.id], current_user.account_id)
@blocking = Account.blocking_map([@account.id], current_user.account_id)
@muting = Account.muting_map([@account.id], current_user.account_id)
@requested = Account.requested_map([@account.id], current_user.account_id)
@following = Account.following_map([@account.id], current_user.account_id)
@followed_by = Account.followed_by_map([@account.id], current_user.account_id)
@blocking = Account.blocking_map([@account.id], current_user.account_id)
@muting = Account.muting_map([@account.id], current_user.account_id)
@requested = Account.requested_map([@account.id], current_user.account_id)
@domain_blocking = Account.domain_blocking_map([@account.id], current_user.account_id)
end
def pagination_params(core_params)
......
......@@ -17,7 +17,7 @@ class Api::V1::DomainBlocksController < ApiController
end
def create
current_account.block_domain!(domain_block_params[:domain])
BlockDomainFromAccountService.new.call(current_account, domain_block_params[:domain])
render_empty
end
......
import api, { getLinks } from '../api'
export const DOMAIN_BLOCK_REQUEST = 'DOMAIN_BLOCK_REQUEST';
export const DOMAIN_BLOCK_SUCCESS = 'DOMAIN_BLOCK_SUCCESS';
export const DOMAIN_BLOCK_FAIL = 'DOMAIN_BLOCK_FAIL';
export const DOMAIN_UNBLOCK_REQUEST = 'DOMAIN_UNBLOCK_REQUEST';
export const DOMAIN_UNBLOCK_SUCCESS = 'DOMAIN_UNBLOCK_SUCCESS';
export const DOMAIN_UNBLOCK_FAIL = 'DOMAIN_UNBLOCK_FAIL';
export const DOMAIN_BLOCKS_FETCH_REQUEST = 'DOMAIN_BLOCKS_FETCH_REQUEST';
export const DOMAIN_BLOCKS_FETCH_SUCCESS = 'DOMAIN_BLOCKS_FETCH_SUCCESS';
export const DOMAIN_BLOCKS_FETCH_FAIL = 'DOMAIN_BLOCKS_FETCH_FAIL';
export function blockDomain(domain, accountId) {
return (dispatch, getState) => {
dispatch(blockDomainRequest(domain));
api(getState).post('/api/v1/domain_blocks', { domain }).then(response => {
dispatch(blockDomainSuccess(domain, accountId));
}).catch(err => {
dispatch(blockDomainFail(domain, err));
});
};
};
export function blockDomainRequest(domain) {
return {
type: DOMAIN_BLOCK_REQUEST,
domain
};
};
export function blockDomainSuccess(domain, accountId) {
return {
type: DOMAIN_BLOCK_SUCCESS,
domain,
accountId
};
};
export function blockDomainFail(domain, error) {
return {
type: DOMAIN_BLOCK_FAIL,
domain,
error
};
};
export function unblockDomain(domain, accountId) {
return (dispatch, getState) => {
dispatch(unblockDomainRequest(domain));
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(response => {
dispatch(unblockDomainSuccess(domain, accountId));
}).catch(err => {
dispatch(unblockDomainFail(domain, err));
});
};
};
export function unblockDomainRequest(domain) {
return {
type: DOMAIN_UNBLOCK_REQUEST,
domain
};
};
export function unblockDomainSuccess(domain, accountId) {
return {
type: DOMAIN_UNBLOCK_SUCCESS,
domain,
accountId
};
};
export function unblockDomainFail(domain, error) {
return {
type: DOMAIN_UNBLOCK_FAIL,
domain,
error
};
};
export function fetchDomainBlocks() {
return (dispatch, getState) => {
dispatch(fetchDomainBlocksRequest());
api(getState).get().then(response => {
const next = getLinks(response).refs.find(link => link.rel === 'next');
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
}).catch(err => {
dispatch(fetchDomainBlocksFail(err));
});
};
};
export function fetchDomainBlocksRequest() {
return {
type: DOMAIN_BLOCKS_FETCH_REQUEST
};
};
export function fetchDomainBlocksSuccess(domains, next) {
return {
type: DOMAIN_BLOCKS_FETCH_SUCCESS,
domains,
next
};
};
export function fetchDomainBlocksFail(error) {
return {
type: DOMAIN_BLOCKS_FETCH_FAIL,
error
};
};
......@@ -15,7 +15,9 @@ const messages = defineMessages({
mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' },
follow: { id: 'account.follow', defaultMessage: 'Follow' },
report: { id: 'account.report', defaultMessage: 'Report @{name}' },
disclaimer: { id: 'account.disclaimer', defaultMessage: 'This user is from another instance. This number may be larger.' }
disclaimer: { id: 'account.disclaimer', defaultMessage: 'This user is from another instance. This number may be larger.' },
blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' },
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
});
class ActionBar extends React.PureComponent {
......@@ -28,6 +30,8 @@ class ActionBar extends React.PureComponent {
onMention: PropTypes.func.isRequired,
onReport: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired,
onBlockDomain: PropTypes.func.isRequired,
onUnblockDomain: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired
};
......@@ -59,7 +63,16 @@ class ActionBar extends React.PureComponent {
}
if (account.get('acct') !== account.get('username')) {
const domain = account.get('acct').split('@')[1];
extraInfo = <abbr title={intl.formatMessage(messages.disclaimer)}>*</abbr>;
menu.push(null);
if (account.getIn(['relationship', 'domain_blocking'])) {
menu.push({ text: intl.formatMessage(messages.unblockDomain, { domain }), action: this.props.onUnblockDomain });
} else {
menu.push({ text: intl.formatMessage(messages.blockDomain, { domain }), action: this.props.onBlockDomain });
}
}
return (
......
......@@ -15,7 +15,9 @@ class Header extends ImmutablePureComponent {
onBlock: PropTypes.func.isRequired,
onMention: PropTypes.func.isRequired,
onReport: PropTypes.func.isRequired,
onMute: PropTypes.func.isRequired
onMute: PropTypes.func.isRequired,
onBlockDomain: PropTypes.func.isRequired,
onUnblockDomain: PropTypes.func.isRequired,
};
static contextTypes = {
......@@ -43,6 +45,22 @@ class Header extends ImmutablePureComponent {
this.props.onMute(this.props.account);
}
handleBlockDomain = () => {
const domain = this.props.account.get('acct').split('@')[1];
if (!domain) return;
this.props.onBlockDomain(domain, this.props.account.get('id'));
}
handleUnblockDomain = () => {
const domain = this.props.account.get('acct').split('@')[1];
if (!domain) return;
this.props.onUnblockDomain(domain, this.props.account.get('id'));
}
render () {
const { account, me } = this.props;
......@@ -65,6 +83,8 @@ class Header extends ImmutablePureComponent {
onMention={this.handleMention}
onReport={this.handleReport}
onMute={this.handleMute}
onBlockDomain={this.handleBlockDomain}
onUnblockDomain={this.handleUnblockDomain}
/>
</div>
);
......
......@@ -13,11 +13,13 @@ import {
import { mentionCompose } from '../../../actions/compose';
import { initReport } from '../../../actions/reports';
import { openModal } from '../../../actions/modal';
import { blockDomain, unblockDomain } from '../../../actions/domain_blocks';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
const messages = defineMessages({
blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' },
muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' }
muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' },
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
});
const makeMapStateToProps = () => {
......@@ -70,6 +72,18 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
onConfirm: () => dispatch(muteAccount(account.get('id')))
}));
}
},
onBlockDomain (domain, accountId) {
dispatch(openModal('CONFIRM', {
message: <FormattedMessage id='confirmations.domain_block.message' defaultMessage='Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.' values={{ domain: <strong>{domain}</strong> }} />,
confirm: intl.formatMessage(messages.blockDomainConfirm),
onConfirm: () => dispatch(blockDomain(domain, accountId))
}));
},
onUnblockDomain (domain, accountId) {
dispatch(unblockDomain(domain, accountId));
}
});
......
{
"account.block": "حظر @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "هذا المستخدم من مثيل خادم آخر. قد يكون هذا الرقم أكبر.",
"account.edit_profile": "تعديل الملف الشخصي",
"account.follow": "تابِع",
"account.followers": "المتابعون",
"account.follows": "يتبع",
"account.follows_you": "يتابعك",
"account.media": "Media",
"account.mention": "أُذكُر @{name}",
"account.mute": "أكتم @{name}",
"account.posts": "المشاركات",
"account.report": "أبلغ عن @{name}",
"account.requested": "في انتظار الموافقة",
"account.unblock": "إلغاء الحظر عن @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "إلغاء المتابعة",
"account.unmute": "إلغاء الكتم عن @{name}",
"boost_modal.combo": "يمكنك ضغط {combo} لتخطّي هذه في المرّة القادمة",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "هل أنت متأكد أنك تريد حجب {name} ؟",
"confirmations.delete.confirm": "حذف",
"confirmations.delete.message": "هل أنت متأكد أنك تريد حذف هذا المنشور ؟",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "أكتم",
"confirmations.mute.message": "هل أنت متأكد أنك تريد كتم {name} ؟",
"emoji_button.activity": "الأنشطة",
......
{
"account.block": "Блокирай",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Редактирай профила си",
"account.follow": "Последвай",
"account.followers": "Последователи",
"account.follows": "Следвам",
"account.follows_you": "Твой последовател",
"account.media": "Media",
"account.mention": "Споменаване",
"account.mute": "Mute @{name}",
"account.posts": "Публикации",
"account.report": "Report @{name}",
"account.requested": "В очакване на одобрение",
"account.unblock": "Не блокирай",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Не следвай",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "Bloquejar @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "Aquest usuari és d'un altra instància. Aquest número podria ser més gran.",
"account.edit_profile": "Editar perfil",
"account.follow": "Seguir",
"account.followers": "Seguidors",
"account.follows": "Seguint",
"account.follows_you": "et segueix",
"account.media": "Media",
"account.mention": "Esmentar @{name}",
"account.mute": "Silenciar @{name}",
"account.posts": "Publicacions",
"account.report": "Informe @{name}",
"account.requested": "Esperant aprovació",
"account.unblock": "Desbloquejar @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Deixar de seguir",
"account.unmute": "Treure silenci de @{name}",
"boost_modal.combo": "Pots premer {combo} per saltar-te això el proper cop",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Estàs segur que vols bloquejar {name}?",
"confirmations.delete.confirm": "Esborrar",
"confirmations.delete.message": "Estàs segur que vols esborrar aquest estat?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Silenciar",
"confirmations.mute.message": "Estàs segur que vols silenciar {name}?",
"emoji_button.activity": "Activitat",
......
{
"account.block": "@{name} blocken",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "Dieser Benutzer ist von einer anderen Instanz. Diese Zahl könnte größer sein.",
"account.edit_profile": "Profil bearbeiten",
"account.follow": "Folgen",
"account.followers": "Folgende",
"account.follows": "Folgt",
"account.follows_you": "Folgt dir",
"account.media": "Media",
"account.mention": "@{name} erwähnen",
"account.mute": "@{name} stummschalten",
"account.posts": "Beiträge",
"account.report": "@{name} melden",
"account.requested": "Warte auf Erlaubnis",
"account.unblock": "@{name} entblocken",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Entfolgen",
"account.unmute": "@{name} nicht mehr stummschalten",
"boost_modal.combo": "Du kannst {combo} drücken, um dies beim nächsten Mal zu überspringen",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
......@@ -240,6 +240,15 @@
],
"path": "app/javascript/mastodon/containers/status_container.json"
},
{
"descriptors": [
{
"defaultMessage": "Media",
"id": "account.media"
}
],
"path": "app/javascript/mastodon/features/account_gallery/index.json"
},
{
"descriptors": [
{
......@@ -250,6 +259,10 @@
"defaultMessage": "Mute",
"id": "confirmations.mute.confirm"
},
{
"defaultMessage": "Hide entire domain",
"id": "confirmations.domain_block.confirm"
},
{
"defaultMessage": "Are you sure you want to block {name}?",
"id": "confirmations.block.message"
......@@ -257,6 +270,10 @@
{
"defaultMessage": "Are you sure you want to mute {name}?",
"id": "confirmations.mute.message"
},
{
"defaultMessage": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"id": "confirmations.domain_block.message"
}
],
"path": "app/javascript/mastodon/features/account_timeline/containers/header_container.json"
......@@ -303,6 +320,14 @@
"defaultMessage": "This user is from another instance. This number may be larger.",
"id": "account.disclaimer"
},
{
"defaultMessage": "Hide everything from {domain}",
"id": "account.block_domain"
},
{
"defaultMessage": "Unhide {domain}",
"id": "account.unblock_domain"
},
{
"defaultMessage": "Posts",
"id": "account.posts"
......
{
"account.block": "Block @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Edit profile",
"account.follow": "Follow",
"account.followers": "Followers",
"account.follows": "Follows",
"account.follows_you": "Follows you",
"account.media": "Media",
"account.mention": "Mention @{name}",
"account.mute": "Mute @{name}",
"account.posts": "Posts",
"account.report": "Report @{name}",
"account.requested": "Awaiting approval",
"account.unblock": "Unblock @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Unfollow",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "Bloki @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Redakti la profilon",
"account.follow": "Sekvi",
"account.followers": "Sekvantoj",
"account.follows": "Sekvatoj",
"account.follows_you": "Sekvas vin",
"account.media": "Media",
"account.mention": "Mencii @{name}",
"account.mute": "Mute @{name}",
"account.posts": "Mesaĝoj",
"account.report": "Report @{name}",
"account.requested": "Atendas aprobon",
"account.unblock": "Malbloki @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Malsekvi",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "Bloquear",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Editar perfil",
"account.follow": "Seguir",
"account.followers": "Seguidores",
"account.follows": "Seguir",
"account.follows_you": "Te sigue",
"account.media": "Media",
"account.mention": "Mencionar",
"account.mute": "Silenciar",
"account.posts": "Publicaciones",
"account.report": "Report @{name}",
"account.requested": "Esperando aprobación",
"account.unblock": "Desbloquear",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Dejar de seguir",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "مسدودسازی @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "این کاربر عضو سرور متفاوتی است. شاید عدد واقعی بیشتر از این باشد.",
"account.edit_profile": "ویرایش نمایه",
"account.follow": "پی بگیرید",
"account.followers": "پیگیران",
"account.follows": "پی می‌گیرد",
"account.follows_you": "پیگیر شماست",
"account.media": "Media",
"account.mention": "نام‌بردن از @{name}",
"account.mute": "بی‌صدا کردن @{name}",
"account.posts": "نوشته‌ها",
"account.report": "گزارش @{name}",
"account.requested": "در انتظار پذیرش",
"account.unblock": "رفع انسداد @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "پایان پیگیری",
"account.unmute": "باصدا کردن @{name}",
"boost_modal.combo": "دکمهٔ {combo} را بزنید تا دیگر این را نبینید",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "آیا واقعاً می‌خواهید {name} را مسدود کنید؟",
"confirmations.delete.confirm": "پاک کن",
"confirmations.delete.message": "آیا واقعاً می‌خواهید این نوشته را پاک کنید؟",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "بی‌صدا کن",
"confirmations.mute.message": "آیا واقعاً می‌خواهید {name} را بی‌صدا کنید؟",
"emoji_button.activity": "فعالیت",
......
{
"account.block": "Estä @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Muokkaa",
"account.follow": "Seuraa",
"account.followers": "Seuraajia",
"account.follows": "Seuraa",
"account.follows_you": "Seuraa sinua",
"account.media": "Media",
"account.mention": "Mainitse @{name}",
"account.mute": "Mute @{name}",
"account.posts": "Postit",
"account.report": "Report @{name}",
"account.requested": "Odottaa hyväksyntää",
"account.unblock": "Salli @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Lopeta seuraaminen",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "Bloquer",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "Ce compte est situé sur une autre instance. Les nombres peuvent être plus grands.",
"account.edit_profile": "Modifier le profil",
"account.follow": "Suivre",
"account.followers": "Abonné⋅e⋅s",
"account.follows": "Abonnements",
"account.follows_you": "Vous suit",
"account.media": "Media",
"account.mention": "Mentionner",
"account.mute": "Masquer",
"account.posts": "Statuts",
"account.report": "Signaler",
"account.requested": "Invitation envoyée",
"account.unblock": "Débloquer",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Ne plus suivre",
"account.unmute": "Ne plus masquer",
"boost_modal.combo": "Vous pouvez appuyer sur {combo} pour pouvoir passer ceci, la prochaine fois",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Confirmez vous le blocage de {name} ?",
"confirmations.delete.confirm": "Supprimer",
"confirmations.delete.message": "Confirmez vous la suppression de ce pouet ?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Silencer",
"confirmations.mute.message": "Confirmez vous la silenciation {name} ?",
"emoji_button.activity": "Activités",
......
{
"account.block": "חסימת @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "משתמש זה מגיע מקהילה אחרת. המספר הזה עשוי להיות גדול יותר.",
"account.edit_profile": "עריכת פרופיל",
"account.follow": "מעקב",
"account.followers": "עוקבים",
"account.follows": "נעקבים",
"account.follows_you": "במעקב אחריך",
"account.media": "Media",
"account.mention": "אזכור של @{name}",
"account.mute": "להשתיק את @{name}",
"account.posts": "הודעות",
"account.report": "לדווח על @{name}",
"account.requested": "בהמתנה לאישור",
"account.unblock": "הסרת חסימה מעל @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "הפסקת מעקב",
"account.unmute": "הפסקת השתקת @{name}",
"boost_modal.combo": "ניתן להקיש {combo} כדי לדלג בפעם הבאה",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "לחסום את {name}?",
"confirmations.delete.confirm": "למחוק",
"confirmations.delete.message": "למחוק את ההודעה?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "להשתיק",
"confirmations.mute.message": "להשתיק את {name}?",
"emoji_button.activity": "פעילות",
......
{
"account.block": "Blokiraj @{name}",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "Ovaj korisnik je sa druge instance. Ovaj broj bi mogao biti veći.",
"account.edit_profile": "Uredi profil",
"account.follow": "Slijedi",
"account.followers": "Sljedbenici",
"account.follows": "Slijedi",
"account.follows_you": "te slijedi",
"account.media": "Media",
"account.mention": "Spomeni @{name}",
"account.mute": "Utišaj @{name}",
"account.posts": "Postovi",
"account.report": "Prijavi @{name}",
"account.requested": "Čeka pristanak",
"account.unblock": "Deblokiraj @{name}",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Prestani slijediti",
"account.unmute": "Poništi utišavanje @{name}",
"boost_modal.combo": "Možeš pritisnuti {combo} kako bi ovo preskočio sljedeći put",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
{
"account.block": "Blokkolás",
"account.block_domain": "Hide everything from {domain}",
"account.disclaimer": "This user is from another instance. This number may be larger.",
"account.edit_profile": "Profil szerkesztése",
"account.follow": "Követés",
"account.followers": "Követők",
"account.follows": "Követve",
"account.follows_you": "Követnek téged",
"account.media": "Media",
"account.mention": "Említés",
"account.mute": "Mute @{name}",
"account.posts": "Posts",
"account.report": "Report @{name}",
"account.requested": "Awaiting approval",
"account.unblock": "Blokkolás levétele",
"account.unblock_domain": "Unhide {domain}",
"account.unfollow": "Követés abbahagyása",
"account.unmute": "Unmute @{name}",
"boost_modal.combo": "You can press {combo} to skip this next time",
......@@ -40,6 +43,8 @@
"confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this status?",
"confirmations.domain_block.confirm": "Hide entire domain",
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
"confirmations.mute.confirm": "Mute",
"confirmations.mute.message": "Are you sure you want to mute {name}?",
"emoji_button.activity": "Activity",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment