forked from treehouse/mastodon
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/controllers/statuses_controller.rb minor conflict because of glitch-soc's theming system - app/controllers/stream_entries_controller.rb minor conflict because of glitch-soc's theming systemsignup-info-prompt
commit
68629f2773
|
@ -10,6 +10,7 @@ DB_NAME=postgres
|
||||||
DB_PASS=
|
DB_PASS=
|
||||||
DB_PORT=5432
|
DB_PORT=5432
|
||||||
# Optional ElasticSearch configuration
|
# Optional ElasticSearch configuration
|
||||||
|
# You may also set ES_PREFIX to share the same cluster between multiple Mastodon servers (falls back to REDIS_NAMESPACE if not set)
|
||||||
# ES_ENABLED=true
|
# ES_ENABLED=true
|
||||||
# ES_HOST=es
|
# ES_HOST=es
|
||||||
# ES_PORT=9200
|
# ES_PORT=9200
|
||||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -3,6 +3,18 @@ Changelog
|
||||||
|
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [2.8.2] - 2019-05-05
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Add `SOURCE_TAG` environment variable ([ushitora-anqou](https://github.com/tootsuite/mastodon/pull/10698))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fix cropped hero image on frontpage ([BaptisteGelez](https://github.com/tootsuite/mastodon/pull/10702))
|
||||||
|
- Fix blurhash gem not compiling on some operating systems ([Gargron](https://github.com/tootsuite/mastodon/pull/10700))
|
||||||
|
- Fix unexpected CSS animations in some browsers ([ThibG](https://github.com/tootsuite/mastodon/pull/10699))
|
||||||
|
- Fix closing video modal scrolling timelines to top ([ThibG](https://github.com/tootsuite/mastodon/pull/10695))
|
||||||
|
|
||||||
## [2.8.1] - 2019-05-04
|
## [2.8.1] - 2019-05-04
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
|
2
Gemfile
2
Gemfile
|
@ -117,7 +117,7 @@ group :test do
|
||||||
gem 'rspec-sidekiq', '~> 3.0'
|
gem 'rspec-sidekiq', '~> 3.0'
|
||||||
gem 'simplecov', '~> 0.16', require: false
|
gem 'simplecov', '~> 0.16', require: false
|
||||||
gem 'webmock', '~> 3.5'
|
gem 'webmock', '~> 3.5'
|
||||||
gem 'parallel_tests', '~> 2.28'
|
gem 'parallel_tests', '~> 2.29'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
|
|
|
@ -395,7 +395,7 @@ GEM
|
||||||
av (~> 0.9.0)
|
av (~> 0.9.0)
|
||||||
paperclip (>= 2.5.2)
|
paperclip (>= 2.5.2)
|
||||||
parallel (1.17.0)
|
parallel (1.17.0)
|
||||||
parallel_tests (2.28.0)
|
parallel_tests (2.29.0)
|
||||||
parallel
|
parallel
|
||||||
parser (2.6.3.0)
|
parser (2.6.3.0)
|
||||||
ast (~> 2.4.0)
|
ast (~> 2.4.0)
|
||||||
|
@ -480,7 +480,7 @@ GEM
|
||||||
link_header (~> 0.0, >= 0.0.8)
|
link_header (~> 0.0, >= 0.0.8)
|
||||||
rdf-normalize (0.3.3)
|
rdf-normalize (0.3.3)
|
||||||
rdf (>= 2.2, < 4.0)
|
rdf (>= 2.2, < 4.0)
|
||||||
redis (4.1.0)
|
redis (4.1.1)
|
||||||
redis-actionpack (5.0.2)
|
redis-actionpack (5.0.2)
|
||||||
actionpack (>= 4.0, < 6)
|
actionpack (>= 4.0, < 6)
|
||||||
redis-rack (>= 1, < 3)
|
redis-rack (>= 1, < 3)
|
||||||
|
@ -727,7 +727,7 @@ DEPENDENCIES
|
||||||
ox (~> 2.10)
|
ox (~> 2.10)
|
||||||
paperclip (~> 6.0)
|
paperclip (~> 6.0)
|
||||||
paperclip-av-transcoder (~> 0.6)
|
paperclip-av-transcoder (~> 0.6)
|
||||||
parallel_tests (~> 2.28)
|
parallel_tests (~> 2.29)
|
||||||
pg (~> 1.1)
|
pg (~> 1.1)
|
||||||
pghero (~> 2.2)
|
pghero (~> 2.2)
|
||||||
pkg-config (~> 1.3)
|
pkg-config (~> 1.3)
|
||||||
|
|
|
@ -28,7 +28,11 @@ class StatusesController < ApplicationController
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
use_pack 'public'
|
use_pack 'public'
|
||||||
mark_cacheable! unless user_signed_in?
|
|
||||||
|
unless user_signed_in?
|
||||||
|
skip_session!
|
||||||
|
expires_in 10.seconds, public: true
|
||||||
|
end
|
||||||
|
|
||||||
@body_classes = 'with-modals'
|
@body_classes = 'with-modals'
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,12 @@ class StreamEntriesController < ApplicationController
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
use_pack 'public'
|
use_pack 'public'
|
||||||
|
|
||||||
|
unless user_signed_in?
|
||||||
|
skip_session!
|
||||||
|
expires_in 5.minutes, public: true
|
||||||
|
end
|
||||||
|
|
||||||
redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status'
|
redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) if @type == 'status'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -383,7 +383,7 @@ export function readyComposeSuggestionsAccounts(token, accounts) {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export function selectComposeSuggestion(position, token, suggestion) {
|
export function selectComposeSuggestion(position, token, suggestion, path) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
let completion, startPosition;
|
let completion, startPosition;
|
||||||
|
|
||||||
|
@ -405,6 +405,7 @@ export function selectComposeSuggestion(position, token, suggestion) {
|
||||||
position: startPosition,
|
position: startPosition,
|
||||||
token,
|
token,
|
||||||
completion,
|
completion,
|
||||||
|
path,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,229 @@
|
||||||
|
import React from 'react';
|
||||||
|
import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
|
||||||
|
import AutosuggestEmoji from './autosuggest_emoji';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { isRtl } from '../rtl';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
import { List as ImmutableList } from 'immutable';
|
||||||
|
|
||||||
|
const textAtCursorMatchesToken = (str, caretPosition, searchTokens) => {
|
||||||
|
let word;
|
||||||
|
|
||||||
|
let left = str.slice(0, caretPosition).search(/\S+$/);
|
||||||
|
let right = str.slice(caretPosition).search(/\s/);
|
||||||
|
|
||||||
|
if (right < 0) {
|
||||||
|
word = str.slice(left);
|
||||||
|
} else {
|
||||||
|
word = str.slice(left, right + caretPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!word || word.trim().length < 3 || searchTokens.indexOf(word[0]) === -1) {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
|
||||||
|
word = word.trim().toLowerCase();
|
||||||
|
|
||||||
|
if (word.length > 0) {
|
||||||
|
return [left + 1, word];
|
||||||
|
} else {
|
||||||
|
return [null, null];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class AutosuggestInput extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
value: PropTypes.string,
|
||||||
|
suggestions: ImmutablePropTypes.list,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
onSuggestionSelected: PropTypes.func.isRequired,
|
||||||
|
onSuggestionsClearRequested: PropTypes.func.isRequired,
|
||||||
|
onSuggestionsFetchRequested: PropTypes.func.isRequired,
|
||||||
|
onChange: PropTypes.func.isRequired,
|
||||||
|
onKeyUp: PropTypes.func,
|
||||||
|
onKeyDown: PropTypes.func,
|
||||||
|
autoFocus: PropTypes.bool,
|
||||||
|
className: PropTypes.string,
|
||||||
|
id: PropTypes.string,
|
||||||
|
searchTokens: PropTypes.list,
|
||||||
|
maxLength: PropTypes.number,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
autoFocus: true,
|
||||||
|
searchTokens: ImmutableList(['@', ':', '#']),
|
||||||
|
};
|
||||||
|
|
||||||
|
state = {
|
||||||
|
suggestionsHidden: true,
|
||||||
|
focused: false,
|
||||||
|
selectedSuggestion: 0,
|
||||||
|
lastToken: null,
|
||||||
|
tokenStart: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
onChange = (e) => {
|
||||||
|
const [ tokenStart, token ] = textAtCursorMatchesToken(e.target.value, e.target.selectionStart, this.props.searchTokens);
|
||||||
|
|
||||||
|
if (token !== null && this.state.lastToken !== token) {
|
||||||
|
this.setState({ lastToken: token, selectedSuggestion: 0, tokenStart });
|
||||||
|
this.props.onSuggestionsFetchRequested(token);
|
||||||
|
} else if (token === null) {
|
||||||
|
this.setState({ lastToken: null });
|
||||||
|
this.props.onSuggestionsClearRequested();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onChange(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
onKeyDown = (e) => {
|
||||||
|
const { suggestions, disabled } = this.props;
|
||||||
|
const { selectedSuggestion, suggestionsHidden } = this.state;
|
||||||
|
|
||||||
|
if (disabled) {
|
||||||
|
e.preventDefault();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.which === 229 || e.isComposing) {
|
||||||
|
// Ignore key events during text composition
|
||||||
|
// e.key may be a name of the physical key even in this case (e.x. Safari / Chrome on Mac)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(e.key) {
|
||||||
|
case 'Escape':
|
||||||
|
if (suggestions.size === 0 || suggestionsHidden) {
|
||||||
|
document.querySelector('.ui').parentElement.focus();
|
||||||
|
} else {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ suggestionsHidden: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ArrowDown':
|
||||||
|
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ selectedSuggestion: Math.min(selectedSuggestion + 1, suggestions.size - 1) });
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'ArrowUp':
|
||||||
|
if (suggestions.size > 0 && !suggestionsHidden) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.setState({ selectedSuggestion: Math.max(selectedSuggestion - 1, 0) });
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'Enter':
|
||||||
|
case 'Tab':
|
||||||
|
// Select suggestion
|
||||||
|
if (this.state.lastToken !== null && suggestions.size > 0 && !suggestionsHidden) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestions.get(selectedSuggestion));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.defaultPrevented || !this.props.onKeyDown) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.onKeyDown(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
onBlur = () => {
|
||||||
|
this.setState({ suggestionsHidden: true, focused: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus = () => {
|
||||||
|
this.setState({ focused: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionClick = (e) => {
|
||||||
|
const suggestion = this.props.suggestions.get(e.currentTarget.getAttribute('data-index'));
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onSuggestionSelected(this.state.tokenStart, this.state.lastToken, suggestion);
|
||||||
|
this.input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillReceiveProps (nextProps) {
|
||||||
|
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
||||||
|
this.setState({ suggestionsHidden: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setInput = (c) => {
|
||||||
|
this.input = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuggestion = (suggestion, i) => {
|
||||||
|
const { selectedSuggestion } = this.state;
|
||||||
|
let inner, key;
|
||||||
|
|
||||||
|
if (typeof suggestion === 'object') {
|
||||||
|
inner = <AutosuggestEmoji emoji={suggestion} />;
|
||||||
|
key = suggestion.id;
|
||||||
|
} else if (suggestion[0] === '#') {
|
||||||
|
inner = suggestion;
|
||||||
|
key = suggestion;
|
||||||
|
} else {
|
||||||
|
inner = <AutosuggestAccountContainer id={suggestion} />;
|
||||||
|
key = suggestion;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div role='button' tabIndex='0' key={key} data-index={i} className={classNames('autosuggest-textarea__suggestions__item', { selected: i === selectedSuggestion })} onMouseDown={this.onSuggestionClick}>
|
||||||
|
{inner}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { value, suggestions, disabled, placeholder, onKeyUp, autoFocus, className, id, maxLength } = this.props;
|
||||||
|
const { suggestionsHidden } = this.state;
|
||||||
|
const style = { direction: 'ltr' };
|
||||||
|
|
||||||
|
if (isRtl(value)) {
|
||||||
|
style.direction = 'rtl';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='autosuggest-input'>
|
||||||
|
<label>
|
||||||
|
<span style={{ display: 'none' }}>{placeholder}</span>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
ref={this.setInput}
|
||||||
|
disabled={disabled}
|
||||||
|
placeholder={placeholder}
|
||||||
|
autoFocus={autoFocus}
|
||||||
|
value={value}
|
||||||
|
onChange={this.onChange}
|
||||||
|
onKeyDown={this.onKeyDown}
|
||||||
|
onKeyUp={onKeyUp}
|
||||||
|
onFocus={this.onFocus}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
style={style}
|
||||||
|
aria-autocomplete='list'
|
||||||
|
id={id}
|
||||||
|
className={className}
|
||||||
|
maxLength={maxLength}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
|
||||||
|
{suggestions.map(this.renderSuggestion)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -55,7 +55,8 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
suggestionsHidden: false,
|
suggestionsHidden: true,
|
||||||
|
focused: false,
|
||||||
selectedSuggestion: 0,
|
selectedSuggestion: 0,
|
||||||
lastToken: null,
|
lastToken: null,
|
||||||
tokenStart: 0,
|
tokenStart: 0,
|
||||||
|
@ -134,7 +135,11 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlur = () => {
|
onBlur = () => {
|
||||||
this.setState({ suggestionsHidden: true });
|
this.setState({ suggestionsHidden: true, focused: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onFocus = () => {
|
||||||
|
this.setState({ focused: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuggestionClick = (e) => {
|
onSuggestionClick = (e) => {
|
||||||
|
@ -145,7 +150,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps (nextProps) {
|
componentWillReceiveProps (nextProps) {
|
||||||
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden) {
|
if (nextProps.suggestions !== this.props.suggestions && nextProps.suggestions.size > 0 && this.state.suggestionsHidden && this.state.focused) {
|
||||||
this.setState({ suggestionsHidden: false });
|
this.setState({ suggestionsHidden: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,6 +212,7 @@ export default class AutosuggestTextarea extends ImmutablePureComponent {
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
onKeyUp={onKeyUp}
|
onKeyUp={onKeyUp}
|
||||||
|
onFocus={this.onFocus}
|
||||||
onBlur={this.onBlur}
|
onBlur={this.onBlur}
|
||||||
onPaste={this.onPaste}
|
onPaste={this.onPaste}
|
||||||
style={style}
|
style={style}
|
||||||
|
|
|
@ -69,19 +69,19 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
onModalReblog (status) {
|
onModalReblog (status) {
|
||||||
dispatch(reblog(status));
|
|
||||||
},
|
|
||||||
|
|
||||||
onReblog (status, e) {
|
|
||||||
if (status.get('reblogged')) {
|
if (status.get('reblogged')) {
|
||||||
dispatch(unreblog(status));
|
dispatch(unreblog(status));
|
||||||
} else {
|
} else {
|
||||||
|
dispatch(reblog(status));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onReblog (status, e) {
|
||||||
if (e.shiftKey || !boostModal) {
|
if (e.shiftKey || !boostModal) {
|
||||||
this.onModalReblog(status);
|
this.onModalReblog(status);
|
||||||
} else {
|
} else {
|
||||||
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog }));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
onFavourite (status) {
|
onFavourite (status) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import Icon from 'mastodon/components/icon';
|
||||||
import { autoPlayGif, displayMedia } from 'mastodon/initial_state';
|
import { autoPlayGif, displayMedia } from 'mastodon/initial_state';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { decode } from 'blurhash';
|
import { decode } from 'blurhash';
|
||||||
|
@ -88,8 +89,10 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||||
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
|
const width = `${Math.floor((displayWidth - 4) / 3) - 4}px`;
|
||||||
const height = width;
|
const height = width;
|
||||||
const status = attachment.get('status');
|
const status = attachment.get('status');
|
||||||
|
const title = status.get('spoiler_text') || attachment.get('description');
|
||||||
|
|
||||||
let thumbnail = '';
|
let thumbnail = '';
|
||||||
|
let icon;
|
||||||
|
|
||||||
if (attachment.get('type') === 'unknown') {
|
if (attachment.get('type') === 'unknown') {
|
||||||
// Skip
|
// Skip
|
||||||
|
@ -131,11 +134,20 @@ export default class MediaItem extends ImmutablePureComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!visible) {
|
||||||
|
icon = (
|
||||||
|
<span className='account-gallery__item__icons'>
|
||||||
|
<Icon id='eye-slash' />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='account-gallery__item' style={{ width, height }}>
|
<div className='account-gallery__item' style={{ width, height }}>
|
||||||
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick}>
|
<a className='media-gallery__item-thumbnail' href={status.get('url')} target='_blank' onClick={this.handleClick} title={title}>
|
||||||
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />
|
<canvas width={32} height={32} ref={this.setCanvasRef} className={classNames('media-gallery__preview', { 'media-gallery__preview--hidden': visible && loaded })} />
|
||||||
{visible && thumbnail}
|
{visible && thumbnail}
|
||||||
|
{!visible && icon}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
import ReplyIndicatorContainer from '../containers/reply_indicator_container';
|
||||||
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
import AutosuggestTextarea from '../../../components/autosuggest_textarea';
|
||||||
|
import AutosuggestInput from '../../../components/autosuggest_input';
|
||||||
import PollButtonContainer from '../containers/poll_button_container';
|
import PollButtonContainer from '../containers/poll_button_container';
|
||||||
import UploadButtonContainer from '../containers/upload_button_container';
|
import UploadButtonContainer from '../containers/upload_button_container';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
@ -103,7 +104,11 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSuggestionSelected = (tokenStart, token, value) => {
|
onSuggestionSelected = (tokenStart, token, value) => {
|
||||||
this.props.onSuggestionSelected(tokenStart, token, value);
|
this.props.onSuggestionSelected(tokenStart, token, value, ['text']);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSpoilerSuggestionSelected = (tokenStart, token, value) => {
|
||||||
|
this.props.onSuggestionSelected(tokenStart, token, value, ['spoiler_text']);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeSpoilerText = (e) => {
|
handleChangeSpoilerText = (e) => {
|
||||||
|
@ -136,7 +141,7 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
this.autosuggestTextarea.textarea.focus();
|
this.autosuggestTextarea.textarea.focus();
|
||||||
} else if (this.props.spoiler !== prevProps.spoiler) {
|
} else if (this.props.spoiler !== prevProps.spoiler) {
|
||||||
if (this.props.spoiler) {
|
if (this.props.spoiler) {
|
||||||
this.spoilerText.focus();
|
this.spoilerText.input.focus();
|
||||||
} else {
|
} else {
|
||||||
this.autosuggestTextarea.textarea.focus();
|
this.autosuggestTextarea.textarea.focus();
|
||||||
}
|
}
|
||||||
|
@ -179,10 +184,21 @@ class ComposeForm extends ImmutablePureComponent {
|
||||||
<ReplyIndicatorContainer />
|
<ReplyIndicatorContainer />
|
||||||
|
|
||||||
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
<div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`}>
|
||||||
<label>
|
<AutosuggestInput
|
||||||
<span style={{ display: 'none' }}>{intl.formatMessage(messages.spoiler_placeholder)}</span>
|
placeholder={intl.formatMessage(messages.spoiler_placeholder)}
|
||||||
<input placeholder={intl.formatMessage(messages.spoiler_placeholder)} value={this.props.spoilerText} onChange={this.handleChangeSpoilerText} onKeyDown={this.handleKeyDown} tabIndex={this.props.spoiler ? 0 : -1} type='text' className='spoiler-input__input' id='cw-spoiler-input' ref={this.setSpoilerText} />
|
value={this.props.spoilerText}
|
||||||
</label>
|
onChange={this.handleChangeSpoilerText}
|
||||||
|
onKeyDown={this.handleKeyDown}
|
||||||
|
disabled={!this.props.spoiler}
|
||||||
|
ref={this.setSpoilerText}
|
||||||
|
suggestions={this.props.suggestions}
|
||||||
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
|
onSuggestionSelected={this.onSpoilerSuggestionSelected}
|
||||||
|
searchTokens={[':']}
|
||||||
|
id='cw-spoiler-input'
|
||||||
|
className='spoiler-input__input'
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='compose-form__autosuggest-wrapper'>
|
<div className='compose-form__autosuggest-wrapper'>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import IconButton from 'mastodon/components/icon_button';
|
import IconButton from 'mastodon/components/icon_button';
|
||||||
import Icon from 'mastodon/components/icon';
|
import Icon from 'mastodon/components/icon';
|
||||||
|
import AutosuggestInput from 'mastodon/components/autosuggest_input';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -27,6 +28,10 @@ class Option extends React.PureComponent {
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
onRemove: PropTypes.func.isRequired,
|
onRemove: PropTypes.func.isRequired,
|
||||||
onToggleMultiple: PropTypes.func.isRequired,
|
onToggleMultiple: PropTypes.func.isRequired,
|
||||||
|
suggestions: ImmutablePropTypes.list,
|
||||||
|
onClearSuggestions: PropTypes.func.isRequired,
|
||||||
|
onFetchSuggestions: PropTypes.func.isRequired,
|
||||||
|
onSuggestionSelected: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -38,12 +43,25 @@ class Option extends React.PureComponent {
|
||||||
this.props.onRemove(this.props.index);
|
this.props.onRemove(this.props.index);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
handleToggleMultiple = e => {
|
handleToggleMultiple = e => {
|
||||||
this.props.onToggleMultiple();
|
this.props.onToggleMultiple();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onSuggestionsClearRequested = () => {
|
||||||
|
this.props.onClearSuggestions();
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionsFetchRequested = (token) => {
|
||||||
|
this.props.onFetchSuggestions(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuggestionSelected = (tokenStart, token, value) => {
|
||||||
|
this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { isPollMultiple, title, index, intl } = this.props;
|
const { isPollMultiple, title, index, intl } = this.props;
|
||||||
|
|
||||||
|
@ -57,12 +75,16 @@ class Option extends React.PureComponent {
|
||||||
tabIndex='0'
|
tabIndex='0'
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<input
|
<AutosuggestInput
|
||||||
type='text'
|
|
||||||
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
|
||||||
maxLength={25}
|
maxLength={25}
|
||||||
value={title}
|
value={title}
|
||||||
onChange={this.handleOptionTitleChange}
|
onChange={this.handleOptionTitleChange}
|
||||||
|
suggestions={this.props.suggestions}
|
||||||
|
onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
|
||||||
|
onSuggestionsClearRequested={this.onSuggestionsClearRequested}
|
||||||
|
onSuggestionSelected={this.onSuggestionSelected}
|
||||||
|
searchTokens={[':']}
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
|
@ -87,6 +109,10 @@ class PollForm extends ImmutablePureComponent {
|
||||||
onAddOption: PropTypes.func.isRequired,
|
onAddOption: PropTypes.func.isRequired,
|
||||||
onRemoveOption: PropTypes.func.isRequired,
|
onRemoveOption: PropTypes.func.isRequired,
|
||||||
onChangeSettings: PropTypes.func.isRequired,
|
onChangeSettings: PropTypes.func.isRequired,
|
||||||
|
suggestions: ImmutablePropTypes.list,
|
||||||
|
onClearSuggestions: PropTypes.func.isRequired,
|
||||||
|
onFetchSuggestions: PropTypes.func.isRequired,
|
||||||
|
onSuggestionSelected: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -103,7 +129,7 @@ class PollForm extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl } = this.props;
|
const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl, ...other } = this.props;
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -112,7 +138,7 @@ class PollForm extends ImmutablePureComponent {
|
||||||
return (
|
return (
|
||||||
<div className='compose-form__poll-wrapper'>
|
<div className='compose-form__poll-wrapper'>
|
||||||
<ul>
|
<ul>
|
||||||
{options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} />)}
|
{options.map((title, i) => <Option title={title} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} {...other} />)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className='poll__footer'>
|
<div className='poll__footer'>
|
||||||
|
|
|
@ -45,8 +45,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
dispatch(fetchComposeSuggestions(token));
|
dispatch(fetchComposeSuggestions(token));
|
||||||
},
|
},
|
||||||
|
|
||||||
onSuggestionSelected (position, token, suggestion) {
|
onSuggestionSelected (position, token, suggestion, path) {
|
||||||
dispatch(selectComposeSuggestion(position, token, suggestion));
|
dispatch(selectComposeSuggestion(position, token, suggestion, path));
|
||||||
},
|
},
|
||||||
|
|
||||||
onChangeSpoilerText (checked) {
|
onChangeSpoilerText (checked) {
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PollForm from '../components/poll_form';
|
import PollForm from '../components/poll_form';
|
||||||
import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose';
|
import { addPollOption, removePollOption, changePollOption, changePollSettings } from '../../../actions/compose';
|
||||||
|
import {
|
||||||
|
clearComposeSuggestions,
|
||||||
|
fetchComposeSuggestions,
|
||||||
|
selectComposeSuggestion,
|
||||||
|
} from '../../../actions/compose';
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
|
suggestions: state.getIn(['compose', 'suggestions']),
|
||||||
options: state.getIn(['compose', 'poll', 'options']),
|
options: state.getIn(['compose', 'poll', 'options']),
|
||||||
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
|
expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
|
||||||
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
|
isMultiple: state.getIn(['compose', 'poll', 'multiple']),
|
||||||
|
@ -24,6 +30,19 @@ const mapDispatchToProps = dispatch => ({
|
||||||
onChangeSettings(expiresIn, isMultiple) {
|
onChangeSettings(expiresIn, isMultiple) {
|
||||||
dispatch(changePollSettings(expiresIn, isMultiple));
|
dispatch(changePollSettings(expiresIn, isMultiple));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onClearSuggestions () {
|
||||||
|
dispatch(clearComposeSuggestions());
|
||||||
|
},
|
||||||
|
|
||||||
|
onFetchSuggestions (token) {
|
||||||
|
dispatch(fetchComposeSuggestions(token));
|
||||||
|
},
|
||||||
|
|
||||||
|
onSuggestionSelected (position, token, accountId, path) {
|
||||||
|
dispatch(selectComposeSuggestion(position, token, accountId, path));
|
||||||
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PollForm);
|
export default connect(mapStateToProps, mapDispatchToProps)(PollForm);
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import Icon from 'mastodon/components/icon';
|
import Icon from 'mastodon/components/icon';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
cancel_reblog: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
|
||||||
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, intl } = this.props;
|
const { status, intl } = this.props;
|
||||||
|
const buttonText = status.get('reblogged') ? messages.cancel_reblog : messages.reblog;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='modal-root__modal boost-modal'>
|
<div className='modal-root__modal boost-modal'>
|
||||||
|
@ -76,7 +78,7 @@ class BoostModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
<div className='boost-modal__action-bar'>
|
<div className='boost-modal__action-bar'>
|
||||||
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
|
<div><FormattedMessage id='boost_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <Icon id='retweet' /></span> }} /></div>
|
||||||
<Button text={intl.formatMessage(messages.reblog)} onClick={this.handleReblog} ref={this.setRef} />
|
<Button text={intl.formatMessage(buttonText)} onClick={this.handleReblog} ref={this.setRef} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
"account.hide_reblogs": "Amaga els impulsos de @{name}",
|
"account.hide_reblogs": "Amaga els impulsos de @{name}",
|
||||||
"account.link_verified_on": "La propietat d'aquest enllaç es va verificar el dia {date}",
|
"account.link_verified_on": "La propietat d'aquest enllaç es va verificar el dia {date}",
|
||||||
"account.locked_info": "Aquest estat de privadesa del compte està definit com a bloquejat. El propietari revisa manualment qui pot seguir-lo.",
|
"account.locked_info": "Aquest estat de privadesa del compte està definit com a bloquejat. El propietari revisa manualment qui pot seguir-lo.",
|
||||||
"account.media": "Media",
|
"account.media": "Mèdia",
|
||||||
"account.mention": "Esmentar @{name}",
|
"account.mention": "Esmentar @{name}",
|
||||||
"account.moved_to": "{name} s'ha mogut a:",
|
"account.moved_to": "{name} s'ha mogut a:",
|
||||||
"account.mute": "Silencia @{name}",
|
"account.mute": "Silencia @{name}",
|
||||||
|
@ -77,6 +77,7 @@
|
||||||
"compose_form.poll.remove_option": "Elimina aquesta opció",
|
"compose_form.poll.remove_option": "Elimina aquesta opció",
|
||||||
"compose_form.publish": "Toot",
|
"compose_form.publish": "Toot",
|
||||||
"compose_form.publish_loud": "{publish}!",
|
"compose_form.publish_loud": "{publish}!",
|
||||||
|
"compose_form.sensitive.hide": "Marcar mèdia com a sensible",
|
||||||
"compose_form.sensitive.marked": "Mèdia marcat com a sensible",
|
"compose_form.sensitive.marked": "Mèdia marcat com a sensible",
|
||||||
"compose_form.sensitive.unmarked": "Mèdia no està marcat com a sensible",
|
"compose_form.sensitive.unmarked": "Mèdia no està marcat com a sensible",
|
||||||
"compose_form.spoiler.marked": "Text es ocult sota l'avís",
|
"compose_form.spoiler.marked": "Text es ocult sota l'avís",
|
||||||
|
@ -85,7 +86,7 @@
|
||||||
"confirmation_modal.cancel": "Cancel·la",
|
"confirmation_modal.cancel": "Cancel·la",
|
||||||
"confirmations.block.block_and_report": "Block & Report",
|
"confirmations.block.block_and_report": "Block & Report",
|
||||||
"confirmations.block.confirm": "Bloca",
|
"confirmations.block.confirm": "Bloca",
|
||||||
"confirmations.block.message": "Estàs segur que vols blocar {name}?",
|
"confirmations.block.message": "Estàs segur que vols bloquejar a {name}?",
|
||||||
"confirmations.delete.confirm": "Suprimeix",
|
"confirmations.delete.confirm": "Suprimeix",
|
||||||
"confirmations.delete.message": "Estàs segur que vols suprimir aquest estat?",
|
"confirmations.delete.message": "Estàs segur que vols suprimir aquest estat?",
|
||||||
"confirmations.delete_list.confirm": "Suprimeix",
|
"confirmations.delete_list.confirm": "Suprimeix",
|
||||||
|
@ -125,7 +126,7 @@
|
||||||
"empty_column.favourited_statuses": "Encara no tens cap toot favorit. Quan en tinguis, apareixerà aquí.",
|
"empty_column.favourited_statuses": "Encara no tens cap toot favorit. Quan en tinguis, apareixerà aquí.",
|
||||||
"empty_column.favourites": "Encara ningú ha marcat aquest toot com a favorit. Quan algú ho faci, apareixera aquí.",
|
"empty_column.favourites": "Encara ningú ha marcat aquest toot com a favorit. Quan algú ho faci, apareixera aquí.",
|
||||||
"empty_column.follow_requests": "Encara no teniu cap petició de seguiment. Quan rebeu una, apareixerà aquí.",
|
"empty_column.follow_requests": "Encara no teniu cap petició de seguiment. Quan rebeu una, apareixerà aquí.",
|
||||||
"empty_column.hashtag": "Encara no hi ha res amb aquesta etiqueta.",
|
"empty_column.hashtag": "Encara no hi ha res en aquesta etiqueta.",
|
||||||
"empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.",
|
"empty_column.home": "Encara no segueixes ningú. Visita {public} o fes cerca per començar i conèixer altres usuaris.",
|
||||||
"empty_column.home.public_timeline": "la línia de temps pública",
|
"empty_column.home.public_timeline": "la línia de temps pública",
|
||||||
"empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous estats, apareixeran aquí.",
|
"empty_column.list": "Encara no hi ha res en aquesta llista. Quan els membres d'aquesta llista publiquin nous estats, apareixeran aquí.",
|
||||||
|
@ -209,6 +210,7 @@
|
||||||
"lightbox.close": "Tancar",
|
"lightbox.close": "Tancar",
|
||||||
"lightbox.next": "Següent",
|
"lightbox.next": "Següent",
|
||||||
"lightbox.previous": "Anterior",
|
"lightbox.previous": "Anterior",
|
||||||
|
"lightbox.view_context": "Veure el context",
|
||||||
"lists.account.add": "Afegir a la llista",
|
"lists.account.add": "Afegir a la llista",
|
||||||
"lists.account.remove": "Treure de la llista",
|
"lists.account.remove": "Treure de la llista",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
|
@ -340,7 +342,6 @@
|
||||||
"status.reply": "Respondre",
|
"status.reply": "Respondre",
|
||||||
"status.replyAll": "Respondre al tema",
|
"status.replyAll": "Respondre al tema",
|
||||||
"status.report": "Informar sobre @{name}",
|
"status.report": "Informar sobre @{name}",
|
||||||
"status.sensitive_toggle": "Clic per veure",
|
|
||||||
"status.sensitive_warning": "Contingut sensible",
|
"status.sensitive_warning": "Contingut sensible",
|
||||||
"status.share": "Compartir",
|
"status.share": "Compartir",
|
||||||
"status.show_less": "Mostra menys",
|
"status.show_less": "Mostra menys",
|
||||||
|
|
|
@ -180,10 +180,6 @@
|
||||||
{
|
{
|
||||||
"defaultMessage": "Media hidden",
|
"defaultMessage": "Media hidden",
|
||||||
"id": "status.media_hidden"
|
"id": "status.media_hidden"
|
||||||
},
|
|
||||||
{
|
|
||||||
"defaultMessage": "Click to view",
|
|
||||||
"id": "status.sensitive_toggle"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/components/media_gallery.json"
|
"path": "app/javascript/mastodon/components/media_gallery.json"
|
||||||
|
@ -1096,6 +1092,10 @@
|
||||||
{
|
{
|
||||||
"defaultMessage": "Media is not marked as sensitive",
|
"defaultMessage": "Media is not marked as sensitive",
|
||||||
"id": "compose_form.sensitive.unmarked"
|
"id": "compose_form.sensitive.unmarked"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaultMessage": "Mark media as sensitive",
|
||||||
|
"id": "compose_form.sensitive.hide"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/compose/containers/sensitive_button_container.json"
|
"path": "app/javascript/mastodon/features/compose/containers/sensitive_button_container.json"
|
||||||
|
@ -2262,6 +2262,10 @@
|
||||||
{
|
{
|
||||||
"defaultMessage": "Next",
|
"defaultMessage": "Next",
|
||||||
"id": "lightbox.next"
|
"id": "lightbox.next"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaultMessage": "View context",
|
||||||
|
"id": "lightbox.view_context"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/ui/components/media_modal.json"
|
"path": "app/javascript/mastodon/features/ui/components/media_modal.json"
|
||||||
|
@ -2354,6 +2358,15 @@
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/ui/components/upload_area.json"
|
"path": "app/javascript/mastodon/features/ui/components/upload_area.json"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"descriptors": [
|
||||||
|
{
|
||||||
|
"defaultMessage": "View context",
|
||||||
|
"id": "lightbox.view_context"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"path": "app/javascript/mastodon/features/ui/components/video_modal.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
|
@ -2408,10 +2421,6 @@
|
||||||
{
|
{
|
||||||
"defaultMessage": "Media hidden",
|
"defaultMessage": "Media hidden",
|
||||||
"id": "status.media_hidden"
|
"id": "status.media_hidden"
|
||||||
},
|
|
||||||
{
|
|
||||||
"defaultMessage": "Click to view",
|
|
||||||
"id": "status.sensitive_toggle"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/video/index.json"
|
"path": "app/javascript/mastodon/features/video/index.json"
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
"compose_form.poll.remove_option": "Remove this choice",
|
"compose_form.poll.remove_option": "Remove this choice",
|
||||||
"compose_form.publish": "Toot",
|
"compose_form.publish": "Toot",
|
||||||
"compose_form.publish_loud": "{publish}!",
|
"compose_form.publish_loud": "{publish}!",
|
||||||
|
"compose_form.sensitive.hide": "Mark media as sensitive",
|
||||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||||
|
@ -213,6 +214,7 @@
|
||||||
"lightbox.close": "Close",
|
"lightbox.close": "Close",
|
||||||
"lightbox.next": "Next",
|
"lightbox.next": "Next",
|
||||||
"lightbox.previous": "Previous",
|
"lightbox.previous": "Previous",
|
||||||
|
"lightbox.view_context": "View context",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Add to list",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Remove from list",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
|
@ -345,7 +347,6 @@
|
||||||
"status.reply": "Reply",
|
"status.reply": "Reply",
|
||||||
"status.replyAll": "Reply to thread",
|
"status.replyAll": "Reply to thread",
|
||||||
"status.report": "Report @{name}",
|
"status.report": "Report @{name}",
|
||||||
"status.sensitive_toggle": "Click to view",
|
|
||||||
"status.sensitive_warning": "Sensitive content",
|
"status.sensitive_warning": "Sensitive content",
|
||||||
"status.share": "Share",
|
"status.share": "Share",
|
||||||
"status.show_less": "Show less",
|
"status.show_less": "Show less",
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
"compose_form.poll.remove_option": "この項目を削除",
|
"compose_form.poll.remove_option": "この項目を削除",
|
||||||
"compose_form.publish": "トゥート",
|
"compose_form.publish": "トゥート",
|
||||||
"compose_form.publish_loud": "{publish}!",
|
"compose_form.publish_loud": "{publish}!",
|
||||||
|
"compose_form.sensitive.hide": "メディアを閲覧注意にする",
|
||||||
"compose_form.sensitive.marked": "メディアに閲覧注意が設定されています",
|
"compose_form.sensitive.marked": "メディアに閲覧注意が設定されています",
|
||||||
"compose_form.sensitive.unmarked": "メディアに閲覧注意が設定されていません",
|
"compose_form.sensitive.unmarked": "メディアに閲覧注意が設定されていません",
|
||||||
"compose_form.spoiler.marked": "閲覧注意が設定されています",
|
"compose_form.spoiler.marked": "閲覧注意が設定されています",
|
||||||
|
@ -213,6 +214,7 @@
|
||||||
"lightbox.close": "閉じる",
|
"lightbox.close": "閉じる",
|
||||||
"lightbox.next": "次",
|
"lightbox.next": "次",
|
||||||
"lightbox.previous": "前",
|
"lightbox.previous": "前",
|
||||||
|
"lightbox.view_context": "トゥートを表示",
|
||||||
"lists.account.add": "リストに追加",
|
"lists.account.add": "リストに追加",
|
||||||
"lists.account.remove": "リストから外す",
|
"lists.account.remove": "リストから外す",
|
||||||
"lists.delete": "リストを削除",
|
"lists.delete": "リストを削除",
|
||||||
|
@ -345,7 +347,6 @@
|
||||||
"status.reply": "返信",
|
"status.reply": "返信",
|
||||||
"status.replyAll": "全員に返信",
|
"status.replyAll": "全員に返信",
|
||||||
"status.report": "@{name}さんを通報",
|
"status.report": "@{name}さんを通報",
|
||||||
"status.sensitive_toggle": "クリックして表示",
|
|
||||||
"status.sensitive_warning": "閲覧注意",
|
"status.sensitive_warning": "閲覧注意",
|
||||||
"status.share": "共有",
|
"status.share": "共有",
|
||||||
"status.show_less": "隠す",
|
"status.show_less": "隠す",
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
"compose_form.poll.remove_option": "Deze keuze verwijderen",
|
"compose_form.poll.remove_option": "Deze keuze verwijderen",
|
||||||
"compose_form.publish": "Toot",
|
"compose_form.publish": "Toot",
|
||||||
"compose_form.publish_loud": "{publish}!",
|
"compose_form.publish_loud": "{publish}!",
|
||||||
|
"compose_form.sensitive.hide": "Media als gevoelig markeren",
|
||||||
"compose_form.sensitive.marked": "Media is als gevoelig gemarkeerd",
|
"compose_form.sensitive.marked": "Media is als gevoelig gemarkeerd",
|
||||||
"compose_form.sensitive.unmarked": "Media is niet als gevoelig gemarkeerd",
|
"compose_form.sensitive.unmarked": "Media is niet als gevoelig gemarkeerd",
|
||||||
"compose_form.spoiler.marked": "Tekst is achter een waarschuwing verborgen",
|
"compose_form.spoiler.marked": "Tekst is achter een waarschuwing verborgen",
|
||||||
|
|
|
@ -131,13 +131,15 @@ function removeMedia(state, mediaId) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const insertSuggestion = (state, position, token, completion) => {
|
const insertSuggestion = (state, position, token, completion, path) => {
|
||||||
return state.withMutations(map => {
|
return state.withMutations(map => {
|
||||||
map.update('text', oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`);
|
map.updateIn(path, oldText => `${oldText.slice(0, position)}${completion} ${oldText.slice(position + token.length)}`);
|
||||||
map.set('suggestion_token', null);
|
map.set('suggestion_token', null);
|
||||||
map.update('suggestions', ImmutableList(), list => list.clear());
|
map.set('suggestions', ImmutableList());
|
||||||
|
if (path.length === 1 && path[0] === 'text') {
|
||||||
map.set('focusDate', new Date());
|
map.set('focusDate', new Date());
|
||||||
map.set('caretPosition', position + completion.length + 1);
|
map.set('caretPosition', position + completion.length + 1);
|
||||||
|
}
|
||||||
map.set('idempotencyKey', uuid());
|
map.set('idempotencyKey', uuid());
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -304,7 +306,7 @@ export default function compose(state = initialState, action) {
|
||||||
case COMPOSE_SUGGESTIONS_READY:
|
case COMPOSE_SUGGESTIONS_READY:
|
||||||
return state.set('suggestions', ImmutableList(action.accounts ? action.accounts.map(item => item.id) : action.emojis)).set('suggestion_token', action.token);
|
return state.set('suggestions', ImmutableList(action.accounts ? action.accounts.map(item => item.id) : action.emojis)).set('suggestion_token', action.token);
|
||||||
case COMPOSE_SUGGESTION_SELECT:
|
case COMPOSE_SUGGESTION_SELECT:
|
||||||
return insertSuggestion(state, action.position, action.token, action.completion);
|
return insertSuggestion(state, action.position, action.token, action.completion, action.path);
|
||||||
case COMPOSE_SUGGESTION_TAGS_UPDATE:
|
case COMPOSE_SUGGESTION_TAGS_UPDATE:
|
||||||
return updateSuggestionTags(state, action.token);
|
return updateSuggestionTags(state, action.token);
|
||||||
case COMPOSE_TAG_HISTORY_UPDATE:
|
case COMPOSE_TAG_HISTORY_UPDATE:
|
||||||
|
|
|
@ -67,3 +67,11 @@
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nothing-here {
|
||||||
|
color: $darker-text-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.public-layout .public-account-header__tabs__tabs .counter.active::after {
|
||||||
|
border-bottom: 4px solid $ui-highlight-color;
|
||||||
|
}
|
||||||
|
|
|
@ -319,6 +319,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.autosuggest-textarea,
|
.autosuggest-textarea,
|
||||||
|
.autosuggest-input,
|
||||||
.spoiler-input {
|
.spoiler-input {
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
@ -4829,6 +4830,14 @@ a.status-card.compact:hover {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
|
|
||||||
|
&__icons {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification__filter-bar,
|
.notification__filter-bar,
|
||||||
|
|
|
@ -37,11 +37,14 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.autossugest-input {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
input[type=text] {
|
input[type=text] {
|
||||||
display: block;
|
display: block;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex: 1 1 auto;
|
width: 100%;
|
||||||
width: 20px;
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: $inverted-text-color;
|
color: $inverted-text-color;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -64,6 +67,7 @@
|
||||||
&.editable {
|
&.editable {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
overflow: visible;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,11 +118,14 @@
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
|
|
||||||
&:hover,
|
&:hover {
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
|
&:focus {
|
||||||
|
background-color: rgba($dark-text-color, .1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
|
|
|
@ -65,9 +65,16 @@ class ActivityPub::TagManager
|
||||||
when 'unlisted', 'private'
|
when 'unlisted', 'private'
|
||||||
[account_followers_url(status.account)]
|
[account_followers_url(status.account)]
|
||||||
when 'direct', 'limited'
|
when 'direct', 'limited'
|
||||||
|
if status.account.silenced?
|
||||||
|
# Only notify followers if the account is locally silenced
|
||||||
|
account_ids = status.active_mentions.pluck(:account_id)
|
||||||
|
to = status.account.followers.where(id: account_ids).map { |account| uri_for(account) }
|
||||||
|
to.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })
|
||||||
|
else
|
||||||
status.active_mentions.map { |mention| uri_for(mention.account) }
|
status.active_mentions.map { |mention| uri_for(mention.account) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Secondary audience of a status
|
# Secondary audience of a status
|
||||||
# Public statuses go out to followers as well
|
# Public statuses go out to followers as well
|
||||||
|
@ -86,7 +93,16 @@ class ActivityPub::TagManager
|
||||||
cc << COLLECTIONS[:public]
|
cc << COLLECTIONS[:public]
|
||||||
end
|
end
|
||||||
|
|
||||||
cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility? || status.limited_visibility?
|
unless status.direct_visibility? || status.limited_visibility?
|
||||||
|
if status.account.silenced?
|
||||||
|
# Only notify followers if the account is locally silenced
|
||||||
|
account_ids = status.active_mentions.pluck(:account_id)
|
||||||
|
cc.concat(status.account.followers.where(id: account_ids).map { |account| uri_for(account) })
|
||||||
|
cc.concat(FollowRequest.where(target_account_id: status.account_id, account_id: account_ids).map { |request| uri_for(request.account) })
|
||||||
|
else
|
||||||
|
cc.concat(status.active_mentions.map { |mention| uri_for(mention.account) })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
cc
|
cc
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,7 @@ class Form::StatusBatch
|
||||||
def delete_statuses
|
def delete_statuses
|
||||||
Status.where(id: status_ids).reorder(nil).find_each do |status|
|
Status.where(id: status_ids).reorder(nil).find_each do |status|
|
||||||
RemovalWorker.perform_async(status.id)
|
RemovalWorker.perform_async(status.id)
|
||||||
|
Tombstone.find_or_create_by(uri: status.uri, account: status.account, by_moderator: true)
|
||||||
log_action :destroy, status
|
log_action :destroy, status
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
# uri :string not null
|
# uri :string not null
|
||||||
# created_at :datetime not null
|
# created_at :datetime not null
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
|
# by_moderator :boolean
|
||||||
#
|
#
|
||||||
|
|
||||||
class Tombstone < ApplicationRecord
|
class Tombstone < ApplicationRecord
|
||||||
|
|
|
@ -269,6 +269,7 @@ ca:
|
||||||
created_msg: El bloqueig de domini ara s'està processant
|
created_msg: El bloqueig de domini ara s'està processant
|
||||||
destroyed_msg: El bloqueig de domini s'ha desfet
|
destroyed_msg: El bloqueig de domini s'ha desfet
|
||||||
domain: Domini
|
domain: Domini
|
||||||
|
existing_domain_block_html: Ja has imposat uns limits més estrictes a %{name}, l'hauries de <a href="%{unblock_url}">desbloquejar-lo</a> primer.
|
||||||
new:
|
new:
|
||||||
create: Crea un bloqueig
|
create: Crea un bloqueig
|
||||||
hint: El bloqueig de domini no impedirà la creació de nous comptes en la base de dades, però s'aplicaran de manera retroactiva mètodes de moderació específics sobre aquests comptes.
|
hint: El bloqueig de domini no impedirà la creació de nous comptes en la base de dades, però s'aplicaran de manera retroactiva mètodes de moderació específics sobre aquests comptes.
|
||||||
|
@ -655,7 +656,7 @@ ca:
|
||||||
invalid_token: Els tokens de Keybase són hashs de signatures i han de tenir 66 caràcters hexadecimals
|
invalid_token: Els tokens de Keybase són hashs de signatures i han de tenir 66 caràcters hexadecimals
|
||||||
verification_failed: Keybase no reconeix aquest token com a signatura del usuari de Keybase %{kb_username}. Si us plau prova des de Keybase.
|
verification_failed: Keybase no reconeix aquest token com a signatura del usuari de Keybase %{kb_username}. Si us plau prova des de Keybase.
|
||||||
wrong_user: No es pot crear una prova per a %{proving} mentre es connectava com a %{current}. Inicia sessió com a %{proving} i prova de nou.
|
wrong_user: No es pot crear una prova per a %{proving} mentre es connectava com a %{current}. Inicia sessió com a %{proving} i prova de nou.
|
||||||
explanation_html: Aquí pots connectar criptogràficament les teves altres identitats com ara el teu perfil de Keybase. Això permet que altres persones t'envïin missatges xifrats i continguts de confiança que els hi enviess.
|
explanation_html: Aquí pots connectar criptogràficament les teves altres identitats com ara el teu perfil de Keybase. Això permet que altres persones t'envïin missatges xifrats i confiar en el contingut que els hi envies.
|
||||||
i_am_html: Sóc %{username} a %{service}.
|
i_am_html: Sóc %{username} a %{service}.
|
||||||
identity: Identitat
|
identity: Identitat
|
||||||
inactive: Inactiu
|
inactive: Inactiu
|
||||||
|
@ -675,7 +676,7 @@ ca:
|
||||||
blocking: Llista de blocats
|
blocking: Llista de blocats
|
||||||
domain_blocking: Llistat de dominis bloquejats
|
domain_blocking: Llistat de dominis bloquejats
|
||||||
following: Llista de seguits
|
following: Llista de seguits
|
||||||
muting: Llista d'apagats
|
muting: Llista de silenciats
|
||||||
upload: Carregar
|
upload: Carregar
|
||||||
in_memoriam_html: En Memòria.
|
in_memoriam_html: En Memòria.
|
||||||
invites:
|
invites:
|
||||||
|
@ -778,7 +779,7 @@ ca:
|
||||||
preferences:
|
preferences:
|
||||||
languages: Llengues
|
languages: Llengues
|
||||||
other: Altre
|
other: Altre
|
||||||
publishing: Publicació
|
publishing: Publicant
|
||||||
web: Web
|
web: Web
|
||||||
relationships:
|
relationships:
|
||||||
activity: Activitat del compte
|
activity: Activitat del compte
|
||||||
|
@ -922,7 +923,7 @@ ca:
|
||||||
sensitive_content: Contingut sensible
|
sensitive_content: Contingut sensible
|
||||||
terms:
|
terms:
|
||||||
body_html: |
|
body_html: |
|
||||||
<h2>Privacy Policy</h2>
|
<h2>Política de Privacitat</h2>
|
||||||
<h3 id="collect">Quina informació recollim?</h3>
|
<h3 id="collect">Quina informació recollim?</h3>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
|
|
|
@ -12,7 +12,7 @@ ja:
|
||||||
last_attempt: あと1回失敗するとアカウントがロックされます。
|
last_attempt: あと1回失敗するとアカウントがロックされます。
|
||||||
locked: アカウントはロックされました。
|
locked: アカウントはロックされました。
|
||||||
not_found_in_database: "%{authentication_keys}かパスワードが誤っています。"
|
not_found_in_database: "%{authentication_keys}かパスワードが誤っています。"
|
||||||
pending: あなたのアカウントはまだ審査中です。
|
pending: あなたのアカウントはまだ承認待ちです。
|
||||||
timeout: セッションの有効期限が切れました。続行するには再度ログインしてください。
|
timeout: セッションの有効期限が切れました。続行するには再度ログインしてください。
|
||||||
unauthenticated: 続行するにはログインするか、アカウントを作成してください。
|
unauthenticated: 続行するにはログインするか、アカウントを作成してください。
|
||||||
unconfirmed: 続行するにはメールアドレスを確認する必要があります。
|
unconfirmed: 続行するにはメールアドレスを確認する必要があります。
|
||||||
|
|
|
@ -4,17 +4,25 @@ fr:
|
||||||
about_hashtag_html: Figurent ci-dessous les pouets tagués avec <strong>#%{hashtag}</strong>. Vous pouvez interagir avec eux si vous avez un compte n’importe où dans le Fediverse.
|
about_hashtag_html: Figurent ci-dessous les pouets tagués avec <strong>#%{hashtag}</strong>. Vous pouvez interagir avec eux si vous avez un compte n’importe où dans le Fediverse.
|
||||||
about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé.
|
about_mastodon_html: Mastodon est un réseau social utilisant des formats ouverts et des logiciels libres. Comme le courriel, il est décentralisé.
|
||||||
about_this: À propos
|
about_this: À propos
|
||||||
|
active_count_after: actif·ve·s
|
||||||
|
active_footnote: Utilisateur·rice·s actif·ve·s mensuels (MAU)
|
||||||
administered_by: 'Administrée par :'
|
administered_by: 'Administrée par :'
|
||||||
api: API
|
api: API
|
||||||
apps: Applications mobiles
|
apps: Applications mobiles
|
||||||
|
apps_platforms: Utilisez Mastodon depuis iOS, Android et d’autres plates-formes
|
||||||
|
browse_directory: Parcourir l’annuaire des profils et filtrer par centres d’intérêt
|
||||||
|
browse_public_posts: Parcourir un flux en direct de messages publics sur Mastodon
|
||||||
contact: Contact
|
contact: Contact
|
||||||
contact_missing: Manquant
|
contact_missing: Manquant
|
||||||
contact_unavailable: Non disponible
|
contact_unavailable: Non disponible
|
||||||
|
discover_users: Découvrez des utilisateur·rice·s
|
||||||
documentation: Documentation
|
documentation: Documentation
|
||||||
extended_description_html: |
|
extended_description_html: |
|
||||||
<h3>Un bon endroit pour les règles</h3>
|
<h3>Un bon endroit pour les règles</h3>
|
||||||
<p>La description étendue n’a pas été remplie.</p>
|
<p>La description étendue n’a pas été remplie.</p>
|
||||||
|
federation_hint_html: Avec un compte sur %{instance}, vous pourrez suivre les gens sur n’importe quel serveur Mastodon et au-delà.
|
||||||
generic_description: "%{domain} est seulement un serveur du réseau"
|
generic_description: "%{domain} est seulement un serveur du réseau"
|
||||||
|
get_apps: Essayez une application mobile
|
||||||
hosted_on: Serveur Mastodon hébergée par %{domain}
|
hosted_on: Serveur Mastodon hébergée par %{domain}
|
||||||
learn_more: En savoir plus
|
learn_more: En savoir plus
|
||||||
privacy_policy: Politique de vie privée
|
privacy_policy: Politique de vie privée
|
||||||
|
@ -23,7 +31,8 @@ fr:
|
||||||
one: Statut
|
one: Statut
|
||||||
other: Statuts
|
other: Statuts
|
||||||
status_count_before: Ayant publié
|
status_count_before: Ayant publié
|
||||||
terms: Conditions d'utilisation
|
tagline: Suivez vos ami·e·s et découvrez en de nouveaux·elles
|
||||||
|
terms: Conditions d’utilisation
|
||||||
user_count_after:
|
user_count_after:
|
||||||
one: utilisateur
|
one: utilisateur
|
||||||
other: utilisateurs
|
other: utilisateurs
|
||||||
|
@ -113,15 +122,18 @@ fr:
|
||||||
moderation:
|
moderation:
|
||||||
active: Actif
|
active: Actif
|
||||||
all: Tous
|
all: Tous
|
||||||
|
pending: En cours de traitement
|
||||||
silenced: Masqués
|
silenced: Masqués
|
||||||
suspended: Suspendus
|
suspended: Suspendus
|
||||||
title: Modération
|
title: Modération
|
||||||
moderation_notes: Notes de modération
|
moderation_notes: Notes de modération
|
||||||
most_recent_activity: Dernière activité
|
most_recent_activity: Dernière activité
|
||||||
most_recent_ip: Adresse IP la plus récente
|
most_recent_ip: Adresse IP la plus récente
|
||||||
|
no_account_selected: Aucun compte n’a été modifié, car aucun n’a été sélectionné
|
||||||
no_limits_imposed: Aucune limite imposée
|
no_limits_imposed: Aucune limite imposée
|
||||||
not_subscribed: Non abonné
|
not_subscribed: Non abonné
|
||||||
outbox_url: URL de sortie
|
outbox_url: URL de sortie
|
||||||
|
pending: En attente d’approbation
|
||||||
perform_full_suspension: Suspendre
|
perform_full_suspension: Suspendre
|
||||||
profile_url: URL du profil
|
profile_url: URL du profil
|
||||||
promote: Promouvoir
|
promote: Promouvoir
|
||||||
|
@ -129,8 +141,10 @@ fr:
|
||||||
public: Publique
|
public: Publique
|
||||||
push_subscription_expires: Expiration de l’abonnement PuSH
|
push_subscription_expires: Expiration de l’abonnement PuSH
|
||||||
redownload: Rafraîchir le profil
|
redownload: Rafraîchir le profil
|
||||||
|
reject: Rejeter
|
||||||
|
reject_all: Tout rejeter
|
||||||
remove_avatar: Supprimer l’avatar
|
remove_avatar: Supprimer l’avatar
|
||||||
remove_header: Supprimer l'entête
|
remove_header: Supprimer l’entête
|
||||||
resend_confirmation:
|
resend_confirmation:
|
||||||
already_confirmed: Cet·te utilisateur·ice est déjà confirmé·e
|
already_confirmed: Cet·te utilisateur·ice est déjà confirmé·e
|
||||||
send: Renvoyer un courriel de confirmation
|
send: Renvoyer un courriel de confirmation
|
||||||
|
@ -149,7 +163,7 @@ fr:
|
||||||
shared_inbox_url: URL de la boite de réception partagée
|
shared_inbox_url: URL de la boite de réception partagée
|
||||||
show:
|
show:
|
||||||
created_reports: Signalements faits
|
created_reports: Signalements faits
|
||||||
targeted_reports: Signalés par d'autres
|
targeted_reports: Signalés par d’autres
|
||||||
silence: Masquer
|
silence: Masquer
|
||||||
silenced: Silencié
|
silenced: Silencié
|
||||||
statuses: Statuts
|
statuses: Statuts
|
||||||
|
@ -173,7 +187,7 @@ fr:
|
||||||
create_domain_block: "%{name} a bloqué le domaine %{target}"
|
create_domain_block: "%{name} a bloqué le domaine %{target}"
|
||||||
create_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste noire"
|
create_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste noire"
|
||||||
demote_user: "%{name} a rétrogradé l’utilisateur·ice %{target}"
|
demote_user: "%{name} a rétrogradé l’utilisateur·ice %{target}"
|
||||||
destroy_custom_emoji: "%{name} a détruit l'émoticône %{target}"
|
destroy_custom_emoji: "%{name} a détruit l’émoticône %{target}"
|
||||||
destroy_domain_block: "%{name} a débloqué le domaine %{target}"
|
destroy_domain_block: "%{name} a débloqué le domaine %{target}"
|
||||||
destroy_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste blanche"
|
destroy_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste blanche"
|
||||||
destroy_status: "%{name} a enlevé le statut de %{target}"
|
destroy_status: "%{name} a enlevé le statut de %{target}"
|
||||||
|
@ -230,6 +244,7 @@ fr:
|
||||||
feature_profile_directory: Annuaire des profils
|
feature_profile_directory: Annuaire des profils
|
||||||
feature_registrations: Inscriptions
|
feature_registrations: Inscriptions
|
||||||
feature_relay: Relais de fédération
|
feature_relay: Relais de fédération
|
||||||
|
feature_timeline_preview: Aperçu du fil public
|
||||||
features: Fonctionnalités
|
features: Fonctionnalités
|
||||||
hidden_service: Fédération avec des services cachés
|
hidden_service: Fédération avec des services cachés
|
||||||
open_reports: signalements non résolus
|
open_reports: signalements non résolus
|
||||||
|
@ -249,6 +264,7 @@ fr:
|
||||||
created_msg: Le blocage de domaine est désormais activé
|
created_msg: Le blocage de domaine est désormais activé
|
||||||
destroyed_msg: Le blocage de domaine a été désactivé
|
destroyed_msg: Le blocage de domaine a été désactivé
|
||||||
domain: Domaine
|
domain: Domaine
|
||||||
|
existing_domain_block_html: Vous avez déjà imposé des limites plus strictes à %{name}, vous devez d’abord le <a href="%{unblock_url}">débloquer</a>.
|
||||||
new:
|
new:
|
||||||
create: Créer le blocage
|
create: Créer le blocage
|
||||||
hint: Le blocage de domaine n’empêchera pas la création de comptes dans la base de données, mais il appliquera automatiquement et rétrospectivement des méthodes de modération spécifiques sur ces comptes.
|
hint: Le blocage de domaine n’empêchera pas la création de comptes dans la base de données, mais il appliquera automatiquement et rétrospectivement des méthodes de modération spécifiques sur ces comptes.
|
||||||
|
@ -314,6 +330,8 @@ fr:
|
||||||
expired: Expiré
|
expired: Expiré
|
||||||
title: Filtre
|
title: Filtre
|
||||||
title: Invitations
|
title: Invitations
|
||||||
|
pending_accounts:
|
||||||
|
title: Comptes en attente (%{count})
|
||||||
relays:
|
relays:
|
||||||
add_new: Ajouter un nouveau relais
|
add_new: Ajouter un nouveau relais
|
||||||
delete: Effacer
|
delete: Effacer
|
||||||
|
@ -324,7 +342,7 @@ fr:
|
||||||
enable_hint: Une fois activé, votre serveur souscrira à tous les pouets publics présents sur ce relais et y enverra ses propres pouets publics.
|
enable_hint: Une fois activé, votre serveur souscrira à tous les pouets publics présents sur ce relais et y enverra ses propres pouets publics.
|
||||||
enabled: Activé
|
enabled: Activé
|
||||||
inbox_url: URL de relais
|
inbox_url: URL de relais
|
||||||
pending: En attente de l'approbation du relai
|
pending: En attente de l’approbation du relai
|
||||||
save_and_enable: Sauvegarder et activer
|
save_and_enable: Sauvegarder et activer
|
||||||
setup: Paramétrer une connexion de relais
|
setup: Paramétrer une connexion de relais
|
||||||
status: Statut
|
status: Statut
|
||||||
|
@ -373,13 +391,13 @@ fr:
|
||||||
email: Entrez une adresse courriel publique
|
email: Entrez une adresse courriel publique
|
||||||
username: Entrez un nom d’utilisateur⋅ice
|
username: Entrez un nom d’utilisateur⋅ice
|
||||||
custom_css:
|
custom_css:
|
||||||
desc_html: Modifier l'apparence avec une CSS chargée sur chaque page
|
desc_html: Modifier l’apparence avec une CSS chargée sur chaque page
|
||||||
title: CSS personnalisé
|
title: CSS personnalisé
|
||||||
hero:
|
hero:
|
||||||
desc_html: Affichée sur la page d’accueil. Au moins 600x100px recommandé. Lorsqu’elle n’est pas définie, se rabat sur la vignette du serveur
|
desc_html: Affichée sur la page d’accueil. Au moins 600x100px recommandé. Lorsqu’elle n’est pas définie, se rabat sur la vignette du serveur
|
||||||
title: Image d’en-tête
|
title: Image d’en-tête
|
||||||
mascot:
|
mascot:
|
||||||
desc_html: Affiché sur plusieurs pages. Au moins 293×205px recommandé. Lorsqu'il n'est pas défini, retombe à la mascotte par défaut
|
desc_html: Affiché sur plusieurs pages. Au moins 293×205px recommandé. Lorsqu’il n’est pas défini, retombe à la mascotte par défaut
|
||||||
title: Image de la mascotte
|
title: Image de la mascotte
|
||||||
peers_api_enabled:
|
peers_api_enabled:
|
||||||
desc_html: Noms des domaines que ce serveur a découvert dans le fediverse
|
desc_html: Noms des domaines que ce serveur a découvert dans le fediverse
|
||||||
|
@ -388,8 +406,8 @@ fr:
|
||||||
desc_html: Les liens de prévisualisation sur les autres sites web afficheront une vignette même si le média est sensible
|
desc_html: Les liens de prévisualisation sur les autres sites web afficheront une vignette même si le média est sensible
|
||||||
title: Afficher les médias sensibles dans les prévisualisations OpenGraph
|
title: Afficher les médias sensibles dans les prévisualisations OpenGraph
|
||||||
profile_directory:
|
profile_directory:
|
||||||
desc_html: Permettre aux utilisateurs d'être découverts
|
desc_html: Permettre aux utilisateurs d’être découverts
|
||||||
title: Activer l'annuaire des profils
|
title: Activer l’annuaire des profils
|
||||||
registrations:
|
registrations:
|
||||||
closed_message:
|
closed_message:
|
||||||
desc_html: Affiché sur la page d’accueil lorsque les inscriptions sont fermées<br>Vous pouvez utiliser des balises HTML
|
desc_html: Affiché sur la page d’accueil lorsque les inscriptions sont fermées<br>Vous pouvez utiliser des balises HTML
|
||||||
|
@ -400,6 +418,12 @@ fr:
|
||||||
min_invite_role:
|
min_invite_role:
|
||||||
disabled: Personne
|
disabled: Personne
|
||||||
title: Autoriser les invitations par
|
title: Autoriser les invitations par
|
||||||
|
registrations_mode:
|
||||||
|
modes:
|
||||||
|
approved: Approbation requise pour s’inscrire
|
||||||
|
none: Personne ne peut s’inscrire
|
||||||
|
open: N’importe qui peut s’inscrire
|
||||||
|
title: Mode d’enregistrement
|
||||||
show_known_fediverse_at_about_page:
|
show_known_fediverse_at_about_page:
|
||||||
desc_html: Lorsque l’option est activée, les pouets provenant de toutes les serveurs connues sont affichés dans la prévisualisation. Sinon, seuls les pouets locaux sont affichés.
|
desc_html: Lorsque l’option est activée, les pouets provenant de toutes les serveurs connues sont affichés dans la prévisualisation. Sinon, seuls les pouets locaux sont affichés.
|
||||||
title: Afficher le fediverse connu dans la prévisualisation du fil
|
title: Afficher le fediverse connu dans la prévisualisation du fil
|
||||||
|
@ -410,7 +434,7 @@ fr:
|
||||||
desc_html: Paragraphe introductif sur la page d’accueil. Décrivez ce qui rend spécifique ce serveur Mastodon et toute autre chose importante. Vous pouvez utiliser des balises HTML, en particulier <code><a></code> et <code><em></code>.
|
desc_html: Paragraphe introductif sur la page d’accueil. Décrivez ce qui rend spécifique ce serveur Mastodon et toute autre chose importante. Vous pouvez utiliser des balises HTML, en particulier <code><a></code> et <code><em></code>.
|
||||||
title: Description du serveur
|
title: Description du serveur
|
||||||
site_description_extended:
|
site_description_extended:
|
||||||
desc_html: L'endroit idéal pour afficher votre code de conduite, les règles, les guides et autres choses qui rendent votre serveur différent. Vous pouvez utiliser des balises HTML
|
desc_html: L’endroit idéal pour afficher votre code de conduite, les règles, les guides et autres choses qui rendent votre serveur différent. Vous pouvez utiliser des balises HTML
|
||||||
title: Description étendue du serveur
|
title: Description étendue du serveur
|
||||||
site_short_description:
|
site_short_description:
|
||||||
desc_html: Affichée dans la barre latérale et dans les méta-tags. Décrivez ce qui rend spécifique ce serveur Mastodon en un seul paragraphe. Si laissée vide, la description du serveur sera affiché par défaut.
|
desc_html: Affichée dans la barre latérale et dans les méta-tags. Décrivez ce qui rend spécifique ce serveur Mastodon en un seul paragraphe. Si laissée vide, la description du serveur sera affiché par défaut.
|
||||||
|
@ -449,19 +473,22 @@ fr:
|
||||||
tags:
|
tags:
|
||||||
accounts: Comptes
|
accounts: Comptes
|
||||||
hidden: Masqué
|
hidden: Masqué
|
||||||
hide: Masquer dans l'annuaire
|
hide: Masquer dans l’annuaire
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
title: Hashtags
|
title: Hashtags
|
||||||
unhide: Afficher dans l'annuaire
|
unhide: Afficher dans l’annuaire
|
||||||
visible: Visible
|
visible: Visible
|
||||||
title: Administration
|
title: Administration
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Ajouter un nouveau
|
add_new: Ajouter un nouveau
|
||||||
delete: Effacer
|
delete: Effacer
|
||||||
edit: Éditer
|
edit: Éditer
|
||||||
edit_preset: Éditer la présélection d'attention
|
edit_preset: Éditer la présélection d’avertissement
|
||||||
title: Gérer les présélections d'attention
|
title: Gérer les présélections d’avertissement
|
||||||
admin_mailer:
|
admin_mailer:
|
||||||
|
new_pending_account:
|
||||||
|
body: Les détails du nouveau compte se trouvent ci-dessous. Vous pouvez approuver ou rejeter cette demande.
|
||||||
|
subject: Nouveau compte à examiner sur %{instance} (%{username})
|
||||||
new_report:
|
new_report:
|
||||||
body: "%{reporter} a signalé %{target}"
|
body: "%{reporter} a signalé %{target}"
|
||||||
body_remote: Quelqu’un de %{domain} a signalé %{target}
|
body_remote: Quelqu’un de %{domain} a signalé %{target}
|
||||||
|
@ -482,7 +509,9 @@ fr:
|
||||||
warning: Soyez prudent⋅e avec ces données. Ne les partagez pas !
|
warning: Soyez prudent⋅e avec ces données. Ne les partagez pas !
|
||||||
your_token: Votre jeton d’accès
|
your_token: Votre jeton d’accès
|
||||||
auth:
|
auth:
|
||||||
|
apply_for_account: Demander une invitation
|
||||||
change_password: Mot de passe
|
change_password: Mot de passe
|
||||||
|
checkbox_agreement_html: J’accepte les <a href="%{rules_path}" target="_blank">règles du serveur</a> et les <a href="%{terms_path}" target="_blank">conditions de service</a>
|
||||||
confirm_email: Confirmer mon adresse mail
|
confirm_email: Confirmer mon adresse mail
|
||||||
delete_account: Supprimer le compte
|
delete_account: Supprimer le compte
|
||||||
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
delete_account_html: Si vous désirez supprimer votre compte, vous pouvez <a href="%{path}">cliquer ici</a>. Il vous sera demandé de confirmer cette action.
|
||||||
|
@ -498,10 +527,12 @@ fr:
|
||||||
cas: CAS
|
cas: CAS
|
||||||
saml: SAML
|
saml: SAML
|
||||||
register: S’inscrire
|
register: S’inscrire
|
||||||
|
registration_closed: "%{instance} n’accepte pas de nouveaux membres"
|
||||||
resend_confirmation: Envoyer à nouveau les consignes de confirmation
|
resend_confirmation: Envoyer à nouveau les consignes de confirmation
|
||||||
reset_password: Réinitialiser le mot de passe
|
reset_password: Réinitialiser le mot de passe
|
||||||
security: Sécurité
|
security: Sécurité
|
||||||
set_new_password: Définir le nouveau mot de passe
|
set_new_password: Définir le nouveau mot de passe
|
||||||
|
trouble_logging_in: Vous avez un problème pour vous connecter ?
|
||||||
authorize_follow:
|
authorize_follow:
|
||||||
already_following: Vous suivez déjà ce compte
|
already_following: Vous suivez déjà ce compte
|
||||||
error: Malheureusement, il y a eu une erreur en cherchant les détails du compte distant
|
error: Malheureusement, il y a eu une erreur en cherchant les détails du compte distant
|
||||||
|
@ -537,11 +568,11 @@ fr:
|
||||||
warning_title: Disponibilité du contenu disséminé
|
warning_title: Disponibilité du contenu disséminé
|
||||||
directories:
|
directories:
|
||||||
directory: Annuaire des profils
|
directory: Annuaire des profils
|
||||||
enabled: Vous êtes actuellement listé dans l'annuaire.
|
enabled: Vous êtes actuellement listé dans l’annuaire.
|
||||||
enabled_but_waiting: Vous avez choisi d'être listé dans l'annuaire, mais vous n'avez pas encore le nombre minimum de suiveurs (%{min_followers}) pour y être inscrit.
|
enabled_but_waiting: Vous avez choisi d’être listé dans l’annuaire, mais vous n’avez pas encore le nombre minimum de suiveurs (%{min_followers}) pour y être inscrit.
|
||||||
explanation: Découvrir des utilisateurs en se basant sur leurs centres d'intérêt
|
explanation: Découvrir des utilisateurs en se basant sur leurs centres d’intérêt
|
||||||
explore_mastodon: Explorer %{title}
|
explore_mastodon: Explorer %{title}
|
||||||
how_to_enable: Vous n'êtes pas encore inscrit dans l'annuaire. Vous pouvez vous inscrire ci-dessous. Utilisez des hashtags dans votre texte biographique pour être listé sous des hashtags spécifiques !
|
how_to_enable: Vous n’êtes pas encore inscrit dans l’annuaire. Vous pouvez vous inscrire ci-dessous. Utilisez des hashtags dans votre texte biographique pour être listé sous des hashtags spécifiques !
|
||||||
people:
|
people:
|
||||||
one: "%{count} personne"
|
one: "%{count} personne"
|
||||||
other: "%{count} personne"
|
other: "%{count} personne"
|
||||||
|
@ -557,6 +588,9 @@ fr:
|
||||||
content: Nous sommes désolé·e·s, mais quelque chose s’est mal passé de notre côté.
|
content: Nous sommes désolé·e·s, mais quelque chose s’est mal passé de notre côté.
|
||||||
title: Cette page n’est pas correcte
|
title: Cette page n’est pas correcte
|
||||||
noscript_html: Pour utiliser Mastodon, veuillez activer JavaScript. Sinon, essayez l’une des <a href="%{apps_path}">applications natives</a> pour Mastodon pour votre plate-forme.
|
noscript_html: Pour utiliser Mastodon, veuillez activer JavaScript. Sinon, essayez l’une des <a href="%{apps_path}">applications natives</a> pour Mastodon pour votre plate-forme.
|
||||||
|
existing_username_validator:
|
||||||
|
not_found: n’a pas trouvé d’utilisateur·rice local·e avec ce nom
|
||||||
|
not_found_multiple: n’a pas trouvé %{usernames}
|
||||||
exports:
|
exports:
|
||||||
archive_takeout:
|
archive_takeout:
|
||||||
date: Date
|
date: Date
|
||||||
|
@ -597,19 +631,41 @@ fr:
|
||||||
more: Davantage…
|
more: Davantage…
|
||||||
resources: Ressources
|
resources: Ressources
|
||||||
generic:
|
generic:
|
||||||
|
all: Tous
|
||||||
changes_saved_msg: Les modifications ont été enregistrées avec succès !
|
changes_saved_msg: Les modifications ont été enregistrées avec succès !
|
||||||
copy: Copier
|
copy: Copier
|
||||||
|
order_by: Classer par
|
||||||
save_changes: Enregistrer les modifications
|
save_changes: Enregistrer les modifications
|
||||||
validation_errors:
|
validation_errors:
|
||||||
one: Quelque chose ne va pas ! Vérifiez l’erreur ci-dessous
|
one: Quelque chose ne va pas ! Vérifiez l’erreur ci-dessous
|
||||||
other: Certaines choses ne vont pas ! Vérifiez les %{count} erreurs ci-dessous
|
other: Certaines choses ne vont pas ! Vérifiez les %{count} erreurs ci-dessous
|
||||||
|
html_validator:
|
||||||
|
invalid_markup: 'contient un balisage HTML invalide: %{error}'
|
||||||
|
identity_proofs:
|
||||||
|
active: Actif
|
||||||
|
authorize: Oui, autoriser
|
||||||
|
authorize_connection_prompt: Autoriser cette connexion chiffrée ?
|
||||||
|
errors:
|
||||||
|
failed: La connexion chiffrée a échoué. Veuillez réessayer à partir de %{provider}.
|
||||||
|
keybase:
|
||||||
|
invalid_token: Les jetons Keybase sont des hachages de signatures et doivent comporter 66 caractères hexadécimaux
|
||||||
|
verification_failed: Keybase ne reconnaît pas ce jeton comme une signature de l’utilisateur Keybase %{kb_username}. Veuillez réessayer à partir de Keybase.
|
||||||
|
wrong_user: Impossible de créer une preuve pour %{proving} lorsque vous êtes connecté en tant que %{current}. Connectez-vous en tant que %{proving} et réessayez.
|
||||||
|
explanation_html: Ici, vous pouvez connecter de manière chiffrée vos autres identités, par exemple un profil Keybase. Cela permet à d’autres personnes de vous envoyer des messages chiffrés et de faire confiance au contenu que vous leur envoyez.
|
||||||
|
i_am_html: Je suis %{username} sur %{service}.
|
||||||
|
identity: Identité
|
||||||
|
inactive: Inactif
|
||||||
|
publicize_checkbox: 'Et le poueter:'
|
||||||
|
publicize_toot: 'C’est prouvé ! Je suis %{username} sur %{service}: %{url}'
|
||||||
|
status: Statut de vérification
|
||||||
|
view_proof: Voir la preuve
|
||||||
imports:
|
imports:
|
||||||
modes:
|
modes:
|
||||||
merge: Fusionner
|
merge: Fusionner
|
||||||
merge_long: Garder les enregistrements existants et ajouter les nouveaux
|
merge_long: Garder les enregistrements existants et ajouter les nouveaux
|
||||||
overwrite: Réécrire
|
overwrite: Réécrire
|
||||||
overwrite_long: Remplacer les enregistrements actuels par les nouveaux
|
overwrite_long: Remplacer les enregistrements actuels par les nouveaux
|
||||||
preface: Vous pouvez importer certaines données que vous avez exporté d'un autre serveur, comme une liste des personnes que vous suivez ou bloquez sur votre compte.
|
preface: Vous pouvez importer certaines données que vous avez exporté d’un autre serveur, comme une liste des personnes que vous suivez ou bloquez sur votre compte.
|
||||||
success: Vos données ont été importées avec succès et seront traitées en temps et en heure
|
success: Vos données ont été importées avec succès et seront traitées en temps et en heure
|
||||||
types:
|
types:
|
||||||
blocking: Liste d’utilisateur⋅ice⋅s bloqué⋅e⋅s
|
blocking: Liste d’utilisateur⋅ice⋅s bloqué⋅e⋅s
|
||||||
|
@ -713,13 +769,26 @@ fr:
|
||||||
duration_too_short: est trop tôt
|
duration_too_short: est trop tôt
|
||||||
expired: Ce sondage est déjà terminé
|
expired: Ce sondage est déjà terminé
|
||||||
over_character_limit: ne peuvent être plus long que %{max} caractères chacun
|
over_character_limit: ne peuvent être plus long que %{max} caractères chacun
|
||||||
too_few_options: doit avoir plus qu'une proposition
|
too_few_options: doit avoir plus qu’une proposition
|
||||||
too_many_options: ne peut contenir plus que %{max} propositions
|
too_many_options: ne peut contenir plus que %{max} propositions
|
||||||
preferences:
|
preferences:
|
||||||
languages: Langues
|
languages: Langues
|
||||||
other: Autre
|
other: Autre
|
||||||
publishing: Publication
|
publishing: Publication
|
||||||
web: Web
|
web: Web
|
||||||
|
relationships:
|
||||||
|
activity: Activité du compte
|
||||||
|
dormant: Dormant
|
||||||
|
last_active: Dernière activité
|
||||||
|
most_recent: Plus récent
|
||||||
|
moved: Déménagé
|
||||||
|
mutual: Mutuel
|
||||||
|
primary: Primaire
|
||||||
|
relationship: Relation
|
||||||
|
remove_selected_domains: Supprimer tous les abonné·e·s des domaines sélectionnés
|
||||||
|
remove_selected_followers: Supprimer les abonné·e·s sélectionnés
|
||||||
|
remove_selected_follows: Cesser de suivre les utilisateur·rice·s sélectionné·e·s
|
||||||
|
status: Statut du compte
|
||||||
remote_follow:
|
remote_follow:
|
||||||
acct: Entrez l’adresse profil@serveur depuis laquelle vous voulez vous abonner
|
acct: Entrez l’adresse profil@serveur depuis laquelle vous voulez vous abonner
|
||||||
missing_resource: L’URL de redirection n’a pas pu être trouvée
|
missing_resource: L’URL de redirection n’a pas pu être trouvée
|
||||||
|
@ -729,7 +798,7 @@ fr:
|
||||||
reason_html: "<strong>Pourquoi cette étape est-elle nécessaire?</strong> <code>%{instance}</code> pourrait ne pas être le serveur où vous vous êtes inscrit, et nous devons donc vous rediriger vers votre serveur de base en premier."
|
reason_html: "<strong>Pourquoi cette étape est-elle nécessaire?</strong> <code>%{instance}</code> pourrait ne pas être le serveur où vous vous êtes inscrit, et nous devons donc vous rediriger vers votre serveur de base en premier."
|
||||||
remote_interaction:
|
remote_interaction:
|
||||||
favourite:
|
favourite:
|
||||||
proceed: Confirmer l'ajout aux favoris
|
proceed: Confirmer l’ajout aux favoris
|
||||||
prompt: 'Vous souhaitez mettre ce pouet en favori :'
|
prompt: 'Vous souhaitez mettre ce pouet en favori :'
|
||||||
reblog:
|
reblog:
|
||||||
proceed: Confirmer le repartage
|
proceed: Confirmer le repartage
|
||||||
|
@ -787,6 +856,9 @@ fr:
|
||||||
revoke_success: Session révoquée avec succès
|
revoke_success: Session révoquée avec succès
|
||||||
title: Sessions
|
title: Sessions
|
||||||
settings:
|
settings:
|
||||||
|
account: Compte
|
||||||
|
account_settings: Paramètres du compte
|
||||||
|
appearance: Apparence
|
||||||
authorized_apps: Applications autorisées
|
authorized_apps: Applications autorisées
|
||||||
back: Retour vers Mastodon
|
back: Retour vers Mastodon
|
||||||
delete: Suppression de compte
|
delete: Suppression de compte
|
||||||
|
@ -794,10 +866,13 @@ fr:
|
||||||
edit_profile: Modifier le profil
|
edit_profile: Modifier le profil
|
||||||
export: Export de données
|
export: Export de données
|
||||||
featured_tags: Hashtags mis en avant
|
featured_tags: Hashtags mis en avant
|
||||||
|
identity_proofs: Preuves d’identité
|
||||||
import: Import de données
|
import: Import de données
|
||||||
migrate: Migration de compte
|
migrate: Migration de compte
|
||||||
notifications: Notifications
|
notifications: Notifications
|
||||||
preferences: Préférences
|
preferences: Préférences
|
||||||
|
profile: Profil
|
||||||
|
relationships: Abonnements et abonné·e·s
|
||||||
two_factor_authentication: Identification à deux facteurs
|
two_factor_authentication: Identification à deux facteurs
|
||||||
statuses:
|
statuses:
|
||||||
attached:
|
attached:
|
||||||
|
@ -954,8 +1029,8 @@ fr:
|
||||||
title: Récupération de l’archive
|
title: Récupération de l’archive
|
||||||
warning:
|
warning:
|
||||||
explanation:
|
explanation:
|
||||||
disable: Lorsque votre compte est gelé, les données de votre compte demeurent intactes, mais vous ne pouvez effectuer aucune action jusqu'à ce qu'il soit débloqué.
|
disable: Lorsque votre compte est gelé, les données de votre compte demeurent intactes, mais vous ne pouvez effectuer aucune action jusqu’à ce qu’il soit débloqué.
|
||||||
silence: Lorsque votre compte est limité, seulement les utilisateurs qui vous suivent déjà verront vos pouets sur ce serveur, et vous pourriez être exclu de plusieurs listes publiques. Néanmoins, d'autres utilisateurs peuvent vous suivre manuellement.
|
silence: Lorsque votre compte est limité, seulement les utilisateurs qui vous suivent déjà verront vos pouets sur ce serveur, et vous pourriez être exclu de plusieurs listes publiques. Néanmoins, d’autres utilisateurs peuvent vous suivre manuellement.
|
||||||
suspend: Votre compte a été suspendu, et tous vos pouets et vos fichiers multimédia téléversés ont été supprimés irréversiblement de ce serveur, et des serveurs où vous aviez des abonné⋅e⋅s.
|
suspend: Votre compte a été suspendu, et tous vos pouets et vos fichiers multimédia téléversés ont été supprimés irréversiblement de ce serveur, et des serveurs où vous aviez des abonné⋅e⋅s.
|
||||||
review_server_policies: Passer en revue les politiques du serveur
|
review_server_policies: Passer en revue les politiques du serveur
|
||||||
subject:
|
subject:
|
||||||
|
@ -993,5 +1068,5 @@ fr:
|
||||||
seamless_external_login: Vous êtes connecté via un service externe, donc les paramètres concernant le mot de passe et le courriel ne sont pas disponibles.
|
seamless_external_login: Vous êtes connecté via un service externe, donc les paramètres concernant le mot de passe et le courriel ne sont pas disponibles.
|
||||||
signed_in_as: 'Connecté·e en tant que :'
|
signed_in_as: 'Connecté·e en tant que :'
|
||||||
verification:
|
verification:
|
||||||
explanation_html: 'Vous pouvez <strong>vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil</strong>. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour <strong>doit</strong>avoir un attribut <code>rel="me"</code>. Le contenu textuel du lien n''a pas d''importance. En voici un exemple :'
|
explanation_html: 'Vous pouvez <strong>vérifier vous-même que vous êtes le propriétaire des liens dans les métadonnées de votre profil</strong>. Pour cela, le site Web lié doit contenir un lien vers votre profil Mastodon. Le lien de retour <strong>doit</strong>avoir un attribut <code>rel="me"</code>. Le contenu textuel du lien n’a pas d’importance. En voici un exemple :'
|
||||||
verification: Vérification
|
verification: Vérification
|
||||||
|
|
|
@ -20,7 +20,7 @@ ja:
|
||||||
extended_description_html: |
|
extended_description_html: |
|
||||||
<h3>ルールを書くのに適した場所</h3>
|
<h3>ルールを書くのに適した場所</h3>
|
||||||
<p>詳細説明が設定されていません。</p>
|
<p>詳細説明が設定されていません。</p>
|
||||||
federation_hint_html: "%{instance} にアカウントがあればどの互換性のあるサーバーのユーザーでもフォローできるでしょう。"
|
federation_hint_html: "%{instance} のアカウントひとつでどんなMastodon互換サーバーのユーザーでもフォローできるでしょう。"
|
||||||
generic_description: "%{domain} は、Mastodon サーバーの一つです"
|
generic_description: "%{domain} は、Mastodon サーバーの一つです"
|
||||||
get_apps: モバイルアプリを試す
|
get_apps: モバイルアプリを試す
|
||||||
hosted_on: Mastodon hosted on %{domain}
|
hosted_on: Mastodon hosted on %{domain}
|
||||||
|
@ -269,6 +269,7 @@ ja:
|
||||||
created_msg: ドメインブロック処理を完了しました
|
created_msg: ドメインブロック処理を完了しました
|
||||||
destroyed_msg: ドメインブロックを外しました
|
destroyed_msg: ドメインブロックを外しました
|
||||||
domain: ドメイン
|
domain: ドメイン
|
||||||
|
existing_domain_block_html: 既に%{name}に対しより厳しい制限を課しています 。まずは<a href="%{unblock_url}">それを解除する</a>必要があります。
|
||||||
new:
|
new:
|
||||||
create: ブロックを作成
|
create: ブロックを作成
|
||||||
hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。
|
hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。
|
||||||
|
@ -660,7 +661,7 @@ ja:
|
||||||
i_am_html: I am %{username} on %{service}.
|
i_am_html: I am %{username} on %{service}.
|
||||||
identity: Identity
|
identity: Identity
|
||||||
inactive: 非アクティブ
|
inactive: 非アクティブ
|
||||||
publicize_checkbox: 'そしてこれをトゥートしてください:'
|
publicize_checkbox: 'そしてこれをトゥートします:'
|
||||||
publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'
|
publicize_toot: 'It is proven! I am %{username} on %{service}: %{url}'
|
||||||
status: 認証状態
|
status: 認証状態
|
||||||
view_proof: 証明を表示
|
view_proof: 証明を表示
|
||||||
|
@ -1051,19 +1052,19 @@ ja:
|
||||||
suspend: アカウントが停止されました
|
suspend: アカウントが停止されました
|
||||||
welcome:
|
welcome:
|
||||||
edit_profile_action: プロフィールを設定
|
edit_profile_action: プロフィールを設定
|
||||||
edit_profile_step: アバター画像やヘッダー画像をアップロードしたり、表示名やその他プロフィールを変更しカスタマイズすることができます。新しいフォロワーからのフォローを許可する前に検討したい場合、アカウントを承認制にすることができます。
|
edit_profile_step: アイコンやヘッダーの画像をアップロードしたり、表示名を変更したりして、自分のプロフィールをカスタマイズすることができます。また、誰かからの新規フォローを許可する前にその人の様子を見ておきたい場合、アカウントを承認制にすることもできます。
|
||||||
explanation: 始めるにあたってのアドバイスです
|
explanation: 始めるにあたってのアドバイスです
|
||||||
final_action: 始めましょう
|
final_action: 始めましょう
|
||||||
final_step: 'さあ始めましょう! たとえフォロワーがいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどで誰かの目に止まるかもしれません。自己紹介をしたい時は #introductions ハッシュタグを使うといいかもしれません。'
|
final_step: 'さあ、始めましょう! たとえフォロワーがまだいなくても、あなたの公開した投稿はローカルタイムラインやハッシュタグなどを通じて誰かの目にとまるはずです。自己紹介をしたいときには #introductions ハッシュタグが便利かもしれません。'
|
||||||
full_handle: あなたの正式なユーザー名
|
full_handle: あなたの正式なユーザーID
|
||||||
full_handle_hint: これは別のサーバーからフォローしてもらったりメッセージのやり取りをする際に、友達に伝えるといいでしょう。
|
full_handle_hint: 別のサーバーの友達とフォローやメッセージをやり取りする際には、これを伝えることになります。
|
||||||
review_preferences_action: 設定の変更
|
review_preferences_action: 設定の変更
|
||||||
review_preferences_step: 受け取りたいメールや投稿の公開範囲などの設定を必ず行ってください。不快でないならアニメーション GIF の自動再生を有効にすることもできます。
|
review_preferences_step: 受け取りたいメールの種類や投稿のデフォルト公開範囲など、ユーザー設定を必ず済ませておきましょう。目が回らない自信があるなら、アニメーション GIF を自動再生する設定もご検討ください。
|
||||||
subject: Mastodon へようこそ
|
subject: Mastodon へようこそ
|
||||||
tip_federated_timeline: 連合タイムラインは Mastodon ネットワークの流れを見られるものです。ただしあなたと同じサーバーの人がフォローしている人だけが含まれるので、それが全てではありません。
|
tip_federated_timeline: 連合タイムラインは、Mastodon ネットワークによる巨大流しそうめんです。ただし、あなたの「隣人」達がフォローしている人々だけが流れてくる場所なので、決してそこに全てがあるわけではありません。
|
||||||
tip_following: 標準では自動でサーバーの管理者をフォローしています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してください。
|
tip_following: 最初は、サーバーの管理者をフォローした状態になっています。もっと興味のある人たちを見つけるには、ローカルタイムラインと連合タイムラインを確認してみましょう。
|
||||||
tip_local_timeline: ローカルタイムラインは %{instance} にいる人々の流れを見られるものです。彼らはあなたと同じサーバーにいる隣人のようなものです!
|
tip_local_timeline: ローカルタイムラインには、%{instance} にいる人々が流しそうめんのごとく流れてきます。彼らはあなたと同じサーバーに暮らす、愛すべき隣人です!
|
||||||
tip_mobile_webapp: もしモバイル端末のブラウザで Mastodon をホーム画面に追加できる場合、プッシュ通知を受け取ることができます。それはまるでネイティブアプリのように動作します!
|
tip_mobile_webapp: お使いのモバイル端末で、ブラウザから Mastodon をホーム画面に追加できますか? もし追加できる場合、プッシュ通知の受け取りなど、まるで「普通の」アプリのような機能が楽しめます!
|
||||||
tips: 豆知識
|
tips: 豆知識
|
||||||
title: ようこそ、%{name}!
|
title: ようこそ、%{name}!
|
||||||
users:
|
users:
|
||||||
|
|
|
@ -5,8 +5,8 @@ fr:
|
||||||
account_warning_preset:
|
account_warning_preset:
|
||||||
text: Vous pouvez utiliser la syntaxe des pouets, comme les URLs, les hashtags et les mentions
|
text: Vous pouvez utiliser la syntaxe des pouets, comme les URLs, les hashtags et les mentions
|
||||||
admin_account_action:
|
admin_account_action:
|
||||||
send_email_notification: L'utilisateur recevra une explication de ce qu'il s'est passé avec son compte
|
send_email_notification: L’utilisateur recevra une explication de ce qu’il s’est passé avec son compte
|
||||||
text_html: Optionnel. Vous pouvez utilisez la syntaxe des pouets. Vous pouvez <a href="%{path}">ajouter des présélections d'attention</a> pour économiser du temps
|
text_html: Optionnel. Vous pouvez utilisez la syntaxe des pouets. Vous pouvez <a href="%{path}">ajouter des présélections d’attention</a> pour économiser du temps
|
||||||
type_html: Choisir que faire avec <strong>%{acct}</strong>
|
type_html: Choisir que faire avec <strong>%{acct}</strong>
|
||||||
warning_preset_id: Optionnel. Vous pouvez toujours ajouter un texte personnalisé à la fin de la présélection
|
warning_preset_id: Optionnel. Vous pouvez toujours ajouter un texte personnalisé à la fin de la présélection
|
||||||
defaults:
|
defaults:
|
||||||
|
@ -15,7 +15,7 @@ fr:
|
||||||
bot: Ce compte exécute principalement des actions automatisées et pourrait ne pas être surveillé
|
bot: Ce compte exécute principalement des actions automatisées et pourrait ne pas être surveillé
|
||||||
context: Un ou plusieurs contextes où le filtre devrait s’appliquer
|
context: Un ou plusieurs contextes où le filtre devrait s’appliquer
|
||||||
digest: Uniquement envoyé après une longue période d’inactivité et uniquement si vous avez reçu des messages personnels pendant votre absence
|
digest: Uniquement envoyé après une longue période d’inactivité et uniquement si vous avez reçu des messages personnels pendant votre absence
|
||||||
discoverable_html: L'<a href="%{path}" target="_blank">annuaire</a> permet aux gens de trouver des comptes en se basant sur les intérêts et les activités. Nécessite au moins %{min_followers} abonnés
|
discoverable_html: L’<a href="%{path}" target="_blank">annuaire</a> permet aux gens de trouver des comptes en se basant sur les intérêts et les activités. Nécessite au moins %{min_followers} abonnés
|
||||||
email: Vous recevrez un courriel de confirmation
|
email: Vous recevrez un courriel de confirmation
|
||||||
fields: Vous pouvez avoir jusqu’à 4 éléments affichés en tant que tableau sur votre profil
|
fields: Vous pouvez avoir jusqu’à 4 éléments affichés en tant que tableau sur votre profil
|
||||||
header: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px
|
header: Au format PNG, GIF ou JPG. %{size} maximum. Sera réduit à %{dimensions}px
|
||||||
|
@ -26,21 +26,23 @@ fr:
|
||||||
password: Utilisez au moins 8 caractères
|
password: Utilisez au moins 8 caractères
|
||||||
phrase: Sera trouvé sans que la case ou l’avertissement de contenu du pouet soit pris en compte
|
phrase: Sera trouvé sans que la case ou l’avertissement de contenu du pouet soit pris en compte
|
||||||
scopes: À quelles APIs l’application sera autorisée à accéder. Si vous sélectionnez un périmètre de haut-niveau, vous n’avez pas besoin de sélectionner les individuels.
|
scopes: À quelles APIs l’application sera autorisée à accéder. Si vous sélectionnez un périmètre de haut-niveau, vous n’avez pas besoin de sélectionner les individuels.
|
||||||
setting_aggregate_reblogs: Ne pas afficher de nouveaux repartagés pour les pouets qui ont été récemment repartagés (n'affecte que les repartagés nouvellement reçus)
|
setting_aggregate_reblogs: Ne pas afficher de nouveaux repartagés pour les pouets qui ont été récemment repartagés (n’affecte que les repartagés nouvellement reçus)
|
||||||
setting_default_language: La langue de vos pouets peut être détectée automatiquement, mais ça n’est pas toujours pertinent
|
setting_default_language: La langue de vos pouets peut être détectée automatiquement, mais ça n’est pas toujours pertinent
|
||||||
setting_display_media_default: Masquer les supports marqués comme sensibles
|
setting_display_media_default: Masquer les supports marqués comme sensibles
|
||||||
setting_display_media_hide_all: Toujours masquer tous les médias
|
setting_display_media_hide_all: Toujours masquer tous les médias
|
||||||
setting_display_media_show_all: Toujours afficher les médias marqués comme sensibles
|
setting_display_media_show_all: Toujours afficher les médias marqués comme sensibles
|
||||||
setting_hide_network: Ceux que vous suivez et ceux qui vous suivent ne seront pas affichés sur votre profil
|
setting_hide_network: Ceux que vous suivez et ceux qui vous suivent ne seront pas affichés sur votre profil
|
||||||
setting_noindex: Affecte votre profil public ainsi que vos statuts
|
setting_noindex: Affecte votre profil public ainsi que vos statuts
|
||||||
setting_show_application: Le nom de l'application que vous utilisez afin d'envoyer des pouets sera affiché dans la vue détaillée de ceux-ci
|
setting_show_application: Le nom de l’application que vous utilisez afin d’envoyer des pouets sera affiché dans la vue détaillée de ceux-ci
|
||||||
setting_theme: Affecte l’apparence de Mastodon quand vous êtes connecté·e depuis n’importe quel appareil.
|
setting_theme: Affecte l’apparence de Mastodon quand vous êtes connecté·e depuis n’importe quel appareil.
|
||||||
username: Votre nom d’utilisateur sera unique sur %{domain}
|
username: Votre nom d’utilisateur sera unique sur %{domain}
|
||||||
whole_word: Lorsque le mot-clef ou la phrase-clef est uniquement alphanumérique, ça sera uniquement appliqué s’il correspond au mot entier
|
whole_word: Lorsque le mot-clef ou la phrase-clef est uniquement alphanumérique, ça sera uniquement appliqué s’il correspond au mot entier
|
||||||
featured_tag:
|
featured_tag:
|
||||||
name: 'Vous pourriez utiliser l''un d''entre eux :'
|
name: 'Vous pourriez vouloir utiliser l’un d’entre eux :'
|
||||||
imports:
|
imports:
|
||||||
data: Un fichier CSV généré par un autre serveur de Mastodon
|
data: Un fichier CSV généré par un autre serveur de Mastodon
|
||||||
|
invite_request:
|
||||||
|
text: Cela nous aidera à considérer votre demande
|
||||||
sessions:
|
sessions:
|
||||||
otp: 'Entrez le code d’authentification à deux facteurs généré par l’application de votre téléphone ou utilisez un de vos codes de récupération :'
|
otp: 'Entrez le code d’authentification à deux facteurs généré par l’application de votre téléphone ou utilisez un de vos codes de récupération :'
|
||||||
user:
|
user:
|
||||||
|
@ -53,7 +55,7 @@ fr:
|
||||||
account_warning_preset:
|
account_warning_preset:
|
||||||
text: Texte de présélection
|
text: Texte de présélection
|
||||||
admin_account_action:
|
admin_account_action:
|
||||||
send_email_notification: Notifier l'utilisateur par courriel
|
send_email_notification: Notifier l’utilisateur par courriel
|
||||||
text: Attention personnalisée
|
text: Attention personnalisée
|
||||||
type: Action
|
type: Action
|
||||||
types:
|
types:
|
||||||
|
@ -61,7 +63,7 @@ fr:
|
||||||
none: Ne rien faire
|
none: Ne rien faire
|
||||||
silence: Silence
|
silence: Silence
|
||||||
suspend: Suspendre et effacer les données du compte de manière irréversible
|
suspend: Suspendre et effacer les données du compte de manière irréversible
|
||||||
warning_preset_id: Utiliser un modèle d'avertissement
|
warning_preset_id: Utiliser un modèle d’avertissement
|
||||||
defaults:
|
defaults:
|
||||||
autofollow: Invitation à suivre votre compte
|
autofollow: Invitation à suivre votre compte
|
||||||
avatar: Image de profil
|
avatar: Image de profil
|
||||||
|
@ -72,7 +74,7 @@ fr:
|
||||||
context: Contextes du filtre
|
context: Contextes du filtre
|
||||||
current_password: Mot de passe actuel
|
current_password: Mot de passe actuel
|
||||||
data: Données
|
data: Données
|
||||||
discoverable: Inscrire ce compte dans l'annuaire
|
discoverable: Inscrire ce compte dans l’annuaire
|
||||||
display_name: Nom public
|
display_name: Nom public
|
||||||
email: Adresse courriel
|
email: Adresse courriel
|
||||||
expires_in: Expire après
|
expires_in: Expire après
|
||||||
|
@ -103,7 +105,7 @@ fr:
|
||||||
setting_hide_network: Cacher votre réseau
|
setting_hide_network: Cacher votre réseau
|
||||||
setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles
|
setting_noindex: Demander aux moteurs de recherche de ne pas indexer vos informations personnelles
|
||||||
setting_reduce_motion: Réduire la vitesse des animations
|
setting_reduce_motion: Réduire la vitesse des animations
|
||||||
setting_show_application: Dévoiler le nom de l'application utilisée pour envoyer des pouets
|
setting_show_application: Dévoiler le nom de l’application utilisée pour envoyer des pouets
|
||||||
setting_system_font_ui: Utiliser la police par défaut du système
|
setting_system_font_ui: Utiliser la police par défaut du système
|
||||||
setting_theme: Thème du site
|
setting_theme: Thème du site
|
||||||
setting_unfollow_modal: Afficher une fenêtre de confirmation avant de vous désabonner d’un compte
|
setting_unfollow_modal: Afficher une fenêtre de confirmation avant de vous désabonner d’un compte
|
||||||
|
@ -118,6 +120,8 @@ fr:
|
||||||
must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
|
must_be_follower: Masquer les notifications des personnes qui ne vous suivent pas
|
||||||
must_be_following: Masquer les notifications des personnes que vous ne suivez pas
|
must_be_following: Masquer les notifications des personnes que vous ne suivez pas
|
||||||
must_be_following_dm: Bloquer les messages directs des personnes que vous ne suivez pas
|
must_be_following_dm: Bloquer les messages directs des personnes que vous ne suivez pas
|
||||||
|
invite_request:
|
||||||
|
text: Pourquoi voulez-vous vous inscrire ?
|
||||||
notification_emails:
|
notification_emails:
|
||||||
digest: Envoyer des courriels récapitulatifs
|
digest: Envoyer des courriels récapitulatifs
|
||||||
favourite: Envoyer un courriel lorsque quelqu’un ajoute mes statuts à ses favoris
|
favourite: Envoyer un courriel lorsque quelqu’un ajoute mes statuts à ses favoris
|
||||||
|
|
|
@ -115,7 +115,7 @@ sk:
|
||||||
followers: Sledujúci
|
followers: Sledujúci
|
||||||
followers_url: URL adresa sledujúcich
|
followers_url: URL adresa sledujúcich
|
||||||
follows: Sledovania
|
follows: Sledovania
|
||||||
header: Hlavička
|
header: Záhlavie
|
||||||
inbox_url: URL adresa prijatých správ
|
inbox_url: URL adresa prijatých správ
|
||||||
invited_by: Pozvaný/á užívateľom
|
invited_by: Pozvaný/á užívateľom
|
||||||
ip: IP adresa
|
ip: IP adresa
|
||||||
|
@ -138,6 +138,7 @@ sk:
|
||||||
moderation_notes: Moderátorské poznámky
|
moderation_notes: Moderátorské poznámky
|
||||||
most_recent_activity: Posledná aktivita
|
most_recent_activity: Posledná aktivita
|
||||||
most_recent_ip: Posledná IP adresa
|
most_recent_ip: Posledná IP adresa
|
||||||
|
no_account_selected: Nedošlo k žiadnému pozmeneniu účtov, keďže žiadne neboli vybrané
|
||||||
no_limits_imposed: Nie sú stanovené žiadné obmedzenia
|
no_limits_imposed: Nie sú stanovené žiadné obmedzenia
|
||||||
not_subscribed: Neodoberá
|
not_subscribed: Neodoberá
|
||||||
outbox_url: URL poslaných
|
outbox_url: URL poslaných
|
||||||
|
@ -152,7 +153,7 @@ sk:
|
||||||
reject: Zamietni
|
reject: Zamietni
|
||||||
reject_all: Zamietni všetky
|
reject_all: Zamietni všetky
|
||||||
remove_avatar: Vymaž avatar
|
remove_avatar: Vymaž avatar
|
||||||
remove_header: Vymaž hlavičku
|
remove_header: Vymaž záhlavie
|
||||||
resend_confirmation:
|
resend_confirmation:
|
||||||
already_confirmed: Tento užívateľ je už potvrdený
|
already_confirmed: Tento užívateľ je už potvrdený
|
||||||
send: Odošli potvrdzovací email znovu
|
send: Odošli potvrdzovací email znovu
|
||||||
|
@ -319,7 +320,7 @@ sk:
|
||||||
by_domain: Doména
|
by_domain: Doména
|
||||||
delivery_available: Je v dosahu doručovania
|
delivery_available: Je v dosahu doručovania
|
||||||
known_accounts:
|
known_accounts:
|
||||||
few: "%{count} známe účty"
|
few: "%{count} známych účtov"
|
||||||
one: "%{count} známy účet"
|
one: "%{count} známy účet"
|
||||||
other: "%{count} známe účty"
|
other: "%{count} známe účty"
|
||||||
moderation:
|
moderation:
|
||||||
|
@ -340,18 +341,20 @@ sk:
|
||||||
expired: Vypršalo
|
expired: Vypršalo
|
||||||
title: Filtruj
|
title: Filtruj
|
||||||
title: Pozvánky
|
title: Pozvánky
|
||||||
|
pending_accounts:
|
||||||
|
title: Čakajúcich účtov (%{count})
|
||||||
relays:
|
relays:
|
||||||
add_new: Pridaj nový federovací mostík
|
add_new: Pridaj nový federovací mostík
|
||||||
delete: Vymaž
|
delete: Vymaž
|
||||||
description_html: "<strong>Federovací mostík</strong> je prechodný server ktorý obmieňa veľké množstvá verejných príspevkov medzi tými servermi ktoré na od neho odoberajú, aj doňho prispievajú. <strong>Môže to pomôcť malým a stredným instanciám objavovať federovaný obsah</strong>, čo inak vyžaduje aby miestni užívatelia ručne následovali iných ľudí zo vzdialených instancií."
|
description_html: "<strong>Federovací mostík</strong> je prechodný server, ktorý obmieňa veľké množstvá verejných príspevkov medzi tými servermi ktoré na od neho odoberajú, aj doňho prispievajú. <strong>Môže to pomôcť malým a stredným instanciám objavovať federovaný obsah</strong>, čo inak vyžaduje aby miestni užívatelia ručne následovali iných ľudí zo vzdialených instancií."
|
||||||
disable: Pozastav
|
disable: Vypni
|
||||||
disabled: Zastavené
|
disabled: Vypnutý
|
||||||
enable: Povoľ
|
enable: Povoľ
|
||||||
enable_hint: Ak povolíš, tvoj server bude odoberať všetky verejné príspevky z tohto mostu, a začne posielať verejné príspevky tvojho servera na tento most.
|
enable_hint: Ak povolíš, tvoj server bude odoberať všetky verejné príspevky z tohto mostu, a začne posielať verejné príspevky tvojho servera na tento most.
|
||||||
enabled: Povolené
|
enabled: Povolené
|
||||||
inbox_url: URL adresa mostu
|
inbox_url: URL adresa mostu
|
||||||
pending: Čakám na povolenie od prechodného mostu
|
pending: Čaká sa na povolenie od prechodného mostu
|
||||||
save_and_enable: Uložiť a povoliť
|
save_and_enable: Ulož a povoľ
|
||||||
setup: Nastav prepojenie s mostom
|
setup: Nastav prepojenie s mostom
|
||||||
status: Stav
|
status: Stav
|
||||||
title: Mosty
|
title: Mosty
|
||||||
|
@ -390,7 +393,7 @@ sk:
|
||||||
updated_at: Aktualizované
|
updated_at: Aktualizované
|
||||||
settings:
|
settings:
|
||||||
activity_api_enabled:
|
activity_api_enabled:
|
||||||
desc_html: Sčítanie lokálne publikovaných príspevkov, aktívnych užívateľov, a nových registrácii, v týždenných intervaloch
|
desc_html: Sčítanie miestne uverejnených príspevkov, aktívnych užívateľov, a nových registrácii, v týždenných intervaloch
|
||||||
title: Vydať hromadné štatistiky o užívateľskej aktivite
|
title: Vydať hromadné štatistiky o užívateľskej aktivite
|
||||||
bootstrap_timeline_accounts:
|
bootstrap_timeline_accounts:
|
||||||
desc_html: Ak je prezývok viacero, každú oddeľte čiarkou. Možno zadať iba miestne, odomknuté účty. Pokiaľ necháte prázdne, je to pre všetkých miestnych administrátorov.
|
desc_html: Ak je prezývok viacero, každú oddeľte čiarkou. Možno zadať iba miestne, odomknuté účty. Pokiaľ necháte prázdne, je to pre všetkých miestnych administrátorov.
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddByModeratorToTombstone < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
add_column :tombstones, :by_moderator, :boolean
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2019_04_20_025523) do
|
ActiveRecord::Schema.define(version: 2019_05_09_164208) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -688,6 +688,7 @@ ActiveRecord::Schema.define(version: 2019_04_20_025523) do
|
||||||
t.string "uri", null: false
|
t.string "uri", null: false
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
|
t.boolean "by_moderator"
|
||||||
t.index ["account_id"], name: "index_tombstones_on_account_id"
|
t.index ["account_id"], name: "index_tombstones_on_account_id"
|
||||||
t.index ["uri"], name: "index_tombstones_on_uri"
|
t.index ["uri"], name: "index_tombstones_on_uri"
|
||||||
end
|
end
|
||||||
|
|
|
@ -28,10 +28,15 @@ module Mastodon
|
||||||
say('.', :green, false)
|
say('.', :green, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
DomainBlock.where(domain: domain).destroy_all
|
DomainBlock.where(domain: domain).destroy_all unless options[:dry_run]
|
||||||
|
|
||||||
say
|
say
|
||||||
say("Removed #{removed} accounts#{dry_run}", :green)
|
say("Removed #{removed} accounts#{dry_run}", :green)
|
||||||
|
|
||||||
|
custom_emojis = CustomEmoji.where(domain: domain)
|
||||||
|
custom_emojis_count = custom_emojis.count
|
||||||
|
custom_emojis.destroy_all unless options[:dry_run]
|
||||||
|
say("Removed #{custom_emojis_count} custom emojis", :green)
|
||||||
end
|
end
|
||||||
|
|
||||||
option :concurrency, type: :numeric, default: 50, aliases: [:c]
|
option :concurrency, type: :numeric, default: 50, aliases: [:c]
|
||||||
|
|
|
@ -13,7 +13,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def patch
|
def patch
|
||||||
1
|
2
|
||||||
end
|
end
|
||||||
|
|
||||||
def pre
|
def pre
|
||||||
|
|
|
@ -41,6 +41,22 @@ RSpec.describe ActivityPub::TagManager do
|
||||||
status.mentions.create(account: mentioned)
|
status.mentions.create(account: mentioned)
|
||||||
expect(subject.to(status)).to eq [subject.uri_for(mentioned)]
|
expect(subject.to(status)).to eq [subject.uri_for(mentioned)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns URIs of mentions for direct silenced author's status only if they are followers or requesting to be" do
|
||||||
|
bob = Fabricate(:account, username: 'bob')
|
||||||
|
alice = Fabricate(:account, username: 'alice')
|
||||||
|
foo = Fabricate(:account)
|
||||||
|
author = Fabricate(:account, username: 'author', silenced: true)
|
||||||
|
status = Fabricate(:status, visibility: :direct, account: author)
|
||||||
|
bob.follow!(author)
|
||||||
|
FollowRequest.create!(account: foo, target_account: author)
|
||||||
|
status.mentions.create(account: alice)
|
||||||
|
status.mentions.create(account: bob)
|
||||||
|
status.mentions.create(account: foo)
|
||||||
|
expect(subject.to(status)).to include(subject.uri_for(bob))
|
||||||
|
expect(subject.to(status)).to include(subject.uri_for(foo))
|
||||||
|
expect(subject.to(status)).to_not include(subject.uri_for(alice))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cc' do
|
describe '#cc' do
|
||||||
|
@ -70,6 +86,22 @@ RSpec.describe ActivityPub::TagManager do
|
||||||
status.mentions.create(account: mentioned)
|
status.mentions.create(account: mentioned)
|
||||||
expect(subject.cc(status)).to include(subject.uri_for(mentioned))
|
expect(subject.cc(status)).to include(subject.uri_for(mentioned))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "returns URIs of mentions for silenced author's non-direct status only if they are followers or requesting to be" do
|
||||||
|
bob = Fabricate(:account, username: 'bob')
|
||||||
|
alice = Fabricate(:account, username: 'alice')
|
||||||
|
foo = Fabricate(:account)
|
||||||
|
author = Fabricate(:account, username: 'author', silenced: true)
|
||||||
|
status = Fabricate(:status, visibility: :public, account: author)
|
||||||
|
bob.follow!(author)
|
||||||
|
FollowRequest.create!(account: foo, target_account: author)
|
||||||
|
status.mentions.create(account: alice)
|
||||||
|
status.mentions.create(account: bob)
|
||||||
|
status.mentions.create(account: foo)
|
||||||
|
expect(subject.cc(status)).to include(subject.uri_for(bob))
|
||||||
|
expect(subject.cc(status)).to include(subject.uri_for(foo))
|
||||||
|
expect(subject.cc(status)).to_not include(subject.uri_for(alice))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#local_uri?' do
|
describe '#local_uri?' do
|
||||||
|
|
|
@ -2,9 +2,10 @@ require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe ProcessMentionsService, type: :service do
|
RSpec.describe ProcessMentionsService, type: :service do
|
||||||
let(:account) { Fabricate(:account, username: 'alice') }
|
let(:account) { Fabricate(:account, username: 'alice') }
|
||||||
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}") }
|
let(:visibility) { :public }
|
||||||
|
let(:status) { Fabricate(:status, account: account, text: "Hello @#{remote_user.acct}", visibility: visibility) }
|
||||||
|
|
||||||
context 'OStatus' do
|
context 'OStatus with public toot' do
|
||||||
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
|
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
|
||||||
|
|
||||||
subject { ProcessMentionsService.new }
|
subject { ProcessMentionsService.new }
|
||||||
|
@ -23,6 +24,26 @@ RSpec.describe ProcessMentionsService, type: :service do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'OStatus with private toot' do
|
||||||
|
let(:visibility) { :private }
|
||||||
|
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :ostatus, domain: 'example.com', salmon_url: 'http://salmon.example.com') }
|
||||||
|
|
||||||
|
subject { ProcessMentionsService.new }
|
||||||
|
|
||||||
|
before do
|
||||||
|
stub_request(:post, remote_user.salmon_url)
|
||||||
|
subject.call(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not create a mention' do
|
||||||
|
expect(remote_user.mentions.where(status: status).count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not post to remote user\'s Salmon end point' do
|
||||||
|
expect(a_request(:post, remote_user.salmon_url)).to_not have_been_made
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'ActivityPub' do
|
context 'ActivityPub' do
|
||||||
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
let(:remote_user) { Fabricate(:account, username: 'remote_user', protocol: :activitypub, domain: 'example.com', inbox_url: 'http://example.com/inbox') }
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue