Merge remote-tracking branch 'tootsuite/master' into glitchsoc/master
commit
82236a3703
|
@ -89,7 +89,8 @@ module Admin
|
||||||
:username,
|
:username,
|
||||||
:display_name,
|
:display_name,
|
||||||
:email,
|
:email,
|
||||||
:ip
|
:ip,
|
||||||
|
:staff
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -92,7 +92,9 @@ module Admin
|
||||||
def filter_params
|
def filter_params
|
||||||
params.permit(
|
params.permit(
|
||||||
:local,
|
:local,
|
||||||
:remote
|
:remote,
|
||||||
|
:by_domain,
|
||||||
|
:shortcode
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Admin::FilterHelper
|
module Admin::FilterHelper
|
||||||
ACCOUNT_FILTERS = %i(local remote by_domain silenced suspended recent username display_name email ip).freeze
|
ACCOUNT_FILTERS = %i(local remote by_domain silenced suspended recent username display_name email ip staff).freeze
|
||||||
REPORT_FILTERS = %i(resolved account_id target_account_id).freeze
|
REPORT_FILTERS = %i(resolved account_id target_account_id).freeze
|
||||||
INVITE_FILTER = %i(available expired).freeze
|
INVITE_FILTER = %i(available expired).freeze
|
||||||
|
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
|
||||||
|
|
||||||
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER
|
FILTERS = ACCOUNT_FILTERS + REPORT_FILTERS + INVITE_FILTER + CUSTOM_EMOJI_FILTERS
|
||||||
|
|
||||||
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
|
def filter_link_to(text, link_to_params, link_class_params = link_to_params)
|
||||||
new_url = filtered_url_for(link_to_params)
|
new_url = filtered_url_for(link_to_params)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from 'react';
|
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 { autoPlayGif } from '../initial_state';
|
||||||
|
|
||||||
export default class Avatar extends React.PureComponent {
|
export default class Avatar extends React.PureComponent {
|
||||||
|
|
||||||
|
@ -8,12 +9,12 @@ export default class Avatar extends React.PureComponent {
|
||||||
account: ImmutablePropTypes.map.isRequired,
|
account: ImmutablePropTypes.map.isRequired,
|
||||||
size: PropTypes.number.isRequired,
|
size: PropTypes.number.isRequired,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
animate: PropTypes.bool,
|
|
||||||
inline: PropTypes.bool,
|
inline: PropTypes.bool,
|
||||||
|
animate: PropTypes.bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
animate: false,
|
animate: autoPlayGif,
|
||||||
size: 20,
|
size: 20,
|
||||||
inline: false,
|
inline: false,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,22 +1,29 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import { autoPlayGif } from '../initial_state';
|
||||||
|
|
||||||
export default class AvatarOverlay extends React.PureComponent {
|
export default class AvatarOverlay extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
account: ImmutablePropTypes.map.isRequired,
|
account: ImmutablePropTypes.map.isRequired,
|
||||||
friend: ImmutablePropTypes.map.isRequired,
|
friend: ImmutablePropTypes.map.isRequired,
|
||||||
|
animate: PropTypes.bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
animate: autoPlayGif,
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { account, friend } = this.props;
|
const { account, friend, animate } = this.props;
|
||||||
|
|
||||||
const baseStyle = {
|
const baseStyle = {
|
||||||
backgroundImage: `url(${account.get('avatar_static')})`,
|
backgroundImage: `url(${account.get(animate ? 'avatar' : 'avatar_static')})`,
|
||||||
};
|
};
|
||||||
|
|
||||||
const overlayStyle = {
|
const overlayStyle = {
|
||||||
backgroundImage: `url(${friend.get('avatar_static')})`,
|
backgroundImage: `url(${friend.get(animate ? 'avatar' : 'avatar_static')})`,
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -156,6 +156,8 @@ export default class ComposeForm extends ImmutablePureComponent {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='compose-form'>
|
<div className='compose-form'>
|
||||||
|
<WarningContainer />
|
||||||
|
|
||||||
<Collapsable isVisible={this.props.spoiler} fullHeight={50}>
|
<Collapsable isVisible={this.props.spoiler} fullHeight={50}>
|
||||||
<div className='spoiler-input'>
|
<div className='spoiler-input'>
|
||||||
<label>
|
<label>
|
||||||
|
@ -165,8 +167,6 @@ export default class ComposeForm extends ImmutablePureComponent {
|
||||||
</div>
|
</div>
|
||||||
</Collapsable>
|
</Collapsable>
|
||||||
|
|
||||||
<WarningContainer />
|
|
||||||
|
|
||||||
<ReplyIndicatorContainer />
|
<ReplyIndicatorContainer />
|
||||||
|
|
||||||
<div className='compose-form__autosuggest-wrapper'>
|
<div className='compose-form__autosuggest-wrapper'>
|
||||||
|
@ -199,13 +199,13 @@ export default class ComposeForm extends ImmutablePureComponent {
|
||||||
<SensitiveButtonContainer />
|
<SensitiveButtonContainer />
|
||||||
<SpoilerButtonContainer />
|
<SpoilerButtonContainer />
|
||||||
</div>
|
</div>
|
||||||
|
<div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='compose-form__publish'>
|
<div className='compose-form__publish'>
|
||||||
<div className='character-counter__wrapper'><CharacterCounter max={500} text={text} /></div>
|
|
||||||
<div className='compose-form__publish-button-wrapper'><Button text={publishText} onClick={this.handleSubmit} disabled={disabled || this.props.is_uploading || length(text) > 500 || (text.length !== 0 && text.trim().length === 0)} block /></div>
|
<div className='compose-form__publish-button-wrapper'><Button text={publishText} onClick={this.handleSubmit} disabled={disabled || this.props.is_uploading || length(text) > 500 || (text.length !== 0 && text.trim().length === 0)} block /></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ import IconButton from '../../../components/icon_button';
|
||||||
import DisplayName from '../../../components/display_name';
|
import DisplayName from '../../../components/display_name';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import { isRtl } from '../../../rtl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
|
||||||
|
@ -43,6 +44,9 @@ export default class ReplyIndicator extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
const content = { __html: status.get('contentHtml') };
|
const content = { __html: status.get('contentHtml') };
|
||||||
|
const style = {
|
||||||
|
direction: isRtl(status.get('search_index')) ? 'rtl' : 'ltr',
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='reply-indicator'>
|
<div className='reply-indicator'>
|
||||||
|
@ -55,7 +59,7 @@ export default class ReplyIndicator extends ImmutablePureComponent {
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='reply-indicator__content' dangerouslySetInnerHTML={content} />
|
<div className='reply-indicator__content' style={style} dangerouslySetInnerHTML={content} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ export default class Upload extends ImmutablePureComponent {
|
||||||
render () {
|
render () {
|
||||||
const { intl, media } = this.props;
|
const { intl, media } = this.props;
|
||||||
const active = this.state.hovered || this.state.focused;
|
const active = this.state.hovered || this.state.focused;
|
||||||
const description = this.state.dirtyDescription || media.get('description') || '';
|
const description = this.state.dirtyDescription || (this.state.dirtyDescription !== '' && media.get('description')) || '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='compose-form__upload' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
<div className='compose-form__upload' onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
|
||||||
|
|
|
@ -161,7 +161,7 @@ export default class ListTimeline extends React.PureComponent {
|
||||||
scrollKey={`list_timeline-${columnId}`}
|
scrollKey={`list_timeline-${columnId}`}
|
||||||
timelineId={`list:${id}`}
|
timelineId={`list:${id}`}
|
||||||
loadMore={this.handleLoadMore}
|
loadMore={this.handleLoadMore}
|
||||||
emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet.' />}
|
emptyMessage={<FormattedMessage id='empty_column.list' defaultMessage='There is nothing in this list yet. When members of this list post new statuses, they will appear here.' />}
|
||||||
/>
|
/>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,6 +8,7 @@ import {
|
||||||
} from '../../../actions/timelines';
|
} from '../../../actions/timelines';
|
||||||
import Column from '../../../components/column';
|
import Column from '../../../components/column';
|
||||||
import ColumnHeader from '../../../components/column_header';
|
import ColumnHeader from '../../../components/column_header';
|
||||||
|
import { connectHashtagStream } from '../../../actions/streaming';
|
||||||
|
|
||||||
@connect()
|
@connect()
|
||||||
export default class HashtagTimeline extends React.PureComponent {
|
export default class HashtagTimeline extends React.PureComponent {
|
||||||
|
@ -29,16 +30,13 @@ export default class HashtagTimeline extends React.PureComponent {
|
||||||
const { dispatch, hashtag } = this.props;
|
const { dispatch, hashtag } = this.props;
|
||||||
|
|
||||||
dispatch(refreshHashtagTimeline(hashtag));
|
dispatch(refreshHashtagTimeline(hashtag));
|
||||||
|
this.disconnect = dispatch(connectHashtagStream(hashtag));
|
||||||
this.polling = setInterval(() => {
|
|
||||||
dispatch(refreshHashtagTimeline(hashtag));
|
|
||||||
}, 10000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
if (typeof this.polling !== 'undefined') {
|
if (this.disconnect) {
|
||||||
clearInterval(this.polling);
|
this.disconnect();
|
||||||
this.polling = null;
|
this.disconnect = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import {
|
||||||
import Column from '../../../components/column';
|
import Column from '../../../components/column';
|
||||||
import ColumnHeader from '../../../components/column_header';
|
import ColumnHeader from '../../../components/column_header';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
import { connectPublicStream } from '../../../actions/streaming';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
title: { id: 'standalone.public_title', defaultMessage: 'A look inside...' },
|
title: { id: 'standalone.public_title', defaultMessage: 'A look inside...' },
|
||||||
|
@ -35,16 +36,13 @@ export default class PublicTimeline extends React.PureComponent {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
|
|
||||||
dispatch(refreshPublicTimeline());
|
dispatch(refreshPublicTimeline());
|
||||||
|
this.disconnect = dispatch(connectPublicStream());
|
||||||
this.polling = setInterval(() => {
|
|
||||||
dispatch(refreshPublicTimeline());
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
if (typeof this.polling !== 'undefined') {
|
if (this.disconnect) {
|
||||||
clearInterval(this.polling);
|
this.disconnect();
|
||||||
this.polling = null;
|
this.disconnect = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ const componentMap = {
|
||||||
'LIST': ListTimeline,
|
'LIST': ListTimeline,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isRtlLayout = document.getElementsByTagName('body')[0].classList.contains('rtl');
|
||||||
|
|
||||||
@component => injectIntl(component, { withRef: true })
|
@component => injectIntl(component, { withRef: true })
|
||||||
export default class ColumnsArea extends ImmutablePureComponent {
|
export default class ColumnsArea extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
@ -79,7 +81,8 @@ export default class ColumnsArea extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleChildrenContentChange() {
|
handleChildrenContentChange() {
|
||||||
if (!this.props.singleColumn) {
|
if (!this.props.singleColumn) {
|
||||||
this._interruptScrollAnimation = scrollRight(this.node, this.node.scrollWidth - window.innerWidth);
|
const modifier = isRtlLayout ? -1 : 1;
|
||||||
|
this._interruptScrollAnimation = scrollRight(this.node, (this.node.scrollWidth - window.innerWidth) * modifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@
|
||||||
"column.favourites": "المفضلة",
|
"column.favourites": "المفضلة",
|
||||||
"column.follow_requests": "طلبات المتابعة",
|
"column.follow_requests": "طلبات المتابعة",
|
||||||
"column.home": "الرئيسية",
|
"column.home": "الرئيسية",
|
||||||
"column.lists": "Lists",
|
"column.lists": "القوائم",
|
||||||
"column.mutes": "الحسابات المكتومة",
|
"column.mutes": "الحسابات المكتومة",
|
||||||
"column.notifications": "الإشعارات",
|
"column.notifications": "الإخطارات",
|
||||||
"column.pins": "التبويقات المثبتة",
|
"column.pins": "التبويقات المثبتة",
|
||||||
"column.public": "الخيط العام الموحد",
|
"column.public": "الخيط العام الموحد",
|
||||||
"column_back_button.label": "العودة",
|
"column_back_button.label": "العودة",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "حذف",
|
"confirmations.delete.confirm": "حذف",
|
||||||
"confirmations.delete.message": "هل أنت متأكد أنك تريد حذف هذا المنشور ؟",
|
"confirmations.delete.message": "هل أنت متأكد أنك تريد حذف هذا المنشور ؟",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "هل تود حقا حذف هذه القائمة ؟",
|
||||||
"confirmations.domain_block.confirm": "إخفاء إسم النطاق كاملا",
|
"confirmations.domain_block.confirm": "إخفاء إسم النطاق كاملا",
|
||||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.",
|
||||||
"confirmations.mute.confirm": "أكتم",
|
"confirmations.mute.confirm": "أكتم",
|
||||||
|
@ -109,32 +109,32 @@
|
||||||
"home.settings": "إعدادات العمود",
|
"home.settings": "إعدادات العمود",
|
||||||
"keyboard_shortcuts.back": "للعودة",
|
"keyboard_shortcuts.back": "للعودة",
|
||||||
"keyboard_shortcuts.boost": "للترقية",
|
"keyboard_shortcuts.boost": "للترقية",
|
||||||
"keyboard_shortcuts.column": "to focus a status in one of the columns",
|
"keyboard_shortcuts.column": "للتركيز على منشور على أحد الأعمدة",
|
||||||
"keyboard_shortcuts.compose": "to focus the compose textarea",
|
"keyboard_shortcuts.compose": "للتركيز على نافذة تحرير النصوص",
|
||||||
"keyboard_shortcuts.description": "Description",
|
"keyboard_shortcuts.description": "Description",
|
||||||
"keyboard_shortcuts.down": "للإنتقال إلى أسفل القائمة",
|
"keyboard_shortcuts.down": "للإنتقال إلى أسفل القائمة",
|
||||||
"keyboard_shortcuts.enter": "to open status",
|
"keyboard_shortcuts.enter": "to open status",
|
||||||
"keyboard_shortcuts.favourite": "to favourite",
|
"keyboard_shortcuts.favourite": "للإضافة إلى المفضلة",
|
||||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||||
"keyboard_shortcuts.hotkey": "Hotkey",
|
"keyboard_shortcuts.hotkey": "مفتاح الإختصار",
|
||||||
"keyboard_shortcuts.legend": "to display this legend",
|
"keyboard_shortcuts.legend": "لعرض هذا المفتاح",
|
||||||
"keyboard_shortcuts.mention": "لذِكر الناشر",
|
"keyboard_shortcuts.mention": "لذِكر الناشر",
|
||||||
"keyboard_shortcuts.reply": "للردّ",
|
"keyboard_shortcuts.reply": "للردّ",
|
||||||
"keyboard_shortcuts.search": "to focus search",
|
"keyboard_shortcuts.search": "للتركيز على البحث",
|
||||||
"keyboard_shortcuts.toot": "لتحرير تبويق جديد",
|
"keyboard_shortcuts.toot": "لتحرير تبويق جديد",
|
||||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||||
"keyboard_shortcuts.up": "للإنتقال إلى أعلى القائمة",
|
"keyboard_shortcuts.up": "للإنتقال إلى أعلى القائمة",
|
||||||
"lightbox.close": "إغلاق",
|
"lightbox.close": "إغلاق",
|
||||||
"lightbox.next": "التالي",
|
"lightbox.next": "التالي",
|
||||||
"lightbox.previous": "العودة",
|
"lightbox.previous": "العودة",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "أضف إلى القائمة",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "إحذف من القائمة",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "تعديل القائمة",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "إنشاء قائمة",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "عنوان القائمة الجديدة",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "إبحث في قائمة الحسابات التي تُتابِعها",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "قوائمك",
|
||||||
"loading_indicator.label": "تحميل ...",
|
"loading_indicator.label": "تحميل ...",
|
||||||
"media_gallery.toggle_visible": "عرض / إخفاء",
|
"media_gallery.toggle_visible": "عرض / إخفاء",
|
||||||
"missing_indicator.label": "تعذر العثور عليه",
|
"missing_indicator.label": "تعذر العثور عليه",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "طلبات المتابعة",
|
"navigation_bar.follow_requests": "طلبات المتابعة",
|
||||||
"navigation_bar.info": "معلومات إضافية",
|
"navigation_bar.info": "معلومات إضافية",
|
||||||
"navigation_bar.keyboard_shortcuts": "إختصارات لوحة المفاتيح",
|
"navigation_bar.keyboard_shortcuts": "إختصارات لوحة المفاتيح",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "القوائم",
|
||||||
"navigation_bar.logout": "خروج",
|
"navigation_bar.logout": "خروج",
|
||||||
"navigation_bar.mutes": "الحسابات المكتومة",
|
"navigation_bar.mutes": "الحسابات المكتومة",
|
||||||
"navigation_bar.pins": "التبويقات المثبتة",
|
"navigation_bar.pins": "التبويقات المثبتة",
|
||||||
|
@ -209,7 +209,7 @@
|
||||||
"search_popout.search_format": "نمط البحث المتقدم",
|
"search_popout.search_format": "نمط البحث المتقدم",
|
||||||
"search_popout.tips.hashtag": "وسم",
|
"search_popout.tips.hashtag": "وسم",
|
||||||
"search_popout.tips.status": "حالة",
|
"search_popout.tips.status": "حالة",
|
||||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
"search_popout.tips.text": "جملة قصيرة تُمكّنُك من عرض أسماء و حسابات و كلمات رمزية",
|
||||||
"search_popout.tips.user": "مستخدِم",
|
"search_popout.tips.user": "مستخدِم",
|
||||||
"search_results.total": "{count, number} {count, plural, one {result} و {results}}",
|
"search_results.total": "{count, number} {count, plural, one {result} و {results}}",
|
||||||
"standalone.public_title": "نظرة على ...",
|
"standalone.public_title": "نظرة على ...",
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"column.favourites": "Favorits",
|
"column.favourites": "Favorits",
|
||||||
"column.follow_requests": "Peticions per seguir-te",
|
"column.follow_requests": "Peticions per seguir-te",
|
||||||
"column.home": "Inici",
|
"column.home": "Inici",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Llistes",
|
||||||
"column.mutes": "Usuaris silenciats",
|
"column.mutes": "Usuaris silenciats",
|
||||||
"column.notifications": "Notificacions",
|
"column.notifications": "Notificacions",
|
||||||
"column.pins": "Toot fixat",
|
"column.pins": "Toot fixat",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "Esborrar",
|
"confirmations.delete.confirm": "Esborrar",
|
||||||
"confirmations.delete.message": "Estàs segur que vols esborrar aquest estat?",
|
"confirmations.delete.message": "Estàs segur que vols esborrar aquest estat?",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Estàs segur que vols esborrar permanenment aquesta llista?",
|
||||||
"confirmations.domain_block.confirm": "Amagar tot el domini",
|
"confirmations.domain_block.confirm": "Amagar tot el domini",
|
||||||
"confirmations.domain_block.message": "Estàs realment, realment segur que vols bloquejar totalment {domain}? En la majoria dels casos bloquejar o silenciar és suficient i preferible.",
|
"confirmations.domain_block.message": "Estàs realment, realment segur que vols bloquejar totalment {domain}? En la majoria dels casos bloquejar o silenciar és suficient i preferible.",
|
||||||
"confirmations.mute.confirm": "Silenciar",
|
"confirmations.mute.confirm": "Silenciar",
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
"lightbox.close": "Tancar",
|
"lightbox.close": "Tancar",
|
||||||
"lightbox.next": "Següent",
|
"lightbox.next": "Següent",
|
||||||
"lightbox.previous": "Anterior",
|
"lightbox.previous": "Anterior",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Afegir a la llista",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Treure de la llista",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "Editar llista",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "Afegir llista",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "Nou títol de llista",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "Cercar entre les persones que segueixes",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "Les teves llistes",
|
||||||
"loading_indicator.label": "Carregant...",
|
"loading_indicator.label": "Carregant...",
|
||||||
"media_gallery.toggle_visible": "Alternar visibilitat",
|
"media_gallery.toggle_visible": "Alternar visibilitat",
|
||||||
"missing_indicator.label": "No trobat",
|
"missing_indicator.label": "No trobat",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "Sol·licituds de seguiment",
|
"navigation_bar.follow_requests": "Sol·licituds de seguiment",
|
||||||
"navigation_bar.info": "Informació addicional",
|
"navigation_bar.info": "Informació addicional",
|
||||||
"navigation_bar.keyboard_shortcuts": "Dreceres de teclat",
|
"navigation_bar.keyboard_shortcuts": "Dreceres de teclat",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Llistes",
|
||||||
"navigation_bar.logout": "Tancar sessió",
|
"navigation_bar.logout": "Tancar sessió",
|
||||||
"navigation_bar.mutes": "Usuaris silenciats",
|
"navigation_bar.mutes": "Usuaris silenciats",
|
||||||
"navigation_bar.pins": "Toots fixats",
|
"navigation_bar.pins": "Toots fixats",
|
||||||
|
|
|
@ -93,7 +93,7 @@
|
||||||
"empty_column.hashtag": "There is nothing in this hashtag yet.",
|
"empty_column.hashtag": "There is nothing in this hashtag yet.",
|
||||||
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
|
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
|
||||||
"empty_column.home.public_timeline": "the public timeline",
|
"empty_column.home.public_timeline": "the public timeline",
|
||||||
"empty_column.list": "There is nothing in this list yet.",
|
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
|
||||||
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
|
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
|
||||||
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
"empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up",
|
||||||
"follow_request.authorize": "Authorize",
|
"follow_request.authorize": "Authorize",
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
"empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag",
|
"empty_column.hashtag": "Il n’y a encore aucun contenu associé à ce hashtag",
|
||||||
"empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.",
|
"empty_column.home": "Vous ne suivez encore personne. Visitez {public} ou bien utilisez la recherche pour vous connecter à d’autres utilisateur⋅ice⋅s.",
|
||||||
"empty_column.home.public_timeline": "le fil public",
|
"empty_column.home.public_timeline": "le fil public",
|
||||||
"empty_column.list": "Il n'y a rien dans cette liste pour l'instant.",
|
"empty_column.list": "Il n'y a rien dans cette liste pour l'instant. Dès que des personnes de cette listes publierons de nouveaux statuts ils apparaîtront ici.",
|
||||||
"empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateur⋅ice⋅s pour débuter la conversation.",
|
"empty_column.notifications": "Vous n’avez pas encore de notification. Interagissez avec d’autres utilisateur⋅ice⋅s pour débuter la conversation.",
|
||||||
"empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice⋅s d’autres instances pour remplir le fil public.",
|
"empty_column.public": "Il n’y a rien ici ! Écrivez quelque chose publiquement, ou bien suivez manuellement des utilisateur⋅ice⋅s d’autres instances pour remplir le fil public.",
|
||||||
"follow_request.authorize": "Accepter",
|
"follow_request.authorize": "Accepter",
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"column.favourites": "Favoritas",
|
"column.favourites": "Favoritas",
|
||||||
"column.follow_requests": "Peticións de seguimento",
|
"column.follow_requests": "Peticións de seguimento",
|
||||||
"column.home": "Inicio",
|
"column.home": "Inicio",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Usuarias acaladas",
|
"column.mutes": "Usuarias acaladas",
|
||||||
"column.notifications": "Notificacións",
|
"column.notifications": "Notificacións",
|
||||||
"column.pins": "Mensaxes fixadas",
|
"column.pins": "Mensaxes fixadas",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "Borrar",
|
"confirmations.delete.confirm": "Borrar",
|
||||||
"confirmations.delete.message": "Está segura de que quere eliminar este estado?",
|
"confirmations.delete.message": "Está segura de que quere eliminar este estado?",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Estás seguro de que queres eliminar permanentemente esta lista?",
|
||||||
"confirmations.domain_block.confirm": "Agochar un dominio completo",
|
"confirmations.domain_block.confirm": "Agochar un dominio completo",
|
||||||
"confirmations.domain_block.message": "Realmente está segura de que quere bloquear por completo o dominio {domain}? Normalmente é suficiente, e preferible, bloquear de xeito selectivo varios elementos.",
|
"confirmations.domain_block.message": "Realmente está segura de que quere bloquear por completo o dominio {domain}? Normalmente é suficiente, e preferible, bloquear de xeito selectivo varios elementos.",
|
||||||
"confirmations.mute.confirm": "Acalar",
|
"confirmations.mute.confirm": "Acalar",
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
"lightbox.close": "Fechar",
|
"lightbox.close": "Fechar",
|
||||||
"lightbox.next": "Seguinte",
|
"lightbox.next": "Seguinte",
|
||||||
"lightbox.previous": "Anterior",
|
"lightbox.previous": "Anterior",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Engadir á lista",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Eliminar da lista",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "Editar lista",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "Engadir lista",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "Novo título da lista",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "Procurar entre a xente que segues",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "As túas listas",
|
||||||
"loading_indicator.label": "Cargando...",
|
"loading_indicator.label": "Cargando...",
|
||||||
"media_gallery.toggle_visible": "Dar visibilidade",
|
"media_gallery.toggle_visible": "Dar visibilidade",
|
||||||
"missing_indicator.label": "Non atopado",
|
"missing_indicator.label": "Non atopado",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "Peticións de seguimento",
|
"navigation_bar.follow_requests": "Peticións de seguimento",
|
||||||
"navigation_bar.info": "Sobre esta instancia",
|
"navigation_bar.info": "Sobre esta instancia",
|
||||||
"navigation_bar.keyboard_shortcuts": "Atallos do teclado",
|
"navigation_bar.keyboard_shortcuts": "Atallos do teclado",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Listas",
|
||||||
"navigation_bar.logout": "Sair",
|
"navigation_bar.logout": "Sair",
|
||||||
"navigation_bar.mutes": "Usuarias acaladas",
|
"navigation_bar.mutes": "Usuarias acaladas",
|
||||||
"navigation_bar.pins": "Mensaxes fixadas",
|
"navigation_bar.pins": "Mensaxes fixadas",
|
||||||
|
|
|
@ -95,7 +95,7 @@
|
||||||
"empty_column.home.public_timeline": "連合タイムライン",
|
"empty_column.home.public_timeline": "連合タイムライン",
|
||||||
"empty_column.list": "このリストにはまだなにもありません。",
|
"empty_column.list": "このリストにはまだなにもありません。",
|
||||||
"empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。",
|
"empty_column.notifications": "まだ通知がありません。他の人とふれ合って会話を始めましょう。",
|
||||||
"empty_column.public": "ここにはまだ何もありません!公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう!",
|
"empty_column.public": "ここにはまだ何もありません! 公開で何かを投稿したり、他のインスタンスのユーザーをフォローしたりしていっぱいにしましょう",
|
||||||
"follow_request.authorize": "許可",
|
"follow_request.authorize": "許可",
|
||||||
"follow_request.reject": "拒否",
|
"follow_request.reject": "拒否",
|
||||||
"getting_started.appsshort": "アプリ",
|
"getting_started.appsshort": "アプリ",
|
||||||
|
@ -162,12 +162,12 @@
|
||||||
"notifications.clear": "通知を消去",
|
"notifications.clear": "通知を消去",
|
||||||
"notifications.clear_confirmation": "本当に通知を消去しますか?",
|
"notifications.clear_confirmation": "本当に通知を消去しますか?",
|
||||||
"notifications.column_settings.alert": "デスクトップ通知",
|
"notifications.column_settings.alert": "デスクトップ通知",
|
||||||
"notifications.column_settings.favourite": "お気に入り",
|
"notifications.column_settings.favourite": "お気に入り:",
|
||||||
"notifications.column_settings.follow": "新しいフォロワー",
|
"notifications.column_settings.follow": "新しいフォロワー:",
|
||||||
"notifications.column_settings.mention": "返信",
|
"notifications.column_settings.mention": "返信:",
|
||||||
"notifications.column_settings.push": "プッシュ通知",
|
"notifications.column_settings.push": "プッシュ通知",
|
||||||
"notifications.column_settings.push_meta": "このデバイス",
|
"notifications.column_settings.push_meta": "このデバイス",
|
||||||
"notifications.column_settings.reblog": "ブースト",
|
"notifications.column_settings.reblog": "ブースト:",
|
||||||
"notifications.column_settings.show": "カラムに表示",
|
"notifications.column_settings.show": "カラムに表示",
|
||||||
"notifications.column_settings.sound": "通知音を再生",
|
"notifications.column_settings.sound": "通知音を再生",
|
||||||
"onboarding.done": "完了",
|
"onboarding.done": "完了",
|
||||||
|
@ -176,7 +176,7 @@
|
||||||
"onboarding.page_four.home": "「ホーム」タイムラインではあなたがフォローしている人の投稿を表示します。",
|
"onboarding.page_four.home": "「ホーム」タイムラインではあなたがフォローしている人の投稿を表示します。",
|
||||||
"onboarding.page_four.notifications": "「通知」ではあなたへの他の人からの関わりを表示します。",
|
"onboarding.page_four.notifications": "「通知」ではあなたへの他の人からの関わりを表示します。",
|
||||||
"onboarding.page_one.federation": "Mastodonは誰でも参加できるSNSです。",
|
"onboarding.page_one.federation": "Mastodonは誰でも参加できるSNSです。",
|
||||||
"onboarding.page_one.handle": "あなたは今数あるMastodonインスタンスの1つである{domain}にいます。あなたのフルハンドルは{handle}です。",
|
"onboarding.page_one.handle": "今あなたは数あるMastodonインスタンスの1つである{domain}にいます。あなたのフルハンドルは{handle}です",
|
||||||
"onboarding.page_one.welcome": "Mastodonへようこそ!",
|
"onboarding.page_one.welcome": "Mastodonへようこそ!",
|
||||||
"onboarding.page_six.admin": "あなたのインスタンスの管理者は{admin}です。",
|
"onboarding.page_six.admin": "あなたのインスタンスの管理者は{admin}です。",
|
||||||
"onboarding.page_six.almost_done": "以上です。",
|
"onboarding.page_six.almost_done": "以上です。",
|
||||||
|
@ -184,7 +184,7 @@
|
||||||
"onboarding.page_six.apps_available": "iOS、Androidあるいは他のプラットフォームで使える{apps}があります。",
|
"onboarding.page_six.apps_available": "iOS、Androidあるいは他のプラットフォームで使える{apps}があります。",
|
||||||
"onboarding.page_six.github": "MastodonはOSSです。バグ報告や機能要望あるいは貢献を{github}から行なえます。",
|
"onboarding.page_six.github": "MastodonはOSSです。バグ報告や機能要望あるいは貢献を{github}から行なえます。",
|
||||||
"onboarding.page_six.guidelines": "コミュニティガイドライン",
|
"onboarding.page_six.guidelines": "コミュニティガイドライン",
|
||||||
"onboarding.page_six.read_guidelines": "{guidelines}を読むことを忘れないようにしてください。",
|
"onboarding.page_six.read_guidelines": "{guidelines}を読むことを忘れないようにしてください!",
|
||||||
"onboarding.page_six.various_app": "様々なモバイルアプリ",
|
"onboarding.page_six.various_app": "様々なモバイルアプリ",
|
||||||
"onboarding.page_three.profile": "「プロフィールを編集」から、あなたの自己紹介や表示名を変更できます。またそこでは他の設定ができます。",
|
"onboarding.page_three.profile": "「プロフィールを編集」から、あなたの自己紹介や表示名を変更できます。またそこでは他の設定ができます。",
|
||||||
"onboarding.page_three.search": "検索バーで、{illustration}や{introductions}のように特定のハッシュタグの投稿を見たり、ユーザーを探したりできます。",
|
"onboarding.page_three.search": "検索バーで、{illustration}や{introductions}のように特定のハッシュタグの投稿を見たり、ユーザーを探したりできます。",
|
||||||
|
@ -215,7 +215,7 @@
|
||||||
"search_popout.tips.text": "表示名やユーザー名、ハッシュタグに一致する単純なテキスト",
|
"search_popout.tips.text": "表示名やユーザー名、ハッシュタグに一致する単純なテキスト",
|
||||||
"search_popout.tips.user": "ユーザー",
|
"search_popout.tips.user": "ユーザー",
|
||||||
"search_results.total": "{count, number}件の結果",
|
"search_results.total": "{count, number}件の結果",
|
||||||
"standalone.public_title": "今こんな話をしています",
|
"standalone.public_title": "今こんな話をしています...",
|
||||||
"status.cannot_reblog": "この投稿はブーストできません",
|
"status.cannot_reblog": "この投稿はブーストできません",
|
||||||
"status.delete": "削除",
|
"status.delete": "削除",
|
||||||
"status.embed": "埋め込み",
|
"status.embed": "埋め込み",
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"column.favourites": "Favorieten",
|
"column.favourites": "Favorieten",
|
||||||
"column.follow_requests": "Volgverzoeken",
|
"column.follow_requests": "Volgverzoeken",
|
||||||
"column.home": "Start",
|
"column.home": "Start",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Lijsten",
|
||||||
"column.mutes": "Genegeerde gebruikers",
|
"column.mutes": "Genegeerde gebruikers",
|
||||||
"column.notifications": "Meldingen",
|
"column.notifications": "Meldingen",
|
||||||
"column.pins": "Vastgezette toots",
|
"column.pins": "Vastgezette toots",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "Verwijderen",
|
"confirmations.delete.confirm": "Verwijderen",
|
||||||
"confirmations.delete.message": "Weet je het zeker dat je deze toot wilt verwijderen?",
|
"confirmations.delete.message": "Weet je het zeker dat je deze toot wilt verwijderen?",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Weet je zeker dat je deze lijst permanent wilt verwijderen?",
|
||||||
"confirmations.domain_block.confirm": "Negeer alles van deze server",
|
"confirmations.domain_block.confirm": "Negeer alles van deze server",
|
||||||
"confirmations.domain_block.message": "Weet je het echt, echt zeker dat je alles van {domain} wil negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en gewenst.",
|
"confirmations.domain_block.message": "Weet je het echt, echt zeker dat je alles van {domain} wil negeren? In de meeste gevallen is het blokkeren of negeren van een paar specifieke personen voldoende en gewenst.",
|
||||||
"confirmations.mute.confirm": "Negeren",
|
"confirmations.mute.confirm": "Negeren",
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
"lightbox.close": "Sluiten",
|
"lightbox.close": "Sluiten",
|
||||||
"lightbox.next": "Volgende",
|
"lightbox.next": "Volgende",
|
||||||
"lightbox.previous": "Vorige",
|
"lightbox.previous": "Vorige",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Aan lijst toevoegen",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Uit lijst verwijderen",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "Lijst bewerken",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "Lijst toevoegen",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "Naam nieuwe lijst",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "Zoek naar mensen die je volgt",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "Jouw lijsten",
|
||||||
"loading_indicator.label": "Laden…",
|
"loading_indicator.label": "Laden…",
|
||||||
"media_gallery.toggle_visible": "Media wel/niet tonen",
|
"media_gallery.toggle_visible": "Media wel/niet tonen",
|
||||||
"missing_indicator.label": "Niet gevonden",
|
"missing_indicator.label": "Niet gevonden",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "Volgverzoeken",
|
"navigation_bar.follow_requests": "Volgverzoeken",
|
||||||
"navigation_bar.info": "Uitgebreide informatie",
|
"navigation_bar.info": "Uitgebreide informatie",
|
||||||
"navigation_bar.keyboard_shortcuts": "Toetsenbord sneltoetsen",
|
"navigation_bar.keyboard_shortcuts": "Toetsenbord sneltoetsen",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Lijsten",
|
||||||
"navigation_bar.logout": "Afmelden",
|
"navigation_bar.logout": "Afmelden",
|
||||||
"navigation_bar.mutes": "Genegeerde gebruikers",
|
"navigation_bar.mutes": "Genegeerde gebruikers",
|
||||||
"navigation_bar.pins": "Vastgezette toots",
|
"navigation_bar.pins": "Vastgezette toots",
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
"empty_column.hashtag": "I a pas encara de contengut ligat a aquesta etiqueta.",
|
"empty_column.hashtag": "I a pas encara de contengut ligat a aquesta etiqueta.",
|
||||||
"empty_column.home": "Vòstre flux d’acuèlh es void. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.",
|
"empty_column.home": "Vòstre flux d’acuèlh es void. Visitatz {public} o utilizatz la recèrca per vos connectar a d’autras personas.",
|
||||||
"empty_column.home.public_timeline": "lo flux public",
|
"empty_column.home.public_timeline": "lo flux public",
|
||||||
"empty_column.list": "I a pas res dins la lista pel moment.",
|
"empty_column.list": "I a pas res dins la lista pel moment. Quand de membres d’aquesta lista publiquen de novèls estatuts los veiretz aquí.",
|
||||||
"empty_column.notifications": "Avètz pas encara de notificacions. Respondètz a qualqu’un per començar una conversacion.",
|
"empty_column.notifications": "Avètz pas encara de notificacions. Respondètz a qualqu’un per començar una conversacion.",
|
||||||
"empty_column.public": "I a pas res aquí ! Escrivètz quicòm de public, o seguètz de personas d’autras instàncias per garnir lo flux public",
|
"empty_column.public": "I a pas res aquí ! Escrivètz quicòm de public, o seguètz de personas d’autras instàncias per garnir lo flux public",
|
||||||
"follow_request.authorize": "Autorizar",
|
"follow_request.authorize": "Autorizar",
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
"column.favourites": "Favoritos",
|
"column.favourites": "Favoritos",
|
||||||
"column.follow_requests": "Seguidores pendentes",
|
"column.follow_requests": "Seguidores pendentes",
|
||||||
"column.home": "Página inicial",
|
"column.home": "Página inicial",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Usuários silenciados",
|
"column.mutes": "Usuários silenciados",
|
||||||
"column.notifications": "Notificações",
|
"column.notifications": "Notificações",
|
||||||
"column.pins": "Postagens fixadas",
|
"column.pins": "Postagens fixadas",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "Excluir",
|
"confirmations.delete.confirm": "Excluir",
|
||||||
"confirmations.delete.message": "Você tem certeza de que quer excluir esta postagem?",
|
"confirmations.delete.message": "Você tem certeza de que quer excluir esta postagem?",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Você tem certeza que quer deletar permanentemente a lista?",
|
||||||
"confirmations.domain_block.confirm": "Esconder o domínio inteiro",
|
"confirmations.domain_block.confirm": "Esconder o domínio inteiro",
|
||||||
"confirmations.domain_block.message": "Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado.",
|
"confirmations.domain_block.message": "Você quer mesmo bloquear {domain} inteiro? Na maioria dos casos, silenciar ou bloquear alguns usuários é o suficiente e o recomendado.",
|
||||||
"confirmations.mute.confirm": "Silenciar",
|
"confirmations.mute.confirm": "Silenciar",
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
"keyboard_shortcuts.back": "para navegar de volta",
|
"keyboard_shortcuts.back": "para navegar de volta",
|
||||||
"keyboard_shortcuts.boost": "para compartilhar",
|
"keyboard_shortcuts.boost": "para compartilhar",
|
||||||
"keyboard_shortcuts.column": "Focar um status em uma das colunas",
|
"keyboard_shortcuts.column": "Focar um status em uma das colunas",
|
||||||
"keyboard_shortcuts.compose": "to focus the compose textarea",
|
"keyboard_shortcuts.compose": "para focar a área de redação",
|
||||||
"keyboard_shortcuts.description": "Description",
|
"keyboard_shortcuts.description": "Description",
|
||||||
"keyboard_shortcuts.down": "para mover para baixo na lista",
|
"keyboard_shortcuts.down": "para mover para baixo na lista",
|
||||||
"keyboard_shortcuts.enter": "to open status",
|
"keyboard_shortcuts.enter": "to open status",
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
"lightbox.close": "Fechar",
|
"lightbox.close": "Fechar",
|
||||||
"lightbox.next": "Próximo",
|
"lightbox.next": "Próximo",
|
||||||
"lightbox.previous": "Anterior",
|
"lightbox.previous": "Anterior",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Adicionar a listas",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Remover da lista",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "Editar lista",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "Adicionar lista",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "Novo título da lista",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "Procurar entre as pessoas que você segue",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "Suas listas",
|
||||||
"loading_indicator.label": "Carregando...",
|
"loading_indicator.label": "Carregando...",
|
||||||
"media_gallery.toggle_visible": "Esconder/Mostrar",
|
"media_gallery.toggle_visible": "Esconder/Mostrar",
|
||||||
"missing_indicator.label": "Não encontrado",
|
"missing_indicator.label": "Não encontrado",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "Seguidores pendentes",
|
"navigation_bar.follow_requests": "Seguidores pendentes",
|
||||||
"navigation_bar.info": "Mais informações",
|
"navigation_bar.info": "Mais informações",
|
||||||
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
|
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Listas",
|
||||||
"navigation_bar.logout": "Sair",
|
"navigation_bar.logout": "Sair",
|
||||||
"navigation_bar.mutes": "Usuários silenciados",
|
"navigation_bar.mutes": "Usuários silenciados",
|
||||||
"navigation_bar.pins": "Postagens fixadas",
|
"navigation_bar.pins": "Postagens fixadas",
|
||||||
|
@ -177,7 +177,7 @@
|
||||||
"onboarding.page_one.welcome": "Seja bem-vindo(a) ao Mastodon!",
|
"onboarding.page_one.welcome": "Seja bem-vindo(a) ao Mastodon!",
|
||||||
"onboarding.page_six.admin": "O administrador de sua instância é {admin}.",
|
"onboarding.page_six.admin": "O administrador de sua instância é {admin}.",
|
||||||
"onboarding.page_six.almost_done": "Quase acabando...",
|
"onboarding.page_six.almost_done": "Quase acabando...",
|
||||||
"onboarding.page_six.appetoot": "Bon Appetoot!",
|
"onboarding.page_six.appetoot": "Bom Apetoot!",
|
||||||
"onboarding.page_six.apps_available": "Há {apps} disponíveis para iOS, Android e outras plataformas.",
|
"onboarding.page_six.apps_available": "Há {apps} disponíveis para iOS, Android e outras plataformas.",
|
||||||
"onboarding.page_six.github": "Mastodon é um software gratuito e de código aberto. Você pode reportar bugs, prequisitar novas funções ou contribuir para o código no {github}.",
|
"onboarding.page_six.github": "Mastodon é um software gratuito e de código aberto. Você pode reportar bugs, prequisitar novas funções ou contribuir para o código no {github}.",
|
||||||
"onboarding.page_six.guidelines": "diretrizes da comunidade",
|
"onboarding.page_six.guidelines": "diretrizes da comunidade",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"account.block": "Bloquear @{name}",
|
"account.block": "Bloquear @{name}",
|
||||||
"account.block_domain": "Esconder tudo do domínio {domain}",
|
"account.block_domain": "Esconder tudo do domínio {domain}",
|
||||||
"account.disclaimer_full": "Information below may reflect the user's profile incompletely.",
|
"account.disclaimer_full": "As informações abaixo podem refletir o perfil do usuário de forma incompleta.",
|
||||||
"account.edit_profile": "Editar perfil",
|
"account.edit_profile": "Editar perfil",
|
||||||
"account.follow": "Seguir",
|
"account.follow": "Seguir",
|
||||||
"account.followers": "Seguidores",
|
"account.followers": "Seguidores",
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
"account.share": "Partilhar o perfil @{name}",
|
"account.share": "Partilhar o perfil @{name}",
|
||||||
"account.show_reblogs": "Mostrar partilhas de @{name}",
|
"account.show_reblogs": "Mostrar partilhas de @{name}",
|
||||||
"account.unblock": "Não bloquear @{name}",
|
"account.unblock": "Não bloquear @{name}",
|
||||||
"account.unblock_domain": "Unhide {domain}",
|
"account.unblock_domain": "Mostrar {domain}",
|
||||||
"account.unfollow": "Deixar de seguir",
|
"account.unfollow": "Deixar de seguir",
|
||||||
"account.unmute": "Não silenciar @{name}",
|
"account.unmute": "Não silenciar @{name}",
|
||||||
"account.unmute_notifications": "Deixar de silenciar @{name}",
|
"account.unmute_notifications": "Deixar de silenciar @{name}",
|
||||||
|
@ -36,7 +36,7 @@
|
||||||
"column.favourites": "Favoritos",
|
"column.favourites": "Favoritos",
|
||||||
"column.follow_requests": "Seguidores Pendentes",
|
"column.follow_requests": "Seguidores Pendentes",
|
||||||
"column.home": "Home",
|
"column.home": "Home",
|
||||||
"column.lists": "Lists",
|
"column.lists": "Listas",
|
||||||
"column.mutes": "Utilizadores silenciados",
|
"column.mutes": "Utilizadores silenciados",
|
||||||
"column.notifications": "Notificações",
|
"column.notifications": "Notificações",
|
||||||
"column.pins": "Pinned toot",
|
"column.pins": "Pinned toot",
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
"confirmations.delete.confirm": "Eliminar",
|
"confirmations.delete.confirm": "Eliminar",
|
||||||
"confirmations.delete.message": "De certeza que queres eliminar esta publicação?",
|
"confirmations.delete.message": "De certeza que queres eliminar esta publicação?",
|
||||||
"confirmations.delete_list.confirm": "Delete",
|
"confirmations.delete_list.confirm": "Delete",
|
||||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
"confirmations.delete_list.message": "Tens a certeza de que desejas apagar permanentemente esta lista?",
|
||||||
"confirmations.domain_block.confirm": "Esconder tudo deste domínio",
|
"confirmations.domain_block.confirm": "Esconder tudo deste domínio",
|
||||||
"confirmations.domain_block.message": "De certeza que queres bloquear por completo o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é o suficiente e o recomendado.",
|
"confirmations.domain_block.message": "De certeza que queres bloquear por completo o domínio {domain}? Na maioria dos casos, silenciar ou bloquear alguns utilizadores é o suficiente e o recomendado.",
|
||||||
"confirmations.mute.confirm": "Silenciar",
|
"confirmations.mute.confirm": "Silenciar",
|
||||||
|
@ -88,12 +88,12 @@
|
||||||
"emoji_button.symbols": "Símbolos",
|
"emoji_button.symbols": "Símbolos",
|
||||||
"emoji_button.travel": "Viagens & Lugares",
|
"emoji_button.travel": "Viagens & Lugares",
|
||||||
"empty_column.community": "Ainda não existe conteúdo local para mostrar!",
|
"empty_column.community": "Ainda não existe conteúdo local para mostrar!",
|
||||||
"empty_column.hashtag": "Não foram encontradas publicações com essa hashtag",
|
"empty_column.hashtag": "Não foram encontradas publicações com essa hashtag.",
|
||||||
"empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.",
|
"empty_column.home": "Ainda não segues qualquer utilizador. Visita {public} ou utiliza a pesquisa para procurar outros utilizadores.",
|
||||||
"empty_column.home.public_timeline": "global",
|
"empty_column.home.public_timeline": "global",
|
||||||
"empty_column.list": "Ainda não existem publicações nesta lista.",
|
"empty_column.list": "Ainda não existem publicações nesta lista.",
|
||||||
"empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.",
|
"empty_column.notifications": "Não tens notificações. Interage com outros utilizadores para iniciar uma conversa.",
|
||||||
"empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos.",
|
"empty_column.public": "Não há nada aqui! Escreve algo publicamente ou segue outros utilizadores para ver aqui os conteúdos públicos",
|
||||||
"follow_request.authorize": "Autorizar",
|
"follow_request.authorize": "Autorizar",
|
||||||
"follow_request.reject": "Rejeitar",
|
"follow_request.reject": "Rejeitar",
|
||||||
"getting_started.appsshort": "Aplicações",
|
"getting_started.appsshort": "Aplicações",
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
"keyboard_shortcuts.enter": "para expandir uma publicação",
|
"keyboard_shortcuts.enter": "para expandir uma publicação",
|
||||||
"keyboard_shortcuts.favourite": "para adicionar aos favoritos",
|
"keyboard_shortcuts.favourite": "para adicionar aos favoritos",
|
||||||
"keyboard_shortcuts.heading": "Atalhos do teclado",
|
"keyboard_shortcuts.heading": "Atalhos do teclado",
|
||||||
"keyboard_shortcuts.hotkey": "Hotkey",
|
"keyboard_shortcuts.hotkey": "Atalho",
|
||||||
"keyboard_shortcuts.legend": "para mostrar esta legenda",
|
"keyboard_shortcuts.legend": "para mostrar esta legenda",
|
||||||
"keyboard_shortcuts.mention": "para mencionar o autor",
|
"keyboard_shortcuts.mention": "para mencionar o autor",
|
||||||
"keyboard_shortcuts.reply": "para responder",
|
"keyboard_shortcuts.reply": "para responder",
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
"lightbox.close": "Fechar",
|
"lightbox.close": "Fechar",
|
||||||
"lightbox.next": "Próximo",
|
"lightbox.next": "Próximo",
|
||||||
"lightbox.previous": "Anterior",
|
"lightbox.previous": "Anterior",
|
||||||
"lists.account.add": "Add to list",
|
"lists.account.add": "Adicionar à lista",
|
||||||
"lists.account.remove": "Remove from list",
|
"lists.account.remove": "Remover da lista",
|
||||||
"lists.delete": "Delete list",
|
"lists.delete": "Delete list",
|
||||||
"lists.edit": "Edit list",
|
"lists.edit": "Editar lista",
|
||||||
"lists.new.create": "Add list",
|
"lists.new.create": "Adicionar lista",
|
||||||
"lists.new.title_placeholder": "New list title",
|
"lists.new.title_placeholder": "Novo título da lista",
|
||||||
"lists.search": "Search among people you follow",
|
"lists.search": "Pesquisa entre as pessoas que segues",
|
||||||
"lists.subheading": "Your lists",
|
"lists.subheading": "As tuas listas",
|
||||||
"loading_indicator.label": "A carregar...",
|
"loading_indicator.label": "A carregar...",
|
||||||
"media_gallery.toggle_visible": "Esconder/Mostrar",
|
"media_gallery.toggle_visible": "Esconder/Mostrar",
|
||||||
"missing_indicator.label": "Não encontrado",
|
"missing_indicator.label": "Não encontrado",
|
||||||
|
@ -146,7 +146,7 @@
|
||||||
"navigation_bar.follow_requests": "Seguidores pendentes",
|
"navigation_bar.follow_requests": "Seguidores pendentes",
|
||||||
"navigation_bar.info": "Mais informações",
|
"navigation_bar.info": "Mais informações",
|
||||||
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
|
"navigation_bar.keyboard_shortcuts": "Atalhos de teclado",
|
||||||
"navigation_bar.lists": "Lists",
|
"navigation_bar.lists": "Listas",
|
||||||
"navigation_bar.logout": "Sair",
|
"navigation_bar.logout": "Sair",
|
||||||
"navigation_bar.mutes": "Utilizadores silenciados",
|
"navigation_bar.mutes": "Utilizadores silenciados",
|
||||||
"navigation_bar.pins": "Posts fixos",
|
"navigation_bar.pins": "Posts fixos",
|
||||||
|
@ -209,13 +209,13 @@
|
||||||
"search_popout.search_format": "Formato avançado de pesquisa",
|
"search_popout.search_format": "Formato avançado de pesquisa",
|
||||||
"search_popout.tips.hashtag": "hashtag",
|
"search_popout.tips.hashtag": "hashtag",
|
||||||
"search_popout.tips.status": "status",
|
"search_popout.tips.status": "status",
|
||||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
"search_popout.tips.text": "O texto simples retorna a correspondência de nomes, utilizadores e hashtags",
|
||||||
"search_popout.tips.user": "utilizador",
|
"search_popout.tips.user": "utilizador",
|
||||||
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
|
"search_results.total": "{count, number} {count, plural, one {resultado} other {resultados}}",
|
||||||
"standalone.public_title": "Espreitar lá dentro...",
|
"standalone.public_title": "Espreitar lá dentro...",
|
||||||
"status.cannot_reblog": "Este post não pode ser partilhado",
|
"status.cannot_reblog": "Este post não pode ser partilhado",
|
||||||
"status.delete": "Eliminar",
|
"status.delete": "Eliminar",
|
||||||
"status.embed": "Embed",
|
"status.embed": "Incorporar",
|
||||||
"status.favourite": "Adicionar aos favoritos",
|
"status.favourite": "Adicionar aos favoritos",
|
||||||
"status.load_more": "Carregar mais",
|
"status.load_more": "Carregar mais",
|
||||||
"status.media_hidden": "Media escondida",
|
"status.media_hidden": "Media escondida",
|
||||||
|
|
|
@ -91,7 +91,7 @@
|
||||||
"empty_column.hashtag": "这个话题标签下暂时没有内容。",
|
"empty_column.hashtag": "这个话题标签下暂时没有内容。",
|
||||||
"empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。",
|
"empty_column.home": "你还没有关注任何用户。快看看{public},向其他用户搭讪吧。",
|
||||||
"empty_column.home.public_timeline": "公共时间轴",
|
"empty_column.home.public_timeline": "公共时间轴",
|
||||||
"empty_column.list": "这个列表中暂时没有内容。",
|
"empty_column.list": "这个列表中暂时没有内容。列表中用户所发送的的新嘟文将会在这里显示。",
|
||||||
"empty_column.notifications": "你还没有收到过通知信息,快向其他用户搭讪吧。",
|
"empty_column.notifications": "你还没有收到过通知信息,快向其他用户搭讪吧。",
|
||||||
"empty_column.public": "这里神马都没有!写一些公开的嘟文,或者关注其他实例的用户,这里就会有嘟文出现了哦!",
|
"empty_column.public": "这里神马都没有!写一些公开的嘟文,或者关注其他实例的用户,这里就会有嘟文出现了哦!",
|
||||||
"follow_request.authorize": "同意",
|
"follow_request.authorize": "同意",
|
||||||
|
|
|
@ -62,7 +62,13 @@ export function connectStream(path, pollingRefresh = null, callbacks = () => ({
|
||||||
|
|
||||||
|
|
||||||
export default function getStream(streamingAPIBaseURL, accessToken, stream, { connected, received, disconnected, reconnected }) {
|
export default function getStream(streamingAPIBaseURL, accessToken, stream, { connected, received, disconnected, reconnected }) {
|
||||||
const ws = new WebSocketClient(`${streamingAPIBaseURL}/api/v1/streaming/?access_token=${accessToken}&stream=${stream}`);
|
const params = [ `stream=${stream}` ];
|
||||||
|
|
||||||
|
if (accessToken !== null) {
|
||||||
|
params.push(`access_token=${accessToken}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ws = new WebSocketClient(`${streamingAPIBaseURL}/api/v1/streaming/?${params.join('&')}`);
|
||||||
|
|
||||||
ws.onopen = connected;
|
ws.onopen = connected;
|
||||||
ws.onmessage = e => received(JSON.parse(e.data));
|
ws.onmessage = e => received(JSON.parse(e.data));
|
||||||
|
|
|
@ -265,7 +265,6 @@
|
||||||
|
|
||||||
.compose-form {
|
.compose-form {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__warning {
|
.compose-form__warning {
|
||||||
color: darken($ui-secondary-color, 65%);
|
color: darken($ui-secondary-color, 65%);
|
||||||
|
@ -301,47 +300,121 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compose-form__autosuggest-wrapper {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.emoji-picker-dropdown {
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea,
|
||||||
|
.spoiler-input {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea__textarea,
|
||||||
|
.spoiler-input__input {
|
||||||
|
display: block;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0;
|
||||||
|
color: $ui-base-color;
|
||||||
|
background: $simple-background-color;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 14px;
|
||||||
|
resize: vertical;
|
||||||
|
border: 0;
|
||||||
|
outline: 0;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.spoiler-input__input {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea__textarea {
|
||||||
|
min-height: 100px;
|
||||||
|
border-radius: 4px 4px 0 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-right: 10px + 22px;
|
||||||
|
resize: none;
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
height: 100px !important; // prevent auto-resize textarea
|
||||||
|
resize: vertical;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea__suggestions {
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 99;
|
||||||
|
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
|
||||||
|
background: $ui-secondary-color;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
color: $ui-base-color;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 6px;
|
||||||
|
|
||||||
|
&.autosuggest-textarea__suggestions--visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-textarea__suggestions__item {
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus,
|
||||||
|
&:active,
|
||||||
|
&.selected {
|
||||||
|
background: darken($ui-secondary-color, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-account,
|
||||||
|
.autosuggest-emoji {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
line-height: 18px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-account-icon,
|
||||||
|
.autosuggest-emoji img {
|
||||||
|
display: block;
|
||||||
|
margin-right: 8px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autosuggest-account .display-name__account {
|
||||||
|
color: lighten($ui-base-color, 36%);
|
||||||
|
}
|
||||||
|
|
||||||
.compose-form__modifiers {
|
.compose-form__modifiers {
|
||||||
color: $ui-base-color;
|
color: $ui-base-color;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
background: $simple-background-color;
|
background: $simple-background-color;
|
||||||
border-radius: 0 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__buttons-wrapper {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__buttons {
|
|
||||||
padding: 10px;
|
|
||||||
background: darken($simple-background-color, 8%);
|
|
||||||
box-shadow: inset 0 5px 5px rgba($base-shadow-color, 0.05);
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
box-sizing: content-box;
|
|
||||||
padding: 0 3px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__upload-button-icon {
|
|
||||||
line-height: 27px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__sensitive-button {
|
|
||||||
display: none;
|
|
||||||
|
|
||||||
&.compose-form__sensitive-button--visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__sensitive-button__icon {
|
|
||||||
line-height: 27px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__upload-wrapper {
|
.compose-form__upload-wrapper {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -410,54 +483,69 @@
|
||||||
height: 100px;
|
height: 100px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.compose-form__label {
|
.compose-form__buttons-wrapper {
|
||||||
|
padding: 10px;
|
||||||
|
background: darken($simple-background-color, 8%);
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
.compose-form__buttons {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.compose-form__upload-button-icon {
|
||||||
|
line-height: 27px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compose-form__sensitive-button {
|
||||||
|
display: none;
|
||||||
|
|
||||||
|
&.compose-form__sensitive-button--visible {
|
||||||
display: block;
|
display: block;
|
||||||
line-height: 24px;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
&.with-border {
|
|
||||||
border-top: 1px solid $ui-base-color;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__label__text {
|
.compose-form__sensitive-button__icon {
|
||||||
display: inline-block;
|
line-height: 27px;
|
||||||
vertical-align: middle;
|
}
|
||||||
margin-bottom: 14px;
|
|
||||||
margin-left: 8px;
|
|
||||||
color: $ui-primary-color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__textarea,
|
.icon-button {
|
||||||
.follow-form__input {
|
box-sizing: content-box;
|
||||||
background: $simple-background-color;
|
padding: 0 3px;
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
background: $ui-secondary-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__autosuggest-wrapper {
|
.character-counter__wrapper {
|
||||||
position: relative;
|
align-self: center;
|
||||||
|
margin-right: 4px;
|
||||||
|
|
||||||
.emoji-picker-dropdown {
|
.character-counter {
|
||||||
position: absolute;
|
cursor: default;
|
||||||
right: 5px;
|
font-family: 'mastodon-font-sans-serif', sans-serif;
|
||||||
top: 5px;
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: lighten($ui-base-color, 12%);
|
||||||
|
|
||||||
|
&.character-counter--over {
|
||||||
|
color: $warning-red;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__publish {
|
.compose-form__publish {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
|
||||||
|
|
||||||
.compose-form__publish-button-wrapper {
|
.compose-form__publish-button-wrapper {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.emojione {
|
.emojione {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -1973,121 +2061,6 @@
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autosuggest-textarea,
|
|
||||||
.spoiler-input {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__textarea,
|
|
||||||
.spoiler-input__input {
|
|
||||||
display: block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
color: $ui-base-color;
|
|
||||||
background: $simple-background-color;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: 14px;
|
|
||||||
resize: vertical;
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.spoiler-input__input {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__textarea {
|
|
||||||
min-height: 100px;
|
|
||||||
border-radius: 4px 4px 0 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
padding-right: 10px + 22px;
|
|
||||||
resize: none;
|
|
||||||
|
|
||||||
@media screen and (max-width: 600px) {
|
|
||||||
height: 100px !important; // prevent auto-resize textarea
|
|
||||||
resize: vertical;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions {
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 99;
|
|
||||||
box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
|
|
||||||
background: $ui-secondary-color;
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
color: $ui-base-color;
|
|
||||||
font-size: 14px;
|
|
||||||
padding: 6px;
|
|
||||||
|
|
||||||
&.autosuggest-textarea__suggestions--visible {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-textarea__suggestions__item {
|
|
||||||
padding: 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active,
|
|
||||||
&.selected {
|
|
||||||
background: darken($ui-secondary-color, 10%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account,
|
|
||||||
.autosuggest-emoji {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: flex-start;
|
|
||||||
line-height: 18px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account-icon,
|
|
||||||
.autosuggest-emoji img {
|
|
||||||
display: block;
|
|
||||||
margin-right: 8px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.autosuggest-account .display-name__account {
|
|
||||||
color: lighten($ui-base-color, 36%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-counter__wrapper {
|
|
||||||
line-height: 36px;
|
|
||||||
margin: 0 16px 0 8px;
|
|
||||||
padding-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-counter {
|
|
||||||
cursor: default;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.character-counter--over {
|
|
||||||
color: $warning-red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.getting-started__wrapper {
|
.getting-started__wrapper {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
|
@ -7,9 +7,9 @@ body.rtl {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.character-counter__wrapper {
|
.compose-form .compose-form__buttons-wrapper .character-counter__wrapper {
|
||||||
margin-right: 8px;
|
margin-right: 0;
|
||||||
margin-left: 16px;
|
margin-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navigation-bar__profile {
|
.navigation-bar__profile {
|
||||||
|
@ -30,6 +30,22 @@ body.rtl {
|
||||||
.column-header__buttons {
|
.column-header__buttons {
|
||||||
left: 0;
|
left: 0;
|
||||||
right: auto;
|
right: auto;
|
||||||
|
margin-left: -15px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-inline-form .icon-button {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-header__links .text-btn {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account__avatar-wrapper {
|
||||||
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-header__back-button {
|
.column-header__back-button {
|
||||||
|
@ -41,10 +57,6 @@ body.rtl {
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.compose-form__modifiers {
|
|
||||||
border-radius: 0 0 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.setting-toggle {
|
.setting-toggle {
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
|
|
|
@ -2,13 +2,26 @@
|
||||||
|
|
||||||
class ProviderDiscovery < OEmbed::ProviderDiscovery
|
class ProviderDiscovery < OEmbed::ProviderDiscovery
|
||||||
class << self
|
class << self
|
||||||
|
def get(url, **options)
|
||||||
|
provider = discover_provider(url, options)
|
||||||
|
|
||||||
|
options.delete(:html)
|
||||||
|
|
||||||
|
provider.get(url, options)
|
||||||
|
end
|
||||||
|
|
||||||
def discover_provider(url, **options)
|
def discover_provider(url, **options)
|
||||||
res = Request.new(:get, url).perform
|
|
||||||
format = options[:format]
|
format = options[:format]
|
||||||
|
|
||||||
|
if options[:html]
|
||||||
|
html = Nokogiri::HTML(options[:html])
|
||||||
|
else
|
||||||
|
res = Request.new(:get, url).perform
|
||||||
|
|
||||||
raise OEmbed::NotFound, url if res.code != 200 || res.mime_type != 'text/html'
|
raise OEmbed::NotFound, url if res.code != 200 || res.mime_type != 'text/html'
|
||||||
|
|
||||||
html = Nokogiri::HTML(res.to_s)
|
html = Nokogiri::HTML(res.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
if format.nil? || format == :json
|
if format.nil? || format == :json
|
||||||
provider_endpoint ||= html.at_xpath('//link[@type="application/json+oembed"]')&.attribute('href')&.value
|
provider_endpoint ||= html.at_xpath('//link[@type="application/json+oembed"]')&.attribute('href')&.value
|
||||||
|
|
|
@ -45,6 +45,8 @@ class AccountFilter
|
||||||
else
|
else
|
||||||
Account.default_scoped
|
Account.default_scoped
|
||||||
end
|
end
|
||||||
|
when 'staff'
|
||||||
|
accounts_with_users.merge User.staff
|
||||||
else
|
else
|
||||||
raise "Unknown filter: #{key}"
|
raise "Unknown filter: #{key}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,8 @@ class CustomEmojiFilter
|
||||||
CustomEmoji.remote
|
CustomEmoji.remote
|
||||||
when 'by_domain'
|
when 'by_domain'
|
||||||
CustomEmoji.where(domain: value)
|
CustomEmoji.where(domain: value)
|
||||||
|
when 'shortcode'
|
||||||
|
CustomEmoji.where(shortcode: value)
|
||||||
else
|
else
|
||||||
raise "Unknown filter: #{key}"
|
raise "Unknown filter: #{key}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -40,6 +40,12 @@ class FetchLinkCardService < BaseService
|
||||||
|
|
||||||
return if res.code != 405 && (res.code != 200 || res.mime_type != 'text/html')
|
return if res.code != 405 && (res.code != 200 || res.mime_type != 'text/html')
|
||||||
|
|
||||||
|
@response = Request.new(:get, @url).perform
|
||||||
|
|
||||||
|
return if @response.code != 200 || @response.mime_type != 'text/html'
|
||||||
|
|
||||||
|
@html = @response.to_s
|
||||||
|
|
||||||
attempt_oembed || attempt_opengraph
|
attempt_oembed || attempt_opengraph
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -70,30 +76,32 @@ class FetchLinkCardService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def attempt_oembed
|
def attempt_oembed
|
||||||
response = OEmbed::Providers.get(@url)
|
embed = OEmbed::Providers.get(@url, html: @html)
|
||||||
|
|
||||||
return false unless response.respond_to?(:type)
|
return false unless embed.respond_to?(:type)
|
||||||
|
|
||||||
@card.type = response.type
|
@card.type = embed.type
|
||||||
@card.title = response.respond_to?(:title) ? response.title : ''
|
@card.title = embed.respond_to?(:title) ? embed.title : ''
|
||||||
@card.author_name = response.respond_to?(:author_name) ? response.author_name : ''
|
@card.author_name = embed.respond_to?(:author_name) ? embed.author_name : ''
|
||||||
@card.author_url = response.respond_to?(:author_url) ? response.author_url : ''
|
@card.author_url = embed.respond_to?(:author_url) ? embed.author_url : ''
|
||||||
@card.provider_name = response.respond_to?(:provider_name) ? response.provider_name : ''
|
@card.provider_name = embed.respond_to?(:provider_name) ? embed.provider_name : ''
|
||||||
@card.provider_url = response.respond_to?(:provider_url) ? response.provider_url : ''
|
@card.provider_url = embed.respond_to?(:provider_url) ? embed.provider_url : ''
|
||||||
@card.width = 0
|
@card.width = 0
|
||||||
@card.height = 0
|
@card.height = 0
|
||||||
|
|
||||||
case @card.type
|
case @card.type
|
||||||
when 'link'
|
when 'link'
|
||||||
@card.image = URI.parse(response.thumbnail_url) if response.respond_to?(:thumbnail_url)
|
@card.image = URI.parse(embed.thumbnail_url) if embed.respond_to?(:thumbnail_url)
|
||||||
when 'photo'
|
when 'photo'
|
||||||
@card.embed_url = response.url
|
return false unless embed.respond_to?(:url)
|
||||||
@card.width = response.width.presence || 0
|
@card.embed_url = embed.url
|
||||||
@card.height = response.height.presence || 0
|
@card.image = URI.parse(embed.url)
|
||||||
|
@card.width = embed.width.presence || 0
|
||||||
|
@card.height = embed.height.presence || 0
|
||||||
when 'video'
|
when 'video'
|
||||||
@card.width = response.width.presence || 0
|
@card.width = embed.width.presence || 0
|
||||||
@card.height = response.height.presence || 0
|
@card.height = embed.height.presence || 0
|
||||||
@card.html = Formatter.instance.sanitize(response.html, Sanitize::Config::MASTODON_OEMBED)
|
@card.html = Formatter.instance.sanitize(embed.html, Sanitize::Config::MASTODON_OEMBED)
|
||||||
when 'rich'
|
when 'rich'
|
||||||
# Most providers rely on <script> tags, which is a no-no
|
# Most providers rely on <script> tags, which is a no-no
|
||||||
return false
|
return false
|
||||||
|
@ -105,17 +113,11 @@ class FetchLinkCardService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def attempt_opengraph
|
def attempt_opengraph
|
||||||
response = Request.new(:get, @url).perform
|
|
||||||
|
|
||||||
return if response.code != 200 || response.mime_type != 'text/html'
|
|
||||||
|
|
||||||
html = response.to_s
|
|
||||||
|
|
||||||
detector = CharlockHolmes::EncodingDetector.new
|
detector = CharlockHolmes::EncodingDetector.new
|
||||||
detector.strip_tags = true
|
detector.strip_tags = true
|
||||||
|
|
||||||
guess = detector.detect(html, response.charset)
|
guess = detector.detect(@html, @response.charset)
|
||||||
page = Nokogiri::HTML(html, nil, guess&.fetch(:encoding, nil))
|
page = Nokogiri::HTML(@html, nil, guess&.fetch(:encoding, nil))
|
||||||
|
|
||||||
if meta_property(page, 'twitter:player')
|
if meta_property(page, 'twitter:player')
|
||||||
@card.type = :video
|
@card.type = :video
|
||||||
|
@ -140,8 +142,8 @@ class FetchLinkCardService < BaseService
|
||||||
@card.save_with_optional_image!
|
@card.save_with_optional_image!
|
||||||
end
|
end
|
||||||
|
|
||||||
def meta_property(html, property)
|
def meta_property(page, property)
|
||||||
html.at_xpath("//meta[@property=\"#{property}\"]")&.attribute('content')&.value || html.at_xpath("//meta[@name=\"#{property}\"]")&.attribute('content')&.value
|
page.at_xpath("//meta[@property=\"#{property}\"]")&.attribute('content')&.value || page.at_xpath("//meta[@name=\"#{property}\"]")&.attribute('content')&.value
|
||||||
end
|
end
|
||||||
|
|
||||||
def lock_options
|
def lock_options
|
||||||
|
|
|
@ -40,6 +40,6 @@ class FetchRemoteStatusService < BaseService
|
||||||
end
|
end
|
||||||
|
|
||||||
def confirmed_domain?(domain, account)
|
def confirmed_domain?(domain, account)
|
||||||
account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url || account.uri).normalized_host).zero?
|
account.domain.nil? || domain.casecmp(account.domain).zero? || domain.casecmp(Addressable::URI.parse(account.remote_url.presence || account.uri).normalized_host).zero?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@ class FollowService < BaseService
|
||||||
elsif source_account.requested?(target_account)
|
elsif source_account.requested?(target_account)
|
||||||
# This isn't managed by a method in AccountInteractions, so we modify it
|
# This isn't managed by a method in AccountInteractions, so we modify it
|
||||||
# ourselves if necessary.
|
# ourselves if necessary.
|
||||||
req = follow_requests.find_by(target_account: other_account)
|
req = source_account.follow_requests.find_by(target_account: target_account)
|
||||||
req.update!(show_reblogs: reblogs)
|
req.update!(show_reblogs: reblogs)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,22 +4,11 @@
|
||||||
%td.domain
|
%td.domain
|
||||||
- unless account.local?
|
- unless account.local?
|
||||||
= link_to account.domain, admin_accounts_path(by_domain: account.domain)
|
= link_to account.domain, admin_accounts_path(by_domain: account.domain)
|
||||||
%td.protocol
|
%td
|
||||||
- unless account.local?
|
- if account.local?
|
||||||
|
= t("admin.accounts.roles.#{account.user&.role}")
|
||||||
|
- else
|
||||||
= account.protocol.humanize
|
= account.protocol.humanize
|
||||||
%td.confirmed
|
|
||||||
- if account.local?
|
|
||||||
- if account.user_confirmed?
|
|
||||||
%i.fa.fa-check
|
|
||||||
- else
|
|
||||||
%i.fa.fa-times
|
|
||||||
%td.subscribed
|
|
||||||
- if account.local?
|
|
||||||
= t('admin.accounts.location.local')
|
|
||||||
- elsif account.subscribed?
|
|
||||||
%i.fa.fa-check
|
|
||||||
- else
|
|
||||||
%i.fa.fa-times
|
|
||||||
%td
|
%td
|
||||||
= table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}")
|
= table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}")
|
||||||
= table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account)
|
= table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account)
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
= filter_link_to t('admin.accounts.moderation.suspended'), {suspended: nil}, {suspended: '1'}
|
= filter_link_to t('admin.accounts.moderation.suspended'), {suspended: nil}, {suspended: '1'}
|
||||||
- else
|
- else
|
||||||
= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1'
|
= filter_link_to t('admin.accounts.moderation.suspended'), suspended: '1'
|
||||||
|
.filter-subset
|
||||||
|
%strong= t('admin.accounts.role')
|
||||||
|
%ul
|
||||||
|
%li= filter_link_to t('admin.accounts.moderation.all'), staff: nil
|
||||||
|
%li= filter_link_to t('admin.accounts.roles.staff'), staff: '1'
|
||||||
.filter-subset
|
.filter-subset
|
||||||
%strong= t('admin.accounts.order.title')
|
%strong= t('admin.accounts.order.title')
|
||||||
%ul
|
%ul
|
||||||
|
@ -56,9 +61,7 @@
|
||||||
%tr
|
%tr
|
||||||
%th= t('admin.accounts.username')
|
%th= t('admin.accounts.username')
|
||||||
%th= t('admin.accounts.domain')
|
%th= t('admin.accounts.domain')
|
||||||
%th= t('admin.accounts.protocol')
|
%th
|
||||||
%th= t('admin.accounts.confirmed')
|
|
||||||
%th= fa_icon 'paper-plane-o'
|
|
||||||
%th
|
%th
|
||||||
%tbody
|
%tbody
|
||||||
= render @accounts
|
= render @accounts
|
||||||
|
|
|
@ -104,7 +104,7 @@
|
||||||
- else
|
- else
|
||||||
= link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account)
|
= link_to t('admin.accounts.perform_full_suspension'), admin_account_suspension_path(@account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') }, class: 'button' if can?(:suspend, @account)
|
||||||
|
|
||||||
- unless @account.local?
|
- if !@account.local? && @account.hub_url.present?
|
||||||
%hr
|
%hr
|
||||||
%h3 OStatus
|
%h3 OStatus
|
||||||
|
|
||||||
|
@ -132,6 +132,7 @@
|
||||||
- if @account.subscribed?
|
- if @account.subscribed?
|
||||||
= link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account)
|
= link_to t('admin.accounts.unsubscribe'), unsubscribe_admin_account_path(@account.id), method: :post, class: 'button negative' if can?(:unsubscribe, @account)
|
||||||
|
|
||||||
|
- if !@account.local? && @account.inbox_url.present?
|
||||||
%hr
|
%hr
|
||||||
%h3 ActivityPub
|
%h3 ActivityPub
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
- if custom_emoji.local?
|
- if custom_emoji.local?
|
||||||
= t('admin.accounts.location.local')
|
= t('admin.accounts.location.local')
|
||||||
- else
|
- else
|
||||||
= custom_emoji.domain
|
= link_to custom_emoji.domain, admin_custom_emojis_path(by_domain: custom_emoji.domain)
|
||||||
%td
|
%td
|
||||||
- if custom_emoji.local?
|
- if custom_emoji.local?
|
||||||
- if custom_emoji.visible_in_picker
|
- if custom_emoji.visible_in_picker
|
||||||
|
|
|
@ -17,6 +17,20 @@
|
||||||
- else
|
- else
|
||||||
= filter_link_to t('admin.accounts.location.remote'), remote: '1', local: nil
|
= filter_link_to t('admin.accounts.location.remote'), remote: '1', local: nil
|
||||||
|
|
||||||
|
= form_tag admin_custom_emojis_url, method: 'GET', class: 'simple_form' do
|
||||||
|
.fields-group
|
||||||
|
- Admin::FilterHelper::CUSTOM_EMOJI_FILTERS.each do |key|
|
||||||
|
- if params[key].present?
|
||||||
|
= hidden_field_tag key, params[key]
|
||||||
|
|
||||||
|
- %i(shortcode by_domain).each do |key|
|
||||||
|
.input.string.optional
|
||||||
|
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.custom_emojis.#{key}")
|
||||||
|
|
||||||
|
.actions
|
||||||
|
%button= t('admin.accounts.search')
|
||||||
|
= link_to t('admin.accounts.reset'), admin_accounts_path, class: 'button negative'
|
||||||
|
|
||||||
.table-wrapper
|
.table-wrapper
|
||||||
%table.table
|
%table.table
|
||||||
%thead
|
%thead
|
||||||
|
|
|
@ -17,9 +17,12 @@ Rails.application.configure do
|
||||||
config.x.alternate_domains = alternate_domains.split(/\s*,\s*/)
|
config.x.alternate_domains = alternate_domains.split(/\s*,\s*/)
|
||||||
|
|
||||||
config.action_mailer.default_url_options = { host: web_host, protocol: https ? 'https://' : 'http://', trailing_slash: false }
|
config.action_mailer.default_url_options = { host: web_host, protocol: https ? 'https://' : 'http://', trailing_slash: false }
|
||||||
config.x.streaming_api_base_url = 'ws://localhost:4000'
|
|
||||||
|
|
||||||
|
config.x.streaming_api_base_url = ENV.fetch('STREAMING_API_BASE_URL') do
|
||||||
if Rails.env.production?
|
if Rails.env.production?
|
||||||
config.x.streaming_api_base_url = ENV.fetch('STREAMING_API_BASE_URL') { "ws#{https ? 's' : ''}://#{web_host}" }
|
"ws#{https ? 's' : ''}://#{web_host}"
|
||||||
|
else
|
||||||
|
"ws://#{ENV['REMOTE_DEV'] == 'true' ? host.split(':').first : 'localhost'}:4000"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,20 +57,65 @@ ar:
|
||||||
order:
|
order:
|
||||||
title: الترتيب
|
title: الترتيب
|
||||||
profile_url: رابط الملف الشخصي
|
profile_url: رابط الملف الشخصي
|
||||||
|
role: التصريحات
|
||||||
|
roles:
|
||||||
|
admin: مدير
|
||||||
|
user: مستخدِم
|
||||||
|
search: البحث
|
||||||
|
statuses: المنشورات
|
||||||
|
title: الحسابات
|
||||||
|
username: إسم المستخدم
|
||||||
|
web: الويب
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
|
copy: نسخ
|
||||||
delete: حذف
|
delete: حذف
|
||||||
|
emoji: إيموجي
|
||||||
|
enable: تفعيل
|
||||||
|
upload: رفع
|
||||||
|
domain_blocks:
|
||||||
|
domain: النطاق
|
||||||
|
show:
|
||||||
|
undo: إلغاء
|
||||||
|
undo: إلغاء
|
||||||
email_domain_blocks:
|
email_domain_blocks:
|
||||||
delete: حذف
|
delete: حذف
|
||||||
|
domain: النطاق
|
||||||
|
new:
|
||||||
|
create: إضافة نطاق
|
||||||
|
instances:
|
||||||
|
domain_name: النطاق
|
||||||
|
search: البحث
|
||||||
reports:
|
reports:
|
||||||
|
are_you_sure: هل أنت متأكد ؟
|
||||||
|
comment:
|
||||||
|
label: تعليق
|
||||||
delete: حذف
|
delete: حذف
|
||||||
|
report_contents: المحتويات
|
||||||
|
reported_by: أبلغ عنه من طرف
|
||||||
|
status: الحالة
|
||||||
|
title: التقارير
|
||||||
|
view: عرض
|
||||||
settings:
|
settings:
|
||||||
|
contact_information:
|
||||||
|
email: البريد الإلكتروني المهني
|
||||||
registrations:
|
registrations:
|
||||||
deletion:
|
deletion:
|
||||||
desc_html: السماح لأي مستخدم إغلاق حسابه
|
desc_html: السماح لأي مستخدم إغلاق حسابه
|
||||||
|
open:
|
||||||
|
title: فتح التسجيل
|
||||||
|
site_terms:
|
||||||
|
title: شروط الخدمة المخصصة
|
||||||
|
site_title: إسم مثيل الخادم
|
||||||
|
title: إعدادات الموقع
|
||||||
statuses:
|
statuses:
|
||||||
|
back_to_account: العودة إلى صفحة الحساب
|
||||||
batch:
|
batch:
|
||||||
delete: حذف
|
delete: حذف
|
||||||
|
media:
|
||||||
|
title: الوسائط
|
||||||
|
title: الإدارة
|
||||||
application_mailer:
|
application_mailer:
|
||||||
|
salutation: "%{name},"
|
||||||
settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}'
|
settings: 'تغيير تفضيلات البريد الإلكتروني : %{link}'
|
||||||
signature: إشعارات ماستدون من %{instance}
|
signature: إشعارات ماستدون من %{instance}
|
||||||
view: 'View:'
|
view: 'View:'
|
||||||
|
@ -83,6 +128,7 @@ ar:
|
||||||
forgot_password: نسيت كلمة المرور ؟
|
forgot_password: نسيت كلمة المرور ؟
|
||||||
login: تسجيل الدخول
|
login: تسجيل الدخول
|
||||||
logout: خروج
|
logout: خروج
|
||||||
|
migrate_account: الإنتقال إلى حساب آخر
|
||||||
register: إنشاء حساب
|
register: إنشاء حساب
|
||||||
resend_confirmation: إعادة إرسال تعليمات التأكيد
|
resend_confirmation: إعادة إرسال تعليمات التأكيد
|
||||||
reset_password: إعادة تعيين كلمة المرور
|
reset_password: إعادة تعيين كلمة المرور
|
||||||
|
@ -106,15 +152,20 @@ ar:
|
||||||
x_months: "%{count} شه"
|
x_months: "%{count} شه"
|
||||||
x_seconds: "%{count}ث"
|
x_seconds: "%{count}ث"
|
||||||
deletes:
|
deletes:
|
||||||
|
bad_password_msg: محاولة جيدة يا هاكرز ! كلمة السر خاطئة
|
||||||
proceed: حذف حساب
|
proceed: حذف حساب
|
||||||
|
success_msg: تم حذف حسابك بنجاح
|
||||||
exports:
|
exports:
|
||||||
blocks: قمت بحظر
|
blocks: قمت بحظر
|
||||||
csv: CSV
|
csv: CSV
|
||||||
follows: أنت تتبع
|
follows: أنت تتبع
|
||||||
storage: ذاكرة التخزين
|
storage: ذاكرة التخزين
|
||||||
|
followers:
|
||||||
|
domain: النطاق
|
||||||
|
followers_count: عدد المتابِعين
|
||||||
generic:
|
generic:
|
||||||
changes_saved_msg: تم حفظ التعديلات بنجاح !
|
changes_saved_msg: تم حفظ التعديلات بنجاح !
|
||||||
powered_by: powered by %{link}
|
powered_by: مدعوم بـ %{link}
|
||||||
save_changes: حفظ التغييرات
|
save_changes: حفظ التغييرات
|
||||||
validation_errors:
|
validation_errors:
|
||||||
one: Something isn't quite right yet! Please review the error below
|
one: Something isn't quite right yet! Please review the error below
|
||||||
|
@ -128,14 +179,19 @@ ar:
|
||||||
upload: تحميل
|
upload: تحميل
|
||||||
landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse.."
|
landing_strip_html: "<strong>%{name}</strong> is a user on %{link_to_root_path}. You can follow them or interact with them if you have an account anywhere in the fediverse.."
|
||||||
landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>.
|
landing_strip_signup_html: If you don't, you can <a href="%{sign_up_path}">sign up here</a>.
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: لقد بلغت الحد الأقصى للقوائم
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: ليس بالإمكان إرفاق فيديو في منشور يحتوي مسبقا على صور
|
images_and_video: ليس بالإمكان إرفاق فيديو في منشور يحتوي مسبقا على صور
|
||||||
too_many: لا يمكن إرفاق أكثر من 4 ملفات
|
too_many: لا يمكن إرفاق أكثر من 4 ملفات
|
||||||
|
migrations:
|
||||||
|
acct: username@domain للحساب الجديد
|
||||||
notification_mailer:
|
notification_mailer:
|
||||||
digest:
|
digest:
|
||||||
body: 'Here is a brief summary of what you missed on %{instance} since your last visit on %{since}:'
|
body: 'Here is a brief summary of what you missed on %{instance} since your last visit on %{since}:'
|
||||||
mention: "%{name} mentioned you in:"
|
mention: "%{name} أشار إليك في :"
|
||||||
new_followers_summary:
|
new_followers_summary:
|
||||||
one: لقد حصلت على متابع جديد !
|
one: لقد حصلت على متابع جديد !
|
||||||
other: لقد تحصلت على %{count} متتبعين جدد ! رائع !
|
other: لقد تحصلت على %{count} متتبعين جدد ! رائع !
|
||||||
|
@ -143,11 +199,11 @@ ar:
|
||||||
one: "إشعار واحد منذ زيارتك الأخيرة \U0001F418"
|
one: "إشعار واحد منذ زيارتك الأخيرة \U0001F418"
|
||||||
other: "%{count} إشعارات جديدة منذ زيارتك الأخيرة \U0001F418"
|
other: "%{count} إشعارات جديدة منذ زيارتك الأخيرة \U0001F418"
|
||||||
favourite:
|
favourite:
|
||||||
body: أُعجب %{name} بمنشورك
|
body: 'أُعجب %{name} بمنشورك :'
|
||||||
subject: "%{name} favourited your status"
|
subject: "%{name} favourited your status"
|
||||||
follow:
|
follow:
|
||||||
body: "%{name} من متتبعيك الآن !"
|
body: "%{name} من متتبعيك الآن !"
|
||||||
subject: "%{name} من متتبعيك الآن !"
|
subject: "%{name} من متتبعيك الآن"
|
||||||
follow_request:
|
follow_request:
|
||||||
body: "%{name} has requested to follow you"
|
body: "%{name} has requested to follow you"
|
||||||
subject: 'Pending follower: %{name}'
|
subject: 'Pending follower: %{name}'
|
||||||
|
@ -171,16 +227,21 @@ ar:
|
||||||
pagination:
|
pagination:
|
||||||
next: التالي
|
next: التالي
|
||||||
prev: السابق
|
prev: السابق
|
||||||
|
preferences:
|
||||||
|
languages: اللغات
|
||||||
|
other: إعدادات أخرى
|
||||||
|
publishing: النشر
|
||||||
remote_follow:
|
remote_follow:
|
||||||
acct: Enter your username@domain you want to follow from
|
acct: قم بإدخال عنوان حسابك username@domain الذي من خلاله تود المتابعة
|
||||||
missing_resource: Could not find the required redirect URL for your account
|
missing_resource: Could not find the required redirect URL for your account
|
||||||
proceed: Proceed to follow
|
proceed: أكمل المتابعة
|
||||||
prompt: 'إنك بصدد متابعة :'
|
prompt: 'إنك بصدد متابعة :'
|
||||||
settings:
|
settings:
|
||||||
authorized_apps: التطبيقات المرخص لها
|
authorized_apps: التطبيقات المرخص لها
|
||||||
back: عودة إلى ماستدون
|
back: عودة إلى ماستدون
|
||||||
edit_profile: تعديل الملف الشخصي
|
edit_profile: تعديل الملف الشخصي
|
||||||
export: تصدير البيانات
|
export: تصدير البيانات
|
||||||
|
followers: المتابِعون المُرَخّصون
|
||||||
import: إستيراد
|
import: إستيراد
|
||||||
preferences: التفضيلات
|
preferences: التفضيلات
|
||||||
settings: الإعدادات
|
settings: الإعدادات
|
||||||
|
|
|
@ -286,7 +286,7 @@ ca:
|
||||||
desc_html: Mostra una insígnia de personal en una pàgina d'usuari
|
desc_html: Mostra una insígnia de personal en una pàgina d'usuari
|
||||||
title: Mostra insígnia de personal
|
title: Mostra insígnia de personal
|
||||||
site_description:
|
site_description:
|
||||||
desc_html: Paràgraf introductori a la pàgina principal i en etiquetes meta.<br>Pots utilitzar etiquetes HTML, en particular <code><a></code> i <code><em></code>.
|
desc_html: Paràgraf introductori a la pàgina principal i en etiquetes meta. Pots utilitzar etiquetes HTML, en particular <code><a></code> i <code><em></code>.
|
||||||
title: Descripció del lloc
|
title: Descripció del lloc
|
||||||
site_description_extended:
|
site_description_extended:
|
||||||
desc_html: Un bon lloc per al codi de conducta, regles, directrius i altres coses que distingeixen la vostra instància. Pots utilitzar etiquetes HTML
|
desc_html: Un bon lloc per al codi de conducta, regles, directrius i altres coses que distingeixen la vostra instància. Pots utilitzar etiquetes HTML
|
||||||
|
|
|
@ -8,8 +8,11 @@ ar:
|
||||||
inactive: لم يتم تنشيط حسابك بعد.
|
inactive: لم يتم تنشيط حسابك بعد.
|
||||||
last_attempt: بإمكانك إعادة المحاولة مرة واحدة قبل أن يتم قفل حسابك.
|
last_attempt: بإمكانك إعادة المحاولة مرة واحدة قبل أن يتم قفل حسابك.
|
||||||
locked: إن حسابك مقفل.
|
locked: إن حسابك مقفل.
|
||||||
|
unauthenticated: يجب عليك تسجيل الدخول أو إنشاء حساب قبل المواصلة.
|
||||||
unconfirmed: يجب عليك تأكيد عنوان بريدك الإلكتروني قبل المواصلة.
|
unconfirmed: يجب عليك تأكيد عنوان بريدك الإلكتروني قبل المواصلة.
|
||||||
mailer:
|
mailer:
|
||||||
|
confirmation_instructions:
|
||||||
|
subject: 'ماستدون : تعليمات التأكيد لمثيل الخادوم %{instance}'
|
||||||
password_change:
|
password_change:
|
||||||
subject: 'ماستدون : تم تغيير كلمة المرور'
|
subject: 'ماستدون : تم تغيير كلمة المرور'
|
||||||
reset_password_instructions:
|
reset_password_instructions:
|
||||||
|
|
|
@ -35,7 +35,7 @@ ja:
|
||||||
updated_not_active: パスワードは正常に更新されました。
|
updated_not_active: パスワードは正常に更新されました。
|
||||||
registrations:
|
registrations:
|
||||||
destroyed: アカウントの作成はキャンセルされました。またのご利用をお待ちしています。
|
destroyed: アカウントの作成はキャンセルされました。またのご利用をお待ちしています。
|
||||||
signed_up: アカウントの作成が完了しました。Mastodonへようこそ!
|
signed_up: アカウントの作成が完了しました。Mastodonへようこそ。
|
||||||
signed_up_but_inactive: アカウントの作成が完了しました。しかし、アカウントが有効化されていないためログインできませんでした。
|
signed_up_but_inactive: アカウントの作成が完了しました。しかし、アカウントが有効化されていないためログインできませんでした。
|
||||||
signed_up_but_locked: アカウントの作成が完了しました。しかし、アカウントがロックされているためログインできませんでした。
|
signed_up_but_locked: アカウントの作成が完了しました。しかし、アカウントがロックされているためログインできませんでした。
|
||||||
signed_up_but_unconfirmed: メールアドレスの確認用のリンクが入力したメールアドレスに送信されました。メール内のリンクをクリックしてアカウントを有効化してください。
|
signed_up_but_unconfirmed: メールアドレスの確認用のリンクが入力したメールアドレスに送信されました。メール内のリンクをクリックしてアカウントを有効化してください。
|
||||||
|
@ -58,4 +58,4 @@ ja:
|
||||||
not_locked: ロックされていません
|
not_locked: ロックされていません
|
||||||
not_saved:
|
not_saved:
|
||||||
one: エラーが発生したため、%{resource}の保存に失敗しました。
|
one: エラーが発生したため、%{resource}の保存に失敗しました。
|
||||||
other: "%{count}個のエラーが発生したため、保存に失敗しました。 %{resource}"
|
other: "%{count}個のエラーが発生したため、%{resource}の保存に失敗しました:"
|
||||||
|
|
|
@ -10,7 +10,7 @@ pt:
|
||||||
inactive: A tua conta ainda não está ativada.
|
inactive: A tua conta ainda não está ativada.
|
||||||
invalid: "%{authentication_keys} ou palavra-passe não válida."
|
invalid: "%{authentication_keys} ou palavra-passe não válida."
|
||||||
last_attempt: Tens mais uma tentativa antes de a tua conta ficar bloqueada.
|
last_attempt: Tens mais uma tentativa antes de a tua conta ficar bloqueada.
|
||||||
locked: A tua conta está bloqueada
|
locked: A tua conta está bloqueada.
|
||||||
not_found_in_database: "%{authentication_keys} ou palavra-passe não válida."
|
not_found_in_database: "%{authentication_keys} ou palavra-passe não válida."
|
||||||
timeout: A tua sessão expirou. Por favor, entra de novo para continuares.
|
timeout: A tua sessão expirou. Por favor, entra de novo para continuares.
|
||||||
unauthenticated: Precisas de entrar na tua conta ou registares-te antes de continuar.
|
unauthenticated: Precisas de entrar na tua conta ou registares-te antes de continuar.
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
gl:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
doorkeeper/application:
|
||||||
|
name: Nome do aplicativo
|
||||||
|
redirect_uri: URI a redireccionar
|
||||||
|
website: Sitio web do aplicativo
|
||||||
|
errors:
|
||||||
|
models:
|
||||||
|
doorkeeper/application:
|
||||||
|
attributes:
|
||||||
|
redirect_uri:
|
||||||
|
fragment_present: non pode conter un fragmento.
|
||||||
|
invalid_uri: debe ser un URI válido.
|
||||||
|
relative_uri: debe ser un URI absoluto.
|
||||||
|
secured_uri: debe ser un URI HTTPS/SSL.
|
||||||
|
doorkeeper:
|
||||||
|
applications:
|
||||||
|
buttons:
|
||||||
|
authorize: Autorizar
|
||||||
|
cancel: Cancelar
|
||||||
|
destroy: Destruír
|
||||||
|
edit: Editar
|
||||||
|
submit: Enviar
|
||||||
|
confirmations:
|
||||||
|
destroy: Está segura?
|
||||||
|
edit:
|
||||||
|
title: Editar aplicativo
|
||||||
|
form:
|
||||||
|
error: Eeeeepa! Comprobe os posibles erros no formulario
|
||||||
|
help:
|
||||||
|
native_redirect_uri: Utilice %{native_redirect_uri} para probas locais
|
||||||
|
redirect_uri: Utilice unha liña por URI
|
|
@ -116,6 +116,7 @@ en:
|
||||||
roles:
|
roles:
|
||||||
admin: Administrator
|
admin: Administrator
|
||||||
moderator: Moderator
|
moderator: Moderator
|
||||||
|
staff: Staff
|
||||||
user: User
|
user: User
|
||||||
salmon_url: Salmon URL
|
salmon_url: Salmon URL
|
||||||
search: Search
|
search: Search
|
||||||
|
@ -160,6 +161,7 @@ en:
|
||||||
update_status: "%{name} updated status by %{target}"
|
update_status: "%{name} updated status by %{target}"
|
||||||
title: Audit log
|
title: Audit log
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
|
by_domain: Domain
|
||||||
copied_msg: Successfully created local copy of the emoji
|
copied_msg: Successfully created local copy of the emoji
|
||||||
copy: Copy
|
copy: Copy
|
||||||
copy_failed_msg: Could not make a local copy of that emoji
|
copy_failed_msg: Could not make a local copy of that emoji
|
||||||
|
@ -599,7 +601,7 @@ en:
|
||||||
notifications: Notifications
|
notifications: Notifications
|
||||||
preferences: Preferences
|
preferences: Preferences
|
||||||
settings: Settings
|
settings: Settings
|
||||||
two_factor_authentication: Two-factor Authentication
|
two_factor_authentication: Two-factor Auth
|
||||||
your_apps: Your applications
|
your_apps: Your applications
|
||||||
statuses:
|
statuses:
|
||||||
open_in_web: Open in web
|
open_in_web: Open in web
|
||||||
|
|
|
@ -116,6 +116,7 @@ fr:
|
||||||
roles:
|
roles:
|
||||||
admin: Administrateur
|
admin: Administrateur
|
||||||
moderator: Modérateur
|
moderator: Modérateur
|
||||||
|
staff: Personnel
|
||||||
user: Utilisateur
|
user: Utilisateur
|
||||||
salmon_url: URL Salmon
|
salmon_url: URL Salmon
|
||||||
search: Rechercher
|
search: Rechercher
|
||||||
|
@ -135,12 +136,13 @@ fr:
|
||||||
web: Web
|
web: Web
|
||||||
action_logs:
|
action_logs:
|
||||||
actions:
|
actions:
|
||||||
confirm_user: "%{name} adresse e-mail confirmée de l'utilisateur %{target}"
|
confirm_user: "%{name} adresse courriel confirmée de l'utilisateur %{target}"
|
||||||
create_custom_emoji: "%{name} a importé de nouveaux emoji %{target}"
|
create_custom_emoji: "%{name} a importé de nouveaux emoji %{target}"
|
||||||
create_domain_block: "%{name} a bloqué le domaine %{target}"
|
create_domain_block: "%{name} a bloqué le domaine %{target}"
|
||||||
create_email_domain_block: "%{name} a blacklisté le domaine de l'e-mail %{target}"
|
create_email_domain_block: "%{name} a mis le domaine du courriel %{target} sur liste noire"
|
||||||
|
demote_user: "%{name} a rétrogradé l'utilisateur %{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 de l'e-mail %{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}"
|
||||||
disable_2fa_user: "%{name} a désactivé l'authentification à deux facteurs pour l'utilisateur %{target}"
|
disable_2fa_user: "%{name} a désactivé l'authentification à deux facteurs pour l'utilisateur %{target}"
|
||||||
disable_custom_emoji: "%{name} a désactivé l'emoji %{target}"
|
disable_custom_emoji: "%{name} a désactivé l'emoji %{target}"
|
||||||
|
@ -159,6 +161,7 @@ fr:
|
||||||
update_status: "%{name} a mis à jour le statut de %{target}"
|
update_status: "%{name} a mis à jour le statut de %{target}"
|
||||||
title: Journal d'audit
|
title: Journal d'audit
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
|
by_domain: Domaine
|
||||||
copied_msg: Copie locale de l’émoji créée avec succès !
|
copied_msg: Copie locale de l’émoji créée avec succès !
|
||||||
copy: Copier
|
copy: Copier
|
||||||
copy_failed_msg: Impossible de faire une copie locale de cet émoji
|
copy_failed_msg: Impossible de faire une copie locale de cet émoji
|
||||||
|
@ -191,7 +194,7 @@ fr:
|
||||||
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.
|
||||||
severity:
|
severity:
|
||||||
desc_html: "<strong>Silence</strong> rendra les messages des comptes concernés invisibles à ceux qui ne les suivent pas. <strong>Suspendre</strong> supprimera tout le contenu des comptes concernés, les médias, et les données du profil."
|
desc_html: "<strong>Silence</strong> rendra les messages des comptes concernés invisibles à ceux qui ne les suivent pas. <strong>Suspendre</strong> supprimera tout le contenu des comptes concernés, les médias, et les données du profil. Utilisez <strong>Aucun</strong> si vous voulez simplement rejeter les fichiers multimédia."
|
||||||
noop: Aucune
|
noop: Aucune
|
||||||
silence: Masqué
|
silence: Masqué
|
||||||
suspend: Suspendre
|
suspend: Suspendre
|
||||||
|
@ -285,7 +288,7 @@ fr:
|
||||||
desc_html: Montrer un badge de responsable sur une page utilisateur
|
desc_html: Montrer un badge de responsable sur une page utilisateur
|
||||||
title: Montrer un badge de responsable
|
title: Montrer un badge de responsable
|
||||||
site_description:
|
site_description:
|
||||||
desc_html: Affichée sous la forme d’un paragraphe sur la page d’accueil et utilisée comme balise meta.<br/>Vous pouvez utiliser des balises HTML, en particulier <code><a></code> et <code><em></code>.
|
desc_html: Paragraphe introductif sur la page d'accueil et dans les balises meta. Vous pouvez utiliser des balises HTML, en particulier <code><a></code> et <code><em></code>.
|
||||||
title: Description du site
|
title: Description du site
|
||||||
site_description_extended:
|
site_description_extended:
|
||||||
desc_html: Affichée sur la page d’informations complémentaires du site<br>Vous pouvez utiliser des balises HTML
|
desc_html: Affichée sur la page d’informations complémentaires du site<br>Vous pouvez utiliser des balises HTML
|
||||||
|
@ -457,6 +460,9 @@ fr:
|
||||||
title: Inviter des gens
|
title: Inviter des gens
|
||||||
landing_strip_html: <strong>%{name}</strong> utilise %{link_to_root_path}. Vous pouvez læ suivre et interagir si vous possédez un compte quelque part dans le "fediverse".
|
landing_strip_html: <strong>%{name}</strong> utilise %{link_to_root_path}. Vous pouvez læ suivre et interagir si vous possédez un compte quelque part dans le "fediverse".
|
||||||
landing_strip_signup_html: Si ce n’est pas le cas, vous pouvez <a href="%{sign_up_path}">en créer un ici</a>.
|
landing_strip_signup_html: Si ce n’est pas le cas, vous pouvez <a href="%{sign_up_path}">en créer un ici</a>.
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: Vous avez atteint le nombre maximum de listes
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: Impossible de joindre une vidéo à un statut contenant déjà des images
|
images_and_video: Impossible de joindre une vidéo à un statut contenant déjà des images
|
||||||
|
@ -590,11 +596,12 @@ fr:
|
||||||
open_in_web: Ouvrir sur le web
|
open_in_web: Ouvrir sur le web
|
||||||
over_character_limit: limite de caractères dépassée de %{max} caractères
|
over_character_limit: limite de caractères dépassée de %{max} caractères
|
||||||
pin_errors:
|
pin_errors:
|
||||||
limit: Trop de pouets épinglés
|
limit: Vous avez déjà épinglé le nombre maximum de pouets
|
||||||
ownership: Vous ne pouvez pas épingler un statut ne vous appartenant pas
|
ownership: Vous ne pouvez pas épingler un statut ne vous appartenant pas
|
||||||
private: Les statuts non-publics ne peuvent pas être épinglés
|
private: Les statuts non-publics ne peuvent pas être épinglés
|
||||||
reblog: Un partage ne peut pas être épinglé
|
reblog: Un partage ne peut pas être épinglé
|
||||||
show_more: Afficher plus
|
show_more: Afficher plus
|
||||||
|
title: '%{name} : "%{quote}"'
|
||||||
visibilities:
|
visibilities:
|
||||||
private: Abonné⋅e⋅s uniquement
|
private: Abonné⋅e⋅s uniquement
|
||||||
private_long: Seul⋅e⋅s vos abonné⋅e⋅s verront vos statuts
|
private_long: Seul⋅e⋅s vos abonné⋅e⋅s verront vos statuts
|
||||||
|
@ -693,7 +700,7 @@ fr:
|
||||||
manual_instructions: 'Si vous ne pouvez pas scanner ce QR code et devez l’entrer manuellement, voici le secret en clair :'
|
manual_instructions: 'Si vous ne pouvez pas scanner ce QR code et devez l’entrer manuellement, voici le secret en clair :'
|
||||||
recovery_codes: Codes de récupération
|
recovery_codes: Codes de récupération
|
||||||
recovery_codes_regenerated: Codes de récupération régénérés avec succès
|
recovery_codes_regenerated: Codes de récupération régénérés avec succès
|
||||||
recovery_instructions_html: Si vous perdez l’accès à votre téléphone, vous pouvez utiliser un des codes de récupération ci-dessous pour récupérer l’accès à votre compte. Conservez les codes de récupération en toute sécurité, par exemple, en les imprimant et en les stockant avec vos autres documents importants.
|
recovery_instructions_html: Si vous perdez l’accès à votre téléphone, vous pouvez utiliser un des codes de récupération ci-dessous pour retrouver l’accès à votre compte. <strong>Conservez les codes de récupération en sécurité</strong>. Par exemple, en les imprimant et en les stockant avec vos autres documents importants.
|
||||||
setup: Installer
|
setup: Installer
|
||||||
wrong_code: Les codes entrés sont incorrects ! L’heure du serveur et celle de votre appareil sont-elles correctes ?
|
wrong_code: Les codes entrés sont incorrects ! L’heure du serveur et celle de votre appareil sont-elles correctes ?
|
||||||
users:
|
users:
|
||||||
|
|
|
@ -151,7 +151,7 @@ ja:
|
||||||
memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました"
|
memorialize_account: "%{name} さんが %{target} さんを追悼アカウントページに登録しました"
|
||||||
promote_user: "%{name} さんが %{target} さんを昇格しました"
|
promote_user: "%{name} さんが %{target} さんを昇格しました"
|
||||||
reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました"
|
reset_password_user: "%{name} さんが %{target} さんのパスワードをリセットしました"
|
||||||
resolve_report: "%{name} さんがレポート %{target} を棄却しました"
|
resolve_report: "%{name} さんがレポート %{target} を解決済みにしました"
|
||||||
silence_account: "%{name} さんが %{target} さんをサイレンスにしました"
|
silence_account: "%{name} さんが %{target} さんをサイレンスにしました"
|
||||||
suspend_account: "%{name} さんが %{target} さんを停止しました"
|
suspend_account: "%{name} さんが %{target} さんを停止しました"
|
||||||
unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました"
|
unsilence_account: "%{name} さんが %{target} さんのサイレンスを解除しました"
|
||||||
|
@ -192,13 +192,13 @@ ja:
|
||||||
create: ブロックを作成
|
create: ブロックを作成
|
||||||
hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。
|
hint: ドメインブロックはデータベース中のアカウント項目の作成を妨げませんが、遡って自動的に指定されたモデレーションをそれらのアカウントに適用します。
|
||||||
severity:
|
severity:
|
||||||
desc_html: "<strong>サイレンス</strong>はアカウントのトゥートをフォローしていない人から隠します。<strong>停止</strong>はそのアカウントのコンテンツ、メディア、プロフィールデータをすべて削除します。"
|
desc_html: "<strong>サイレンス</strong>はアカウントのトゥートをフォローしていない人から隠します。<strong>停止</strong>はそのアカウントのコンテンツ、メディア、プロフィールデータをすべて削除します。メディアファイルの拒否は<strong>なし</strong>を使います。"
|
||||||
noop: なし
|
noop: なし
|
||||||
silence: サイレンス
|
silence: サイレンス
|
||||||
suspend: 停止
|
suspend: 停止
|
||||||
title: 新規ドメインブロック
|
title: 新規ドメインブロック
|
||||||
reject_media: メディアファイルを拒否
|
reject_media: メディアファイルを拒否
|
||||||
reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です。
|
reject_media_hint: ローカルに保存されたメディアファイルを削除し、今後のダウンロードを拒否します。停止とは無関係です
|
||||||
severities:
|
severities:
|
||||||
noop: なし
|
noop: なし
|
||||||
silence: サイレンス
|
silence: サイレンス
|
||||||
|
@ -271,7 +271,7 @@ ja:
|
||||||
username: 連絡先のユーザー名
|
username: 連絡先のユーザー名
|
||||||
registrations:
|
registrations:
|
||||||
closed_message:
|
closed_message:
|
||||||
desc_html: 新規登録を停止しているときにフロントページに表示されます。HTMLタグが使えます。
|
desc_html: 新規登録を停止しているときにフロントページに表示されます。HTMLタグが使えます
|
||||||
title: 新規登録停止時のメッセージ
|
title: 新規登録停止時のメッセージ
|
||||||
deletion:
|
deletion:
|
||||||
desc_html: 誰でも自分のアカウントを削除できるようにします
|
desc_html: 誰でも自分のアカウントを削除できるようにします
|
||||||
|
@ -289,14 +289,14 @@ ja:
|
||||||
desc_html: フロントページへの表示と meta タグに使用される紹介文です。HTMLタグ、特に<code><a></code> と <code><em></code>が使えます。
|
desc_html: フロントページへの表示と meta タグに使用される紹介文です。HTMLタグ、特に<code><a></code> と <code><em></code>が使えます。
|
||||||
title: インスタンスの説明
|
title: インスタンスの説明
|
||||||
site_description_extended:
|
site_description_extended:
|
||||||
desc_html: あなたのインスタンスにおける行動規範やルール、ガイドライン、そのほかの記述をする際に最適な場所です。HTMLタグが使えます。
|
desc_html: あなたのインスタンスにおける行動規範やルール、ガイドライン、そのほかの記述をする際に最適な場所です。HTMLタグが使えます
|
||||||
title: カスタム詳細説明
|
title: カスタム詳細説明
|
||||||
site_terms:
|
site_terms:
|
||||||
desc_html: あなたは独自のプライバシーポリシーや利用規約、そのほかの法的根拠を書くことができます。HTMLタグが使えます。
|
desc_html: あなたは独自のプライバシーポリシーや利用規約、そのほかの法的根拠を書くことができます。HTMLタグが使えます
|
||||||
title: カスタム利用規約
|
title: カスタム利用規約
|
||||||
site_title: インスタンスの名前
|
site_title: インスタンスの名前
|
||||||
thumbnail:
|
thumbnail:
|
||||||
desc_html: OpenGraphとAPIによるプレビューに使用されます。サイズは1200×630px推奨です。
|
desc_html: OpenGraphとAPIによるプレビューに使用されます。サイズは1200×630px推奨です
|
||||||
title: インスタンスのサムネイル
|
title: インスタンスのサムネイル
|
||||||
timeline_preview:
|
timeline_preview:
|
||||||
desc_html: ランディングページに公開タイムラインを表示します
|
desc_html: ランディングページに公開タイムラインを表示します
|
||||||
|
@ -333,7 +333,7 @@ ja:
|
||||||
salutation: "%{name} さん"
|
salutation: "%{name} さん"
|
||||||
settings: 'メール設定の変更: %{link}'
|
settings: 'メール設定の変更: %{link}'
|
||||||
signature: Mastodon %{instance} インスタンスからの通知
|
signature: Mastodon %{instance} インスタンスからの通知
|
||||||
view: リンク
|
view: 'リンク:'
|
||||||
applications:
|
applications:
|
||||||
created: アプリが作成されました
|
created: アプリが作成されました
|
||||||
destroyed: アプリが削除されました
|
destroyed: アプリが削除されました
|
||||||
|
@ -359,12 +359,12 @@ ja:
|
||||||
reset_password: パスワードを再発行
|
reset_password: パスワードを再発行
|
||||||
set_new_password: 新しいパスワード
|
set_new_password: 新しいパスワード
|
||||||
authorize_follow:
|
authorize_follow:
|
||||||
error: 残念ながら、リモートアカウント情報の取得中にエラーが発生しました。
|
error: 残念ながら、リモートアカウント情報の取得中にエラーが発生しました
|
||||||
follow: フォロー
|
follow: フォロー
|
||||||
follow_request: 'あなたは以下のアカウントにフォローリクエストを送信しました:'
|
follow_request: 'あなたは以下のアカウントにフォローリクエストを送信しました:'
|
||||||
following: '成功! あなたは現在以下のアカウントをフォローしています:'
|
following: '成功! あなたは現在以下のアカウントをフォローしています:'
|
||||||
post_follow:
|
post_follow:
|
||||||
close: またはこのウィンドウを閉じます
|
close: またはこのウィンドウを閉じます。
|
||||||
return: ユーザーのプロフィールに戻る
|
return: ユーザーのプロフィールに戻る
|
||||||
web: Web を開く
|
web: Web を開く
|
||||||
title: "%{acct} をフォロー"
|
title: "%{acct} をフォロー"
|
||||||
|
@ -384,7 +384,7 @@ ja:
|
||||||
x_seconds: "%{count}秒"
|
x_seconds: "%{count}秒"
|
||||||
deletes:
|
deletes:
|
||||||
bad_password_msg: パスワードが違います
|
bad_password_msg: パスワードが違います
|
||||||
confirm_password: 本人確認のため、現在のパスワードを入力してください。
|
confirm_password: 本人確認のため、現在のパスワードを入力してください
|
||||||
description_html: あなたのアカウントに含まれるコンテンツは全て削除され、アカウントは無効化されます。これは恒久的なもので、<strong>取り消すことはできません</strong>。なりすましを防ぐために、同じユーザー名で再度登録することはできなくなります。
|
description_html: あなたのアカウントに含まれるコンテンツは全て削除され、アカウントは無効化されます。これは恒久的なもので、<strong>取り消すことはできません</strong>。なりすましを防ぐために、同じユーザー名で再度登録することはできなくなります。
|
||||||
proceed: アカウントを削除する
|
proceed: アカウントを削除する
|
||||||
success_msg: アカウントは正常に削除されました
|
success_msg: アカウントは正常に削除されました
|
||||||
|
@ -397,7 +397,7 @@ ja:
|
||||||
'422':
|
'422':
|
||||||
content: セキュリティ認証に失敗しました。Cookieをブロックしていませんか?
|
content: セキュリティ認証に失敗しました。Cookieをブロックしていませんか?
|
||||||
title: セキュリティ認証に失敗
|
title: セキュリティ認証に失敗
|
||||||
'429': リクエストの制限に達しました。
|
'429': リクエストの制限に達しました
|
||||||
'500':
|
'500':
|
||||||
content: もうしわけありませんが、なにかが間違っています。
|
content: もうしわけありませんが、なにかが間違っています。
|
||||||
title: このページは正しくありません
|
title: このページは正しくありません
|
||||||
|
@ -419,24 +419,24 @@ ja:
|
||||||
other: "%{count} 個のドメインからソフトブロックするフォロワーを処理中..."
|
other: "%{count} 個のドメインからソフトブロックするフォロワーを処理中..."
|
||||||
true_privacy_html: "<strong>プライバシーの保護はエンドツーエンドの暗号化でのみ実現可能</strong>であることに留意ください。"
|
true_privacy_html: "<strong>プライバシーの保護はエンドツーエンドの暗号化でのみ実現可能</strong>であることに留意ください。"
|
||||||
unlocked_warning_html: 誰でもあなたをフォローすることができ、あなたのプライベート投稿をすぐに見ることができます。フォローする人を限定したい場合は%{lock_link}に設定してください。
|
unlocked_warning_html: 誰でもあなたをフォローすることができ、あなたのプライベート投稿をすぐに見ることができます。フォローする人を限定したい場合は%{lock_link}に設定してください。
|
||||||
unlocked_warning_title: このアカウントは非公開アカウントに設定されていません。
|
unlocked_warning_title: このアカウントは非公開アカウントに設定されていません
|
||||||
generic:
|
generic:
|
||||||
changes_saved_msg: 正常に変更されました
|
changes_saved_msg: 正常に変更されました!
|
||||||
powered_by: powered by %{link}
|
powered_by: powered by %{link}
|
||||||
save_changes: 変更を保存
|
save_changes: 変更を保存
|
||||||
use_this: これを使う
|
use_this: これを使う
|
||||||
validation_errors:
|
validation_errors:
|
||||||
one: エラーが発生しました。以下のエラーを確認してください。
|
one: エラーが発生しました! 以下のエラーを確認してください
|
||||||
other: エラーが発生しました。以下の%{count}個のエラーを確認してください。
|
other: エラーが発生しました! 以下の%{count}個のエラーを確認してください
|
||||||
imports:
|
imports:
|
||||||
preface: 他のインスタンスでエクスポートされたファイルから、フォロー/ブロックした情報をこのインスタンス上のアカウントにインポートできます。
|
preface: 他のインスタンスでエクスポートされたファイルから、フォロー/ブロックした情報をこのインスタンス上のアカウントにインポートできます。
|
||||||
success: ファイルは正常にアップロードされ、現在処理中です。しばらくしてから確認してください。
|
success: ファイルは正常にアップロードされ、現在処理中です。しばらくしてから確認してください
|
||||||
types:
|
types:
|
||||||
blocking: ブロックしたアカウントリスト
|
blocking: ブロックしたアカウントリスト
|
||||||
following: フォロー中のアカウントリスト
|
following: フォロー中のアカウントリスト
|
||||||
muting: ミュートしたアカウントリスト
|
muting: ミュートしたアカウントリスト
|
||||||
upload: アップロード
|
upload: アップロード
|
||||||
in_memoriam_html: 故人を偲んで
|
in_memoriam_html: 故人を偲んで。
|
||||||
invites:
|
invites:
|
||||||
delete: 無効化
|
delete: 無効化
|
||||||
expired: 期限切れ
|
expired: 期限切れ
|
||||||
|
@ -452,7 +452,7 @@ ja:
|
||||||
one: '1'
|
one: '1'
|
||||||
other: "%{count}"
|
other: "%{count}"
|
||||||
max_uses_prompt: 無制限
|
max_uses_prompt: 無制限
|
||||||
prompt: リンクを生成・共有してこのインスタンスへの新規登録を受け付けることができます。
|
prompt: リンクを生成・共有してこのインスタンスへの新規登録を受け付けることができます
|
||||||
table:
|
table:
|
||||||
expires_at: 有効期限
|
expires_at: 有効期限
|
||||||
uses: 使用
|
uses: 使用
|
||||||
|
@ -467,15 +467,18 @@ ja:
|
||||||
remove_all: すべて削除
|
remove_all: すべて削除
|
||||||
landing_strip_html: "<strong>%{name}</strong> さんはインスタンス %{link_to_root_path} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。"
|
landing_strip_html: "<strong>%{name}</strong> さんはインスタンス %{link_to_root_path} のユーザーです。アカウントさえ持っていればフォローしたり会話したりできます。"
|
||||||
landing_strip_signup_html: もしお持ちでないなら <a href="%{sign_up_path}">こちら</a> からサインアップできます。
|
landing_strip_signup_html: もしお持ちでないなら <a href="%{sign_up_path}">こちら</a> からサインアップできます。
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: リストの上限に達しました
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: 既に画像が追加されているため、動画を追加することはできません。
|
images_and_video: 既に画像が追加されているため、動画を追加することはできません
|
||||||
too_many: 追加できるファイルは4つまでです。
|
too_many: 追加できるファイルは4つまでです
|
||||||
migrations:
|
migrations:
|
||||||
acct: 引っ越し先の ユーザー名@ドメイン
|
acct: 引っ越し先の ユーザー名@ドメイン
|
||||||
currently_redirecting: 'あなたのプロフィールは引っ越し先が設定されています:'
|
currently_redirecting: 'あなたのプロフィールは引っ越し先が設定されています:'
|
||||||
proceed: 保存
|
proceed: 保存
|
||||||
updated_msg: アカウントの引っ越し設定を更新しました
|
updated_msg: アカウントの引っ越し設定を更新しました!
|
||||||
moderation:
|
moderation:
|
||||||
title: モデレーション
|
title: モデレーション
|
||||||
notification_mailer:
|
notification_mailer:
|
||||||
|
@ -492,7 +495,7 @@ ja:
|
||||||
body: "%{name} さんにお気に入り登録された、あなたのトゥートがあります:"
|
body: "%{name} さんにお気に入り登録された、あなたのトゥートがあります:"
|
||||||
subject: "%{name} さんにお気に入りに登録されました"
|
subject: "%{name} さんにお気に入りに登録されました"
|
||||||
follow:
|
follow:
|
||||||
body: "%{name} さんにフォローされています"
|
body: "%{name} さんにフォローされています!"
|
||||||
subject: "%{name} さんにフォローされています"
|
subject: "%{name} さんにフォローされています"
|
||||||
follow_request:
|
follow_request:
|
||||||
body: "%{name} さんがあなたにフォローをリクエストしました"
|
body: "%{name} さんがあなたにフォローをリクエストしました"
|
||||||
|
@ -601,7 +604,7 @@ ja:
|
||||||
open_in_web: Webで開く
|
open_in_web: Webで開く
|
||||||
over_character_limit: 上限は %{max}文字までです
|
over_character_limit: 上限は %{max}文字までです
|
||||||
pin_errors:
|
pin_errors:
|
||||||
limit: 固定されているトゥートが多すぎます
|
limit: 固定されているトゥートの上限に達しました
|
||||||
ownership: 他人のトゥートを固定することはできません
|
ownership: 他人のトゥートを固定することはできません
|
||||||
private: 非公開のトゥートを固定することはできません
|
private: 非公開のトゥートを固定することはできません
|
||||||
reblog: ブーストされたトゥートを固定することはできません
|
reblog: ブーストされたトゥートを固定することはできません
|
||||||
|
@ -692,7 +695,7 @@ ja:
|
||||||
formats:
|
formats:
|
||||||
default: "%Y年%m月%d日 %H:%M"
|
default: "%Y年%m月%d日 %H:%M"
|
||||||
two_factor_authentication:
|
two_factor_authentication:
|
||||||
code_hint: 確認するには認証アプリで表示されたコードを入力してください。
|
code_hint: 確認するには認証アプリで表示されたコードを入力してください
|
||||||
description_html: "<strong>二段階認証</strong>を有効にするとログイン時、電話でコードを受け取る必要があります。"
|
description_html: "<strong>二段階認証</strong>を有効にするとログイン時、電話でコードを受け取る必要があります。"
|
||||||
disable: 無効
|
disable: 無効
|
||||||
enable: 有効
|
enable: 有効
|
||||||
|
@ -703,7 +706,7 @@ ja:
|
||||||
lost_recovery_codes: リカバリーコードを使用すると携帯電話を紛失した場合でもアカウントにアクセスできるようになります。 リカバリーコードを紛失した場合もここで再生成することができますが、古いリカバリーコードは無効になります。
|
lost_recovery_codes: リカバリーコードを使用すると携帯電話を紛失した場合でもアカウントにアクセスできるようになります。 リカバリーコードを紛失した場合もここで再生成することができますが、古いリカバリーコードは無効になります。
|
||||||
manual_instructions: 'QRコードがスキャンできず、手動での登録を希望の場合はこのシークレットコードを利用してください。:'
|
manual_instructions: 'QRコードがスキャンできず、手動での登録を希望の場合はこのシークレットコードを利用してください。:'
|
||||||
recovery_codes: リカバリーコード
|
recovery_codes: リカバリーコード
|
||||||
recovery_codes_regenerated: リカバリーコードが再生成されました。
|
recovery_codes_regenerated: リカバリーコードが再生成されました
|
||||||
recovery_instructions_html: 携帯電話を紛失した場合、以下の内どれかのリカバリーコードを使用してアカウントへアクセスすることができます。<strong>リカバリーコードは大切に保全してください。</strong>たとえば印刷してほかの重要な書類と一緒に保管することができます。
|
recovery_instructions_html: 携帯電話を紛失した場合、以下の内どれかのリカバリーコードを使用してアカウントへアクセスすることができます。<strong>リカバリーコードは大切に保全してください。</strong>たとえば印刷してほかの重要な書類と一緒に保管することができます。
|
||||||
setup: 初期設定
|
setup: 初期設定
|
||||||
wrong_code: コードが間違っています。サーバー上の時間とデバイス上の時間が一致していることを確認してください。
|
wrong_code: コードが間違っています。サーバー上の時間とデバイス上の時間が一致していることを確認してください。
|
||||||
|
|
|
@ -458,6 +458,9 @@ nl:
|
||||||
title: Mensen uitnodigen
|
title: Mensen uitnodigen
|
||||||
landing_strip_html: "<strong>%{name}</strong> is een gebruiker op %{link_to_root_path}. Je kunt deze volgen en ermee communiceren als je op Mastodon (of ergens anders in de fediverse) een account hebt."
|
landing_strip_html: "<strong>%{name}</strong> is een gebruiker op %{link_to_root_path}. Je kunt deze volgen en ermee communiceren als je op Mastodon (of ergens anders in de fediverse) een account hebt."
|
||||||
landing_strip_signup_html: Als je dat niet hebt, kun je je <a href="%{sign_up_path}">hier registreren</a>.
|
landing_strip_signup_html: Als je dat niet hebt, kun je je <a href="%{sign_up_path}">hier registreren</a>.
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: Je hebt het maximaal aantal lijsten bereikt
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: Een video kan niet aan een toot met afbeeldingen worden gekoppeld
|
images_and_video: Een video kan niet aan een toot met afbeeldingen worden gekoppeld
|
||||||
|
@ -591,7 +594,7 @@ nl:
|
||||||
open_in_web: In de webapp openen
|
open_in_web: In de webapp openen
|
||||||
over_character_limit: Limiet van %{max} tekens overschreden
|
over_character_limit: Limiet van %{max} tekens overschreden
|
||||||
pin_errors:
|
pin_errors:
|
||||||
limit: Te veel toots vastgezet
|
limit: Je hebt het maximaal aantal toots al vastgezet
|
||||||
ownership: Een toot van iemand anders kan niet worden vastgezet
|
ownership: Een toot van iemand anders kan niet worden vastgezet
|
||||||
private: Alleen openbare toots kunnen worden vastgezet
|
private: Alleen openbare toots kunnen worden vastgezet
|
||||||
reblog: Een boost kan niet worden vastgezet
|
reblog: Een boost kan niet worden vastgezet
|
||||||
|
|
|
@ -114,8 +114,9 @@ oc:
|
||||||
resubscribe: Se tornar abonar
|
resubscribe: Se tornar abonar
|
||||||
role: Permissions
|
role: Permissions
|
||||||
roles:
|
roles:
|
||||||
admin: Admin
|
admin: Administrator
|
||||||
moderator: Mod
|
moderator: Moderator
|
||||||
|
staff: Personnal
|
||||||
user: Uitlizaire
|
user: Uitlizaire
|
||||||
salmon_url: URL Salmon
|
salmon_url: URL Salmon
|
||||||
search: Cercar
|
search: Cercar
|
||||||
|
@ -160,6 +161,7 @@ oc:
|
||||||
update_status: "%{name} metèt a jorn l’estatut a %{target}"
|
update_status: "%{name} metèt a jorn l’estatut a %{target}"
|
||||||
title: Audit log
|
title: Audit log
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
|
by_domain: Domeni
|
||||||
copied_msg: Còpia locala de l’emoji ben creada
|
copied_msg: Còpia locala de l’emoji ben creada
|
||||||
copy: Copiar
|
copy: Copiar
|
||||||
copy_failed_msg: Fracàs de la còpia locala de l’emoji
|
copy_failed_msg: Fracàs de la còpia locala de l’emoji
|
||||||
|
@ -343,7 +345,7 @@ oc:
|
||||||
warning: Mèfi ! Agachatz de partejar aquela donada amb degun !
|
warning: Mèfi ! Agachatz de partejar aquela donada amb degun !
|
||||||
your_token: Vòstre geton d’accès
|
your_token: Vòstre geton d’accès
|
||||||
auth:
|
auth:
|
||||||
agreement_html: En vos marcar acceptatz <a href="%{rules_path}">nòstres tèrmes de servici</a> e <a href="%{terms_path}">politica de confidencialitat</a>.
|
agreement_html: En vos marcar acceptatz <a href="%{rules_path}">las règlas de l’instància</a> e <a href="%{terms_path}">politica de confidencialitat</a>.
|
||||||
change_password: Seguretat
|
change_password: Seguretat
|
||||||
delete_account: Suprimir lo compte
|
delete_account: Suprimir lo compte
|
||||||
delete_account_html: Se volètz suprimir vòstre compte, podètz <a href="%{path}">o far aquí</a>. Vos demandarem que confirmetz.
|
delete_account_html: Se volètz suprimir vòstre compte, podètz <a href="%{path}">o far aquí</a>. Vos demandarem que confirmetz.
|
||||||
|
@ -677,6 +679,7 @@ oc:
|
||||||
private: Se pòt pas penjar los tuts pas publics
|
private: Se pòt pas penjar los tuts pas publics
|
||||||
reblog: Se pòt pas penjar un tut partejat
|
reblog: Se pòt pas penjar un tut partejat
|
||||||
show_more: Ne veire mai
|
show_more: Ne veire mai
|
||||||
|
title: '%{name} : "%{quote}"'
|
||||||
visibilities:
|
visibilities:
|
||||||
private: Seguidors solament
|
private: Seguidors solament
|
||||||
private_long: Mostrar pas qu’als seguidors
|
private_long: Mostrar pas qu’als seguidors
|
||||||
|
|
|
@ -469,6 +469,9 @@ pl:
|
||||||
remove_all: Usuń wszystkie
|
remove_all: Usuń wszystkie
|
||||||
landing_strip_html: "<strong>%{name}</strong> ma konto na %{link_to_root_path}. Możesz je śledzić i wejść z nim w interakcję jeśli masz konto gdziekolwiek w Fediwersum."
|
landing_strip_html: "<strong>%{name}</strong> ma konto na %{link_to_root_path}. Możesz je śledzić i wejść z nim w interakcję jeśli masz konto gdziekolwiek w Fediwersum."
|
||||||
landing_strip_signup_html: Jeśli jeszcze go nie masz, możesz <a href="%{sign_up_path}">stworzyć konto</a>.
|
landing_strip_signup_html: Jeśli jeszcze go nie masz, możesz <a href="%{sign_up_path}">stworzyć konto</a>.
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: Przekroczyłeś maksymalną liczbę utworzonych list
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia
|
images_and_video: Nie możesz załączyć pliku wideo do wpisu, który zawiera już zdjęcia
|
||||||
|
@ -606,7 +609,7 @@ pl:
|
||||||
open_in_web: Otwórz w przeglądarce
|
open_in_web: Otwórz w przeglądarce
|
||||||
over_character_limit: limit %{max} znaków przekroczony
|
over_character_limit: limit %{max} znaków przekroczony
|
||||||
pin_errors:
|
pin_errors:
|
||||||
limit: Nie możesz przypiąć więcej wpisów
|
limit: Przekroczyłeś maksymalną liczbę przypiętych wpisów
|
||||||
ownership: Nie możesz przypiąć cudzego wpisu
|
ownership: Nie możesz przypiąć cudzego wpisu
|
||||||
private: Nie możesz przypiąć niepublicznego wpisu
|
private: Nie możesz przypiąć niepublicznego wpisu
|
||||||
reblog: Nie możesz przypiąć podbicia wpisu
|
reblog: Nie możesz przypiąć podbicia wpisu
|
||||||
|
|
|
@ -282,6 +282,9 @@ pt-BR:
|
||||||
open:
|
open:
|
||||||
desc_html: Permitir que qualquer um crie uma conta
|
desc_html: Permitir que qualquer um crie uma conta
|
||||||
title: Cadastro aberto
|
title: Cadastro aberto
|
||||||
|
show_staff_badge:
|
||||||
|
desc_html: Mostrar uma insígnia de equipe na página de usuário
|
||||||
|
title: Mostrar insígnia de equipe
|
||||||
site_description:
|
site_description:
|
||||||
desc_html: Parágrafo introdutório na página inicial e em meta tags. Você pode usar tags HTML, em especial <code><a></code> e <code><em></code>.
|
desc_html: Parágrafo introdutório na página inicial e em meta tags. Você pode usar tags HTML, em especial <code><a></code> e <code><em></code>.
|
||||||
title: Descrição da instância
|
title: Descrição da instância
|
||||||
|
@ -350,7 +353,7 @@ pt-BR:
|
||||||
login: Entrar
|
login: Entrar
|
||||||
logout: Sair
|
logout: Sair
|
||||||
migrate_account: Mudar para uma conta diferente
|
migrate_account: Mudar para uma conta diferente
|
||||||
migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href="%{path}">configura isso aqui</a>.
|
migrate_account_html: Se você quer redirecionar essa conta para uma outra você pode <a href="%{path}">configurar isso aqui</a>.
|
||||||
register: Cadastrar-se
|
register: Cadastrar-se
|
||||||
resend_confirmation: Reenviar instruções de confirmação
|
resend_confirmation: Reenviar instruções de confirmação
|
||||||
reset_password: Redefinir senha
|
reset_password: Redefinir senha
|
||||||
|
@ -455,6 +458,9 @@ pt-BR:
|
||||||
title: Convidar pessoas
|
title: Convidar pessoas
|
||||||
landing_strip_html: "<strong>%{name}</strong> é um usuário no %{link_to_root_path}. Você pode segui-lo ou interagir com ele se você tiver uma conta em qualquer lugar no fediverso."
|
landing_strip_html: "<strong>%{name}</strong> é um usuário no %{link_to_root_path}. Você pode segui-lo ou interagir com ele se você tiver uma conta em qualquer lugar no fediverso."
|
||||||
landing_strip_signup_html: Se não, você pode <a href="%{sign_up_path}">se cadastrar aqui</a>.
|
landing_strip_signup_html: Se não, você pode <a href="%{sign_up_path}">se cadastrar aqui</a>.
|
||||||
|
lists:
|
||||||
|
errors:
|
||||||
|
limit: Você alcançou o número máximo de listas
|
||||||
media_attachments:
|
media_attachments:
|
||||||
validations:
|
validations:
|
||||||
images_and_video: Não é possível anexar um vídeo a uma postagem que já contém imagens
|
images_and_video: Não é possível anexar um vídeo a uma postagem que já contém imagens
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
gl:
|
||||||
|
simple_form:
|
||||||
|
hints:
|
||||||
|
defaults:
|
||||||
|
avatar: PNG, GIF ou JPG. Como moito 2MB. Será reducida ate 120x120px
|
||||||
|
digest: Enviar despois de un período longo de inactividade con un resumo das
|
||||||
|
mencións que recibeu na súa ausencia
|
||||||
|
display_name:
|
||||||
|
one: <span class="name-counter">1</span> caracter restante
|
||||||
|
other: <span class="name-counter">%{count}</span> caracteres restantes
|
||||||
|
header: PNG, GIF ou JPG. Como moito 2MB. Será reducida a 700x335px
|
||||||
|
locked: Require que vostede aprove as seguidoras de xeito manual
|
||||||
|
note:
|
||||||
|
one: <span class="note-counter">1</span> caracter restante
|
||||||
|
other: <span class="note-counter">%{count}</span> caracteres restantes
|
||||||
|
setting_noindex: Afecta ao seu perfil público e páxinas de estado
|
||||||
|
setting_theme: Afecta ao aspecto de Mastodon en calquer dispositivo cando
|
||||||
|
está conectada.
|
||||||
|
imports:
|
||||||
|
data: Ficheiro CSV exportado desde outra instancia Mastodon
|
||||||
|
sessions:
|
||||||
|
otp: Introduza o código de Doble-Factor desde o seu teléfono ou utilice un
|
||||||
|
dos seus códigos de recuperación.
|
||||||
|
user:
|
||||||
|
filtered_languages: Os idiomas marcados filtraranse das liñas temporais públicas
|
||||||
|
para vostede
|
||||||
|
labels:
|
||||||
|
defaults:
|
||||||
|
avatar: Avatar
|
||||||
|
confirm_new_password: Confirme o novo contrasinal
|
||||||
|
confirm_password: Confirme o contrasinal
|
||||||
|
current_password: Contrasinal actual
|
||||||
|
data: Data
|
||||||
|
display_name: Nome mostrado
|
||||||
|
email: enderezo correo electrónico
|
||||||
|
expires_in: Caducidade despois de
|
||||||
|
filtered_languages: Idiomas filtrados
|
||||||
|
header: Cabezallo
|
||||||
|
locale: Idioma
|
||||||
|
locked: Protexer conta
|
||||||
|
max_uses: Número máximo de usos
|
||||||
|
new_password: Novo contrasinal
|
||||||
|
note: Sobre vostede
|
||||||
|
otp_attempt: Código de Doble-Factor
|
||||||
|
password: Contrasinal
|
||||||
|
setting_auto_play_gif: Reprodución automática de GIFs animados
|
||||||
|
setting_boost_modal: Pedir confirmación antes de promocionar
|
||||||
|
setting_default_privacy: Intimidade da publicación
|
||||||
|
setting_default_sensitive: Marcar sempre multimedia como sensible
|
||||||
|
setting_delete_modal: Solicitar confirmación antes de eliminar unha mensaxe
|
||||||
|
setting_noindex: Pedir non aparecer nas buscas dos motores de busca
|
||||||
|
setting_reduce_motion: Reducir o movemento nas animacións
|
||||||
|
setting_system_font_ui: Utilizar a tipografía por defecto do sistema
|
||||||
|
setting_theme: Decorado da instancia
|
||||||
|
setting_unfollow_modal: Solicitar confirmación antes de deixar de seguir alguén
|
||||||
|
severity: Severidade
|
||||||
|
type: Tipo de importación
|
||||||
|
username: Nome de usuaria
|
||||||
|
interactions:
|
||||||
|
must_be_follower: Bloquear as notificacións de non-seguidoras
|
||||||
|
must_be_following: Bloquea as notificacións de personas que non segue
|
||||||
|
must_be_following_dm: Bloquea as mensaxes directas de personas que non segue
|
||||||
|
notification_emails:
|
||||||
|
digest: Enviar correos con resumos
|
||||||
|
favourite: Enviar un correo cando alguén marca como favorita unha das súas
|
||||||
|
publicacións
|
||||||
|
follow: Enviar un correo cando alguén a segue
|
||||||
|
follow_request: Enviar un correo cando alguén solicita seguila
|
||||||
|
mention: Enviar un correo cando alguén a menciona
|
||||||
|
reblog: Enviar un correo cando alguén promociona a súa mensaxe
|
||||||
|
'no': Non
|
||||||
|
required:
|
||||||
|
mark: '*'
|
||||||
|
text: requerido
|
||||||
|
'yes': Si
|
|
@ -116,6 +116,7 @@ zh-CN:
|
||||||
roles:
|
roles:
|
||||||
admin: 管理员
|
admin: 管理员
|
||||||
moderator: 协管
|
moderator: 协管
|
||||||
|
staff: 工作人员
|
||||||
user: 普通用户
|
user: 普通用户
|
||||||
salmon_url: Salmon URL
|
salmon_url: Salmon URL
|
||||||
search: 搜索
|
search: 搜索
|
||||||
|
@ -160,6 +161,7 @@ zh-CN:
|
||||||
update_status: "%{name} 刷新了 %{target} 的嘟文"
|
update_status: "%{name} 刷新了 %{target} 的嘟文"
|
||||||
title: 运营日志
|
title: 运营日志
|
||||||
custom_emojis:
|
custom_emojis:
|
||||||
|
by_domain: 域名
|
||||||
copied_msg: 成功将表情复制到本地
|
copied_msg: 成功将表情复制到本地
|
||||||
copy: 复制
|
copy: 复制
|
||||||
copy_failed_msg: 无法将表情复制到本地
|
copy_failed_msg: 无法将表情复制到本地
|
||||||
|
@ -281,8 +283,8 @@ zh-CN:
|
||||||
desc_html: 允许任何人建立一个帐户
|
desc_html: 允许任何人建立一个帐户
|
||||||
title: 开放注册
|
title: 开放注册
|
||||||
show_staff_badge:
|
show_staff_badge:
|
||||||
desc_html: 在个人资料页上显示管理员标志
|
desc_html: 在个人资料页上显示工作人员标志
|
||||||
title: 显示管理员标志
|
title: 显示工作人员标志
|
||||||
site_description:
|
site_description:
|
||||||
desc_html: 展示在首页以及 meta 标签中的网站简介。可以使用 HTML 标签,包括 <code><a></code> 和 <code><em></code>。
|
desc_html: 展示在首页以及 meta 标签中的网站简介。可以使用 HTML 标签,包括 <code><a></code> 和 <code><em></code>。
|
||||||
title: 本站简介
|
title: 本站简介
|
||||||
|
@ -341,7 +343,7 @@ zh-CN:
|
||||||
warning: 一定小心,千万不要把它分享给任何人!
|
warning: 一定小心,千万不要把它分享给任何人!
|
||||||
your_token: 你的访问令牌
|
your_token: 你的访问令牌
|
||||||
auth:
|
auth:
|
||||||
agreement_html: 注册即表示你同意<a href="%{rules_path}">我们的使用条款</a>和<a href="%{terms_path}">隐私权政策</a>。
|
agreement_html: 注册即表示你同意遵守<a href="%{rules_path}">本实例的相关规定</a>和<a href="%{terms_path}">我们的使用条款</a>。
|
||||||
change_password: 帐户安全
|
change_password: 帐户安全
|
||||||
delete_account: 删除帐户
|
delete_account: 删除帐户
|
||||||
delete_account_html: 如果你想删除你的帐户,请<a href="%{path}">点击这里继续</a>。你需要确认你的操作。
|
delete_account_html: 如果你想删除你的帐户,请<a href="%{path}">点击这里继续</a>。你需要确认你的操作。
|
||||||
|
@ -591,6 +593,7 @@ zh-CN:
|
||||||
private: 不能置顶非公开的嘟文
|
private: 不能置顶非公开的嘟文
|
||||||
reblog: 不能置顶转嘟
|
reblog: 不能置顶转嘟
|
||||||
show_more: 显示更多
|
show_more: 显示更多
|
||||||
|
title: "%{name}:“%{quote}”"
|
||||||
visibilities:
|
visibilities:
|
||||||
private: 仅关注者
|
private: 仅关注者
|
||||||
private_long: 只有关注你的用户能看到
|
private_long: 只有关注你的用户能看到
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
class RemoveDuplicateIndexesInLists < ActiveRecord::Migration[5.1]
|
||||||
|
def change
|
||||||
|
remove_index :list_accounts, name: "index_list_accounts_on_account_id"
|
||||||
|
remove_index :list_accounts, name: "index_list_accounts_on_list_id"
|
||||||
|
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: 20171201000000) do
|
ActiveRecord::Schema.define(version: 20171212195226) 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"
|
||||||
|
@ -211,10 +211,8 @@ ActiveRecord::Schema.define(version: 20171201000000) do
|
||||||
t.bigint "account_id", null: false
|
t.bigint "account_id", null: false
|
||||||
t.bigint "follow_id", null: false
|
t.bigint "follow_id", null: false
|
||||||
t.index ["account_id", "list_id"], name: "index_list_accounts_on_account_id_and_list_id", unique: true
|
t.index ["account_id", "list_id"], name: "index_list_accounts_on_account_id_and_list_id", unique: true
|
||||||
t.index ["account_id"], name: "index_list_accounts_on_account_id"
|
|
||||||
t.index ["follow_id"], name: "index_list_accounts_on_follow_id"
|
t.index ["follow_id"], name: "index_list_accounts_on_follow_id"
|
||||||
t.index ["list_id", "account_id"], name: "index_list_accounts_on_list_id_and_account_id"
|
t.index ["list_id", "account_id"], name: "index_list_accounts_on_list_id_and_account_id"
|
||||||
t.index ["list_id"], name: "index_list_accounts_on_list_id"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "lists", force: :cascade do |t|
|
create_table "lists", force: :cascade do |t|
|
||||||
|
|
|
@ -17,7 +17,7 @@ module Mastodon
|
||||||
end
|
end
|
||||||
|
|
||||||
def pre
|
def pre
|
||||||
'rc3'
|
'rc4'
|
||||||
end
|
end
|
||||||
|
|
||||||
def flags
|
def flags
|
||||||
|
|
|
@ -97,6 +97,8 @@ const startWorker = (workerId) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
app.set('trusted proxy', process.env.TRUSTED_PROXY_IP || 'loopback,uniquelocal');
|
||||||
|
|
||||||
const pgPool = new pg.Pool(Object.assign(pgConfigs[env], dbUrlToConfig(process.env.DATABASE_URL)));
|
const pgPool = new pg.Pool(Object.assign(pgConfigs[env], dbUrlToConfig(process.env.DATABASE_URL)));
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const redisNamespace = process.env.REDIS_NAMESPACE || null;
|
const redisNamespace = process.env.REDIS_NAMESPACE || null;
|
||||||
|
@ -177,6 +179,12 @@ const startWorker = (workerId) => {
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setRemoteAddress = (req, res, next) => {
|
||||||
|
req.remoteAddress = req.connection.remoteAddress;
|
||||||
|
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
const accountFromToken = (token, req, next) => {
|
const accountFromToken = (token, req, next) => {
|
||||||
pgPool.connect((err, client, done) => {
|
pgPool.connect((err, client, done) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -208,17 +216,22 @@ const startWorker = (workerId) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const accountFromRequest = (req, next) => {
|
const accountFromRequest = (req, next, required = true) => {
|
||||||
const authorization = req.headers.authorization;
|
const authorization = req.headers.authorization;
|
||||||
const location = url.parse(req.url, true);
|
const location = url.parse(req.url, true);
|
||||||
const accessToken = location.query.access_token;
|
const accessToken = location.query.access_token;
|
||||||
|
|
||||||
if (!authorization && !accessToken) {
|
if (!authorization && !accessToken) {
|
||||||
|
if (required) {
|
||||||
const err = new Error('Missing access token');
|
const err = new Error('Missing access token');
|
||||||
err.statusCode = 401;
|
err.statusCode = 401;
|
||||||
|
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = authorization ? authorization.replace(/^Bearer /, '') : accessToken;
|
const token = authorization ? authorization.replace(/^Bearer /, '') : accessToken;
|
||||||
|
@ -226,7 +239,17 @@ const startWorker = (workerId) => {
|
||||||
accountFromToken(token, req, next);
|
accountFromToken(token, req, next);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PUBLIC_STREAMS = [
|
||||||
|
'public',
|
||||||
|
'public:local',
|
||||||
|
'hashtag',
|
||||||
|
'hashtag:local',
|
||||||
|
];
|
||||||
|
|
||||||
const wsVerifyClient = (info, cb) => {
|
const wsVerifyClient = (info, cb) => {
|
||||||
|
const location = url.parse(info.req.url, true);
|
||||||
|
const authRequired = !PUBLIC_STREAMS.some(stream => stream === location.query.stream);
|
||||||
|
|
||||||
accountFromRequest(info.req, err => {
|
accountFromRequest(info.req, err => {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
cb(true, undefined, undefined);
|
cb(true, undefined, undefined);
|
||||||
|
@ -234,16 +257,24 @@ const startWorker = (workerId) => {
|
||||||
log.error(info.req.requestId, err.toString());
|
log.error(info.req.requestId, err.toString());
|
||||||
cb(false, 401, 'Unauthorized');
|
cb(false, 401, 'Unauthorized');
|
||||||
}
|
}
|
||||||
});
|
}, authRequired);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const PUBLIC_ENDPOINTS = [
|
||||||
|
'/api/v1/streaming/public',
|
||||||
|
'/api/v1/streaming/public/local',
|
||||||
|
'/api/v1/streaming/hashtag',
|
||||||
|
'/api/v1/streaming/hashtag/local',
|
||||||
|
];
|
||||||
|
|
||||||
const authenticationMiddleware = (req, res, next) => {
|
const authenticationMiddleware = (req, res, next) => {
|
||||||
if (req.method === 'OPTIONS') {
|
if (req.method === 'OPTIONS') {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
accountFromRequest(req, next);
|
const authRequired = !PUBLIC_ENDPOINTS.some(endpoint => endpoint === req.path);
|
||||||
|
accountFromRequest(req, next, authRequired);
|
||||||
};
|
};
|
||||||
|
|
||||||
const errorMiddleware = (err, req, res, {}) => {
|
const errorMiddleware = (err, req, res, {}) => {
|
||||||
|
@ -275,8 +306,10 @@ const startWorker = (workerId) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const streamFrom = (id, req, output, attachCloseHandler, needsFiltering = false, notificationOnly = false) => {
|
const streamFrom = (id, req, output, attachCloseHandler, needsFiltering = false, notificationOnly = false) => {
|
||||||
|
const accountId = req.accountId || req.remoteAddress;
|
||||||
|
|
||||||
const streamType = notificationOnly ? ' (notification)' : '';
|
const streamType = notificationOnly ? ' (notification)' : '';
|
||||||
log.verbose(req.requestId, `Starting stream from ${id} for ${req.accountId}${streamType}`);
|
log.verbose(req.requestId, `Starting stream from ${id} for ${accountId}${streamType}`);
|
||||||
|
|
||||||
const listener = message => {
|
const listener = message => {
|
||||||
const { event, payload, queued_at } = JSON.parse(message);
|
const { event, payload, queued_at } = JSON.parse(message);
|
||||||
|
@ -286,7 +319,7 @@ const startWorker = (workerId) => {
|
||||||
const delta = now - queued_at;
|
const delta = now - queued_at;
|
||||||
const encodedPayload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
|
const encodedPayload = typeof payload === 'object' ? JSON.stringify(payload) : payload;
|
||||||
|
|
||||||
log.silly(req.requestId, `Transmitting for ${req.accountId}: ${event} ${encodedPayload} Delay: ${delta}ms`);
|
log.silly(req.requestId, `Transmitting for ${accountId}: ${event} ${encodedPayload} Delay: ${delta}ms`);
|
||||||
output(event, encodedPayload);
|
output(event, encodedPayload);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -313,6 +346,7 @@ const startWorker = (workerId) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (req.accountId) {
|
||||||
const queries = [
|
const queries = [
|
||||||
client.query(`SELECT 1 FROM blocks WHERE (account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})) OR (account_id = $2 AND target_account_id = $1) UNION SELECT 1 FROM mutes WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})`, [req.accountId, unpackedPayload.account.id].concat(targetAccountIds)),
|
client.query(`SELECT 1 FROM blocks WHERE (account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})) OR (account_id = $2 AND target_account_id = $1) UNION SELECT 1 FROM mutes WHERE account_id = $1 AND target_account_id IN (${placeholders(targetAccountIds, 2)})`, [req.accountId, unpackedPayload.account.id].concat(targetAccountIds)),
|
||||||
];
|
];
|
||||||
|
@ -333,6 +367,10 @@ const startWorker = (workerId) => {
|
||||||
done();
|
done();
|
||||||
log.error(err);
|
log.error(err);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
transmit();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
transmit();
|
transmit();
|
||||||
|
@ -345,13 +383,15 @@ const startWorker = (workerId) => {
|
||||||
|
|
||||||
// Setup stream output to HTTP
|
// Setup stream output to HTTP
|
||||||
const streamToHttp = (req, res) => {
|
const streamToHttp = (req, res) => {
|
||||||
|
const accountId = req.accountId || req.remoteAddress;
|
||||||
|
|
||||||
res.setHeader('Content-Type', 'text/event-stream');
|
res.setHeader('Content-Type', 'text/event-stream');
|
||||||
res.setHeader('Transfer-Encoding', 'chunked');
|
res.setHeader('Transfer-Encoding', 'chunked');
|
||||||
|
|
||||||
const heartbeat = setInterval(() => res.write(':thump\n'), 15000);
|
const heartbeat = setInterval(() => res.write(':thump\n'), 15000);
|
||||||
|
|
||||||
req.on('close', () => {
|
req.on('close', () => {
|
||||||
log.verbose(req.requestId, `Ending stream for ${req.accountId}`);
|
log.verbose(req.requestId, `Ending stream for ${accountId}`);
|
||||||
clearInterval(heartbeat);
|
clearInterval(heartbeat);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -383,8 +423,10 @@ const startWorker = (workerId) => {
|
||||||
|
|
||||||
// Setup stream end for WebSockets
|
// Setup stream end for WebSockets
|
||||||
const streamWsEnd = (req, ws, closeHandler = false) => (id, listener) => {
|
const streamWsEnd = (req, ws, closeHandler = false) => (id, listener) => {
|
||||||
|
const accountId = req.accountId || req.remoteAddress;
|
||||||
|
|
||||||
ws.on('close', () => {
|
ws.on('close', () => {
|
||||||
log.verbose(req.requestId, `Ending stream for ${req.accountId}`);
|
log.verbose(req.requestId, `Ending stream for ${accountId}`);
|
||||||
unsubscribe(id, listener);
|
unsubscribe(id, listener);
|
||||||
if (closeHandler) {
|
if (closeHandler) {
|
||||||
closeHandler();
|
closeHandler();
|
||||||
|
@ -392,7 +434,7 @@ const startWorker = (workerId) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on('error', () => {
|
ws.on('error', () => {
|
||||||
log.verbose(req.requestId, `Ending stream for ${req.accountId}`);
|
log.verbose(req.requestId, `Ending stream for ${accountId}`);
|
||||||
unsubscribe(id, listener);
|
unsubscribe(id, listener);
|
||||||
if (closeHandler) {
|
if (closeHandler) {
|
||||||
closeHandler();
|
closeHandler();
|
||||||
|
@ -401,6 +443,7 @@ const startWorker = (workerId) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
app.use(setRequestId);
|
app.use(setRequestId);
|
||||||
|
app.use(setRemoteAddress);
|
||||||
app.use(allowCrossDomain);
|
app.use(allowCrossDomain);
|
||||||
app.use(authenticationMiddleware);
|
app.use(authenticationMiddleware);
|
||||||
app.use(errorMiddleware);
|
app.use(errorMiddleware);
|
||||||
|
@ -455,6 +498,7 @@ const startWorker = (workerId) => {
|
||||||
const req = ws.upgradeReq;
|
const req = ws.upgradeReq;
|
||||||
const location = url.parse(req.url, true);
|
const location = url.parse(req.url, true);
|
||||||
req.requestId = uuid.v4();
|
req.requestId = uuid.v4();
|
||||||
|
req.remoteAddress = ws._socket.remoteAddress;
|
||||||
|
|
||||||
ws.isAlive = true;
|
ws.isAlive = true;
|
||||||
|
|
||||||
|
@ -527,12 +571,14 @@ const startWorker = (workerId) => {
|
||||||
|
|
||||||
const onError = (err) => {
|
const onError = (err) => {
|
||||||
log.error(err);
|
log.error(err);
|
||||||
|
server.close();
|
||||||
|
process.exit(0);
|
||||||
};
|
};
|
||||||
|
|
||||||
process.on('SIGINT', onExit);
|
process.on('SIGINT', onExit);
|
||||||
process.on('SIGTERM', onExit);
|
process.on('SIGTERM', onExit);
|
||||||
process.on('exit', onExit);
|
process.on('exit', onExit);
|
||||||
process.on('error', onError);
|
process.on('uncaughtException', onError);
|
||||||
};
|
};
|
||||||
|
|
||||||
throng({
|
throng({
|
||||||
|
|
Loading…
Reference in New Issue