Merge commit '3554c527954441fd924586a49c7d99a89101ac7e' into glitch-soc/merge-upstream

Conflicts:
- `app/controllers/authorize_interactions_controller.rb`:
  Small conflict due to our theming system.
- `streaming/index.js`:
  Upstream refactored part of the streaming server.
  We had some extra logic for handling local-only posts.
  Applied the refactor.
pull/2339/head
Claire 2023-07-30 16:11:55 +02:00
commit 92fa9d34b0
131 changed files with 932 additions and 1197 deletions

View File

@ -307,7 +307,7 @@ GEM
activesupport (>= 5.1)
haml (>= 4.0.6)
railties (>= 5.1)
haml_lint (0.49.1)
haml_lint (0.49.2)
haml (>= 4.0, < 6.2)
parallel (~> 1.10)
rainbow
@ -583,7 +583,7 @@ GEM
responders (3.1.0)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.5)
rexml (3.2.6)
rotp (6.2.2)
rouge (4.1.2)
rpam2 (4.0.2)

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
class InstancesIndex < Chewy::Index
settings index: { refresh_interval: '30s' }
index_scope ::Instance.searchable
root date_detection: false do
field :domain, type: 'text', index_prefixes: { min_chars: 1 }
field :accounts_count, type: 'long'
end
end

View File

@ -15,7 +15,7 @@ class Api::V1::Instances::PeersController < Api::BaseController
def index
cache_even_if_authenticated!
render_with_cache(expires_in: 1.day) { Instance.where.not(domain: DomainBlock.select(:domain)).pluck(:domain) }
render_with_cache(expires_in: 1.day) { Instance.searchable.pluck(:domain) }
end
private

View File

@ -0,0 +1,45 @@
# frozen_string_literal: true
class Api::V1::Peers::SearchController < Api::BaseController
before_action :require_enabled_api!
before_action :set_domains
skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
skip_around_action :set_locale
vary_by ''
def index
cache_even_if_authenticated!
render json: @domains
end
private
def require_enabled_api!
head 404 unless Setting.peers_api_enabled && !whitelist_mode?
end
def set_domains
return if params[:q].blank?
if Chewy.enabled?
@domains = InstancesIndex.query(function_score: {
query: {
prefix: {
domain: params[:q],
},
},
field_value_factor: {
field: 'accounts_count',
modifier: 'log2p',
},
}).limit(10).pluck(:domain)
else
domain = params[:q].strip
domain = TagManager.instance.normalize_domain(domain)
@domains = Instance.searchable.where(Instance.arel_table[:domain].matches("#{Instance.sanitize_sql_like(domain)}%", false, true)).limit(10).pluck(:domain)
end
end
end

View File

@ -3,33 +3,19 @@
class AuthorizeInteractionsController < ApplicationController
include Authorization
layout 'modal'
before_action :authenticate_user!
before_action :set_body_classes
before_action :set_resource
before_action :set_pack
def show
if @resource.is_a?(Account)
render :show
redirect_to web_url("@#{@resource.pretty_acct}")
elsif @resource.is_a?(Status)
redirect_to web_url("@#{@resource.account.pretty_acct}/#{@resource.id}")
else
render :error
not_found
end
end
def create
if @resource.is_a?(Account) && FollowService.new.call(current_account, @resource, with_rate_limit: true)
render :success
else
render :error
end
rescue ActiveRecord::RecordNotFound
render :error
end
private
def set_resource
@ -62,12 +48,4 @@ class AuthorizeInteractionsController < ApplicationController
def uri_param
params[:uri] || params.fetch(:acct, '').delete_prefix('acct:')
end
def set_body_classes
@body_classes = 'modal-layout'
end
def set_pack
use_pack 'modal'
end
end

View File

@ -10,7 +10,7 @@ class BackupsController < ApplicationController
def download
case Paperclip::Attachment.default_options[:storage]
when :s3
when :s3, :azure
redirect_to @backup.dump.expiring_url(10), allow_other_host: true
when :fog
if Paperclip::Attachment.default_options.dig(:fog_credentials, :openstack_temp_url_key).present?

View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
class RemoteInteractionHelperController < ApplicationController
vary_by ''
skip_before_action :require_functional!
skip_around_action :set_locale
skip_before_action :update_user_sign_in
content_security_policy do |p|
# We inherit the normal `script-src`
# Set every directive that does not have a fallback
p.default_src :none
p.form_action :none
p.base_uri :none
# Disable every directive with a fallback to cut on response size
p.base_uri false
p.font_src false
p.img_src false
p.style_src false
p.media_src false
p.frame_src false
p.manifest_src false
p.connect_src false
p.child_src false
p.worker_src false
# Widen the directives that we do need
p.frame_ancestors :self
p.connect_src :https
end
def index
expires_in(5.minutes, public: true, stale_while_revalidate: 30.seconds, stale_if_error: 1.day)
response.headers['X-Frame-Options'] = 'SAMEORIGIN'
response.headers['Referrer-Policy'] = 'no-referrer'
render layout: 'helper_frame'
end
end

View File

@ -19,6 +19,7 @@ module WellKnown
def set_account
username = username_from_resource
@account = begin
if username == Rails.configuration.x.local_domain
Account.representative

View File

@ -278,7 +278,7 @@ const mapDispatchToProps = (dispatch, { intl, contextType }) => ({
modalProps: {
type,
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
},

View File

@ -370,16 +370,33 @@ class Header extends ImmutablePureComponent {
const acct = isLocal && domain ? `${account.get('acct')}@${domain}` : account.get('acct');
const isIndexable = !account.get('noindex');
let badge;
const badges = [];
if (account.get('bot')) {
badge = (<div className='account-role bot'><FormattedMessage id='account.badges.bot' defaultMessage='Automated' /></div>);
badges.push(
<div key='bot-badge' className='account-role bot'>
<Icon id='cogs' /> { ' ' }
<FormattedMessage id='account.badges.bot' defaultMessage='Automated' />
</div>
);
} else if (account.get('group')) {
badge = (<div className='account-role group'><FormattedMessage id='account.badges.group' defaultMessage='Group' /></div>);
} else {
badge = null;
badges.push(
<div key='group-badge' className='account-role group'>
<Icon id='users' /> { ' ' }
<FormattedMessage id='account.badges.group' defaultMessage='Group' />
</div>
);
}
account.get('roles', []).forEach((role) => {
badges.push(
<div key={`role-badge-${role.get('id')}`} className={`account-role user-role-${account.getIn(['roles', 0, 'id'])}`}>
<Icon id='circle' /> { ' ' }
<span>{role.get('name')} ({domain})</span>
</div>
);
});
return (
<div className={classNames('account__header', { inactive: !!account.get('moved') })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
{!(suspended || hidden || account.get('moved')) && account.getIn(['relationship', 'requested_by']) && <FollowRequestNoteContainer account={account} />}
@ -414,13 +431,19 @@ class Header extends ImmutablePureComponent {
<div className='account__header__tabs__name'>
<h1>
<span dangerouslySetInnerHTML={displayNameHtml} /> {badge}
<span dangerouslySetInnerHTML={displayNameHtml} />
<small>
<span>@{acct}</span> {lockedIcon}
</small>
</h1>
</div>
{badges.length > 0 && (
<div className='account__header__badges'>
{badges}
</div>
)}
{!(suspended || hidden) && (
<div className='account__header__extra'>
<div className='account__header__bio' ref={this.setRef}>

View File

@ -83,7 +83,7 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
modalProps: {
type: 'follow',
accountId: account.get('id'),
url: account.get('url'),
url: account.get('uri'),
},
}));
},

View File

@ -281,13 +281,12 @@ class ComposeForm extends ImmutablePureComponent {
autoFocus={autoFocus}
lang={this.props.lang}
>
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
<div className='compose-form__modifiers'>
<UploadFormContainer />
<PollFormContainer />
</div>
</AutosuggestTextarea>
<EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
<div className='compose-form__buttons-wrapper'>
<div className='compose-form__buttons'>

View File

@ -139,10 +139,6 @@ class Search extends PureComponent {
this.setState({ expanded: false, selectedOption: -1 });
};
findTarget = () => {
return this.searchForm;
};
handleHashtagClick = () => {
const { router } = this.context;
const { value, onClickSearchResult } = this.props;

View File

@ -22,7 +22,7 @@ export const ExplorePrompt = () => (
<p>
<FormattedMessage
id='home.explore_prompt.body'
defaultMessage="Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. It's looking pretty quiet right now, so how about:"
defaultMessage="Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. If that feels too quiet, you may want to:"
/>
</p>

View File

@ -1,95 +1,296 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import React from 'react';
import { FormattedMessage } from 'react-intl';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { connect } from 'react-redux';
import { throttle, escapeRegExp } from 'lodash';
import { openModal, closeModal } from 'mastodon/actions/modal';
import api from 'mastodon/api';
import Button from 'mastodon/components/button';
import { Icon } from 'mastodon/components/icon';
import { registrationsOpen } from 'mastodon/initial_state';
const messages = defineMessages({
loginPrompt: { id: 'interaction_modal.login.prompt', defaultMessage: 'Domain of your home server, e.g. mastodon.social' },
});
const mapStateToProps = (state, { accountId }) => ({
displayNameHtml: state.getIn(['accounts', accountId, 'display_name_html']),
signupUrl: state.getIn(['server', 'server', 'registrations', 'url'], null) || '/auth/sign_up',
});
const mapDispatchToProps = (dispatch) => ({
onSignupClick() {
dispatch(closeModal({
modalType: undefined,
ignoreFocus: false,
}));
dispatch(openModal({ modalType: 'CLOSED_REGISTRATIONS' }));
dispatch(closeModal());
dispatch(openModal('CLOSED_REGISTRATIONS'));
},
});
class Copypaste extends PureComponent {
const PERSISTENCE_KEY = 'mastodon_home';
const isValidDomain = value => {
const url = new URL('https:///path');
url.hostname = value;
return url.hostname === value;
};
const valueToDomain = value => {
// If the user starts typing an URL
if (/^https?:\/\//.test(value)) {
try {
const url = new URL(value);
// Consider that if there is a path, the URL is more meaningful than a bare domain
if (url.pathname.length > 1) {
return '';
}
return url.host;
} catch {
return undefined;
}
// If the user writes their full handle including username
} else if (value.includes('@')) {
if (value.replace(/^@/, '').split('@').length > 2) {
return undefined;
}
return '';
}
return value;
};
const addInputToOptions = (value, options) => {
value = value.trim();
if (value.includes('.') && isValidDomain(value)) {
return [value].concat(options.filter((x) => x !== value));
}
return options;
};
class LoginForm extends React.PureComponent {
static propTypes = {
value: PropTypes.string,
resourceUrl: PropTypes.string,
intl: PropTypes.object.isRequired,
};
state = {
copied: false,
value: localStorage ? (localStorage.getItem(PERSISTENCE_KEY) || '') : '',
expanded: false,
selectedOption: -1,
isLoading: false,
isSubmitting: false,
error: false,
options: [],
networkOptions: [],
};
setRef = c => {
this.input = c;
};
handleInputClick = () => {
this.setState({ copied: false });
this.input.focus();
this.input.select();
this.input.setSelectionRange(0, this.input.value.length);
handleChange = ({ target }) => {
this.setState(state => ({ value: target.value, isLoading: true, error: false, options: addInputToOptions(target.value, state.networkOptions) }), () => this._loadOptions());
};
handleButtonClick = () => {
const { value } = this.props;
navigator.clipboard.writeText(value);
this.input.blur();
this.setState({ copied: true });
this.timeout = setTimeout(() => this.setState({ copied: false }), 700);
handleMessage = (event) => {
const { resourceUrl } = this.props;
if (event.origin !== window.origin || event.source !== this.iframeRef.contentWindow) {
return;
}
if (event.data?.type === 'fetchInteractionURL-failure') {
this.setState({ isSubmitting: false, error: true });
} else if (event.data?.type === 'fetchInteractionURL-success') {
if (/^https?:\/\//.test(event.data.template)) {
if (localStorage) {
localStorage.setItem(PERSISTENCE_KEY, event.data.uri_or_domain);
}
window.location.href = event.data.template.replace('{uri}', encodeURIComponent(resourceUrl));
} else {
this.setState({ isSubmitting: false, error: true });
}
}
};
componentWillUnmount () {
if (this.timeout) clearTimeout(this.timeout);
componentDidMount () {
window.addEventListener('message', this.handleMessage);
}
componentWillUnmount () {
window.removeEventListener('message', this.handleMessage);
}
handleSubmit = () => {
const { value } = this.state;
this.setState({ isSubmitting: true });
this.iframeRef.contentWindow.postMessage({
type: 'fetchInteractionURL',
uri_or_domain: value.trim(),
}, window.origin);
};
setIFrameRef = (iframe) => {
this.iframeRef = iframe;
}
handleFocus = () => {
this.setState({ expanded: true });
};
handleBlur = () => {
this.setState({ expanded: false });
};
handleKeyDown = (e) => {
const { options, selectedOption } = this.state;
switch(e.key) {
case 'ArrowDown':
e.preventDefault();
if (options.length > 0) {
this.setState({ selectedOption: Math.min(selectedOption + 1, options.length - 1) });
}
break;
case 'ArrowUp':
e.preventDefault();
if (options.length > 0) {
this.setState({ selectedOption: Math.max(selectedOption - 1, -1) });
}
break;
case 'Enter':
e.preventDefault();
if (selectedOption === -1) {
this.handleSubmit();
} else if (options.length > 0) {
this.setState({ value: options[selectedOption], error: false }, () => this.handleSubmit());
}
break;
}
};
handleOptionClick = e => {
const index = Number(e.currentTarget.getAttribute('data-index'));
const option = this.state.options[index];
e.preventDefault();
this.setState({ selectedOption: index, value: option, error: false }, () => this.handleSubmit());
};
_loadOptions = throttle(() => {
const { value } = this.state;
const domain = valueToDomain(value.trim());
if (typeof domain === 'undefined') {
this.setState({ options: [], networkOptions: [], isLoading: false, error: true });
return;
}
if (domain.length === 0) {
this.setState({ options: [], networkOptions: [], isLoading: false });
return;
}
api().get('/api/v1/peers/search', { params: { q: domain } }).then(({ data }) => {
if (!data) {
data = [];
}
this.setState((state) => ({ networkOptions: data, options: addInputToOptions(state.value, data), isLoading: false }));
}).catch(() => {
this.setState({ isLoading: false });
});
}, 200, { leading: true, trailing: true });
render () {
const { value } = this.props;
const { copied } = this.state;
const { intl } = this.props;
const { value, expanded, options, selectedOption, error, isSubmitting } = this.state;
const domain = (valueToDomain(value) || '').trim();
const domainRegExp = new RegExp(`(${escapeRegExp(domain)})`, 'gi');
const hasPopOut = domain.length > 0 && options.length > 0;
return (
<div className={classNames('copypaste', { copied })}>
<input
type='text'
ref={this.setRef}
value={value}
readOnly
onClick={this.handleInputClick}
<div className={classNames('interaction-modal__login', { focused: expanded, expanded: hasPopOut, invalid: error })}>
<iframe
ref={this.setIFrameRef}
style={{display: 'none'}}
src='/remote_interaction_helper'
sandbox='allow-scripts allow-same-origin'
title='remote interaction helper'
/>
<button className='button' onClick={this.handleButtonClick}>
{copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy' defaultMessage='Copy' />}
</button>
<div className='interaction-modal__login__input'>
<input
ref={this.setRef}
type='text'
value={value}
placeholder={intl.formatMessage(messages.loginPrompt)}
aria-label={intl.formatMessage(messages.loginPrompt)}
autoFocus
onChange={this.handleChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onKeyDown={this.handleKeyDown}
/>
<Button onClick={this.handleSubmit} disabled={isSubmitting}><FormattedMessage id='interaction_modal.login.action' defaultMessage='Take me home' /></Button>
</div>
{hasPopOut && (
<div className='search__popout'>
<div className='search__popout__menu'>
{options.map((option, i) => (
<button key={option} onMouseDown={this.handleOptionClick} data-index={i} className={classNames('search__popout__menu__item', { selected: selectedOption === i })}>
{option.split(domainRegExp).map((part, i) => (
part.toLowerCase() === domain.toLowerCase() ? (
<mark key={i}>
{part}
</mark>
) : (
<span key={i}>
{part}
</span>
)
))}
</button>
))}
</div>
</div>
)}
</div>
);
}
}
class InteractionModal extends PureComponent {
const IntlLoginForm = injectIntl(LoginForm);
class InteractionModal extends React.PureComponent {
static propTypes = {
displayNameHtml: PropTypes.string,
url: PropTypes.string,
type: PropTypes.oneOf(['reply', 'reblog', 'favourite', 'follow']),
onSignupClick: PropTypes.func.isRequired,
signupUrl: PropTypes.string.isRequired,
};
handleSignupClick = () => {
@ -97,7 +298,7 @@ class InteractionModal extends PureComponent {
};
render () {
const { url, type, displayNameHtml, signupUrl } = this.props;
const { url, type, displayNameHtml } = this.props;
const name = <bdi dangerouslySetInnerHTML={{ __html: displayNameHtml }} />;
@ -130,13 +331,13 @@ class InteractionModal extends PureComponent {
if (registrationsOpen) {
signupButton = (
<a href={signupUrl} className='button button--block button-tertiary'>
<a href='/auth/sign_up' className='link-button'>
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
</a>
);
} else {
signupButton = (
<button className='button button--block button-tertiary' onClick={this.handleSignupClick}>
<button className='link-button' onClick={this.handleSignupClick}>
<FormattedMessage id='sign_in_banner.create_account' defaultMessage='Create account' />
</button>
);
@ -146,22 +347,13 @@ class InteractionModal extends PureComponent {
<div className='modal-root__modal interaction-modal'>
<div className='interaction-modal__lead'>
<h3><span className='interaction-modal__icon'>{icon}</span> {title}</h3>
<p>{actionDescription} <FormattedMessage id='interaction_modal.preamble' defaultMessage="Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one." /></p>
<p>{actionDescription} <strong><FormattedMessage id='interaction_modal.sign_in' defaultMessage='You are not logged in to this server. Where is your account hosted?' /></strong></p>
</div>
<div className='interaction-modal__choices'>
<div className='interaction-modal__choices__choice'>
<h3><FormattedMessage id='interaction_modal.on_this_server' defaultMessage='On this server' /></h3>
<a href='/auth/sign_in' className='button button--block'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /></a>
{signupButton}
</div>
<IntlLoginForm resourceUrl={url} />
<div className='interaction-modal__choices__choice'>
<h3><FormattedMessage id='interaction_modal.on_another_server' defaultMessage='On a different server' /></h3>
<p><FormattedMessage id='interaction_modal.other_server_instructions' defaultMessage='Copy and paste this URL into the search field of your favorite Mastodon app or the web interface of your Mastodon server.' /></p>
<Copypaste value={url} />
</div>
</div>
<p className='hint'><FormattedMessage id='interaction_modal.sign_in_hint' defaultMessage="Tip: That's the website where you signed up. If you don't remember, look for the welcome e-mail in your inbox. You can also enter your full username! (e.g. @Mastodon@mastodon.social)" /></p>
<p><FormattedMessage id='interaction_modal.no_account_yet' defaultMessage='Not on Mastodon?' /> {signupButton}</p>
</div>
);
}

View File

@ -91,7 +91,7 @@ class Footer extends ImmutablePureComponent {
modalProps: {
type: 'reply',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}
@ -113,7 +113,7 @@ class Footer extends ImmutablePureComponent {
modalProps: {
type: 'favourite',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}
@ -142,7 +142,7 @@ class Footer extends ImmutablePureComponent {
modalProps: {
type: 'reblog',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}

View File

@ -252,7 +252,7 @@ class Status extends ImmutablePureComponent {
modalProps: {
type: 'favourite',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}
@ -289,7 +289,7 @@ class Status extends ImmutablePureComponent {
modalProps: {
type: 'reply',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}
@ -319,7 +319,7 @@ class Status extends ImmutablePureComponent {
modalProps: {
type: 'reblog',
accountId: status.getIn(['account', 'id']),
url: status.get('url'),
url: status.get('uri'),
},
}));
}

View File

@ -191,7 +191,6 @@
"conversation.open": "View conversation",
"conversation.with": "With {names}",
"copypaste.copied": "Copied",
"copypaste.copy": "Copy",
"copypaste.copy_to_clipboard": "Copy to clipboard",
"directory.federated": "From known fediverse",
"directory.local": "From {domain} only",
@ -303,7 +302,7 @@
"home.column_settings.basic": "Basic",
"home.column_settings.show_reblogs": "Show boosts",
"home.column_settings.show_replies": "Show replies",
"home.explore_prompt.body": "Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. It's looking pretty quiet right now, so how about:",
"home.explore_prompt.body": "Your home feed will have a mix of posts from the hashtags you've chosen to follow, the people you've chosen to follow, and the posts they boost. If that feels too quiet, you may want to:",
"home.explore_prompt.title": "This is your home base within Mastodon.",
"home.hide_announcements": "Hide announcements",
"home.show_announcements": "Show announcements",
@ -311,10 +310,13 @@
"interaction_modal.description.follow": "With an account on Mastodon, you can follow {name} to receive their posts in your home feed.",
"interaction_modal.description.reblog": "With an account on Mastodon, you can boost this post to share it with your own followers.",
"interaction_modal.description.reply": "With an account on Mastodon, you can respond to this post.",
"interaction_modal.login.action": "Take me home",
"interaction_modal.login.prompt": "Domain of your home server, e.g. mastodon.social",
"interaction_modal.no_account_yet": "Not on Mastodon?",
"interaction_modal.on_another_server": "On a different server",
"interaction_modal.on_this_server": "On this server",
"interaction_modal.other_server_instructions": "Copy and paste this URL into the search field of your favorite Mastodon app or the web interface of your Mastodon server.",
"interaction_modal.preamble": "Since Mastodon is decentralized, you can use your existing account hosted by another Mastodon server or compatible platform if you don't have an account on this one.",
"interaction_modal.sign_in": "You are not logged in to this server. Where is your account hosted?",
"interaction_modal.sign_in_hint": "Tip: That's the website where you signed up. If you don't remember, look for the welcome e-mail in your inbox. You can also enter your full username! (e.g. @Mastodon@mastodon.social)",
"interaction_modal.title.favourite": "Favorite {name}'s post",
"interaction_modal.title.follow": "Follow {name}",
"interaction_modal.title.reblog": "Boost {name}'s post",

View File

@ -0,0 +1,172 @@
/*
This script is meant to to be used in an `iframe` with the sole purpose of doing webfinger queries
client-side without being restricted by a strict `connect-src` Content-Security-Policy directive.
It communicates with the parent window through message events that are authenticated by origin,
and performs no other task.
*/
import './public-path';
import axios from 'axios';
interface JRDLink {
rel: string;
template?: string;
href?: string;
}
const isJRDLink = (link: unknown): link is JRDLink =>
typeof link === 'object' &&
link !== null &&
'rel' in link &&
typeof link.rel === 'string' &&
(!('template' in link) || typeof link.template === 'string') &&
(!('href' in link) || typeof link.href === 'string');
const findLink = (rel: string, data: unknown): JRDLink | undefined => {
if (
typeof data === 'object' &&
data !== null &&
'links' in data &&
data.links instanceof Array
) {
return data.links.find(
(link): link is JRDLink => isJRDLink(link) && link.rel === rel,
);
} else {
return undefined;
}
};
const findTemplateLink = (data: unknown) =>
findLink('http://ostatus.org/schema/1.0/subscribe', data)?.template;
const fetchInteractionURLSuccess = (
uri_or_domain: string,
template: string,
) => {
window.parent.postMessage(
{
type: 'fetchInteractionURL-success',
uri_or_domain,
template,
},
window.origin,
);
};
const fetchInteractionURLFailure = () => {
window.parent.postMessage(
{
type: 'fetchInteractionURL-failure',
},
window.origin,
);
};
const isValidDomain = (value: string) => {
const url = new URL('https:///path');
url.hostname = value;
return url.hostname === value;
};
// Attempt to find a remote interaction URL from a domain
const fromDomain = (domain: string) => {
const fallbackTemplate = `https://${domain}/authorize_interaction?uri={uri}`;
axios
.get(`https://${domain}/.well-known/webfinger`, {
params: { resource: `https://${domain}` },
})
.then(({ data }) => {
const template = findTemplateLink(data);
fetchInteractionURLSuccess(domain, template ?? fallbackTemplate);
return;
})
.catch(() => {
fetchInteractionURLSuccess(domain, fallbackTemplate);
});
};
// Attempt to find a remote interaction URL from an arbitrary URL
const fromURL = (url: string) => {
const domain = new URL(url).host;
const fallbackTemplate = `https://${domain}/authorize_interaction?uri={uri}`;
axios
.get(`https://${domain}/.well-known/webfinger`, {
params: { resource: url },
})
.then(({ data }) => {
const template = findTemplateLink(data);
fetchInteractionURLSuccess(url, template ?? fallbackTemplate);
return;
})
.catch(() => {
fromDomain(domain);
});
};
// Attempt to find a remote interaction URL from a `user@domain` string
const fromAcct = (acct: string) => {
acct = acct.replace(/^@/, '');
const segments = acct.split('@');
if (segments.length !== 2 || !segments[0] || !isValidDomain(segments[1])) {
fetchInteractionURLFailure();
return;
}
const domain = segments[1];
const fallbackTemplate = `https://${domain}/authorize_interaction?uri={uri}`;
axios
.get(`https://${domain}/.well-known/webfinger`, {
params: { resource: `acct:${acct}` },
})
.then(({ data }) => {
const template = findTemplateLink(data);
fetchInteractionURLSuccess(acct, template ?? fallbackTemplate);
return;
})
.catch(() => {
// TODO: handle host-meta?
fromDomain(domain);
});
};
const fetchInteractionURL = (uri_or_domain: string) => {
if (/^https?:\/\//.test(uri_or_domain)) {
fromURL(uri_or_domain);
} else if (uri_or_domain.includes('@')) {
fromAcct(uri_or_domain);
} else {
fromDomain(uri_or_domain);
}
};
window.addEventListener('message', (event: MessageEvent<unknown>) => {
// Check message origin
if (
!window.origin ||
window.parent !== event.source ||
event.origin !== window.origin
) {
return;
}
if (
event.data &&
typeof event.data === 'object' &&
'type' in event.data &&
event.data.type === 'fetchInteractionURL' &&
'uri_or_domain' in event.data &&
typeof event.data.uri_or_domain === 'string'
) {
fetchInteractionURL(event.data.uri_or_domain);
}
});

View File

@ -188,30 +188,43 @@
}
.account-role,
.information-badge,
.simple_form .recommended,
.simple_form .not_recommended {
display: inline-block;
padding: 4px 6px;
cursor: default;
border-radius: 3px;
border-radius: 4px;
font-size: 12px;
line-height: 12px;
font-weight: 500;
color: var(--user-role-accent, $ui-secondary-color);
background-color: var(--user-role-background, rgba($ui-secondary-color, 0.1));
border: 1px solid var(--user-role-border, rgba($ui-secondary-color, 0.5));
color: $ui-secondary-color;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
&.moderator {
.information-badge,
.simple_form .recommended,
.simple_form .not_recommended {
background-color: rgba($ui-secondary-color, 0.1);
border: 1px solid rgba($ui-secondary-color, 0.5);
}
.account-role {
border: 1px solid $highlight-text-color;
.fa {
color: var(--user-role-accent, $highlight-text-color);
}
}
.information-badge {
&.superapp {
color: $success-green;
background-color: rgba($success-green, 0.1);
border-color: rgba($success-green, 0.5);
}
&.admin {
color: lighten($error-red, 12%);
background-color: rgba(lighten($error-red, 12%), 0.1);
border-color: rgba(lighten($error-red, 12%), 0.5);
}
}
.simple_form .not_recommended {

View File

@ -2891,6 +2891,7 @@ $ui-header-height: 55px;
border-radius: 4px;
transition: box-shadow 300ms linear;
min-height: 0;
position: relative;
&.active {
transition: none;
@ -7331,6 +7332,16 @@ noscript {
}
}
&__badges {
display: flex;
flex-wrap: wrap;
gap: 8px;
.account-role {
line-height: unset;
}
}
&__tabs {
display: flex;
align-items: flex-start;
@ -7369,10 +7380,6 @@ noscript {
margin-top: 16px;
margin-bottom: 16px;
.account-role {
vertical-align: top;
}
.emojione {
width: 22px;
height: 22px;
@ -8350,13 +8357,13 @@ noscript {
.interaction-modal {
max-width: 90vw;
width: 600px;
background: $ui-base-color;
background: var(--modal-background-color);
border: 1px solid var(--modal-border-color);
border-radius: 8px;
overflow-x: hidden;
overflow-y: auto;
overflow: visible;
position: relative;
display: block;
padding: 20px;
padding: 40px;
h3 {
font-size: 22px;
@ -8365,63 +8372,100 @@ noscript {
text-align: center;
}
p {
font-size: 17px;
line-height: 22px;
color: $darker-text-color;
strong {
color: $primary-text-color;
font-weight: 700;
}
}
p.hint {
margin-bottom: 14px;
font-size: 14px;
}
&__icon {
color: $highlight-text-color;
margin: 0 5px;
}
&__lead {
padding: 20px;
text-align: center;
margin-bottom: 20px;
h3 {
margin-bottom: 15px;
}
p {
font-size: 17px;
line-height: 22px;
color: $darker-text-color;
}
}
&__choices {
display: flex;
&__login {
position: relative;
margin-bottom: 20px;
&__choice {
flex: 0 0 auto;
width: 50%;
box-sizing: border-box;
padding: 20px;
&__input {
@include search-input;
h3 {
margin-bottom: 20px;
}
border: 1px solid lighten($ui-base-color, 8%);
padding: 4px 6px;
color: $primary-text-color;
font-size: 16px;
line-height: 18px;
display: flex;
align-items: center;
p {
color: $darker-text-color;
margin-bottom: 20px;
input {
background: transparent;
color: inherit;
font: inherit;
border: 0;
padding: 15px - 4px 15px - 6px;
flex: 1 1 auto;
&::placeholder {
color: lighten($darker-text-color, 4%);
}
&:focus {
outline: 0;
}
}
.button {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
flex: 0 0 auto;
}
}
.search__popout {
margin-top: -1px;
padding-top: 5px;
padding-bottom: 5px;
border: 1px solid lighten($ui-base-color, 8%);
}
&.focused &__input {
border-color: $highlight-text-color;
background: lighten($ui-base-color, 4%);
}
&.invalid &__input {
border-color: $error-red;
}
&.expanded .search__popout {
display: block;
}
&.expanded &__input {
border-radius: 4px 4px 0 0;
}
}
@media screen and (max-width: $no-gap-breakpoint - 1px) {
&__choices {
display: block;
&__choice {
width: auto;
margin-bottom: 20px;
}
}
.link-button {
font-size: inherit;
display: inline;
}
}

View File

@ -96,4 +96,6 @@ $font-monospace: 'mastodon-font-monospace' !default;
--dropdown-background-color: #{lighten($ui-base-color, 4%)};
--dropdown-shadow: 0 20px 25px -5px #{rgba($base-shadow-color, 0.25)},
0 8px 10px -6px #{rgba($base-shadow-color, 0.25)};
--modal-background-color: #{darken($ui-base-color, 4%)};
--modal-border-color: #{lighten($ui-base-color, 4%)};
}

View File

@ -33,6 +33,7 @@ interface AccountApiResponseValues {
note: string;
statuses_count: number;
url: string;
uri: string;
username: string;
}

View File

@ -9,7 +9,7 @@ class ActivityPub::Activity::Flag < ActivityPub::Activity
target_accounts.each do |target_account|
target_statuses = target_statuses_by_account[target_account.id]
replied_to_accounts = Account.local.where(id: target_statuses.filter_map(&:in_reply_to_account_id))
replied_to_accounts = target_statuses.nil? ? [] : Account.local.where(id: target_statuses.filter_map(&:in_reply_to_account_id))
next if target_account.suspended? || (!target_account.local? && replied_to_accounts.none?)

View File

@ -76,6 +76,9 @@ class AttachmentBatch
when :fog
logger.debug { "Deleting #{attachment.path(style)}" }
attachment.directory.files.new(key: attachment.path(style)).destroy
when :azure
logger.debug { "Deleting #{attachment.path(style)}" }
attachment.destroy
end
end
end

View File

@ -0,0 +1,26 @@
# frozen_string_literal: true
class Importer::InstancesIndexImporter < Importer::BaseImporter
def import!
index.adapter.default_scope.find_in_batches(batch_size: @batch_size) do |tmp|
in_work_unit(tmp) do |instances|
bulk = Chewy::Index::Import::BulkBuilder.new(index, to_index: instances).bulk_body
indexed = bulk.count { |entry| entry[:index] }
deleted = bulk.count { |entry| entry[:delete] }
Chewy::Index::Import::BulkRequest.new(index).perform(bulk)
[indexed, deleted]
end
end
wait!
end
private
def index
InstancesIndex
end
end

View File

@ -11,6 +11,8 @@ class WebfingerResource
def username
case resource
when %r{\A(https?://)?#{instance_actor_regexp}/?\Z}
Rails.configuration.x.local_domain
when /\Ahttps?/i
username_from_url
when /@/
@ -22,6 +24,13 @@ class WebfingerResource
private
def instance_actor_regexp
hosts = [Rails.configuration.x.local_domain, Rails.configuration.x.web_domain]
hosts.concat(Rails.configuration.x.alternate_domains) if Rails.configuration.x.alternate_domains.present?
Regexp.union(hosts)
end
def username_from_url
if account_show_page?
path_params[:username]

View File

@ -21,6 +21,7 @@ class Instance < ApplicationRecord
belongs_to :unavailable_domain # skipcq: RB-RL1031
end
scope :searchable, -> { where.not(domain: DomainBlock.select(:domain)) }
scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
scope :by_domain_and_subdomains, ->(domain) { where("reverse('.' || domain) LIKE reverse(?)", "%.#{domain}") }

View File

@ -5,7 +5,7 @@ class REST::AccountSerializer < ActiveModel::Serializer
include FormattingHelper
attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :group, :created_at,
:note, :url, :avatar, :avatar_static, :header, :header_static,
:note, :url, :uri, :avatar, :avatar_static, :header, :header_static,
:followers_count, :following_count, :statuses_count, :last_status_at
has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested?
@ -66,6 +66,10 @@ class REST::AccountSerializer < ActiveModel::Serializer
ActivityPub::TagManager.instance.url_for(object)
end
def uri
ActivityPub::TagManager.instance.uri_for(object)
end
def avatar
full_asset_url(object.suspended? ? object.avatar.default_url : object.avatar_original_url)
end

View File

@ -22,6 +22,7 @@ class WebfingerSerializer < ActiveModel::Serializer
[
{ rel: 'http://webfinger.net/rel/profile-page', type: 'text/html', href: about_more_url(instance_actor: true) },
{ rel: 'self', type: 'application/activity+json', href: instance_actor_url },
{ rel: 'http://ostatus.org/schema/1.0/subscribe', template: "#{authorize_interaction_url}?uri={uri}" },
]
else
[

View File

@ -85,7 +85,7 @@ class SuspendAccountService < BaseService
rescue Aws::S3::Errors::NotImplemented => e
Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}"
end
when :fog
when :fog, :azure
# Not supported
when :filesystem
begin

View File

@ -81,7 +81,7 @@ class UnsuspendAccountService < BaseService
rescue Aws::S3::Errors::NotImplemented => e
Rails.logger.error "Error trying to change ACL on #{attachment.s3_object(style).key}: #{e.message}"
end
when :fog
when :fog, :azure
# Not supported
when :filesystem
begin

View File

@ -9,7 +9,7 @@
%samp= ":#{custom_emoji.shortcode}:"
- if custom_emoji.local?
%span.account-role.bot= custom_emoji.category&.name || t('admin.custom_emojis.uncategorized')
%span.information-badge= custom_emoji.category&.name || t('admin.custom_emojis.uncategorized')
.batch-table__row__content__extra
- if custom_emoji.local?

View File

@ -1,4 +0,0 @@
.post-follow-actions
%div= link_to t('authorize_follow.post_follow.web'), web_url("@#{@resource.pretty_acct}"), class: 'button button--block'
%div= link_to t('authorize_follow.post_follow.return'), ActivityPub::TagManager.instance.url_for(@resource), class: 'button button--block'
%div= t('authorize_follow.post_follow.close')

View File

@ -1,3 +0,0 @@
.form-container
.flash-message#error_explanation
= t('authorize_follow.error')

View File

@ -1,24 +0,0 @@
- content_for :page_title do
= t('authorize_follow.title', acct: @resource.pretty_acct)
.form-container
.follow-prompt
= render 'application/card', account: @resource
- if current_account.following?(@resource)
.flash-message
%strong
= t('authorize_follow.already_following')
= render 'post_follow_actions'
- elsif current_account.requested?(@resource)
.flash-message
%strong
= t('authorize_follow.already_requested')
= render 'post_follow_actions'
- else
= form_tag authorize_interaction_path, method: :post, class: 'simple_form' do
= hidden_field_tag :action, :follow
= hidden_field_tag :acct, @resource.acct
= button_tag t('authorize_follow.follow'), type: :submit

View File

@ -1,13 +0,0 @@
- content_for :page_title do
= t('authorize_follow.title', acct: @resource.pretty_acct)
.form-container
.follow-prompt
- if @resource.locked?
%h2= t('authorize_follow.follow_request')
- else
%h2= t('authorize_follow.following')
= render 'application/card', account: @resource
= render 'post_follow_actions'

View File

@ -5,8 +5,6 @@
<%- UserRole.where(highlighted: true).select { |role| role.color.present? }.each do |role| %>
.user-role-<%= role.id %> {
--user-role-accent: <%= role.color %>;
--user-role-background: <%= role.color + '19' %>;
--user-role-border: <%= role.color + '80' %>;
}
<%- end %>

View File

@ -0,0 +1,8 @@
!!! 5
%html
%head
%meta{ charset: 'utf-8' }/
= javascript_pack_tag 'common', crossorigin: 'anonymous'
= yield :header_tags

View File

@ -14,7 +14,7 @@
%strong.announcements-list__item__title
= application.name
- if application.superapp?
%span.account-role.moderator= t('doorkeeper.authorized_applications.index.superapp')
%span.information-badge.superapp= t('doorkeeper.authorized_applications.index.superapp')
.announcements-list__item__action-bar
.announcements-list__item__meta

View File

@ -0,0 +1,4 @@
- content_for :header_tags do
%meta{ name: 'robots', content: 'noindex' }/
= javascript_pack_tag 'remote_interaction_helper', crossorigin: 'anonymous'

View File

@ -9,7 +9,7 @@ class PushConversationWorker
message = InlineRenderer.render(conversation, conversation.account, :conversation)
timeline_id = "timeline:direct:#{conversation.account_id}"
redis.publish(timeline_id, Oj.dump(event: :conversation, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i))
redis.publish(timeline_id, Oj.dump(event: :conversation, payload: message))
rescue ActiveRecord::RecordNotFound
true
end

View File

@ -9,7 +9,7 @@ class PushEncryptedMessageWorker
message = InlineRenderer.render(encrypted_message, nil, :encrypted_message)
timeline_id = "timeline:#{encrypted_message.device.account_id}:#{encrypted_message.device.device_id}"
redis.publish(timeline_id, Oj.dump(event: :encrypted_message, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i))
redis.publish(timeline_id, Oj.dump(event: :encrypted_message, payload: message))
rescue ActiveRecord::RecordNotFound
true
end

View File

@ -25,8 +25,7 @@ class PushUpdateWorker
def message
Oj.dump(
event: update? ? :'status.update' : :update,
payload: @payload,
queued_at: (Time.now.to_f * 1000.0).to_i
payload: @payload
)
end

View File

@ -7,5 +7,6 @@ class Scheduler::InstanceRefreshScheduler
def perform
Instance.refresh
InstancesIndex.import if Chewy.enabled?
end
end

View File

@ -982,18 +982,6 @@ an:
view_strikes: Veyer amonestacions pasadas contra la tuya cuenta
too_fast: Formulario ninviau masiau rapido, lo intente de nuevo.
use_security_key: Usar la clau de seguranza
authorize_follow:
already_following: Ya yes seguindo a esta cuenta
already_requested: Ya has ninviau una solicitut de seguimiento a ixa cuenta
error: Desafortunadament, ha ocurriu una error buscando la cuenta remota
follow: Seguir
follow_request: 'Tiens una solicitut de seguimiento de:'
following: 'Exito! Agora yes seguindo a:'
post_follow:
close: U, puetz simplament zarrar esta finestra.
return: Tornar ta lo perfil de l'usuario
web: Ir ta lo puesto web
title: Seguir a %{acct}
challenge:
confirm: Continar
hint_html: "<strong>Tip:</strong> No tornaremos a preguntar-te per la clau entre la siguient hora."

View File

@ -1065,18 +1065,6 @@ ar:
view_strikes: عرض السجلات السابقة ضد حسابك
too_fast: تم إرسال النموذج بسرعة كبيرة، حاول مرة أخرى.
use_security_key: استخدام مفتاح الأمان
authorize_follow:
already_following: أنت تتابع بالفعل هذا الحساب
already_requested: لقد قُمتَ بإرسال طلب متابَعة إلى هذا الحساب مِن قَبل
error: يا للأسف، وقع هناك خطأ إثر عملية البحث عن الحساب عن بعد
follow: اتبع
follow_request: 'لقد قمت بإرسال طلب متابعة إلى:'
following: 'مرحى! أنت الآن تتبع:'
post_follow:
close: أو يمكنك إغلاق هذه النافذة.
return: اظهر الملف التعريفي للمستخدم
web: واصل إلى الويب
title: إتباع %{acct}
challenge:
confirm: واصل
hint_html: "<strong>توصية:</strong> لن نطلب منك ثانية كلمتك السرية في غضون الساعة اللاحقة."

View File

@ -481,15 +481,6 @@ ast:
functional: La cuenta ta completamente operativa.
pending: La to solicitú ta pendiente de que la revise'l nuesu personal ya ye posible que tarde tiempu. Vas recibir un mensaxe si s'aprueba.
too_fast: El formulariu xubióse mui rápido, volvi tentalo.
authorize_follow:
already_following: Xá tas siguiendo a esta cuenta
already_requested: Yá unviesti una solicitú de siguimientu a esa cuenta
error: Desafortunadamente, hebo un error al buscar la cuenta remota
follow_request: 'Unviesti una solicitú de siguimientu a:'
post_follow:
close: O pues zarrar esta ventana.
return: Amosar el perfil de la cuenta
web: Dir a la web
challenge:
confirm: Siguir
hint_html: "<strong>Conseyu:</strong> nun vamos volver pidite la contraseña hasta dientro d'una hora."

View File

@ -1095,18 +1095,6 @@ be:
view_strikes: Праглядзець мінулыя папярэджанні для вашага ўліковага запісу
too_fast: Форма адпраўлена занадта хутка, паспрабуйце яшчэ раз.
use_security_key: Выкарыстаеце ключ бяспекі
authorize_follow:
already_following: Вы ўжо падпісаныя на гэты ўліковы запіс
already_requested: Вы ўжо адправілі запыт на гэты ўліковы запіс
error: На жаль, падчас пошуку аддаленага ўліковага запісу здарылася памылка
follow: Падпісацца
follow_request: 'Вы адправілі запыт на падпіску:'
following: 'Поспех! Цяпер вы падпісаны на:'
post_follow:
close: Або, вы можаце проста закрыць гэтае акно.
return: Паказаць профіль карыстальніка
web: Перайсці ў вэб-версію
title: Падпісацца на %{acct}
challenge:
confirm: Працягнуць
hint_html: "<strong>Парада:</strong> Мы не будзем запытваць ваш пароль зноўку на працягу наступнай гадзіны."

View File

@ -1059,18 +1059,6 @@ bg:
view_strikes: Преглед на предишните предупреждения против акаунта ви
too_fast: Образецът подаден пребързо, опитайте пак.
use_security_key: Употреба на ключ за сигурност
authorize_follow:
already_following: Вече следвате този акаунт
already_requested: Вече сте изпратили заявка за последване до този акаунт
error: Възникна грешка, търсейки отдалечения акаунт
follow: Последвай
follow_request: 'Изпратихте следната заявка до:'
following: 'Успешно! Сега сте последвали:'
post_follow:
close: Или просто затворете този прозорец.
return: Показване на профила на потребителя
web: Към мрежата
title: Последвай %{acct}
challenge:
confirm: Продължаване
hint_html: "<strong>Съвет</strong>: няма да ви питаме пак за паролата през следващия час."

View File

@ -299,11 +299,6 @@ br:
security: Diogelroez
status:
account_status: Statud ar gont
authorize_follow:
follow: Heuliañ
post_follow:
web: Distreiñ d'an etrefas web
title: Heuliañ %{acct}
challenge:
confirm: Kenderc' hel
invalid_password: Ger-tremen diwiriek

View File

@ -1060,18 +1060,6 @@ ca:
view_strikes: Veure accions del passat contra el teu compte
too_fast: Formulari enviat massa ràpid, torna a provar-ho.
use_security_key: Usa clau de seguretat
authorize_follow:
already_following: Ja estàs seguint aquest compte
already_requested: Ja has enviat una sol·licitud de seguiment a aquest usuari
error: Malauradament, ha ocorregut un error cercant el compte remot
follow: Segueix
follow_request: 'Has enviat una sol·licitud de seguiment a:'
following: 'Perfecte! Ara segueixes:'
post_follow:
close: O bé, pots tancar aquesta finestra.
return: Mostra el perfil de l'usuari
web: Vés a la web
title: Segueix %{acct}
challenge:
confirm: Continua
hint_html: "<strong>Pista:</strong> No et preguntarem un altre cop la teva contrasenya en la pròxima hora."

View File

@ -620,18 +620,6 @@ ckb:
view_strikes: بینینی لێدانەکانی ڕابردوو لە دژی ئەکاونتەکەت
too_fast: فۆڕم زۆر خێرا پێشکەش کراوە، دووبارە هەوڵبدەرەوە.
use_security_key: کلیلی ئاسایش بەکاربهێنە
authorize_follow:
already_following: ئێوە ئێستا شوێن کەوتووی ئەم هەژمارەیەی
already_requested: تۆ پێشتر داواکاری بەدواداچوت ناردوە بۆ ئەو هەژمارە
error: بەداخەوە هەڵەیەک هەبوو لە کاتی گەڕان بەدوای ئەو هەژمارەیە
follow: شوێن کەوە
follow_request: 'تۆ داواکاری شوێنکەوتنت ناردووە بۆ:'
following: 'ئەنجام بوو! تۆ ئێستا بەدوای ئەم بەکارهێنەرە دەکەویت:'
post_follow:
close: یان، دەتوانیت ئەم پەنجەرەیە دابخەیت.
return: پرۆفایلی بەکارهێنەر نیشان بدە
web: بڕۆ بۆ وێب
title: دوای %{acct} بکەوە
challenge:
confirm: بەردەوام بە
hint_html: "<strong>خاڵ:</strong> ئیمە لە کاتژمێری داهاتوو تێپەروشەت لێداوا ناکەین."

View File

@ -583,18 +583,6 @@ co:
redirecting_to: U vostru contu hè inattivu perchè riindirizza versu %{acct}.
too_fast: Furmulariu mandatu troppu prestu, ripruvate.
use_security_key: Utilizà a chjave di sicurità
authorize_follow:
already_following: Site digià abbunatu·a à stu contu
already_requested: Avete digià mandatu una dumanda d'abbunamentu à stu contu
error: Peccatu, chè statu un prublemu ricercandu u contu
follow: Siguità
follow_request: 'Avete dumandatu di siguità:'
following: 'Eccu! Avà seguitate:'
post_follow:
close: O pudete ancu chjude sta finestra.
return: Vede u prufile di lutilizatore
web: Andà à linterfaccia web
title: Siguità %{acct}
challenge:
confirm: Cuntinuvà
hint_html: "<strong>Astuzia:</strong> Ùn avemu micca da dumandavvi stu codice per l'ore chì vene."

View File

@ -1075,18 +1075,6 @@ cs:
view_strikes: Zobrazit minulé prohřešky vašeho účtu
too_fast: Formulář byl odeslán příliš rychle, zkuste to znovu.
use_security_key: Použít bezpečnostní klíč
authorize_follow:
already_following: Tento účet již sledujete
already_requested: Tomuto účtu už jste žádost o sledování zaslali
error: Při hledání vzdáleného účtu bohužel nastala chyba
follow: Sledovat
follow_request: 'Poslali jste žádost o sledování uživateli:'
following: 'Podařilo se! Nyní sledujete uživatele:'
post_follow:
close: Nebo můžete toto okno klidně zavřít.
return: Zobrazit profil uživatele
web: Přejít na web
title: Sledovat %{acct}
challenge:
confirm: Pokračovat
hint_html: "<strong>Tip:</strong> Po dobu jedné hodiny vás o heslo nebudeme znovu žádat."

View File

@ -1132,18 +1132,6 @@ cy:
view_strikes: Gweld rybuddion y gorffennol yn erbyn eich cyfrif
too_fast: Cafodd y ffurflen ei chyflwyno'n rhy gyflym, ceisiwch eto.
use_security_key: Defnyddiwch allwedd diogelwch
authorize_follow:
already_following: Rydych yn dilyn y cyfrif hwn yn barod
already_requested: Rydych chi eisoes wedi anfon cais i ddilyn y cyfrif hwnnw
error: Yn anffodus, roedd gwall tra'n edrych am y cyfrif pell
follow: Dilyn
follow_request: 'Rydych wedi anfon cais dilyn at:'
following: 'Llwyddiant! Rydych nawr yn dilyn:'
post_follow:
close: Neu, gallwch gau'r ffenest hon.
return: Dangos proffil y defnyddiwr
web: Ewch i'r we
title: Dilyn %{acct}
challenge:
confirm: Parhau
hint_html: "<strong>Awgrym:</strong> Fyddwn ni ddim yn gofyn i chi am eich cyfrinair eto am yr awr nesaf."

View File

@ -1060,18 +1060,6 @@ da:
view_strikes: Se tidligere anmeldelser af din konto
too_fast: Formularen indsendt for hurtigt, forsøg igen.
use_security_key: Brug sikkerhedsnøgle
authorize_follow:
already_following: Du følger allerede denne konto
already_requested: Du har allerede sendt en følgeanmodning til den konto
error: Desværre opstod en fejl under søgning af fjernkontoen
follow: Følg
follow_request: 'Du har sendt en følgeanmodning til:'
following: 'Accepteret! Du følger nu:'
post_follow:
close: Du kan også bare lukke dette vindue.
return: Vis brugerens profil
web: Gå til web
title: Følg %{acct}
challenge:
confirm: Fortsæt
hint_html: "<strong>Tip:</strong> Du bliver ikke anmodet om din adgangskode igen den næste time."

View File

@ -1060,18 +1060,6 @@ de:
view_strikes: Vorherige Verstöße deines Kontos ansehen
too_fast: Formular zu schnell übermittelt. Bitte versuche es erneut.
use_security_key: Sicherheitsschlüssel verwenden
authorize_follow:
already_following: Du folgst diesem Konto bereits
already_requested: Du hast bereits eine Anfrage zum Folgen an dieses Konto gestellt
error: Bedauerlicherweise konnte das externe Konto nicht geladen werden
follow: Folgen
follow_request: 'Du hast eine Anfrage zum Folgen gestellt an:'
following: 'Erfolg! Du folgst nun:'
post_follow:
close: Oder du schließt einfach dieses Fenster.
return: Profil anzeigen
web: Im Webinterface öffnen
title: "%{acct} folgen"
challenge:
confirm: Fortfahren
hint_html: "<strong>Hinweis:</strong> Wir werden dich für die nächste Stunde nicht erneut nach deinem Passwort fragen."

View File

@ -1039,18 +1039,6 @@ el:
view_strikes: Προβολή προηγούμενων ποινών εναντίον του λογαριασμού σας
too_fast: Η φόρμα υποβλήθηκε πολύ γρήγορα, προσπαθήστε ξανά.
use_security_key: Χρήση κλειδιού ασφαλείας
authorize_follow:
already_following: Ήδη ακολουθείς αυτό το λογαριασμό
already_requested: Έχετε ήδη στείλει ένα αίτημα ακολούθησης σε αυτόν τον λογαριασμό
error: Δυστυχώς παρουσιάστηκε ένα σφάλμα κατά την αναζήτηση του απομακρυσμένου λογαριασμού
follow: Ακολούθησε
follow_request: 'Έστειλες αίτημα παρακολούθησης προς:'
following: 'Επιτυχία! Πλέον ακολουθείς τον/την:'
post_follow:
close: Ή, μπορείς απλά να κλείσεις αυτό το παράθυρο.
return: Δείξε το προφίλ του χρήστη
web: Πήγαινε στο δίκτυο
title: Ακολούθησε %{acct}
challenge:
confirm: Συνέχεια
hint_html: "<strong>Συμβουλή:</strong> Δεν θα σου ζητήσουμε τον κωδικό ασφαλείας σου ξανά για την επόμενη ώρα."

View File

@ -1060,18 +1060,6 @@ en-GB:
view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again.
use_security_key: Use security key
authorize_follow:
already_following: You are already following this account
already_requested: You have already sent a follow request to that account
error: Unfortunately, there was an error looking up the remote account
follow: Follow
follow_request: 'You have sent a follow request to:'
following: 'Success! You are now following:'
post_follow:
close: Or, you can just close this window.
return: Show the user's profile
web: Go to web
title: Follow %{acct}
challenge:
confirm: Continue
hint_html: "<strong>Tip:</strong> We won't ask you for your password again for the next hour."

View File

@ -1060,18 +1060,6 @@ en:
view_strikes: View past strikes against your account
too_fast: Form submitted too fast, try again.
use_security_key: Use security key
authorize_follow:
already_following: You are already following this account
already_requested: You have already sent a follow request to that account
error: Unfortunately, there was an error looking up the remote account
follow: Follow
follow_request: 'You have sent a follow request to:'
following: 'Success! You are now following:'
post_follow:
close: Or, you can just close this window.
return: Show the user's profile
web: Go to web
title: Follow %{acct}
challenge:
confirm: Continue
hint_html: "<strong>Tip:</strong> We won't ask you for your password again for the next hour."

View File

@ -1056,18 +1056,6 @@ eo:
view_strikes: Vidi antauaj admonoj kontra via konto
too_fast: Formularo sendita tro rapide, klopodu denove.
use_security_key: Uzi sekurecan ŝlosilon
authorize_follow:
already_following: Vi jam sekvas tiun konton
already_requested: Vi jam sendis peton de sekvado al ĉi tiu konto
error: Bedaŭrinde, estis eraro en la serĉado de la fora konto
follow: Sekvi
follow_request: 'Vi sendis peton de sekvado al:'
following: 'Sukceson! Vi nun sekvas:'
post_follow:
close: Aŭ, vi povas simple fermi ĉi tiun fenestron.
return: Montri la profilon de la uzanto
web: Iri al reto
title: Sekvi %{acct}
challenge:
confirm: Daŭrigi
hint_html: "<strong>Konsileto:</strong> Ni ne demandos pri via pasvorto ĝis 1 horo."

View File

@ -1060,18 +1060,6 @@ es-AR:
view_strikes: Ver incumplimientos pasados contra tu cuenta
too_fast: Formulario enviado demasiado rápido, probá de nuevo.
use_security_key: Usar la llave de seguridad
authorize_follow:
already_following: Ya estás siguiendo a esta cuenta
already_requested: Ya enviaste una solicitud de seguimiento a esa cuenta
error: Lamentablemente, ocurrió un error buscando la cuenta remota
follow: Seguir
follow_request: 'Enviaste una solicitud de seguimiento a:'
following: "¡Listo! Ahora estás siguiendo a:"
post_follow:
close: O simplemente podés cerrar esta ventana.
return: Mostrar el perfil del usuario
web: Ir a la web
title: Seguir a %{acct}
challenge:
confirm: Continuar
hint_html: "<strong>Dato:</strong> No volveremos a preguntarte por la contraseña durante la siguiente hora."

View File

@ -1060,18 +1060,6 @@ es-MX:
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
authorize_follow:
already_following: Ya estás siguiendo a esta cuenta
already_requested: Ya has enviado una solicitud de seguimiento a esa cuenta
error: Desafortunadamente, ha ocurrido un error buscando la cuenta remota
follow: Seguir
follow_request: 'Tienes una solicitud de seguimiento de:'
following: "¡Éxito! Ahora estás siguiendo a:"
post_follow:
close: O, puedes simplemente cerrar esta ventana.
return: Regresar al perfil del usuario
web: Ir al sitio web
title: Seguir a %{acct}
challenge:
confirm: Continuar
hint_html: "<strong>Tip:</strong> No volveremos a preguntarte por la contraseña durante la siguiente hora."

View File

@ -1060,18 +1060,6 @@ es:
view_strikes: Ver amonestaciones pasadas contra tu cuenta
too_fast: Formulario enviado demasiado rápido, inténtelo de nuevo.
use_security_key: Usar la clave de seguridad
authorize_follow:
already_following: Ya estás siguiendo a esta cuenta
already_requested: Ya has enviado una solicitud de seguimiento a esa cuenta
error: Desafortunadamente, ha ocurrido un error buscando la cuenta remota
follow: Seguir
follow_request: 'Tienes una solicitud de seguimiento de:'
following: "¡Éxito! Ahora estás siguiendo a:"
post_follow:
close: O, puedes simplemente cerrar esta ventana.
return: Regresar al perfil del usuario
web: Ir al sitio web
title: Seguir a %{acct}
challenge:
confirm: Continuar
hint_html: "<strong>Tip:</strong> No volveremos a preguntarte por la contraseña durante la siguiente hora."

View File

@ -1060,18 +1060,6 @@ et:
view_strikes: Vaata enda eelnevaid juhtumeid
too_fast: Vorm esitatud liiga kiirelt, proovi uuesti.
use_security_key: Kasuta turvavõtit
authorize_follow:
already_following: Juba jälgid seda kontot
already_requested: Saatsid juba sellele kontole jälgimistaotluse
error: Kahjuks ilmus viga kasutaja kaugserverist otsimisel
follow: Jälgi
follow_request: 'Oled saatnud jälgimistaotluse kasutajale:'
following: 'Õnnestus! Jälgid nüüd kasutajat:'
post_follow:
close: Või sulge lihtsalt see aken.
return: Näita kasutaja profiili
web: Mine veebi
title: Jälgi %{acct}
challenge:
confirm: Jätka
hint_html: "<strong>Nõuanne:</strong> Me ei küsi salasõna uuesti järgmise tunni jooksul."

View File

@ -1051,18 +1051,6 @@ eu:
view_strikes: Ikusi zure kontuaren aurkako neurriak
too_fast: Formularioa azkarregi bidali duzu, saiatu berriro.
use_security_key: Erabili segurtasun gakoa
authorize_follow:
already_following: Kontu hau aurretik jarraitzen duzu
already_requested: Bidali duzu dagoeneko kontu hori jarraitzeko eskaera bat
error: Zoritxarrez, urruneko kontua bilatzean errore bat gertatu da
follow: Jarraitu
follow_request: 'Jarraitzeko eskari bat bidali duzu hona:'
following: 'Ongi! Orain jarraitzen duzu:'
post_follow:
close: Edo, leiho hau besterik gabe itxi dezakezu.
return: Erakutsi erabiltzailearen profila
web: Joan webera
title: Jarraitu %{acct}
challenge:
confirm: Jarraitu
hint_html: "<strong>Oharra:</strong> Ez dizugu pasahitza berriro eskatuko ordu batez."

View File

@ -889,18 +889,6 @@ fa:
view_strikes: دیدن شکایت‌های گذشته از حسابتان
too_fast: فرم با سرعت بسیار زیادی فرستاده شد، دوباره تلاش کنید.
use_security_key: استفاده از کلید امنیتی
authorize_follow:
already_following: شما همین الان هم این حساب را پی‌می‌گیرید
already_requested: درخواست پی‌گیری‌ای برای آن حساب فرستاده‌ بودید
error: متأسفانه حین یافتن آن حساب خطایی رخ داد
follow: پی بگیرید
follow_request: 'شما درخواست پیگیری فرستاده‌اید به:'
following: 'انجام شد! شما هم‌اینک پیگیر این کاربر هستید:'
post_follow:
close: یا این پنجره را ببندید.
return: نمایهٔ این کاربر را نشان بده
web: رفتن به وب
title: پیگیری %{acct}
challenge:
confirm: ادامه
hint_html: "<strong>نکته:</strong> ما در یک ساعت آینده گذرواژه‌تان را از شما نخواهیم پرسید."

View File

@ -1060,18 +1060,6 @@ fi:
view_strikes: Näytä tiliäsi koskevia aiempia varoituksia
too_fast: Lomake lähetettiin liian nopeasti, yritä uudelleen.
use_security_key: Käytä suojausavainta
authorize_follow:
already_following: Sinä seuraat jo tätä tiliä
already_requested: Olet jo lähettänyt seurantapyynnön tälle tilille
error: Valitettavasti etätilin haussa tapahtui virhe
follow: Seuraa
follow_request: 'Olet lähettänyt seuraamispyynnön käyttäjälle:'
following: 'Onnistui! Seuraat käyttäjää:'
post_follow:
close: Tai voit sulkea tämän ikkunan.
return: Palaa käyttäjän profiiliin
web: Siirry verkkosivulle
title: Seuraa käyttäjää %{acct}
challenge:
confirm: Jatka
hint_html: "<strong>Vihje:</strong> Emme pyydä sinulta salasanaa uudelleen seuraavan tunnin aikana."

View File

@ -1060,18 +1060,6 @@ fo:
view_strikes: Vís eldri atsóknir móti tíni kontu
too_fast: Oyðublaðið innsent ov skjótt, royn aftur.
use_security_key: Brúka trygdarlykil
authorize_follow:
already_following: Tú fylgir longu hesi kontuni
already_requested: Tú hevur longu sent eina fylgiumbøn til hasa kontuna
error: Tíverri kom ein feilur, tá vit royndu at finna fjarkontuna
follow: Fylg
follow_request: 'Tú hevur sent eina fylgjaraumbøn til:'
following: 'Góðkent! Tú fylgir nú:'
post_follow:
close: Ella kanst tú bara lata hetta vindeygað aftur.
return: Vís vangan hjá brúkaranum
web: Far á vevið
title: Fylg %{acct}
challenge:
confirm: Hald á
hint_html: "<strong>Góð ráð:</strong> vit spyrja teg ikki aftur um loyniorðið næsta tíman."

View File

@ -1060,18 +1060,6 @@ fr-QC:
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
authorize_follow:
already_following: Vous suivez déjà ce compte
already_requested: Vous avez déjà envoyé une demande dabonnement à ce compte
error: Malheureusement, une erreur s'est produite lors de la recherche du compte distant
follow: Suivre
follow_request: 'Vous avez demandé à suivre:'
following: 'Youpi! Vous suivezmaintenant :'
post_follow:
close: Ou bien, vous pouvez fermer cette fenêtre.
return: Afficher le profil de lutilisateur·ice
web: Retour à linterface web
title: Suivre %{acct}
challenge:
confirm: Continuer
hint_html: "<strong>Astuce :</strong> Nous ne vous demanderons plus votre mot de passe pour la prochaine heure."

View File

@ -1060,18 +1060,6 @@ fr:
view_strikes: Voir les sanctions précédemment appliquées à votre compte
too_fast: Formulaire envoyé trop rapidement, veuillez réessayer.
use_security_key: Utiliser la clé de sécurité
authorize_follow:
already_following: Vous suivez déjà ce compte
already_requested: Vous avez déjà envoyé une demande dabonnement à ce compte
error: Malheureusement, une erreur s'est produite lors de la recherche du compte distant
follow: Suivre
follow_request: 'Vous avez demandé à suivre:'
following: 'Youpi! Vous suivezmaintenant :'
post_follow:
close: Ou bien, vous pouvez fermer cette fenêtre.
return: Afficher le profil de lutilisateur·ice
web: Retour à linterface web
title: Suivre %{acct}
challenge:
confirm: Continuer
hint_html: "<strong>Astuce :</strong> Nous ne vous demanderons plus votre mot de passe pour la prochaine heure."

View File

@ -1060,18 +1060,6 @@ fy:
view_strikes: Besjoch de earder troch moderatoaren fêststelde skeiningen dyt jo makke hawwe
too_fast: Formulier is te fluch yntsjinne. Probearje it nochris.
use_security_key: Befeiligingskaai brûke
authorize_follow:
already_following: Jo folgje dizze account al
already_requested: Jo hawwe al in folchfersyk nei dat account ferstjoerd
error: Spitiger, der is in flater bard by it opsykjen fan de eksterne account
follow: Folgje
follow_request: 'Jo hawwe in folchfersyk yntsjinne by:'
following: 'Slagge! Jo folgje no:'
post_follow:
close: Of jo kinne dit finster gewoan slute.
return: Profyl fan dizze brûker toane
web: Gean nei de webapp
title: "%{acct} folgje"
challenge:
confirm: Trochgean
hint_html: "<strong>Tip:</strong> Wy freegje jo it kommende oere net mear nei jo wachtwurd."

View File

@ -331,11 +331,6 @@ ga:
status:
account_status: Stádas cuntais
too_fast: Cuireadh an fhoirm isteach róthapa, triail arís.
authorize_follow:
follow: Lean
post_follow:
return: Taispeáin próifíl an úsáideora
title: Lean %{acct}
challenge:
confirm: Lean ar aghaidh
datetime:

View File

@ -1095,18 +1095,6 @@ gd:
view_strikes: Seall na rabhaidhean a fhuair an cunntas agad roimhe
too_fast: Chaidh am foirm a chur a-null ro luath, feuch ris a-rithist.
use_security_key: Cleachd iuchair tèarainteachd
authorize_follow:
already_following: Tha thu a leantainn a chunntais seo mu thràth
already_requested: Chuir thu iarrtas leantainn dhan chunntas seo mu thràth
error: Gu mì-fhortanach, thachair mearachd le lorg a chunntais chèin
follow: Lean
follow_request: 'Chuir thu iarrtas leantainn gu:'
following: 'Taghta! Chaidh leat a leantainn:'
post_follow:
close: Air neo dùin an uinneag seo.
return: Seall pròifil a chleachdaiche
web: Tadhail air an duilleag-lìn
title: Lean %{acct}
challenge:
confirm: Lean air adhart
hint_html: "<strong>Gliocas:</strong> Chan iarr sinn am facal-faire agad ort a-rithist fad uair a thìde."

View File

@ -1060,18 +1060,6 @@ gl:
view_strikes: Ver avisos anteriores respecto da túa conta
too_fast: Formulario enviado demasiado rápido, inténtao outra vez.
use_security_key: Usa chave de seguridade
authorize_follow:
already_following: Xa está a seguir esta conta
already_requested: Xa tes enviada unha solicitude de seguimento a esa conta
error: Desgraciadamente, algo fallou ao buscar a conta remota
follow: Seguir
follow_request: 'Enviaches unha petición de seguimento a:'
following: 'Parabéns! Agora segues a:'
post_follow:
close: Ou, podes pechar esta ventá.
return: Mostrar o perfil da usuaria
web: Ir á web
title: Seguir %{acct}
challenge:
confirm: Continuar
hint_html: "<strong>Nota:</strong> Non che pediremos o contrasinal na seguinte hora."

View File

@ -1096,18 +1096,6 @@ he:
view_strikes: צפיה בעברות קודמות שנרשמו נגד חשבונך
too_fast: הטופס הוגש מהר מדי, נסה/י שוב.
use_security_key: שימוש במפתח אבטחה
authorize_follow:
already_following: את/ה כבר עוקב/ת אחרי חשבון זה
already_requested: כבר נשלחה בקשת מעקב לחשבון זה
error: למרבה הצער, היתה שגיאה בחיפוש החשבון המרוחק
follow: לעקוב
follow_request: 'שלחת בקשת מעקב ל:'
following: 'הצלחה! הינך עוקב עכשיו אחרי:'
post_follow:
close: או, פשוט לסגור חלון זה.
return: הצג את פרופיל המשתמש
web: מעבר לווב
title: לעקוב אחרי %{acct}
challenge:
confirm: המשך
hint_html: "<strong>טיפ:</strong> לא נבקש את סיסמתך שוב בשעה הקרובה."

View File

@ -64,10 +64,6 @@ hr:
reset_password: Ponovno postavi lozinku
security: Sigurnost
set_new_password: Postavi novu lozinku
authorize_follow:
error: Nažalost, došlo je do greške tijekom traženja udaljenog računa
follow: Prati
title: Prati %{acct}
datetime:
distance_in_words:
about_x_months: "%{count}mj"

View File

@ -1060,18 +1060,6 @@ hu:
view_strikes: Fiókod ellen felrótt korábbi vétségek megtekintése
too_fast: Túl gyorsan küldted el az űrlapot, próbáld később.
use_security_key: Biztonsági kulcs használata
authorize_follow:
already_following: Már követed ezt a felhasználót
already_requested: Már küldtél követési kérelmet ennek a fióknak
error: Hiba történt a távoli felhasználó keresésekor
follow: Követés
follow_request: 'Engedélyt kértél az alábbi felhasználó követésére:'
following: 'Siker! Mostantól követed az alábbi felhasználót:'
post_follow:
close: Akár be is zárhatod ezt az ablakot.
return: A felhasználó profiljának mutatása
web: Megtekintés a weben
title: "%{acct} követése"
challenge:
confirm: Folytatás
hint_html: "<strong>Hasznos:</strong> Nem fogjuk megint a jelszavadat kérdezni a következő órában."

View File

@ -481,17 +481,6 @@ hy:
account_status: Հաշուի կարգավիճակ
pending: Դիմումը պէտք է քննուի մեր անձնակազմի կողմից, ինչը կարող է մի փոքր ժամանակ խլել։ Դիմումի հաստատուելու դէպքում, կտեղեկացնենք նամակով։
use_security_key: Օգտագործել անվտանգութեան բանալի
authorize_follow:
already_following: Դու արդէն հետեւում ես այս հաշուին
already_requested: Դու արդէն ուղարկել ես հետեւմանն յայտ այս հաշուին
follow: Հետևել
follow_request: Դու ուղարկել ես հետեւելու հայց՝
following: Յաջողութի՜ւն։ Դու այժմ հետեւում ես․
post_follow:
close: Կամ, կարող ես պարզապէս փակել այս պատուհանը։
return: Ցուցադրել օգտատիրոջ էջը
web: Անցնել վէբին
title: Հետեւել %{acct}
challenge:
confirm: Շարունակել
invalid_password: Անվաւեր ծածկագիր

View File

@ -959,18 +959,6 @@ id:
view_strikes: Lihat hukuman lalu yang pernah terjadi kepada akun Anda
too_fast: Formulir dikirim terlalu cepat, coba lagi.
use_security_key: Gunakan kunci keamanan
authorize_follow:
already_following: Anda sudah mengikuti akun ini
already_requested: Anda sudah mengirimkan permintaan untuk mengikuti akun tersebut
error: Sayangnya, ada error saat melihat akun remote
follow: Ikuti
follow_request: 'Anda telah mengirim permintaan untuk mengikuti ke:'
following: 'Berhasil! Anda sekarang mengikuti:'
post_follow:
close: Atau Anda dapat menutup jendela ini.
return: Tampilkan profil pengguna
web: Ke web
title: Mengikuti %{acct}
challenge:
confirm: Lanjut
hint_html: "<strong>Tip:</strong> Kami tidak akan meminta kata sandi Anda lagi untuk beberapa jam ke depan."

View File

@ -935,18 +935,6 @@ io:
view_strikes: Videz antea streki kontre vua konto
too_fast: Formulario sendesis tro rapide, probez itere.
use_security_key: Uzes sekuresklefo
authorize_follow:
already_following: Vu ja sequis ca konto
already_requested: Vu ja sendis sequodemando a ta konto
error: Regretinde, eventis eraro probante konsultar la fora konto
follow: Sequar
follow_request: 'Vu sendis sequodemando a:'
following: 'Suceso! Vu nun sequas:'
post_follow:
close: O, vu volas jus klozar ca panelo.
return: Montrez priflo de uzanti
web: Irez a interreto
title: Sequar %{acct}
challenge:
confirm: Durez
hint_html: "<strong>Guidilo:</strong> Ni ne demandos vua pasvorto itere til 1 horo."

View File

@ -1064,18 +1064,6 @@ is:
view_strikes: Skoða fyrri bönn notandaaðgangsins þíns
too_fast: Innfyllingarform sent inn of hratt, prófaðu aftur.
use_security_key: Nota öryggislykil
authorize_follow:
already_following: Þú ert að þegar fylgjast með þessum aðgangi
already_requested: Þú ert þegar búin/n að senda fylgjendabeiðni á þennan notanda
error: Því miður, það kom upp villa við að fletta upp fjartengda notandaaðgangnum
follow: Fylgjast með
follow_request: 'Þú sendir beiðni um að fylgjast með til:'
following: 'Tókst! Þú ert núna að fylgjast með:'
post_follow:
close: Eða að þú getur lokað þessum glugga.
return: Birta notandasnið notandans
web: Fara á vefinn
title: Fylgjast með %{acct}
challenge:
confirm: Halda áfram
hint_html: "<strong>Ábending:</strong> Við munum ekki spyrja þig um lykilorðið aftur næstu klukkustundina."

View File

@ -1062,18 +1062,6 @@ it:
view_strikes: Visualizza le sanzioni precedenti prese nei confronti del tuo account
too_fast: Modulo inviato troppo velocemente, riprova.
use_security_key: Usa la chiave di sicurezza
authorize_follow:
already_following: Stai già seguendo questo account
already_requested: Hai già mandato una richiesta di seguire questo account
error: Sfortunatamente c'è stato un errore nel consultare l'account remoto
follow: Segui
follow_request: 'Hai mandato una richiesta di seguire:'
following: 'Accettato! Ora stai seguendo:'
post_follow:
close: Oppure puoi chiudere questa finestra.
return: Mostra il profilo dell'utente
web: Vai al web
title: Segui %{acct}
challenge:
confirm: Continua
hint_html: "<strong>Suggerimento:</strong> Non ti chiederemo di nuovo la tua password per la prossima ora."

View File

@ -1042,18 +1042,6 @@ ja:
view_strikes: 過去のストライクを表示
too_fast: フォームの送信が速すぎます。もう一度やり直してください。
use_security_key: セキュリティキーを使用
authorize_follow:
already_following: あなたは既にこのアカウントをフォローしています
already_requested: 既にこのアカウントへフォローリクエストを送信しています
error: 残念ながら、リモートアカウント情報の取得中にエラーが発生しました
follow: フォロー
follow_request: 'あなたは以下のアカウントにフォローリクエストを送信しました:'
following: '成功! あなたは現在以下のアカウントをフォローしています:'
post_follow:
close: またはこのウィンドウを閉じます。
return: ユーザーのプロフィールを見る
web: Webを開く
title: "%{acct}さんをフォロー"
challenge:
confirm: 続ける
hint_html: 以後1時間はパスワードの再入力を求めません

View File

@ -232,17 +232,6 @@ ka:
reset_password: პაროლის გადატვირთვა
security: უსაფრთხოება
set_new_password: ახალი პაროლის დაყენება
authorize_follow:
already_following: უკვე მიჰყვებით ამ ანგარიშს
error: სამწუხაროთ, დისტანციური სერვერის წაკითხვამ გამოიწვია შეცდომა
follow: გაყევი
follow_request: 'დადევნების მოთხონვა გაეგზავნა:'
following: 'წარმატება! ახლა მიჰყვებით:'
post_follow:
close: ან შეგიძლიათ დახუროთ ეს ფანჯარა.
return: მომხმარებლის პროფილის ჩვენება
web: ვებზე გადასვლა
title: გაყევი %{acct}-ს
datetime:
distance_in_words:
about_x_hours: "%{count}სთ"

View File

@ -461,14 +461,6 @@ kab:
status:
account_status: Addad n umiḍan
use_security_key: Seqdec tasarut n teɣlist
authorize_follow:
already_following: Teṭafareḍ ya kan amiḍan-a
follow: Ḍfeṛ
following: 'Igerrez! Aqlik teṭafareḍ tura:'
post_follow:
return: Ssken-d amaɣnu n useqdac
web: Ddu γer Web
title: Ḍfeṛ %{acct}
challenge:
confirm: Kemmel
invalid_password: Yir awal uffir

View File

@ -360,17 +360,6 @@ kk:
confirming: Электрондық поштаны растау аяқталуын күтуде.
pending: Сіздің өтінішіңіз біздің қызметкерлеріміздің қарауында. Бұл біраз уақыт алуы мүмкін. Өтінішіңіз мақұлданса, сізге электрондық пошта хабарламасы келеді.
redirecting_to: Сіздің есептік жазбаңыз белсенді емес, себебі ол %{acct} жүйесіне қайта бағытталуда.
authorize_follow:
already_following: Бұл аккаунтқа жазылғансыз
error: Өкінішке орай, қашықтағы тіркелгіні іздеуде қате пайда болды
follow: Жазылу
follow_request: 'Сіз жазылуға өтініш жібердіңіз:'
following: 'Керемет! Сіз енді жазылдыңыз:'
post_follow:
close: Немесе терезені жаба салыңыз.
return: Қолданушы профилін көрсет
web: Вебте ашу
title: Жазылу %{acct}
challenge:
confirm: Жалғастыру
hint_html: "<strong> Кеңес: </strong> біз келесі сағат ішінде сізден құпия сөзді қайта сұрамаймыз."

View File

@ -1044,18 +1044,6 @@ ko:
view_strikes: 내 계정에 대한 과거 중재 기록 보기
too_fast: 너무 빠르게 양식이 제출되었습니다, 다시 시도하세요.
use_security_key: 보안 키 사용
authorize_follow:
already_following: 이미 이 계정을 팔로우 하고 있습니다
already_requested: 이미 이 계정에게 팔로우 요청을 보냈습니다
error: 리모트 계정을 확인하는 도중 오류가 발생했습니다
follow: 팔로우
follow_request: '팔로우 요청을 보냄:'
following: '성공! 당신은 다음 계정을 팔로우 하고 있습니다:'
post_follow:
close: 혹은, 그저 이 창을 닫을 수도 있습니다.
return: 사용자 프로필 보기
web: 웹으로 가기
title: "%{acct} 를 팔로우"
challenge:
confirm: 계속
hint_html: "<strong>팁:</strong> 한 시간 동안 다시 암호를 묻지 않을 것입니다."

View File

@ -979,18 +979,6 @@ ku:
view_strikes: Binpêkirinên berê yên dijî ajimêrê xwe bibîne
too_fast: Form pir zû hat şandin, dîsa biceribîne.
use_security_key: Kilîteke ewlehiyê bi kar bîne
authorize_follow:
already_following: Jixwe tu vê ajimêrê dişopînî
already_requested: Jixwe te ji vê ajimêrê re daxwazîya şopandinê şandi bû
error: Mixabin, dema ajimêr hat gerandin çewtiyek çêbû
follow: Bişopîne
follow_request: 'Te ji vê kesê re daxwazîya şopandinê şand:'
following: 'Serkeftin! Tu êdî dikarî bişopînî:'
post_follow:
close: An jî, tu dikarî tenê ev çarçoveyê bigirî.
return: Profîla vê bikarhênerê nîşan bike
web: Biçe tevneyê
title: "%{acct} bişopîne"
challenge:
confirm: Bidomîne
hint_html: "<strong>Nîşe:</strong>Ji bo demjimêreke din em ê borînpeyva te careke din ji te nexwazin."

View File

@ -267,17 +267,6 @@ lt:
reset_password: Atstatyti slaptažodį
security: Apsauga
set_new_password: Nustatyti naują slaptažodį
authorize_follow:
already_following: Jūs jau sekate šią paskyrą
error: Dėja, aptikta klaida ieškant tolimosios paskyros
follow: Sekti
follow_request: 'Jūs išsiuntėte sekimo prašymą:'
following: 'Puiku! Jūs pradėjote sekti:'
post_follow:
close: Arba, Jūs galite uždaryti šį langą.
return: Rodyti vartotojo paskyrą
web: Eiti į
title: Sekti %{acct}
datetime:
distance_in_words:
about_x_hours: "%{count} val"

View File

@ -1057,18 +1057,6 @@ lv:
view_strikes: Skati iepriekšējos brīdinājumus par savu kontu
too_fast: Veidlapa ir iesniegta pārāk ātri, mēģini vēlreiz.
use_security_key: Lietot drošības atslēgu
authorize_follow:
already_following: Tu jau seko šim kontam
already_requested: Tu jau esi nosūtījis sekošanas pieteikumu šim kontam
error: Diemžēl, meklējot attālināto kontu, radās kļūda
follow: Sekot
follow_request: 'Tu esi nosūtījis sekošanas pieteikumu:'
following: 'Veiksmīgi! Tu tagad seko:'
post_follow:
close: Vai vienkārši aizver šo logu.
return: Parādīt lietotāja profilu
web: Doties uz tīmekli
title: Sekot %{acct}
challenge:
confirm: Turpināt
hint_html: "<strong>Padoms:</strong> Nākamās stundas laikā mēs tev vairs neprasīsim paroli."

View File

@ -76,16 +76,6 @@ ml:
invites:
filter:
all: എല്ലാം
authorize_follow:
following: 'വിജയകരം! നിങ്ങൾ ഇപ്പോൾ പിന്തുടരുന്നു:'
errors:
'400': The request you submitted was invalid or malformed.
'403': You don't have permission to view this page.
'404': The page you are looking for isn't here.
'406': This page is not available in the requested format.
'410': The page you were looking for doesn't exist here anymore.
'429': Too many requests
'503': The page could not be served due to a temporary server failure.
filters:
contexts:
notifications: അറിയിപ്പുകൾ

View File

@ -767,14 +767,6 @@ ms:
account_status: Status akaun
view_strikes: Lihat pelanggaran yang lepas terhadap akaun anda
use_security_key: Gunakan kunci keselamatan
authorize_follow:
follow: Ikut
follow_request: 'Anda telah menghantar permintaan mengikut kepada:'
post_follow:
close: Atau anda boleh tutup tetingkap ini.
return: Tunjukkan profil pengguna
web: Pergi ke web
title: Ikuti %{acct}
challenge:
confirm: Teruskan
invalid_password: Kata laluan tidak sah

View File

@ -1042,18 +1042,6 @@ my:
view_strikes: သင့်အကောင့်ကို ဆန့်ကျင်သည့် ယခင်ကလုပ်ဆောင်ချက်များကို ကြည့်ပါ
too_fast: ဖောင်တင်သည်မှာ မြန်နေပါသည်။ ထပ်စမ်းကြည့်ပါ။
use_security_key: လုံခြုံရေးကီးကို သုံးပါ
authorize_follow:
already_following: သင်သည် ဤအကောင့်ကို စောင့်ကြည့်နေပြီဖြစ်ပါသည်
already_requested: သင်သည် ထိုအကောင့်စောင့်ကြည့်ရန် တောင်းဆိုမှုတစ်ခု ပေးပို့ခဲ့ပြီးပါပြီ
error: ကံမကောင်းစွာဖြင့် အဝေးမှထိန်းချုပ်သောအကောင့်ရှာဖွေရာတွင် အမှားအယွင်းတစ်ခုရှိခဲ့သည်
follow: စောင့်ကြည့်မယ်
follow_request: သင်သည် စောင့်ကြည့်မည် တောင်းဆိုချက်တစ်ခု ပေးပို့ထားသည်-
following: သင် ယခု အောက်ပါအတိုင်း လုပ်ဆောင်နေပါသည် -
post_follow:
close: သို့မဟုတ် သင်သည် ဤဝင်းဒိုးကို ပိတ်နိုင်သည်
return: အသုံးပြုသူ၏ ပရိုဖိုင်ကိုပြရန်
web: ဝဘ်သို့ သွားပါ
title: "%{acct} ကို စောင့်ကြည့်မယ်"
challenge:
confirm: ဆက်လုပ်မည်
hint_html: "<strong>အကြံပြုချက် -</strong> နောက်နာရီများတွင် သင့်စကားဝှက်ကို ထပ်မံတောင်းဆိုမည်မဟုတ်ပါ။"

View File

@ -1060,18 +1060,6 @@ nl:
view_strikes: Bekijk de eerder door moderatoren vastgestelde overtredingen die je hebt gemaakt
too_fast: Formulier is te snel ingediend. Probeer het nogmaals.
use_security_key: Beveiligingssleutel gebruiken
authorize_follow:
already_following: Je volgt dit account al
already_requested: Je hebt al een volgverzoek naar dat account verstuurd
error: Helaas, er is een fout opgetreden bij het opzoeken van de externe account
follow: Volgen
follow_request: 'Jij hebt een volgverzoek ingediend bij:'
following: 'Succes! Jij volgt nu:'
post_follow:
close: Of je kunt dit venster gewoon sluiten.
return: Profiel van deze gebruiker tonen
web: Ga naar de webapp
title: Volg %{acct}
challenge:
confirm: Doorgaan
hint_html: "<strong>Tip:</strong> We vragen jou het komende uur niet meer naar jouw wachtwoord."

View File

@ -1049,18 +1049,6 @@ nn:
view_strikes: Vis tidligere advarsler mot kontoen din
too_fast: Skjemaet ble sendt inn for raskt, prøv på nytt.
use_security_key: Bruk sikkerhetsnøkkel
authorize_follow:
already_following: Du fylgjer allereie denne kontoen
already_requested: Du har allereie sendt ein fylgjespurnad til den kontoen
error: Uheldigvis skjedde det en feil da vi prøvde å få tak i en bruker fra en annen instans
follow: Fylg
follow_request: 'Du har sendt ein fylgjeførespurnad til:'
following: 'Suksess! No fylgjer du:'
post_follow:
close: Eller så kan du berre lukka att dette vindauget.
return: Vis brukarprofilen
web: Gå til nettet
title: Fylg %{acct}
challenge:
confirm: Hald fram
hint_html: "<strong>Tips:</strong> Vi skal ikkje spørja deg om passordet ditt igjen i laupet av den neste timen."

View File

@ -988,18 +988,6 @@
view_strikes: Vis tidligere advarsler mot kontoen din
too_fast: Skjemaet ble sendt inn for raskt, prøv på nytt.
use_security_key: Bruk sikkerhetsnøkkel
authorize_follow:
already_following: Du følger allerede denne kontoen
already_requested: Du har allerede sendt en følgeforespørsel til denne kontoen
error: Dessverre oppstod det en feil da vi prøvde å få tak i brukeren fra tjeneren
follow: Følg
follow_request: 'Du har sendt en følgeforespørsel til:'
following: 'Suksess! Nå følger du:'
post_follow:
close: Eller så kan du lukke dette vinduet.
return: Gå tilbake til brukerens profil
web: Gå til nettsiden
title: Følg %{acct}
challenge:
confirm: Fortsett
hint_html: "<strong>Tips:</strong> Vi ber deg ikke om passordet ditt igjen i løpet av neste time."

View File

@ -502,17 +502,6 @@ oc:
account_status: Estat del compte
functional: Vòstre compte es complètament foncional.
use_security_key: Utilizar clau de seguretat
authorize_follow:
already_following: Seguètz ja aqueste compte
error: O planhèm, i a agut una error al moment de cercar lo compte
follow: Sègre
follow_request: 'Avètz demandat de sègre:'
following: 'Felicitacion! Seguètz ara:'
post_follow:
close: O podètz tampar aquesta fenèstra.
return: Veire lo perfil a la persona
web: Tornar a linterfàcia Web
title: Sègre %{acct}
challenge:
confirm: Contunhar
hint_html: "<strong>Asutúcia :</strong> vos demandarem pas vòstre senhal de nòu daquí unas oras."

View File

@ -1096,18 +1096,6 @@ pl:
view_strikes: Zobacz dawne ostrzeżenia nałożone na twoje konto
too_fast: Zbyt szybko przesłano formularz, spróbuj ponownie.
use_security_key: Użyj klucza bezpieczeństwa
authorize_follow:
already_following: Już obserwujesz to konto
already_requested: Już wysłałeś(-aś) prośbę o możliwość obserwowania tego konta
error: Niestety, podczas sprawdzania zdalnego konta wystąpił błąd
follow: Obserwuj
follow_request: 'Wysłano prośbę o możliwość obserwowania:'
following: 'Pomyślnie! Od teraz obserwujesz:'
post_follow:
close: Ewentualnie, możesz po prostu zamknąć tę stronę.
return: Pokaż stronę użytkownika
web: Przejdź do sieci
title: Obserwuj %{acct}
challenge:
confirm: Kontynuuj
hint_html: "<strong>Informacja:</strong> Nie będziemy prosić Cię o ponowne podanie hasła przez następną godzinę."

Some files were not shown because too many files have changed in this diff Show More