mirror of
https://git.kescher.at/CatCatNya/catstodon.git
synced 2024-11-22 19:58:07 +01:00
Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
This commit is contained in:
commit
f0bb3ff533
66 changed files with 524 additions and 108 deletions
|
@ -81,6 +81,10 @@ SMTP_FROM_ADDRESS=notifications@example.com
|
|||
# PAPERCLIP_ROOT_URL=/system
|
||||
|
||||
# Optional asset host for multi-server setups
|
||||
# The asset host must allow cross origin request from WEB_DOMAIN or LOCAL_DOMAIN
|
||||
# if WEB_DOMAIN is not set. For example, the server may have the
|
||||
# following header field:
|
||||
# Access-Control-Allow-Origin: https://example.com/
|
||||
# CDN_HOST=https://assets.example.com
|
||||
|
||||
# S3 (optional)
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -26,7 +26,7 @@ gem 'active_model_serializers', '~> 0.10'
|
|||
gem 'addressable', '~> 2.5'
|
||||
gem 'bootsnap'
|
||||
gem 'browser'
|
||||
gem 'charlock_holmes', '~> 0.7.5'
|
||||
gem 'charlock_holmes', '~> 0.7.6'
|
||||
gem 'iso-639'
|
||||
gem 'chewy', '~> 5.0'
|
||||
gem 'cld3', '~> 3.2.0'
|
||||
|
|
|
@ -113,7 +113,7 @@ GEM
|
|||
xpath (~> 2.0)
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
charlock_holmes (0.7.5)
|
||||
charlock_holmes (0.7.6)
|
||||
chewy (5.0.0)
|
||||
activesupport (>= 4.0)
|
||||
elasticsearch (>= 2.0.0)
|
||||
|
@ -635,7 +635,7 @@ DEPENDENCIES
|
|||
capistrano-rbenv (~> 2.1)
|
||||
capistrano-yarn (~> 2.0)
|
||||
capybara (~> 2.15)
|
||||
charlock_holmes (~> 0.7.5)
|
||||
charlock_holmes (~> 0.7.6)
|
||||
chewy (~> 5.0)
|
||||
cld3 (~> 3.2.0)
|
||||
climate_control (~> 0.2)
|
||||
|
|
|
@ -15,6 +15,7 @@ export const COMPOSE_SUBMIT_SUCCESS = 'COMPOSE_SUBMIT_SUCCESS';
|
|||
export const COMPOSE_SUBMIT_FAIL = 'COMPOSE_SUBMIT_FAIL';
|
||||
export const COMPOSE_REPLY = 'COMPOSE_REPLY';
|
||||
export const COMPOSE_REPLY_CANCEL = 'COMPOSE_REPLY_CANCEL';
|
||||
export const COMPOSE_DIRECT = 'COMPOSE_DIRECT';
|
||||
export const COMPOSE_MENTION = 'COMPOSE_MENTION';
|
||||
export const COMPOSE_RESET = 'COMPOSE_RESET';
|
||||
export const COMPOSE_UPLOAD_REQUEST = 'COMPOSE_UPLOAD_REQUEST';
|
||||
|
@ -91,6 +92,19 @@ export function mentionCompose(account, router) {
|
|||
};
|
||||
};
|
||||
|
||||
export function directCompose(account, router) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
type: COMPOSE_DIRECT,
|
||||
account: account,
|
||||
});
|
||||
|
||||
if (!getState().getIn(['compose', 'mounted'])) {
|
||||
router.push('/statuses/new');
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export function submitCompose() {
|
||||
return function (dispatch, getState) {
|
||||
const status = getState().getIn(['compose', 'text'], '');
|
||||
|
|
|
@ -12,12 +12,18 @@ 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) {
|
||||
export const DOMAIN_BLOCKS_EXPAND_REQUEST = 'DOMAIN_BLOCKS_EXPAND_REQUEST';
|
||||
export const DOMAIN_BLOCKS_EXPAND_SUCCESS = 'DOMAIN_BLOCKS_EXPAND_SUCCESS';
|
||||
export const DOMAIN_BLOCKS_EXPAND_FAIL = 'DOMAIN_BLOCKS_EXPAND_FAIL';
|
||||
|
||||
export function blockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(blockDomainRequest(domain));
|
||||
|
||||
api(getState).post('/api/v1/domain_blocks', { domain }).then(() => {
|
||||
dispatch(blockDomainSuccess(domain, accountId));
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
dispatch(blockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
dispatch(blockDomainFail(domain, err));
|
||||
});
|
||||
|
@ -31,11 +37,11 @@ export function blockDomainRequest(domain) {
|
|||
};
|
||||
};
|
||||
|
||||
export function blockDomainSuccess(domain, accountId) {
|
||||
export function blockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
type: DOMAIN_BLOCK_SUCCESS,
|
||||
domain,
|
||||
accountId,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -47,12 +53,14 @@ export function blockDomainFail(domain, error) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unblockDomain(domain, accountId) {
|
||||
export function unblockDomain(domain) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(unblockDomainRequest(domain));
|
||||
|
||||
api(getState).delete('/api/v1/domain_blocks', { params: { domain } }).then(() => {
|
||||
dispatch(unblockDomainSuccess(domain, accountId));
|
||||
const at_domain = '@' + domain;
|
||||
const accounts = getState().get('accounts').filter(item => item.get('acct').endsWith(at_domain)).valueSeq().map(item => item.get('id'));
|
||||
dispatch(unblockDomainSuccess(domain, accounts));
|
||||
}).catch(err => {
|
||||
dispatch(unblockDomainFail(domain, err));
|
||||
});
|
||||
|
@ -66,11 +74,11 @@ export function unblockDomainRequest(domain) {
|
|||
};
|
||||
};
|
||||
|
||||
export function unblockDomainSuccess(domain, accountId) {
|
||||
export function unblockDomainSuccess(domain, accounts) {
|
||||
return {
|
||||
type: DOMAIN_UNBLOCK_SUCCESS,
|
||||
domain,
|
||||
accountId,
|
||||
accounts,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -86,7 +94,7 @@ export function fetchDomainBlocks() {
|
|||
return (dispatch, getState) => {
|
||||
dispatch(fetchDomainBlocksRequest());
|
||||
|
||||
api(getState).get().then(response => {
|
||||
api(getState).get('/api/v1/domain_blocks').then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(fetchDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
|
@ -115,3 +123,43 @@ export function fetchDomainBlocksFail(error) {
|
|||
error,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocks() {
|
||||
return (dispatch, getState) => {
|
||||
const url = getState().getIn(['domain_lists', 'blocks', 'next']);
|
||||
|
||||
if (url === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(expandDomainBlocksRequest());
|
||||
|
||||
api(getState).get(url).then(response => {
|
||||
const next = getLinks(response).refs.find(link => link.rel === 'next');
|
||||
dispatch(expandDomainBlocksSuccess(response.data, next ? next.uri : null));
|
||||
}).catch(err => {
|
||||
dispatch(expandDomainBlocksFail(err));
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksRequest() {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_REQUEST,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksSuccess(domains, next) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||
domains,
|
||||
next,
|
||||
};
|
||||
};
|
||||
|
||||
export function expandDomainBlocksFail(error) {
|
||||
return {
|
||||
type: DOMAIN_BLOCKS_EXPAND_FAIL,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -43,7 +43,9 @@ export function updateNotifications(notification, intlMessages, intlLocale) {
|
|||
const playSound = getState().getIn(['settings', 'notifications', 'sounds', notification.type], true);
|
||||
|
||||
dispatch(importFetchedAccount(notification.account));
|
||||
dispatch(importFetchedStatus(notification.status));
|
||||
if (notification.status) {
|
||||
dispatch(importFetchedStatus(notification.status));
|
||||
}
|
||||
|
||||
dispatch({
|
||||
type: NOTIFICATIONS_UPDATE,
|
||||
|
|
42
app/javascript/mastodon/components/domain.js
Normal file
42
app/javascript/mastodon/components/domain.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import IconButton from './icon_button';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
const messages = defineMessages({
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
@injectIntl
|
||||
export default class Account extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
domain: PropTypes.string,
|
||||
onUnblockDomain: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleDomainUnblock = () => {
|
||||
this.props.onUnblockDomain(this.props.domain);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { domain, intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='domain'>
|
||||
<div className='domain__wrapper'>
|
||||
<span className='domain__domain-name'>
|
||||
<strong>{domain}</strong>
|
||||
</span>
|
||||
|
||||
<div className='domain__buttons'>
|
||||
<IconButton active icon='unlock-alt' title={intl.formatMessage(messages.unblockDomain, { domain })} onClick={this.handleDomainUnblock} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
33
app/javascript/mastodon/containers/domain_container.js
Normal file
33
app/javascript/mastodon/containers/domain_container.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { blockDomain, unblockDomain } from '../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
import Domain from '../components/domain';
|
||||
import { openModal } from '../actions/modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' },
|
||||
});
|
||||
|
||||
const makeMapStateToProps = () => {
|
||||
const mapStateToProps = (state, { }) => ({
|
||||
});
|
||||
|
||||
return mapStateToProps;
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
onBlockDomain (domain) {
|
||||
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)),
|
||||
}));
|
||||
},
|
||||
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
});
|
||||
|
||||
export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Domain));
|
|
@ -8,6 +8,7 @@ import { me } from '../../../initial_state';
|
|||
|
||||
const messages = defineMessages({
|
||||
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
|
||||
direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' },
|
||||
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
|
||||
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
|
||||
unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
|
||||
|
@ -32,6 +33,7 @@ export default class ActionBar extends React.PureComponent {
|
|||
onFollow: PropTypes.func,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onReblogToggle: PropTypes.func.isRequired,
|
||||
onReport: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
|
@ -53,6 +55,7 @@ export default class ActionBar extends React.PureComponent {
|
|||
let extraInfo = '';
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.mention, { name: account.get('username') }), action: this.props.onMention });
|
||||
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.props.onDirect });
|
||||
|
||||
if ('share' in navigator) {
|
||||
menu.push({ text: intl.formatMessage(messages.share, { name: account.get('username') }), action: this.handleShare });
|
||||
|
|
|
@ -16,6 +16,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
onFollow: PropTypes.func.isRequired,
|
||||
onBlock: PropTypes.func.isRequired,
|
||||
onMention: PropTypes.func.isRequired,
|
||||
onDirect: PropTypes.func.isRequired,
|
||||
onReblogToggle: PropTypes.func.isRequired,
|
||||
onReport: PropTypes.func.isRequired,
|
||||
onMute: PropTypes.func.isRequired,
|
||||
|
@ -40,6 +41,10 @@ export default class Header extends ImmutablePureComponent {
|
|||
this.props.onMention(this.props.account, this.context.router.history);
|
||||
}
|
||||
|
||||
handleDirect = () => {
|
||||
this.props.onDirect(this.props.account, this.context.router.history);
|
||||
}
|
||||
|
||||
handleReport = () => {
|
||||
this.props.onReport(this.props.account);
|
||||
}
|
||||
|
@ -57,7 +62,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
if (!domain) return;
|
||||
|
||||
this.props.onBlockDomain(domain, this.props.account.get('id'));
|
||||
this.props.onBlockDomain(domain);
|
||||
}
|
||||
|
||||
handleUnblockDomain = () => {
|
||||
|
@ -65,7 +70,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
|
||||
if (!domain) return;
|
||||
|
||||
this.props.onUnblockDomain(domain, this.props.account.get('id'));
|
||||
this.props.onUnblockDomain(domain);
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -89,6 +94,7 @@ export default class Header extends ImmutablePureComponent {
|
|||
account={account}
|
||||
onBlock={this.handleBlock}
|
||||
onMention={this.handleMention}
|
||||
onDirect={this.handleDirect}
|
||||
onReblogToggle={this.handleReblogToggle}
|
||||
onReport={this.handleReport}
|
||||
onMute={this.handleMute}
|
||||
|
|
|
@ -9,7 +9,10 @@ import {
|
|||
unblockAccount,
|
||||
unmuteAccount,
|
||||
} from '../../../actions/accounts';
|
||||
import { mentionCompose } from '../../../actions/compose';
|
||||
import {
|
||||
mentionCompose,
|
||||
directCompose,
|
||||
} from '../../../actions/compose';
|
||||
import { initMuteModal } from '../../../actions/mutes';
|
||||
import { initReport } from '../../../actions/reports';
|
||||
import { openModal } from '../../../actions/modal';
|
||||
|
@ -67,6 +70,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
dispatch(mentionCompose(account, router));
|
||||
},
|
||||
|
||||
onDirect (account, router) {
|
||||
dispatch(directCompose(account, router));
|
||||
},
|
||||
|
||||
onReblogToggle (account) {
|
||||
if (account.getIn(['relationship', 'showing_reblogs'])) {
|
||||
dispatch(followAccount(account.get('id'), false));
|
||||
|
@ -87,16 +94,16 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||
}
|
||||
},
|
||||
|
||||
onBlockDomain (domain, accountId) {
|
||||
onBlockDomain (domain) {
|
||||
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)),
|
||||
onConfirm: () => dispatch(blockDomain(domain)),
|
||||
}));
|
||||
},
|
||||
|
||||
onUnblockDomain (domain, accountId) {
|
||||
dispatch(unblockDomain(domain, accountId));
|
||||
onUnblockDomain (domain) {
|
||||
dispatch(unblockDomain(domain));
|
||||
},
|
||||
|
||||
});
|
||||
|
|
|
@ -10,15 +10,19 @@ const APPROX_HASHTAG_RE = /(?:^|[^\/\)\w])#(\w*[a-zA-Z·]\w*)/i;
|
|||
const mapStateToProps = state => ({
|
||||
needsLockWarning: state.getIn(['compose', 'privacy']) === 'private' && !state.getIn(['accounts', me, 'locked']),
|
||||
hashtagWarning: state.getIn(['compose', 'privacy']) !== 'public' && APPROX_HASHTAG_RE.test(state.getIn(['compose', 'text'])),
|
||||
directMessageWarning: state.getIn(['compose', 'privacy']) === 'direct',
|
||||
});
|
||||
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning }) => {
|
||||
const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning }) => {
|
||||
if (needsLockWarning) {
|
||||
return <Warning message={<FormattedMessage id='compose_form.lock_disclaimer' defaultMessage='Your account is not {locked}. Anyone can follow you to view your follower-only posts.' values={{ locked: <a href='/settings/profile'><FormattedMessage id='compose_form.lock_disclaimer.lock' defaultMessage='locked' /></a> }} />} />;
|
||||
}
|
||||
if (hashtagWarning) {
|
||||
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag." />} />;
|
||||
}
|
||||
if (directMessageWarning) {
|
||||
return <Warning message={<FormattedMessage id='compose_form.direct_message_warning' defaultMessage='This toot will only be visible to all the mentioned users.' />} />;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
@ -26,6 +30,7 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning }) => {
|
|||
WarningWrapper.propTypes = {
|
||||
needsLockWarning: PropTypes.bool,
|
||||
hashtagWarning: PropTypes.bool,
|
||||
directMessageWarning: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(WarningWrapper);
|
||||
|
|
66
app/javascript/mastodon/features/domain_blocks/index.js
Normal file
66
app/javascript/mastodon/features/domain_blocks/index.js
Normal file
|
@ -0,0 +1,66 @@
|
|||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import PropTypes from 'prop-types';
|
||||
import LoadingIndicator from '../../components/loading_indicator';
|
||||
import Column from '../ui/components/column';
|
||||
import ColumnBackButtonSlim from '../../components/column_back_button_slim';
|
||||
import DomainContainer from '../../containers/domain_container';
|
||||
import { fetchDomainBlocks, expandDomainBlocks } from '../../actions/domain_blocks';
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
import { debounce } from 'lodash';
|
||||
import ScrollableList from '../../components/scrollable_list';
|
||||
|
||||
const messages = defineMessages({
|
||||
heading: { id: 'column.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' },
|
||||
});
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
domains: state.getIn(['domain_lists', 'blocks', 'items']),
|
||||
});
|
||||
|
||||
@connect(mapStateToProps)
|
||||
@injectIntl
|
||||
export default class Blocks extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
domains: ImmutablePropTypes.list,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount () {
|
||||
this.props.dispatch(fetchDomainBlocks());
|
||||
}
|
||||
|
||||
handleLoadMore = debounce(() => {
|
||||
this.props.dispatch(expandDomainBlocks());
|
||||
}, 300, { leading: true });
|
||||
|
||||
render () {
|
||||
const { intl, domains } = this.props;
|
||||
|
||||
if (!domains) {
|
||||
return (
|
||||
<Column>
|
||||
<LoadingIndicator />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Column icon='ban' heading={intl.formatMessage(messages.heading)}>
|
||||
<ColumnBackButtonSlim />
|
||||
<ScrollableList scrollKey='domain_blocks' onLoadMore={this.handleLoadMore}>
|
||||
{domains.map(domain =>
|
||||
<DomainContainer key={domain} domain={domain} />
|
||||
)}
|
||||
</ScrollableList>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -24,6 +24,7 @@ const messages = defineMessages({
|
|||
sign_out: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
|
||||
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },
|
||||
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
|
||||
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
|
||||
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
|
||||
info: { id: 'navigation_bar.info', defaultMessage: 'Extended information' },
|
||||
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' },
|
||||
|
@ -121,6 +122,7 @@ export default class GettingStarted extends ImmutablePureComponent {
|
|||
<ColumnLink icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />
|
||||
<ColumnLink icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />
|
||||
<ColumnLink icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />
|
||||
<ColumnLink icon='ban' text={intl.formatMessage(messages.domain_blocks)} to='/domain_blocks' />
|
||||
<ColumnLink icon='cog' text={intl.formatMessage(messages.preferences)} href='/settings/preferences' />
|
||||
<ColumnLink icon='sign-out' text={intl.formatMessage(messages.sign_out)} href='/auth/sign_out' method='delete' />
|
||||
</div>
|
||||
|
|
|
@ -1,16 +1,10 @@
|
|||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Hammer from 'hammerjs';
|
||||
|
||||
const MIN_SCALE = 1;
|
||||
const MAX_SCALE = 4;
|
||||
|
||||
const getMidpoint = (p1, p2) => ({
|
||||
x: (p1.clientX + p2.clientX) / 2,
|
||||
y: (p1.clientY + p2.clientY) / 2,
|
||||
});
|
||||
|
||||
const getDistance = (p1, p2) =>
|
||||
Math.sqrt(Math.pow(p1.clientX - p2.clientX, 2) + Math.pow(p1.clientY - p2.clientY, 2));
|
||||
const DOUBLE_TAP_SCALE = 2;
|
||||
|
||||
const clamp = (min, max, value) => Math.min(max, Math.max(min, value));
|
||||
|
||||
|
@ -37,83 +31,97 @@ export default class ZoomableImage extends React.PureComponent {
|
|||
removers = [];
|
||||
container = null;
|
||||
image = null;
|
||||
lastTouchEndTime = 0;
|
||||
lastDistance = 0;
|
||||
lastScale = null;
|
||||
zoomCenter = null;
|
||||
|
||||
componentDidMount () {
|
||||
let handler = this.handleTouchStart;
|
||||
this.container.addEventListener('touchstart', handler);
|
||||
this.removers.push(() => this.container.removeEventListener('touchstart', handler));
|
||||
handler = this.handleTouchMove;
|
||||
// on Chrome 56+, touch event listeners will default to passive
|
||||
// https://www.chromestatus.com/features/5093566007214080
|
||||
this.container.addEventListener('touchmove', handler, { passive: false });
|
||||
this.removers.push(() => this.container.removeEventListener('touchend', handler));
|
||||
// register pinch event handlers to the container
|
||||
let hammer = new Hammer.Manager(this.container, {
|
||||
// required to make container scrollable by touch
|
||||
touchAction: 'pan-x pan-y',
|
||||
});
|
||||
hammer.add(new Hammer.Pinch());
|
||||
hammer.on('pinchstart', this.handlePinchStart);
|
||||
hammer.on('pinchmove', this.handlePinchMove);
|
||||
this.removers.push(() => hammer.off('pinchstart pinchmove'));
|
||||
|
||||
// register tap event handlers
|
||||
hammer = new Hammer.Manager(this.image);
|
||||
// NOTE the order of adding is also the order of gesture recognition
|
||||
hammer.add(new Hammer.Tap({ event: 'doubletap', taps: 2 }));
|
||||
hammer.add(new Hammer.Tap());
|
||||
// prevent the 'tap' event handler be fired on double tap
|
||||
hammer.get('tap').requireFailure('doubletap');
|
||||
// NOTE 'tap' and 'doubletap' events are fired by touch and *mouse*
|
||||
hammer.on('tap', this.handleTap);
|
||||
hammer.on('doubletap', this.handleDoubleTap);
|
||||
this.removers.push(() => hammer.off('tap doubletap'));
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
this.removeEventListeners();
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps, prevState) {
|
||||
if (!this.zoomCenter) return;
|
||||
|
||||
const { x: cx, y: cy } = this.zoomCenter;
|
||||
const { scale: prevScale } = prevState;
|
||||
const { scale: nextScale } = this.state;
|
||||
const { scrollLeft, scrollTop } = this.container;
|
||||
|
||||
// math memo:
|
||||
// x = (scrollLeft + cx) / scrollWidth
|
||||
// x' = (nextScrollLeft + cx) / nextScrollWidth
|
||||
// scrollWidth = clientWidth * prevScale
|
||||
// scrollWidth' = clientWidth * nextScale
|
||||
// Solve x = x' for nextScrollLeft
|
||||
const nextScrollLeft = (scrollLeft + cx) * nextScale / prevScale - cx;
|
||||
const nextScrollTop = (scrollTop + cy) * nextScale / prevScale - cy;
|
||||
|
||||
this.container.scrollLeft = nextScrollLeft;
|
||||
this.container.scrollTop = nextScrollTop;
|
||||
}
|
||||
|
||||
removeEventListeners () {
|
||||
this.removers.forEach(listeners => listeners());
|
||||
this.removers = [];
|
||||
}
|
||||
|
||||
handleTouchStart = e => {
|
||||
if (e.touches.length !== 2) return;
|
||||
|
||||
this.lastDistance = getDistance(...e.touches);
|
||||
}
|
||||
|
||||
handleTouchMove = e => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = this.container;
|
||||
if (e.touches.length === 1 && scrollTop !== scrollHeight - clientHeight) {
|
||||
// prevent propagating event to MediaModal
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (e.touches.length !== 2) return;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const distance = getDistance(...e.touches);
|
||||
const midpoint = getMidpoint(...e.touches);
|
||||
const scale = clamp(MIN_SCALE, MAX_SCALE, this.state.scale * distance / this.lastDistance);
|
||||
|
||||
this.zoom(scale, midpoint);
|
||||
|
||||
this.lastMidpoint = midpoint;
|
||||
this.lastDistance = distance;
|
||||
}
|
||||
|
||||
zoom(nextScale, midpoint) {
|
||||
const { scale } = this.state;
|
||||
const { scrollLeft, scrollTop } = this.container;
|
||||
|
||||
// math memo:
|
||||
// x = (scrollLeft + midpoint.x) / scrollWidth
|
||||
// x' = (nextScrollLeft + midpoint.x) / nextScrollWidth
|
||||
// scrollWidth = clientWidth * scale
|
||||
// scrollWidth' = clientWidth * nextScale
|
||||
// Solve x = x' for nextScrollLeft
|
||||
const nextScrollLeft = (scrollLeft + midpoint.x) * nextScale / scale - midpoint.x;
|
||||
const nextScrollTop = (scrollTop + midpoint.y) * nextScale / scale - midpoint.y;
|
||||
|
||||
this.setState({ scale: nextScale }, () => {
|
||||
this.container.scrollLeft = nextScrollLeft;
|
||||
this.container.scrollTop = nextScrollTop;
|
||||
});
|
||||
}
|
||||
|
||||
handleClick = e => {
|
||||
// don't propagate event to MediaModal
|
||||
// prevent the click event propagated to parent
|
||||
e.stopPropagation();
|
||||
|
||||
// the tap event handler is executed at the same time by touch and mouse,
|
||||
// so we don't need to execute the onClick handler here
|
||||
}
|
||||
|
||||
handlePinchStart = () => {
|
||||
this.lastScale = this.state.scale;
|
||||
}
|
||||
|
||||
handlePinchMove = e => {
|
||||
const scale = clamp(MIN_SCALE, MAX_SCALE, this.lastScale * e.scale);
|
||||
this.zoom(scale, e.center);
|
||||
}
|
||||
|
||||
handleTap = () => {
|
||||
const handler = this.props.onClick;
|
||||
if (handler) handler();
|
||||
}
|
||||
|
||||
handleDoubleTap = e => {
|
||||
if (this.state.scale === MIN_SCALE)
|
||||
this.zoom(DOUBLE_TAP_SCALE, e.center);
|
||||
else
|
||||
this.zoom(MIN_SCALE, e.center);
|
||||
}
|
||||
|
||||
zoom (scale, center) {
|
||||
this.zoomCenter = center;
|
||||
this.setState({ scale });
|
||||
}
|
||||
|
||||
setContainerRef = c => {
|
||||
this.container = c;
|
||||
}
|
||||
|
@ -126,6 +134,18 @@ export default class ZoomableImage extends React.PureComponent {
|
|||
const { alt, src } = this.props;
|
||||
const { scale } = this.state;
|
||||
const overflow = scale === 1 ? 'hidden' : 'scroll';
|
||||
const marginStyle = {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: '0 0',
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
|
@ -133,17 +153,18 @@ export default class ZoomableImage extends React.PureComponent {
|
|||
ref={this.setContainerRef}
|
||||
style={{ overflow }}
|
||||
>
|
||||
<img
|
||||
role='presentation'
|
||||
ref={this.setImageRef}
|
||||
alt={alt}
|
||||
src={src}
|
||||
style={{
|
||||
transform: `scale(${scale})`,
|
||||
transformOrigin: '0 0',
|
||||
}}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
<div
|
||||
className='zoomable-image__margin'
|
||||
style={marginStyle}
|
||||
>
|
||||
<img
|
||||
ref={this.setImageRef}
|
||||
role='presentation'
|
||||
alt={alt}
|
||||
src={src}
|
||||
onClick={this.handleClick}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import {
|
|||
FavouritedStatuses,
|
||||
ListTimeline,
|
||||
Blocks,
|
||||
DomainBlocks,
|
||||
Mutes,
|
||||
PinnedStatuses,
|
||||
Lists,
|
||||
|
@ -158,6 +159,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||
|
||||
<WrappedRoute path='/follow_requests' component={FollowRequests} content={children} />
|
||||
<WrappedRoute path='/blocks' component={Blocks} content={children} />
|
||||
<WrappedRoute path='/domain_blocks' component={DomainBlocks} content={children} />
|
||||
<WrappedRoute path='/mutes' component={Mutes} content={children} />
|
||||
<WrappedRoute path='/lists' component={Lists} content={children} />
|
||||
|
||||
|
|
|
@ -90,6 +90,10 @@ export function Blocks () {
|
|||
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
|
||||
}
|
||||
|
||||
export function DomainBlocks () {
|
||||
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
|
||||
}
|
||||
|
||||
export function Mutes () {
|
||||
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "حظر @{name}",
|
||||
"account.block_domain": "إخفاء كل شيئ قادم من إسم النطاق {domain}",
|
||||
"account.blocked": "محظور",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "قد لا تعكس المعلومات أدناه الملف الشخصي الكامل للمستخدم.",
|
||||
"account.domain_blocked": "النطاق مخفي",
|
||||
"account.edit_profile": "تعديل الملف الشخصي",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "فك التدبيس",
|
||||
"column_subheading.navigation": "التصفح",
|
||||
"column_subheading.settings": "الإعدادات",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "هذا التبويق لن يُدرَج تحت أي وسم كان بما أنه غير مُدرَج. لا يُسمح بالبحث إلّا عن التبويقات العمومية عن طريق الوسوم.",
|
||||
"compose_form.lock_disclaimer": "حسابك ليس {locked}. يمكن لأي شخص متابعتك و عرض المنشورات.",
|
||||
"compose_form.lock_disclaimer.lock": "مقفل",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Блокирай",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Редактирай профила си",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloca @{name}",
|
||||
"account.block_domain": "Amaga-ho tot de {domain}",
|
||||
"account.blocked": "Bloquejat",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "La informació següent pot reflectir incompleta el perfil de l'usuari.",
|
||||
"account.domain_blocked": "Domini ocult",
|
||||
"account.edit_profile": "Edita el perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "No fixis",
|
||||
"column_subheading.navigation": "Navegació",
|
||||
"column_subheading.settings": "Configuració",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Aquest toot no es mostrarà en cap etiqueta ja que no està llistat. Només els toots públics poden ser cercats per etiqueta.",
|
||||
"compose_form.lock_disclaimer": "El teu compte no està bloquejat {locked}. Tothom pot seguir-te i veure els teus missatges a seguidors.",
|
||||
"compose_form.lock_disclaimer.lock": "blocat",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "@{name} blocken",
|
||||
"account.block_domain": "Alles von {domain} verstecken",
|
||||
"account.blocked": "Blockiert",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Das Profil wird möglicherweise unvollständig wiedergegeben.",
|
||||
"account.domain_blocked": "Domain versteckt",
|
||||
"account.edit_profile": "Profil bearbeiten",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Lösen",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Einstellungen",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Dieser Beitrag wird nicht unter einen dieser Hashtags sichtbar sein, solange er ungelistet ist. Bei einer Suche kann er nicht gefunden werden.",
|
||||
"compose_form.lock_disclaimer": "Dein Profil ist nicht {locked}. Wer dir folgen will, kann das jederzeit tun und dann auch deine privaten Beiträge sehen.",
|
||||
"compose_form.lock_disclaimer.lock": "gesperrt",
|
||||
|
|
|
@ -380,6 +380,10 @@
|
|||
"defaultMessage": "Mention @{name}",
|
||||
"id": "account.mention"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Direct message @{name}",
|
||||
"id": "account.direct"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Edit profile",
|
||||
"id": "account.edit_profile"
|
||||
|
@ -804,6 +808,10 @@
|
|||
{
|
||||
"defaultMessage": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"id": "compose_form.hashtag_warning"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "This toot will only be visible to all the mentioned users.",
|
||||
"id": "compose_form.direct_message_warning"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/compose/containers/warning_container.json"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Block @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Edit profile",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"column_subheading.lists": "Lists",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloki @{name}",
|
||||
"account.block_domain": "Kaŝi ĉion de {domain}",
|
||||
"account.blocked": "Blokita",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Subaj informoj povas reflekti la profilon de la uzanto nekomplete.",
|
||||
"account.domain_blocked": "Domajno kaŝita",
|
||||
"account.edit_profile": "Redakti profilon",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Depingli",
|
||||
"column_subheading.navigation": "Navigado",
|
||||
"column_subheading.settings": "Agordado",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Ĉi tiu mesaĝo ne estos listigita per ajna kradvorto. Nur publikaj mesaĝoj estas serĉeblaj per kradvortoj.",
|
||||
"compose_form.lock_disclaimer": "Via konta ne estas {locked}. Iu ajn povas sekvi vin por vidi viajn mesaĝojn nur por sekvantoj.",
|
||||
"compose_form.lock_disclaimer.lock": "ŝlosita",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloquear",
|
||||
"account.block_domain": "Ocultar todo de {domain}",
|
||||
"account.blocked": "Bloqueado",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "La siguiente información del usuario puede estar incompleta.",
|
||||
"account.domain_blocked": "Dominio oculto",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Dejar de fijar",
|
||||
"column_subheading.navigation": "Navegación",
|
||||
"column_subheading.settings": "Ajustes",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Este toot no se mostrará bajo hashtags porque no es público. Sólo los toots públicos se pueden buscar por hashtag.",
|
||||
"compose_form.lock_disclaimer": "Tu cuenta no está bloqueada. Todos pueden seguirte para ver tus toots solo para seguidores.",
|
||||
"compose_form.lock_disclaimer.lock": "bloqueado",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "مسدودسازی @{name}",
|
||||
"account.block_domain": "پنهانسازی همه چیز از سرور {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "اطلاعات زیر ممکن است نمایهٔ این کاربر را به تمامی نشان ندهد.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "ویرایش نمایه",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "رهاکردن",
|
||||
"column_subheading.navigation": "گشت و گذار",
|
||||
"column_subheading.settings": "تنظیمات",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "حساب شما {locked} نیست. هر کسی میتواند پیگیر شما شود و نوشتههای ویژهٔ پیگیران شما را ببیند.",
|
||||
"compose_form.lock_disclaimer.lock": "قفل",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Estä @{name}",
|
||||
"account.block_domain": "Piilota kaikki sisältö verkkotunnuksesta {domain}",
|
||||
"account.blocked": "Estetty",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Alla olevat käyttäjän profiilitiedot saattavat olla epätäydellisiä.",
|
||||
"account.domain_blocked": "Verkko-osoite piilotettu",
|
||||
"account.edit_profile": "Muokkaa",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Poista kiinnitys",
|
||||
"column_subheading.navigation": "Navigaatio",
|
||||
"column_subheading.settings": "Asetukset",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Tämä töötti ei tule näkymään hashtag-hauissa, koska se ei näy julkisilla aikajanoilla. Vain julkisia tööttejä voi hakea hashtageilla.",
|
||||
"compose_form.lock_disclaimer": "Tilisi ei ole {locked}. Kuka tahansa voi seurata tiliäsi ja nähdä vain seuraajille -postauksesi.",
|
||||
"compose_form.lock_disclaimer.lock": "lukittu",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloquer @{name}",
|
||||
"account.block_domain": "Tout masquer venant de {domain}",
|
||||
"account.blocked": "Bloqué",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Les données ci-dessous peuvent ne pas refléter ce profil dans sa totalité.",
|
||||
"account.domain_blocked": "Domaine caché",
|
||||
"account.edit_profile": "Modifier le profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Retirer",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Paramètres",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Ce pouet ne sera pas listé dans les recherches par hashtag car sa visibilité est réglée sur \"non-listé\". Seuls les pouets avec une visibilité \"publique\" peuvent être recherchés par hashtag.",
|
||||
"compose_form.lock_disclaimer": "Votre compte n’est pas {locked}. Tout le monde peut vous suivre et voir vos pouets privés.",
|
||||
"compose_form.lock_disclaimer.lock": "verrouillé",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloquear @{name}",
|
||||
"account.block_domain": "Ocultar calquer contido de {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "A información inferior podería mostrar un perfil incompleto da usuaria.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Soltar",
|
||||
"column_subheading.navigation": "Navegación",
|
||||
"column_subheading.settings": "Axustes",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Esta mensaxe non será listada baixo ningunha etiqueta xa que está marcada como non listada. Só os toots públicos poden buscarse por etiquetas.",
|
||||
"compose_form.lock_disclaimer": "A súa conta non está {locked}. Calquera pode seguila para ver as súas mensaxes só-para-seguidoras.",
|
||||
"compose_form.lock_disclaimer.lock": "bloqueado",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "חסימת @{name}",
|
||||
"account.block_domain": "להסתיר הכל מהקהילה {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "המידע להלן עשוי להיות לא עדכני או לא שלם.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "עריכת פרופיל",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "שחרור קיבוע",
|
||||
"column_subheading.navigation": "ניווט",
|
||||
"column_subheading.settings": "אפשרויות",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "חשבונך אינו {locked}. כל אחד יוכל לעקוב אחריך כדי לקרוא את הודעותיך המיועדות לעוקבים בלבד.",
|
||||
"compose_form.lock_disclaimer.lock": "נעול",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokiraj @{name}",
|
||||
"account.block_domain": "Sakrij sve sa {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Ovaj korisnik je sa druge instance. Ovaj broj bi mogao biti veći.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Uredi profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigacija",
|
||||
"column_subheading.settings": "Postavke",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Tvoj račun nije {locked}. Svatko te može slijediti kako bi vidio postove namijenjene samo tvojim sljedbenicima.",
|
||||
"compose_form.lock_disclaimer.lock": "zaključan",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "@{name} letiltása",
|
||||
"account.block_domain": "Minden elrejtése innen: {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Az alul található információk hiányosan mutathatják be a felhasználót.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Profil szerkesztése",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Kitűzés eltávolítása",
|
||||
"column_subheading.navigation": "Navigáció",
|
||||
"column_subheading.settings": "Beállítások",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Ezen tülkölés nem fog megjelenni semmilyen hashtag alatt mivel listázatlan. Csak a publikus tülkölések kereshetőek hashtag-el.",
|
||||
"compose_form.lock_disclaimer": "Az ön fiókja nincs {locked}. Bárki követni tud, hogy megtekintse a kizárt követőknek szánt üzeneteid.",
|
||||
"compose_form.lock_disclaimer.lock": "lezárva",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Արգելափակել @{name}֊ին",
|
||||
"account.block_domain": "Թաքցնել ամենը հետեւյալ տիրույթից՝ {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Ներքոհիշյալը կարող է ոչ ամբողջությամբ արտացոլել օգտատիրոջ էջի տվյալները։",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Խմբագրել անձնական էջը",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Հանել",
|
||||
"column_subheading.navigation": "Նավարկություն",
|
||||
"column_subheading.settings": "Կարգավորումներ",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Այս թութը չի հաշվառվի որեւէ պիտակի տակ, քանզի այն ծածուկ է։ Միայն հրապարակային թթերը հնարավոր է որոնել պիտակներով։",
|
||||
"compose_form.lock_disclaimer": "Քո հաշիվը {locked} չէ։ Յուրաքանչյուր ոք կարող է հետեւել քեզ եւ տեսնել միայն հետեւողների համար նախատեսված գրառումները։",
|
||||
"compose_form.lock_disclaimer.lock": "փակ",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokir @{name}",
|
||||
"account.block_domain": "Sembunyikan segalanya dari {domain}",
|
||||
"account.blocked": "Terblokir",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Informasi di bawah mungkin tidak mencerminkan profil user secara lengkap.",
|
||||
"account.domain_blocked": "Domain disembunyikan",
|
||||
"account.edit_profile": "Ubah profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Lepaskan",
|
||||
"column_subheading.navigation": "Navigasi",
|
||||
"column_subheading.settings": "Pengaturan",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Toot ini tidak akan ada dalam daftar tagar manapun karena telah di set sebagai tidak terdaftar. Hanya postingan publik yang bisa dicari dengan tagar.",
|
||||
"compose_form.lock_disclaimer": "Akun anda tidak {locked}. Semua orang dapat mengikuti anda untuk melihat postingan khusus untuk pengikut anda.",
|
||||
"compose_form.lock_disclaimer.lock": "terkunci",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokusar @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Modifikar profilo",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blocca @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Modifica profilo",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "@{name}さんをブロック",
|
||||
"account.block_domain": "{domain}全体を非表示",
|
||||
"account.blocked": "ブロック済み",
|
||||
"account.direct": "@{name}さんにダイレクトメッセージ",
|
||||
"account.disclaimer_full": "以下の情報は不正確な可能性があります。",
|
||||
"account.domain_blocked": "ドメイン非表示中",
|
||||
"account.edit_profile": "プロフィールを編集",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"column_subheading.lists": "リスト",
|
||||
"column_subheading.navigation": "ナビゲーション",
|
||||
"column_subheading.settings": "設定",
|
||||
"compose_form.direct_message_warning": "このトゥートはメンションされた人だけが見ることができます。",
|
||||
"compose_form.hashtag_warning": "このトゥートは未収載なのでハッシュタグの一覧に表示されません。公開トゥートだけがハッシュタグで検索できます。",
|
||||
"compose_form.lock_disclaimer": "あなたのアカウントは{locked}になっていません。誰でもあなたをフォローすることができ、フォロワー限定の投稿を見ることができます。",
|
||||
"compose_form.lock_disclaimer.lock": "非公開",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "@{name}을 차단",
|
||||
"account.block_domain": "{domain} 전체를 숨김",
|
||||
"account.blocked": "차단 됨",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "여기 있는 정보는 유저의 프로파일을 정확히 반영하지 못 할 수도 있습니다.",
|
||||
"account.domain_blocked": "도메인 숨겨짐",
|
||||
"account.edit_profile": "프로필 편집",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "고정 해제",
|
||||
"column_subheading.navigation": "내비게이션",
|
||||
"column_subheading.settings": "설정",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "이 툿은 어떤 해시태그로도 검색 되지 않습니다. 전체공개로 게시 된 툿만이 해시태그로 검색 될 수 있습니다.",
|
||||
"compose_form.lock_disclaimer": "이 계정은 {locked}로 설정 되어 있지 않습니다. 누구나 이 계정을 팔로우 할 수 있으며, 팔로워 공개의 포스팅을 볼 수 있습니다.",
|
||||
"compose_form.lock_disclaimer.lock": "비공개",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokkeer @{name}",
|
||||
"account.block_domain": "Negeer alles van {domain}",
|
||||
"account.blocked": "Geblokkeerd",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "De informatie hieronder kan mogelijk een incompleet beeld geven van dit gebruikersprofiel.",
|
||||
"account.domain_blocked": "Domein verborgen",
|
||||
"account.edit_profile": "Profiel bewerken",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Losmaken",
|
||||
"column_subheading.navigation": "Navigatie",
|
||||
"column_subheading.settings": "Instellingen",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Deze toot valt niet onder een hashtag te bekijken, omdat deze niet op openbare tijdlijnen wordt getoond. Alleen openbare toots kunnen via hashtags gevonden worden.",
|
||||
"compose_form.lock_disclaimer": "Jouw account is niet {locked}. Iedereen kan jou volgen en toots zien die je alleen aan volgers hebt gericht.",
|
||||
"compose_form.lock_disclaimer.lock": "besloten",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokkér @{name}",
|
||||
"account.block_domain": "Skjul alt fra {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Informasjonen nedenfor kan gi et ufullstendig bilde av brukerens profil.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Rediger profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Løsne",
|
||||
"column_subheading.navigation": "Navigasjon",
|
||||
"column_subheading.settings": "Innstillinger",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Denne tuten blir ikke listet under noen emneknagger da den er ulistet. Kun offentlige tuter kan søktes etter med emneknagg.",
|
||||
"compose_form.lock_disclaimer": "Din konto er ikke {locked}. Hvem som helst kan følge deg og se dine private poster.",
|
||||
"compose_form.lock_disclaimer.lock": "låst",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blocar @{name}",
|
||||
"account.block_domain": "Tot amagar del domeni {domain}",
|
||||
"account.blocked": "Blocat",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Aquelas informacions de perfil pòdon èsser incomplètas.",
|
||||
"account.domain_blocked": "Domeni amagat",
|
||||
"account.edit_profile": "Modificar lo perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Despenjar",
|
||||
"column_subheading.navigation": "Navigacion",
|
||||
"column_subheading.settings": "Paramètres",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Aqueste tut serà pas ligat a cap etiqueta estant qu’es pas listat. Òm pas cercar que los tuts publics per etiqueta.",
|
||||
"compose_form.lock_disclaimer": "Vòstre compte es pas {locked}. Tot lo mond pòt vos sègre e veire los estatuts reservats als seguidors.",
|
||||
"compose_form.lock_disclaimer.lock": "clavat",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokuj @{name}",
|
||||
"account.block_domain": "Blokuj wszystko z {domain}",
|
||||
"account.blocked": "Zablokowany",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Poniższe informacje mogą nie odwzorowywać bezbłędnie profilu użytkownika.",
|
||||
"account.domain_blocked": "Ukryto domenę",
|
||||
"account.edit_profile": "Edytuj profil",
|
||||
|
@ -60,6 +61,7 @@
|
|||
"column_subheading.lists": "Listy",
|
||||
"column_subheading.navigation": "Nawigacja",
|
||||
"column_subheading.settings": "Ustawienia",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Ten wpis nie będzie widoczny pod podanymi hashtagami, ponieważ jest oznaczony jako niewidoczny. Tylko publiczne wpisy mogą zostać znalezione z użyciem hashtagów.",
|
||||
"compose_form.lock_disclaimer": "Twoje konto nie jest {locked}. Każdy, kto Cię śledzi, może wyświetlać Twoje wpisy przeznaczone tylko dla śledzących.",
|
||||
"compose_form.lock_disclaimer.lock": "zablokowane",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloquear @{name}",
|
||||
"account.block_domain": "Esconder tudo de {domain}",
|
||||
"account.blocked": "Bloqueado",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "As informações abaixo podem refletir o perfil do usuário de maneira incompleta.",
|
||||
"account.domain_blocked": "Domínio escondido",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Desafixar",
|
||||
"column_subheading.navigation": "Navegação",
|
||||
"column_subheading.settings": "Configurações",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Esse toot não será listado em nenhuma hashtag por ser não listado. Somente toots públicos podem ser pesquisados por hashtag.",
|
||||
"compose_form.lock_disclaimer": "A sua conta não está {locked}. Qualquer pessoa pode te seguir e visualizar postagens direcionadas a apenas seguidores.",
|
||||
"compose_form.lock_disclaimer.lock": "trancada",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Bloquear @{name}",
|
||||
"account.block_domain": "Esconder tudo do domínio {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "As informações abaixo podem refletir o perfil do usuário de forma incompleta.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Desafixar",
|
||||
"column_subheading.navigation": "Navegação",
|
||||
"column_subheading.settings": "Preferências",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Esta pulbicacção não será listada em nenhuma hashtag por ser não listada. Somente publicações públicas podem ser pesquisadas por hashtag.",
|
||||
"compose_form.lock_disclaimer": "A tua conta não está {locked}. Qualquer pessoa pode seguir-te e ver as publicações direcionadas apenas a seguidores.",
|
||||
"compose_form.lock_disclaimer.lock": "bloqueada",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Блокировать",
|
||||
"account.block_domain": "Блокировать все с {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Нижеуказанная информация может не полностью отражать профиль пользователя.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Изменить профиль",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Открепить",
|
||||
"column_subheading.navigation": "Навигация",
|
||||
"column_subheading.settings": "Настройки",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Этот пост не будет показывается в поиске по хэштегу, т.к. он непубличный. Только публичные посты можно найти в поиске по хэштегу.",
|
||||
"compose_form.lock_disclaimer": "Ваш аккаунт не {locked}. Любой человек может подписаться на Вас и просматривать посты для подписчиков.",
|
||||
"compose_form.lock_disclaimer.lock": "закрыт",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokovať @{name}",
|
||||
"account.block_domain": "Ukryť všetko z {domain}",
|
||||
"account.blocked": "Blokovaný/á",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Inofrmácie nižšie nemusia byť úplným odrazom uživateľovho účtu.",
|
||||
"account.domain_blocked": "Doména ukrytá",
|
||||
"account.edit_profile": "Upraviť profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Odopnúť",
|
||||
"column_subheading.navigation": "Navigácia",
|
||||
"column_subheading.settings": "Nastavenia",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Tento toot nebude zobrazený pod žiadným haštagom lebo nieje listovaný. Iba verejné tooty môžu byť nájdené podľa haštagu.",
|
||||
"compose_form.lock_disclaimer": "Váš účet nie je zamknutý. Ktokoľvek ťa môže nasledovať a vidieť tvoje správy pre sledujúcich.",
|
||||
"compose_form.lock_disclaimer.lock": "zamknutý",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blokiraj korisnika @{name}",
|
||||
"account.block_domain": "Sakrij sve sa domena {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Navedene informacije možda ne odslikavaju korisnički profil u potpunosti.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Izmeni profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Otkači",
|
||||
"column_subheading.navigation": "Navigacija",
|
||||
"column_subheading.settings": "Postavke",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Vaš nalog nije {locked}. Svako može da Vas zaprati i da vidi objave namenjene samo Vašim pratiocima.",
|
||||
"compose_form.lock_disclaimer.lock": "zaključan",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Блокирај корисника @{name}",
|
||||
"account.block_domain": "Сакриј све са домена {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Наведене информације можда не одсликавају кориснички профил у потпуности.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Измени профил",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Откачи",
|
||||
"column_subheading.navigation": "Навигација",
|
||||
"column_subheading.settings": "Поставке",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Ваш налог није {locked}. Свако може да Вас запрати и да види објаве намењене само Вашим пратиоцима.",
|
||||
"compose_form.lock_disclaimer.lock": "закључан",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Blockera @{name}",
|
||||
"account.block_domain": "Dölj allt från {domain}",
|
||||
"account.blocked": "Blockerad",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Informationen nedan kan spegla användarens profil ofullständigt.",
|
||||
"account.domain_blocked": "Domän gömd",
|
||||
"account.edit_profile": "Redigera profil",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Ångra fäst",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Inställningar",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "Denna toot kommer inte att listas under någon hashtag eftersom den är onoterad. Endast offentliga toots kan sökas med hashtag.",
|
||||
"compose_form.lock_disclaimer": "Ditt konto är inte {locked}. Vemsomhelst kan följa dig och även se dina inlägg skrivna för endast dina följare.",
|
||||
"compose_form.lock_disclaimer.lock": "låst",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Block @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Edit profile",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigation",
|
||||
"column_subheading.settings": "Settings",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Engelle @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Profili düzenle",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Navigasyon",
|
||||
"column_subheading.settings": "Ayarlar",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Hesabınız {locked} değil. Sadece takipçilerle paylaştığınız gönderileri görebilmek için sizi herhangi bir kullanıcı takip edebilir.",
|
||||
"compose_form.lock_disclaimer.lock": "kilitli",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "Заблокувати",
|
||||
"account.block_domain": "Заглушити {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Налаштування профілю",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.navigation": "Навігація",
|
||||
"column_subheading.settings": "Налаштування",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Ваш акаунт не {locked}. Кожен може підписатися на Вас та бачити Ваші приватні пости.",
|
||||
"compose_form.lock_disclaimer.lock": "приватний",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "屏蔽 @{name}",
|
||||
"account.block_domain": "隐藏来自 {domain} 的内容",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "此处显示的信息可能不是全部内容。",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "修改个人资料",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "取消固定",
|
||||
"column_subheading.navigation": "导航",
|
||||
"column_subheading.settings": "设置",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "这条嘟文被设置为“不公开”,因此它不会出现在任何话题标签的列表下。只有公开的嘟文才能通过话题标签进行搜索。",
|
||||
"compose_form.lock_disclaimer": "你的帐户没有{locked}。任何人都可以在关注你后立即查看仅关注者可见的嘟文。",
|
||||
"compose_form.lock_disclaimer.lock": "开启保护",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "封鎖 @{name}",
|
||||
"account.block_domain": "隱藏來自 {domain} 的一切文章",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "下列資料不一定完整。",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "修改個人資料",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "取下",
|
||||
"column_subheading.navigation": "瀏覽",
|
||||
"column_subheading.settings": "設定",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "你的用戶狀態為「{locked}」,任何人都能立即關注你,然後看到「只有關注者能看」的文章。",
|
||||
"compose_form.lock_disclaimer.lock": "公共",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"account.block": "封鎖 @{name}",
|
||||
"account.block_domain": "隱藏來自 {domain} 的一切貼文",
|
||||
"account.blocked": "Blocked",
|
||||
"account.direct": "Direct Message @{name}",
|
||||
"account.disclaimer_full": "下列資料不一定完整。",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "編輯用者資訊",
|
||||
|
@ -56,6 +57,7 @@
|
|||
"column_header.unpin": "取下",
|
||||
"column_subheading.navigation": "瀏覽",
|
||||
"column_subheading.settings": "設定",
|
||||
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "你的帳號沒有{locked}。任何人都可以關注你,看到發給關注者的貼文。",
|
||||
"compose_form.lock_disclaimer.lock": "上鎖",
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
COMPOSE_CHANGE,
|
||||
COMPOSE_REPLY,
|
||||
COMPOSE_REPLY_CANCEL,
|
||||
COMPOSE_DIRECT,
|
||||
COMPOSE_MENTION,
|
||||
COMPOSE_SUBMIT_REQUEST,
|
||||
COMPOSE_SUBMIT_SUCCESS,
|
||||
|
@ -262,6 +263,12 @@ export default function compose(state = initialState, action) {
|
|||
.update('text', text => `${text}@${action.account.get('acct')} `)
|
||||
.set('focusDate', new Date())
|
||||
.set('idempotencyKey', uuid());
|
||||
case COMPOSE_DIRECT:
|
||||
return state
|
||||
.update('text', text => `${text}@${action.account.get('acct')} `)
|
||||
.set('privacy', 'direct')
|
||||
.set('focusDate', new Date())
|
||||
.set('idempotencyKey', uuid());
|
||||
case COMPOSE_SUGGESTIONS_CLEAR:
|
||||
return state.update('suggestions', ImmutableList(), list => list.clear()).set('suggestion_token', null);
|
||||
case COMPOSE_SUGGESTIONS_READY:
|
||||
|
|
23
app/javascript/mastodon/reducers/domain_lists.js
Normal file
23
app/javascript/mastodon/reducers/domain_lists.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {
|
||||
DOMAIN_BLOCKS_FETCH_SUCCESS,
|
||||
DOMAIN_BLOCKS_EXPAND_SUCCESS,
|
||||
DOMAIN_UNBLOCK_SUCCESS,
|
||||
} from '../actions/domain_blocks';
|
||||
import { Map as ImmutableMap, OrderedSet as ImmutableOrderedSet } from 'immutable';
|
||||
|
||||
const initialState = ImmutableMap({
|
||||
blocks: ImmutableMap(),
|
||||
});
|
||||
|
||||
export default function domainLists(state = initialState, action) {
|
||||
switch(action.type) {
|
||||
case DOMAIN_BLOCKS_FETCH_SUCCESS:
|
||||
return state.setIn(['blocks', 'items'], ImmutableOrderedSet(action.domains)).setIn(['blocks', 'next'], action.next);
|
||||
case DOMAIN_BLOCKS_EXPAND_SUCCESS:
|
||||
return state.updateIn(['blocks', 'items'], set => set.union(action.domains)).setIn(['blocks', 'next'], action.next);
|
||||
case DOMAIN_UNBLOCK_SUCCESS:
|
||||
return state.updateIn(['blocks', 'items'], set => set.delete(action.domain));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
|
@ -6,6 +6,7 @@ import alerts from './alerts';
|
|||
import { loadingBarReducer } from 'react-redux-loading-bar';
|
||||
import modal from './modal';
|
||||
import user_lists from './user_lists';
|
||||
import domain_lists from './domain_lists';
|
||||
import accounts from './accounts';
|
||||
import accounts_counters from './accounts_counters';
|
||||
import statuses from './statuses';
|
||||
|
@ -34,6 +35,7 @@ const reducers = {
|
|||
loadingBar: loadingBarReducer,
|
||||
modal,
|
||||
user_lists,
|
||||
domain_lists,
|
||||
status_lists,
|
||||
accounts,
|
||||
accounts_counters,
|
||||
|
|
|
@ -23,6 +23,14 @@ const normalizeRelationships = (state, relationships) => {
|
|||
return state;
|
||||
};
|
||||
|
||||
const setDomainBlocking = (state, accounts, blocking) => {
|
||||
return state.withMutations(map => {
|
||||
accounts.forEach(id => {
|
||||
map.setIn([id, 'domain_blocking'], blocking);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const initialState = ImmutableMap();
|
||||
|
||||
export default function relationships(state = initialState, action) {
|
||||
|
@ -37,9 +45,9 @@ export default function relationships(state = initialState, action) {
|
|||
case RELATIONSHIPS_FETCH_SUCCESS:
|
||||
return normalizeRelationships(state, action.relationships);
|
||||
case DOMAIN_BLOCK_SUCCESS:
|
||||
return state.setIn([action.accountId, 'domain_blocking'], true);
|
||||
return setDomainBlocking(state, action.accounts, true);
|
||||
case DOMAIN_UNBLOCK_SUCCESS:
|
||||
return state.setIn([action.accountId, 'domain_blocking'], false);
|
||||
return setDomainBlocking(state, action.accounts, false);
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ import { autoPlayGif } from '../initial_state';
|
|||
const accountAssetKeys = ['avatar', 'avatar_static', 'header', 'header_static'];
|
||||
const avatarKey = autoPlayGif ? 'avatar' : 'avatar_static';
|
||||
const limit = 1024;
|
||||
const asyncCache = caches.open('mastodon-system');
|
||||
|
||||
// ServiceWorker and Cache API is not available on iOS 11
|
||||
// https://webkit.org/status/#specification-service-workers
|
||||
const asyncCache = window.caches ? caches.open('mastodon-system') : Promise.reject();
|
||||
|
||||
function put(name, objects, onupdate, oncreate) {
|
||||
return asyncDB.then(db => new Promise((resolve, reject) => {
|
||||
|
|
|
@ -1001,6 +1001,30 @@
|
|||
}
|
||||
}
|
||||
|
||||
.domain {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||
|
||||
.domain__domain-name {
|
||||
flex: 1 1 auto;
|
||||
display: block;
|
||||
color: $primary-text-color;
|
||||
text-decoration: none;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.domain__wrapper {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.domain_buttons {
|
||||
height: 18px;
|
||||
padding: 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.account {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid lighten($ui-base-color, 8%);
|
||||
|
@ -1459,9 +1483,6 @@
|
|||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
img {
|
||||
max-width: $media-modal-media-max-width;
|
||||
|
|
|
@ -79,6 +79,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
|||
hashtag = Tag.where(name: hashtag).first_or_initialize(name: hashtag)
|
||||
|
||||
status.tags << hashtag
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
nil
|
||||
end
|
||||
|
||||
def process_mention(tag, status)
|
||||
|
@ -113,13 +115,13 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
|||
media_attachments = []
|
||||
|
||||
as_array(@object['attachment']).each do |attachment|
|
||||
next if unsupported_media_type?(attachment['mediaType']) || attachment['url'].blank?
|
||||
next if attachment['url'].blank?
|
||||
|
||||
href = Addressable::URI.parse(attachment['url']).normalize.to_s
|
||||
media_attachment = MediaAttachment.create(account: @account, remote_url: href, description: attachment['name'].presence, focus: attachment['focalPoint'])
|
||||
media_attachments << media_attachment
|
||||
|
||||
next if skip_download?
|
||||
next if unsupported_media_type?(attachment['mediaType']) || skip_download?
|
||||
|
||||
media_attachment.file_remote_url = href
|
||||
media_attachment.save
|
||||
|
|
|
@ -44,7 +44,7 @@ class FetchAtomService < BaseService
|
|||
json = body_to_json(body)
|
||||
if supported_context?(json) && json['type'] == 'Person' && json['inbox'].present?
|
||||
[json['id'], { prefetched_body: body, id: true }, :activitypub]
|
||||
elsif supported_context?(json) && json['type'] == 'Note'
|
||||
elsif supported_context?(json) && expected_type?(json)
|
||||
[json['id'], { prefetched_body: body, id: true }, :activitypub]
|
||||
else
|
||||
@unsupported_activity = true
|
||||
|
@ -61,6 +61,10 @@ class FetchAtomService < BaseService
|
|||
end
|
||||
end
|
||||
|
||||
def expected_type?(json)
|
||||
(ActivityPub::Activity::Create::SUPPORTED_TYPES + ActivityPub::Activity::Create::CONVERTED_TYPES).include? json['type']
|
||||
end
|
||||
|
||||
def process_html(response)
|
||||
page = Nokogiri::HTML(response.body_with_limit)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class ResolveURLService < BaseService
|
|||
case type
|
||||
when 'Person'
|
||||
FetchRemoteAccountService.new.call(atom_url, body, protocol)
|
||||
when 'Note'
|
||||
when 'Note', 'Article', 'Image', 'Video'
|
||||
FetchRemoteStatusService.new.call(atom_url, body, protocol)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
"file-loader": "^0.11.2",
|
||||
"font-awesome": "^4.7.0",
|
||||
"glob": "^7.1.1",
|
||||
"hammerjs": "^2.0.8",
|
||||
"http-link-header": "^0.8.0",
|
||||
"immutable": "^3.8.2",
|
||||
"imports-loader": "^0.8.0",
|
||||
|
|
|
@ -3096,6 +3096,10 @@ gzip-size@^3.0.0:
|
|||
dependencies:
|
||||
duplexer "^0.1.1"
|
||||
|
||||
hammerjs@^2.0.8:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
|
||||
|
||||
handle-thing@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4"
|
||||
|
|
Loading…
Reference in a new issue