forked from treehouse/mastodon
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - app/controllers/auth/sessions_controller.rb Minor conflict due to glitch-soc's theming codesignup-info-prompt
commit
5cadb47238
4
Gemfile
4
Gemfile
|
@ -116,9 +116,9 @@ group :production, :test do
|
|||
end
|
||||
|
||||
group :test do
|
||||
gem 'capybara', '~> 3.28'
|
||||
gem 'capybara', '~> 3.29'
|
||||
gem 'climate_control', '~> 0.2'
|
||||
gem 'faker', '~> 2.2'
|
||||
gem 'faker', '~> 2.3'
|
||||
gem 'microformats', '~> 4.1'
|
||||
gem 'rails-controller-testing', '~> 1.0'
|
||||
gem 'rspec-sidekiq', '~> 3.0'
|
||||
|
|
20
Gemfile.lock
20
Gemfile.lock
|
@ -150,7 +150,7 @@ GEM
|
|||
sshkit (~> 1.3)
|
||||
capistrano-yarn (2.0.2)
|
||||
capistrano (~> 3.0)
|
||||
capybara (3.28.0)
|
||||
capybara (3.29.0)
|
||||
addressable
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (~> 1.8)
|
||||
|
@ -231,7 +231,7 @@ GEM
|
|||
tzinfo
|
||||
excon (0.62.0)
|
||||
fabrication (2.20.2)
|
||||
faker (2.2.2)
|
||||
faker (2.3.0)
|
||||
i18n (~> 1.6.0)
|
||||
faraday (0.15.0)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
|
@ -323,7 +323,7 @@ GEM
|
|||
multi_json (~> 1.12)
|
||||
rdf (~> 3.0)
|
||||
jsonapi-renderer (0.2.2)
|
||||
jwt (2.2.1)
|
||||
jwt (2.1.0)
|
||||
kaminari (1.1.1)
|
||||
activesupport (>= 4.1.0)
|
||||
kaminari-actionview (= 1.1.1)
|
||||
|
@ -381,7 +381,7 @@ GEM
|
|||
net-scp (2.0.0)
|
||||
net-ssh (>= 2.6.5, < 6.0.0)
|
||||
net-ssh (5.2.0)
|
||||
nio4r (2.4.0)
|
||||
nio4r (2.5.1)
|
||||
nokogiri (1.10.4)
|
||||
mini_portile2 (~> 2.4.0)
|
||||
nokogumbo (2.0.1)
|
||||
|
@ -447,7 +447,7 @@ GEM
|
|||
pry-rails (0.3.9)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (4.0.1)
|
||||
puma (4.1.0)
|
||||
puma (4.1.1)
|
||||
nio4r (~> 2.0)
|
||||
pundit (2.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
|
@ -640,7 +640,7 @@ GEM
|
|||
unf (~> 0.1.0)
|
||||
tzinfo (1.2.5)
|
||||
thread_safe (~> 0.1)
|
||||
tzinfo-data (1.2019.2)
|
||||
tzinfo-data (1.2019.3)
|
||||
tzinfo (>= 1.0.0)
|
||||
unf (0.1.4)
|
||||
unf_ext
|
||||
|
@ -649,7 +649,7 @@ GEM
|
|||
uniform_notifier (1.12.1)
|
||||
warden (1.2.8)
|
||||
rack (>= 2.0.6)
|
||||
webmock (3.7.1)
|
||||
webmock (3.7.3)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
@ -657,7 +657,7 @@ GEM
|
|||
activesupport (>= 4.2)
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 4.2)
|
||||
webpush (1.0.0)
|
||||
webpush (0.3.8)
|
||||
hkdf (~> 0.2)
|
||||
jwt (~> 2.0)
|
||||
websocket-driver (0.7.0)
|
||||
|
@ -688,7 +688,7 @@ DEPENDENCIES
|
|||
capistrano-rails (~> 1.4)
|
||||
capistrano-rbenv (~> 2.1)
|
||||
capistrano-yarn (~> 2.0)
|
||||
capybara (~> 3.28)
|
||||
capybara (~> 3.29)
|
||||
charlock_holmes (~> 0.7.6)
|
||||
chewy (~> 5.0)
|
||||
cld3 (~> 3.2.4)
|
||||
|
@ -703,7 +703,7 @@ DEPENDENCIES
|
|||
doorkeeper (~> 5.1)
|
||||
dotenv-rails (~> 2.7)
|
||||
fabrication (~> 2.20)
|
||||
faker (~> 2.2)
|
||||
faker (~> 2.3)
|
||||
fast_blank (~> 1.0)
|
||||
fastimage
|
||||
fog-core (<= 2.1.0)
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
module Admin
|
||||
class TagsController < BaseController
|
||||
before_action :set_tags, only: :index
|
||||
before_action :set_tag, except: [:index, :batch, :approve_all, :reject_all]
|
||||
before_action :set_usage_by_domain, except: [:index, :batch, :approve_all, :reject_all]
|
||||
before_action :set_counters, except: [:index, :batch, :approve_all, :reject_all]
|
||||
|
@ -10,6 +9,7 @@ module Admin
|
|||
def index
|
||||
authorize :tag, :index?
|
||||
|
||||
@tags = filtered_tags.page(params[:page])
|
||||
@form = Form::TagBatch.new
|
||||
end
|
||||
|
||||
|
@ -48,10 +48,6 @@ module Admin
|
|||
|
||||
private
|
||||
|
||||
def set_tags
|
||||
@tags = filtered_tags.page(params[:page])
|
||||
end
|
||||
|
||||
def set_tag
|
||||
@tag = Tag.find(params[:id])
|
||||
end
|
||||
|
@ -73,16 +69,11 @@ module Admin
|
|||
end
|
||||
|
||||
def filtered_tags
|
||||
scope = Tag
|
||||
scope = scope.discoverable if filter_params[:context] == 'directory'
|
||||
scope = scope.unreviewed if filter_params[:review] == 'unreviewed'
|
||||
scope = scope.reviewed.order(reviewed_at: :desc) if filter_params[:review] == 'reviewed'
|
||||
scope = scope.pending_review.order(requested_review_at: :desc) if filter_params[:review] == 'pending_review'
|
||||
scope.order(max_score: :desc)
|
||||
TagFilter.new(filter_params).results
|
||||
end
|
||||
|
||||
def filter_params
|
||||
params.slice(:context, :review, :page).permit(:context, :review, :page)
|
||||
params.slice(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name).permit(:directory, :reviewed, :unreviewed, :pending_review, :page, :popular, :active, :name)
|
||||
end
|
||||
|
||||
def tag_params
|
||||
|
|
|
@ -8,7 +8,6 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
skip_before_action :require_no_authentication, only: [:create]
|
||||
skip_before_action :require_functional!
|
||||
|
||||
prepend_before_action :authenticate_with_two_factor, if: :two_factor_enabled?, only: [:create]
|
||||
prepend_before_action :set_pack
|
||||
|
||||
before_action :set_instance_presenter, only: [:new]
|
||||
|
@ -23,9 +22,22 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
end
|
||||
|
||||
def create
|
||||
super do |resource|
|
||||
remember_me(resource)
|
||||
flash.delete(:notice)
|
||||
self.resource = begin
|
||||
if user_params[:email].blank? && session[:otp_user_id].present?
|
||||
User.find(session[:otp_user_id])
|
||||
else
|
||||
warden.authenticate!(auth_options)
|
||||
end
|
||||
end
|
||||
|
||||
if resource.otp_required_for_login?
|
||||
if user_params[:otp_attempt].present? && session[:otp_user_id].present?
|
||||
authenticate_with_two_factor_via_otp(resource)
|
||||
else
|
||||
prompt_for_two_factor(resource)
|
||||
end
|
||||
else
|
||||
authenticate_and_respond(resource)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,18 +50,6 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
protected
|
||||
|
||||
def find_user
|
||||
if session[:otp_user_id]
|
||||
User.find(session[:otp_user_id])
|
||||
elsif user_params[:email]
|
||||
if use_seamless_external_login? && Devise.check_at_sign && user_params[:email].index('@').nil?
|
||||
User.joins(:account).find_by(accounts: { username: user_params[:email] })
|
||||
else
|
||||
User.find_for_authentication(email: user_params[:email])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:email, :password, :otp_attempt)
|
||||
end
|
||||
|
@ -72,32 +72,17 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
super
|
||||
end
|
||||
|
||||
def two_factor_enabled?
|
||||
find_user.try(:otp_required_for_login?)
|
||||
end
|
||||
|
||||
def valid_otp_attempt?(user)
|
||||
user.validate_and_consume_otp!(user_params[:otp_attempt]) ||
|
||||
user.invalidate_otp_backup_code!(user_params[:otp_attempt])
|
||||
rescue OpenSSL::Cipher::CipherError => _error
|
||||
rescue OpenSSL::Cipher::CipherError
|
||||
false
|
||||
end
|
||||
|
||||
def authenticate_with_two_factor
|
||||
user = self.resource = find_user
|
||||
|
||||
if user_params[:otp_attempt].present? && session[:otp_user_id]
|
||||
authenticate_with_two_factor_via_otp(user)
|
||||
elsif user&.valid_password?(user_params[:password])
|
||||
prompt_for_two_factor(user)
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_with_two_factor_via_otp(user)
|
||||
if valid_otp_attempt?(user)
|
||||
session.delete(:otp_user_id)
|
||||
remember_me(user)
|
||||
sign_in(user)
|
||||
authenticate_and_respond(user)
|
||||
else
|
||||
flash.now[:alert] = I18n.t('users.invalid_otp_token')
|
||||
prompt_for_two_factor(user)
|
||||
|
@ -109,6 +94,13 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
render :two_factor
|
||||
end
|
||||
|
||||
def authenticate_and_respond(user)
|
||||
sign_in(user)
|
||||
remember_me(user)
|
||||
|
||||
respond_with user, location: after_sign_in_path_for(user)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_pack
|
||||
|
@ -125,9 +117,11 @@ class Auth::SessionsController < Devise::SessionsController
|
|||
|
||||
def home_paths(resource)
|
||||
paths = [about_path]
|
||||
|
||||
if single_user_mode? && resource.is_a?(User)
|
||||
paths << short_account_path(username: resource.account)
|
||||
end
|
||||
|
||||
paths
|
||||
end
|
||||
|
||||
|
|
|
@ -14,12 +14,11 @@ class Settings::DeletesController < Settings::BaseController
|
|||
end
|
||||
|
||||
def destroy
|
||||
if current_user.valid_password?(delete_params[:password])
|
||||
Admin::SuspensionWorker.perform_async(current_user.account_id, true)
|
||||
sign_out
|
||||
if challenge_passed?
|
||||
destroy_account!
|
||||
redirect_to new_user_session_path, notice: I18n.t('deletes.success_msg')
|
||||
else
|
||||
redirect_to settings_delete_path, alert: I18n.t('deletes.bad_password_msg')
|
||||
redirect_to settings_delete_path, alert: I18n.t('deletes.challenge_not_passed')
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -29,11 +28,25 @@ class Settings::DeletesController < Settings::BaseController
|
|||
redirect_to root_path unless Setting.open_deletion
|
||||
end
|
||||
|
||||
def delete_params
|
||||
params.require(:form_delete_confirmation).permit(:password)
|
||||
def resource_params
|
||||
params.require(:form_delete_confirmation).permit(:password, :username)
|
||||
end
|
||||
|
||||
def require_not_suspended!
|
||||
forbidden if current_account.suspended?
|
||||
end
|
||||
|
||||
def challenge_passed?
|
||||
if current_user.encrypted_password.blank?
|
||||
current_account.username == resource_params[:username]
|
||||
else
|
||||
current_user.valid_password?(resource_params[:password])
|
||||
end
|
||||
end
|
||||
|
||||
def destroy_account!
|
||||
current_account.suspend!
|
||||
Admin::SuspensionWorker.perform_async(current_user.account_id, true)
|
||||
sign_out
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,7 +15,7 @@ module Settings
|
|||
end
|
||||
|
||||
def create
|
||||
if current_user.validate_and_consume_otp!(confirmation_params[:code])
|
||||
if current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt])
|
||||
flash.now[:notice] = I18n.t('two_factor_authentication.enabled_success')
|
||||
|
||||
current_user.otp_required_for_login = true
|
||||
|
@ -33,7 +33,7 @@ module Settings
|
|||
private
|
||||
|
||||
def confirmation_params
|
||||
params.require(:form_two_factor_confirmation).permit(:code)
|
||||
params.require(:form_two_factor_confirmation).permit(:otp_attempt)
|
||||
end
|
||||
|
||||
def prepare_two_factor_form
|
||||
|
|
|
@ -34,7 +34,7 @@ module Settings
|
|||
private
|
||||
|
||||
def confirmation_params
|
||||
params.require(:form_two_factor_confirmation).permit(:code)
|
||||
params.require(:form_two_factor_confirmation).permit(:otp_attempt)
|
||||
end
|
||||
|
||||
def verify_otp_required
|
||||
|
@ -42,8 +42,8 @@ module Settings
|
|||
end
|
||||
|
||||
def acceptable_code?
|
||||
current_user.validate_and_consume_otp!(confirmation_params[:code]) ||
|
||||
current_user.invalidate_otp_backup_code!(confirmation_params[:code])
|
||||
current_user.validate_and_consume_otp!(confirmation_params[:otp_attempt]) ||
|
||||
current_user.invalidate_otp_backup_code!(confirmation_params[:otp_attempt])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,18 +5,22 @@ module WellKnown
|
|||
include RoutingHelper
|
||||
|
||||
before_action { response.headers['Vary'] = 'Accept' }
|
||||
before_action :set_account
|
||||
before_action :check_account_suspension
|
||||
|
||||
rescue_from ActiveRecord::RecordNotFound, ActionController::ParameterMissing, with: :not_found
|
||||
|
||||
def show
|
||||
@account = Account.find_local!(username_from_resource)
|
||||
|
||||
expires_in 3.days, public: true
|
||||
render json: @account, serializer: WebfingerSerializer, content_type: 'application/jrd+json'
|
||||
rescue ActiveRecord::RecordNotFound, ActionController::ParameterMissing
|
||||
head 404
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_account
|
||||
@account = Account.find_local!(username_from_resource)
|
||||
end
|
||||
|
||||
def username_from_resource
|
||||
resource_user = resource_param
|
||||
username, domain = resource_user.split('@')
|
||||
|
@ -28,5 +32,17 @@ module WellKnown
|
|||
def resource_param
|
||||
params.require(:resource)
|
||||
end
|
||||
|
||||
def check_account_suspension
|
||||
expires_in(3.minutes, public: true) && gone if @account.suspended?
|
||||
end
|
||||
|
||||
def not_found
|
||||
head 404
|
||||
end
|
||||
|
||||
def gone
|
||||
head 410
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ module Admin::FilterHelper
|
|||
REPORT_FILTERS = %i(resolved account_id target_account_id).freeze
|
||||
INVITE_FILTER = %i(available expired).freeze
|
||||
CUSTOM_EMOJI_FILTERS = %i(local remote by_domain shortcode).freeze
|
||||
TAGS_FILTERS = %i(context review).freeze
|
||||
TAGS_FILTERS = %i(directory reviewed unreviewed pending_review popular active name).freeze
|
||||
INSTANCES_FILTERS = %i(limited by_domain).freeze
|
||||
FOLLOWERS_FILTERS = %i(relationship status by_domain activity order).freeze
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ module SettingsHelper
|
|||
no: 'Norsk',
|
||||
oc: 'Occitan',
|
||||
pl: 'Polski',
|
||||
pt: 'Português (Portugal)',
|
||||
pt: 'Português',
|
||||
'pt-PT': 'Português (Portugal)',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
ro: 'Română',
|
||||
ru: 'Русский',
|
||||
|
|
|
@ -151,7 +151,7 @@ export function expandNotifications({ maxId } = {}, done = noOp) {
|
|||
dispatch(importFetchedAccounts(response.data.map(item => item.account)));
|
||||
dispatch(importFetchedStatuses(response.data.map(item => item.status).filter(status => !!status)));
|
||||
|
||||
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent && preferPendingItems));
|
||||
dispatch(expandNotificationsSuccess(response.data, next ? next.uri : null, isLoadingMore, isLoadingRecent, isLoadingRecent && preferPendingItems));
|
||||
fetchRelatedRelationships(dispatch, response.data);
|
||||
done();
|
||||
}).catch(error => {
|
||||
|
@ -168,11 +168,12 @@ export function expandNotificationsRequest(isLoadingMore) {
|
|||
};
|
||||
};
|
||||
|
||||
export function expandNotificationsSuccess(notifications, next, isLoadingMore, usePendingItems) {
|
||||
export function expandNotificationsSuccess(notifications, next, isLoadingMore, isLoadingRecent, usePendingItems) {
|
||||
return {
|
||||
type: NOTIFICATIONS_EXPAND_SUCCESS,
|
||||
notifications,
|
||||
next,
|
||||
isLoadingRecent: isLoadingRecent,
|
||||
usePendingItems,
|
||||
skipLoading: !isLoadingMore,
|
||||
};
|
||||
|
|
|
@ -32,8 +32,38 @@ class Poll extends ImmutablePureComponent {
|
|||
|
||||
state = {
|
||||
selected: {},
|
||||
expired: null,
|
||||
};
|
||||
|
||||
static getDerivedStateFromProps (props, state) {
|
||||
const { poll, intl } = props;
|
||||
const expired = poll.get('expired') || (new Date(poll.get('expires_at'))).getTime() < intl.now();
|
||||
return (expired === state.expired) ? null : { expired };
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this._setupTimer();
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
this._setupTimer();
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
clearTimeout(this._timer);
|
||||
}
|
||||
|
||||
_setupTimer () {
|
||||
const { poll, intl } = this.props;
|
||||
clearTimeout(this._timer);
|
||||
if (!this.state.expired) {
|
||||
const delay = (new Date(poll.get('expires_at'))).getTime() - intl.now();
|
||||
this._timer = setTimeout(() => {
|
||||
this.setState({ expired: true });
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
handleOptionChange = e => {
|
||||
const { target: { value } } = e;
|
||||
|
||||
|
@ -68,12 +98,11 @@ class Poll extends ImmutablePureComponent {
|
|||
this.props.dispatch(fetchPoll(this.props.poll.get('id')));
|
||||
};
|
||||
|
||||
renderOption (option, optionIndex) {
|
||||
renderOption (option, optionIndex, showResults) {
|
||||
const { poll, disabled } = this.props;
|
||||
const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
|
||||
const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
|
||||
const active = !!this.state.selected[`${optionIndex}`];
|
||||
const showResults = poll.get('voted') || poll.get('expired');
|
||||
|
||||
let titleEmojified = option.get('title_emojified');
|
||||
if (!titleEmojified) {
|
||||
|
@ -112,19 +141,20 @@ class Poll extends ImmutablePureComponent {
|
|||
|
||||
render () {
|
||||
const { poll, intl } = this.props;
|
||||
const { expired } = this.state;
|
||||
|
||||
if (!poll) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
|
||||
const showResults = poll.get('voted') || poll.get('expired');
|
||||
const timeRemaining = expired ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
|
||||
const showResults = poll.get('voted') || expired;
|
||||
const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
|
||||
|
||||
return (
|
||||
<div className='poll'>
|
||||
<ul>
|
||||
{poll.get('options').map((option, i) => this.renderOption(option, i))}
|
||||
{poll.get('options').map((option, i) => this.renderOption(option, i, showResults))}
|
||||
</ul>
|
||||
|
||||
<div className='poll__footer'>
|
||||
|
|
|
@ -172,8 +172,9 @@ export default class ScrollableList extends PureComponent {
|
|||
const someItemInserted = React.Children.count(prevProps.children) > 0 &&
|
||||
React.Children.count(prevProps.children) < React.Children.count(this.props.children) &&
|
||||
this.getFirstChildKey(prevProps) !== this.getFirstChildKey(this.props);
|
||||
const pendingChanged = (prevProps.numPending > 0) !== (this.props.numPending > 0);
|
||||
|
||||
if (someItemInserted && (this.getScrollTop() > 0 || this.mouseMovedRecently)) {
|
||||
if (pendingChanged || someItemInserted && (this.getScrollTop() > 0 || this.mouseMovedRecently)) {
|
||||
return this.getScrollHeight() - this.getScrollTop();
|
||||
} else {
|
||||
return null;
|
||||
|
@ -261,6 +262,13 @@ export default class ScrollableList extends PureComponent {
|
|||
handleLoadPending = e => {
|
||||
e.preventDefault();
|
||||
this.props.onLoadPending();
|
||||
// Prevent the weird scroll-jumping behavior, as we explicitly don't want to
|
||||
// scroll to top, and we know the scroll height is going to change
|
||||
this.scrollToTopOnMouseIdle = false;
|
||||
this.lastScrollWasSynthetic = false;
|
||||
this.clearMouseIdleTimer();
|
||||
this.mouseIdleTimer = setTimeout(this.handleMouseIdle, MOUSE_IDLE_DELAY);
|
||||
this.mouseMovedRecently = true;
|
||||
}
|
||||
|
||||
render () {
|
||||
|
|
|
@ -18,9 +18,10 @@ const mapStateToProps = (state, { onlyMedia, columnId }) => {
|
|||
const uuid = columnId;
|
||||
const columns = state.getIn(['settings', 'columns']);
|
||||
const index = columns.findIndex(c => c.get('uuid') === uuid);
|
||||
const timelineState = state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`]);
|
||||
|
||||
return {
|
||||
hasUnread: state.getIn(['timelines', `community${onlyMedia ? ':media' : ''}`, 'unread']) > 0,
|
||||
hasUnread: !!timelineState && (timelineState.get('unread') > 0 || timelineState.get('pendingItems').size > 0),
|
||||
onlyMedia: (columnId && index >= 0) ? columns.get(index).getIn(['params', 'other', 'onlyMedia']) : state.getIn(['settings', 'community', 'other', 'onlyMedia']),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ const mapStateToProps = state => ({
|
|||
showFilterBar: state.getIn(['settings', 'notifications', 'quickFilter', 'show']),
|
||||
notifications: getNotifications(state),
|
||||
isLoading: state.getIn(['notifications', 'isLoading'], true),
|
||||
isUnread: state.getIn(['notifications', 'unread']) > 0,
|
||||
isUnread: state.getIn(['notifications', 'unread']) > 0 || state.getIn(['notifications', 'pendingItems']).size > 0,
|
||||
hasMore: state.getIn(['notifications', 'hasMore']),
|
||||
numPending: state.getIn(['notifications', 'pendingItems'], ImmutableList()).size,
|
||||
});
|
||||
|
|
|
@ -226,7 +226,7 @@ class FocalPointModal extends ImmutablePureComponent {
|
|||
<CharacterCounter max={1500} text={detecting ? '' : description} />
|
||||
</div>
|
||||
|
||||
<Button disabled={!dirty || detecting || length(description) > 420} text={intl.formatMessage(messages.apply)} onClick={this.handleSubmit} />
|
||||
<Button disabled={!dirty || detecting || length(description) > 1500} text={intl.formatMessage(messages.apply)} onClick={this.handleSubmit} />
|
||||
</div>
|
||||
|
||||
<div className='focal-point-modal__content'>
|
||||
|
|
|
@ -66,6 +66,7 @@ const mapStateToProps = state => ({
|
|||
isComposing: state.getIn(['compose', 'is_composing']),
|
||||
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
|
||||
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
|
||||
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < 4,
|
||||
dropdownMenuIsOpen: state.getIn(['dropdown_menu', 'openId']) !== null,
|
||||
});
|
||||
|
||||
|
@ -232,6 +233,7 @@ class UI extends React.PureComponent {
|
|||
isComposing: PropTypes.bool,
|
||||
hasComposingText: PropTypes.bool,
|
||||
hasMediaAttachments: PropTypes.bool,
|
||||
canUploadMore: PropTypes.bool,
|
||||
location: PropTypes.object,
|
||||
intl: PropTypes.object.isRequired,
|
||||
dropdownMenuIsOpen: PropTypes.bool,
|
||||
|
@ -278,13 +280,14 @@ class UI extends React.PureComponent {
|
|||
this.dragTargets.push(e.target);
|
||||
}
|
||||
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files')) {
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore) {
|
||||
this.setState({ draggingOver: true });
|
||||
}
|
||||
}
|
||||
|
||||
handleDragOver = (e) => {
|
||||
if (this.dataTransferIsText(e.dataTransfer)) return false;
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
|
@ -299,12 +302,13 @@ class UI extends React.PureComponent {
|
|||
|
||||
handleDrop = (e) => {
|
||||
if (this.dataTransferIsText(e.dataTransfer)) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.setState({ draggingOver: false });
|
||||
this.dragTargets = [];
|
||||
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1) {
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore) {
|
||||
this.props.dispatch(uploadCompose(e.dataTransfer.files));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "الإخطارات",
|
||||
"column.pins": "التبويقات المثبتة",
|
||||
"column.public": "الخيط العام الموحد",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "العودة",
|
||||
"column_header.hide_settings": "إخفاء الإعدادات",
|
||||
"column_header.moveLeft_settings": "نقل القائمة إلى اليسار",
|
||||
|
@ -112,8 +113,8 @@
|
|||
"confirmations.unfollow.message": "متأكد من أنك تريد إلغاء متابعة {name} ؟",
|
||||
"directory.federated": "From known fediverse",
|
||||
"directory.local": "From {domain} only",
|
||||
"directory.new_arrivals": "New arrivals",
|
||||
"directory.recently_active": "Recently active",
|
||||
"directory.new_arrivals": "الوافدون الجُدد",
|
||||
"directory.recently_active": "نشط مؤخرا",
|
||||
"embed.instructions": "يمكنكم إدماج هذا المنشور على موقعكم الإلكتروني عن طريق نسخ الشفرة أدناه.",
|
||||
"embed.preview": "هكذا ما سوف يبدو عليه:",
|
||||
"emoji_button.activity": "الأنشطة",
|
||||
|
@ -368,7 +369,7 @@
|
|||
"status.show_more": "أظهر المزيد",
|
||||
"status.show_more_all": "توسيع الكل",
|
||||
"status.show_thread": "الكشف عن المحادثة",
|
||||
"status.uncached_media_warning": "Not available",
|
||||
"status.uncached_media_warning": "غير متوفر",
|
||||
"status.unmute_conversation": "فك الكتم عن المحادثة",
|
||||
"status.unpin": "فك التدبيس من الملف الشخصي",
|
||||
"suggestions.dismiss": "إلغاء الاقتراح",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Avisos",
|
||||
"column.pins": "Toots fixaos",
|
||||
"column.public": "Llinia temporal federada",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Atrás",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Mover la columna a la esquierda",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Известия",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Публичен канал",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Назад",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "প্রজ্ঞাপনগুলো",
|
||||
"column.pins": "পিন করা টুট",
|
||||
"column.public": "যুক্ত সময়রেখা",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "পেছনে",
|
||||
"column_header.hide_settings": "সেটিংগুলো সরান",
|
||||
"column_header.moveLeft_settings": "কলমটা বামে সরান",
|
||||
|
|
|
@ -0,0 +1,414 @@
|
|||
{
|
||||
"account.add_or_remove_from_list": "Add or Remove from lists",
|
||||
"account.badges.bot": "Bot",
|
||||
"account.block": "Block @{name}",
|
||||
"account.block_domain": "Hide everything from {domain}",
|
||||
"account.blocked": "Blocked",
|
||||
"account.cancel_follow_request": "Cancel follow request",
|
||||
"account.direct": "Direct message @{name}",
|
||||
"account.domain_blocked": "Domain hidden",
|
||||
"account.edit_profile": "Edit profile",
|
||||
"account.endorse": "Feature on profile",
|
||||
"account.follow": "Follow",
|
||||
"account.followers": "Followers",
|
||||
"account.followers.empty": "No one follows this user yet.",
|
||||
"account.follows": "Follows",
|
||||
"account.follows.empty": "This user doesn't follow anyone yet.",
|
||||
"account.follows_you": "Follows you",
|
||||
"account.hide_reblogs": "Hide boosts from @{name}",
|
||||
"account.last_status": "Last active",
|
||||
"account.link_verified_on": "Ownership of this link was checked on {date}",
|
||||
"account.locked_info": "This account privacy status is set to locked. The owner manually reviews who can follow them.",
|
||||
"account.media": "Media",
|
||||
"account.mention": "Mention @{name}",
|
||||
"account.moved_to": "{name} has moved to:",
|
||||
"account.mute": "Mute @{name}",
|
||||
"account.mute_notifications": "Mute notifications from @{name}",
|
||||
"account.muted": "Muted",
|
||||
"account.never_active": "Never",
|
||||
"account.posts": "Toots",
|
||||
"account.posts_with_replies": "Toots and replies",
|
||||
"account.report": "Report @{name}",
|
||||
"account.requested": "Awaiting approval",
|
||||
"account.share": "Share @{name}'s profile",
|
||||
"account.show_reblogs": "Show boosts from @{name}",
|
||||
"account.unblock": "Unblock @{name}",
|
||||
"account.unblock_domain": "Unhide {domain}",
|
||||
"account.unendorse": "Don't feature on profile",
|
||||
"account.unfollow": "Unfollow",
|
||||
"account.unmute": "Unmute @{name}",
|
||||
"account.unmute_notifications": "Unmute notifications from @{name}",
|
||||
"alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
|
||||
"alert.rate_limited.title": "Rate limited",
|
||||
"alert.unexpected.message": "An unexpected error occurred.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"autosuggest_hashtag.per_week": "{count} per week",
|
||||
"boost_modal.combo": "You can press {combo} to skip this next time",
|
||||
"bundle_column_error.body": "Something went wrong while loading this component.",
|
||||
"bundle_column_error.retry": "Try again",
|
||||
"bundle_column_error.title": "Network error",
|
||||
"bundle_modal_error.close": "Close",
|
||||
"bundle_modal_error.message": "Something went wrong while loading this component.",
|
||||
"bundle_modal_error.retry": "Try again",
|
||||
"column.blocks": "Blocked users",
|
||||
"column.community": "Local timeline",
|
||||
"column.direct": "Direct messages",
|
||||
"column.directory": "Browse profiles",
|
||||
"column.domain_blocks": "Hidden domains",
|
||||
"column.favourites": "Favourites",
|
||||
"column.follow_requests": "Follow requests",
|
||||
"column.home": "Home",
|
||||
"column.lists": "Lists",
|
||||
"column.mutes": "Muted users",
|
||||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federated timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
"column_header.moveRight_settings": "Move column to the right",
|
||||
"column_header.pin": "Pin",
|
||||
"column_header.show_settings": "Show settings",
|
||||
"column_header.unpin": "Unpin",
|
||||
"column_subheading.settings": "Settings",
|
||||
"community.column_settings.media_only": "Media only",
|
||||
"compose_form.direct_message_warning": "This toot will only be sent to all the mentioned users.",
|
||||
"compose_form.direct_message_warning_learn_more": "Learn more",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
"compose_form.placeholder": "What is on your mind?",
|
||||
"compose_form.poll.add_option": "Add a choice",
|
||||
"compose_form.poll.duration": "Poll duration",
|
||||
"compose_form.poll.option_placeholder": "Choice {number}",
|
||||
"compose_form.poll.remove_option": "Remove this choice",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.hide": "Mark media as sensitive",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.spoiler_placeholder": "Write your warning here",
|
||||
"confirmation_modal.cancel": "Cancel",
|
||||
"confirmations.block.block_and_report": "Block & Report",
|
||||
"confirmations.block.confirm": "Block",
|
||||
"confirmations.block.message": "Are you sure you want to block {name}?",
|
||||
"confirmations.delete.confirm": "Delete",
|
||||
"confirmations.delete.message": "Are you sure you want to delete this status?",
|
||||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||
"confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications. Your followers from that domain will be removed.",
|
||||
"confirmations.logout.confirm": "Log out",
|
||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||
"confirmations.mute.confirm": "Mute",
|
||||
"confirmations.mute.message": "Are you sure you want to mute {name}?",
|
||||
"confirmations.redraft.confirm": "Delete & redraft",
|
||||
"confirmations.redraft.message": "Are you sure you want to delete this status and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
|
||||
"confirmations.reply.confirm": "Reply",
|
||||
"confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"directory.federated": "From known fediverse",
|
||||
"directory.local": "From {domain} only",
|
||||
"directory.new_arrivals": "New arrivals",
|
||||
"directory.recently_active": "Recently active",
|
||||
"embed.instructions": "Embed this status on your website by copying the code below.",
|
||||
"embed.preview": "Here is what it will look like:",
|
||||
"emoji_button.activity": "Activity",
|
||||
"emoji_button.custom": "Custom",
|
||||
"emoji_button.flags": "Flags",
|
||||
"emoji_button.food": "Food & Drink",
|
||||
"emoji_button.label": "Insert emoji",
|
||||
"emoji_button.nature": "Nature",
|
||||
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Objects",
|
||||
"emoji_button.people": "People",
|
||||
"emoji_button.recent": "Frequently used",
|
||||
"emoji_button.search": "Search...",
|
||||
"emoji_button.search_results": "Search results",
|
||||
"emoji_button.symbols": "Symbols",
|
||||
"emoji_button.travel": "Travel & Places",
|
||||
"empty_column.account_timeline": "No toots here!",
|
||||
"empty_column.account_unavailable": "Profile unavailable",
|
||||
"empty_column.blocks": "You haven't blocked any users yet.",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.domain_blocks": "There are no hidden domains yet.",
|
||||
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
|
||||
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
|
||||
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
|
||||
"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.public_timeline": "the public timeline",
|
||||
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
|
||||
"empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
|
||||
"empty_column.mutes": "You haven't muted any users yet.",
|
||||
"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 servers to fill it up",
|
||||
"follow_request.authorize": "Authorize",
|
||||
"follow_request.reject": "Reject",
|
||||
"getting_started.developers": "Developers",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Getting started",
|
||||
"getting_started.invite": "Invite people",
|
||||
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
|
||||
"getting_started.security": "Security",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"hashtag.column_header.tag_mode.all": "and {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "or {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "without {additional}",
|
||||
"hashtag.column_settings.select.no_options_message": "No suggestions found",
|
||||
"hashtag.column_settings.select.placeholder": "Enter hashtags…",
|
||||
"hashtag.column_settings.tag_mode.all": "All of these",
|
||||
"hashtag.column_settings.tag_mode.any": "Any of these",
|
||||
"hashtag.column_settings.tag_mode.none": "None of these",
|
||||
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
||||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.show_reblogs": "Show boosts",
|
||||
"home.column_settings.show_replies": "Show replies",
|
||||
"home.column_settings.update_live": "Update in real-time",
|
||||
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
|
||||
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
|
||||
"introduction.federation.action": "Next",
|
||||
"introduction.federation.federated.headline": "Federated",
|
||||
"introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
|
||||
"introduction.federation.home.headline": "Home",
|
||||
"introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
|
||||
"introduction.federation.local.headline": "Local",
|
||||
"introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
|
||||
"introduction.interactions.action": "Finish toot-orial!",
|
||||
"introduction.interactions.favourite.headline": "Favourite",
|
||||
"introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
|
||||
"introduction.interactions.reblog.headline": "Boost",
|
||||
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
|
||||
"introduction.interactions.reply.headline": "Reply",
|
||||
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
|
||||
"introduction.welcome.action": "Let's go!",
|
||||
"introduction.welcome.headline": "First steps",
|
||||
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
|
||||
"keyboard_shortcuts.back": "to navigate back",
|
||||
"keyboard_shortcuts.blocked": "to open blocked users list",
|
||||
"keyboard_shortcuts.boost": "to boost",
|
||||
"keyboard_shortcuts.column": "to focus a status in one of the columns",
|
||||
"keyboard_shortcuts.compose": "to focus the compose textarea",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.direct": "to open direct messages column",
|
||||
"keyboard_shortcuts.down": "to move down in the list",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.favourite": "to favourite",
|
||||
"keyboard_shortcuts.favourites": "to open favourites list",
|
||||
"keyboard_shortcuts.federated": "to open federated timeline",
|
||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||
"keyboard_shortcuts.home": "to open home timeline",
|
||||
"keyboard_shortcuts.hotkey": "Hotkey",
|
||||
"keyboard_shortcuts.legend": "to display this legend",
|
||||
"keyboard_shortcuts.local": "to open local timeline",
|
||||
"keyboard_shortcuts.mention": "to mention author",
|
||||
"keyboard_shortcuts.muted": "to open muted users list",
|
||||
"keyboard_shortcuts.my_profile": "to open your profile",
|
||||
"keyboard_shortcuts.notifications": "to open notifications column",
|
||||
"keyboard_shortcuts.pinned": "to open pinned toots list",
|
||||
"keyboard_shortcuts.profile": "to open author's profile",
|
||||
"keyboard_shortcuts.reply": "to reply",
|
||||
"keyboard_shortcuts.requests": "to open follow requests list",
|
||||
"keyboard_shortcuts.search": "to focus search",
|
||||
"keyboard_shortcuts.start": "to open \"get started\" column",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
|
||||
"keyboard_shortcuts.toot": "to start a brand new toot",
|
||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||
"keyboard_shortcuts.up": "to move up in the list",
|
||||
"lightbox.close": "Close",
|
||||
"lightbox.next": "Next",
|
||||
"lightbox.previous": "Previous",
|
||||
"lightbox.view_context": "View context",
|
||||
"lists.account.add": "Add to list",
|
||||
"lists.account.remove": "Remove from list",
|
||||
"lists.delete": "Delete list",
|
||||
"lists.edit": "Edit list",
|
||||
"lists.edit.submit": "Change title",
|
||||
"lists.new.create": "Add list",
|
||||
"lists.new.title_placeholder": "New list title",
|
||||
"lists.search": "Search among people you follow",
|
||||
"lists.subheading": "Your lists",
|
||||
"load_pending": "{count, plural, one {# new item} other {# new items}}",
|
||||
"loading_indicator.label": "Loading...",
|
||||
"media_gallery.toggle_visible": "Toggle visibility",
|
||||
"missing_indicator.label": "Not found",
|
||||
"missing_indicator.sublabel": "This resource could not be found",
|
||||
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||
"navigation_bar.apps": "Mobile apps",
|
||||
"navigation_bar.blocks": "Blocked users",
|
||||
"navigation_bar.community_timeline": "Local timeline",
|
||||
"navigation_bar.compose": "Compose new toot",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Edit profile",
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.follows_and_followers": "Follows and followers",
|
||||
"navigation_bar.info": "About this server",
|
||||
"navigation_bar.keyboard_shortcuts": "Hotkeys",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Logout",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pinned toots",
|
||||
"navigation_bar.preferences": "Preferences",
|
||||
"navigation_bar.public_timeline": "Federated timeline",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
|
||||
"notification.favourite": "{name} favourited your status",
|
||||
"notification.follow": "{name} followed you",
|
||||
"notification.mention": "{name} mentioned you",
|
||||
"notification.poll": "A poll you have voted in has ended",
|
||||
"notification.reblog": "{name} boosted your status",
|
||||
"notifications.clear": "Clear notifications",
|
||||
"notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
|
||||
"notifications.column_settings.alert": "Desktop notifications",
|
||||
"notifications.column_settings.favourite": "Favourites:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Display all categories",
|
||||
"notifications.column_settings.filter_bar.category": "Quick filter bar",
|
||||
"notifications.column_settings.filter_bar.show": "Show",
|
||||
"notifications.column_settings.follow": "New followers:",
|
||||
"notifications.column_settings.mention": "Mentions:",
|
||||
"notifications.column_settings.poll": "Poll results:",
|
||||
"notifications.column_settings.push": "Push notifications",
|
||||
"notifications.column_settings.reblog": "Boosts:",
|
||||
"notifications.column_settings.show": "Show in column",
|
||||
"notifications.column_settings.sound": "Play sound",
|
||||
"notifications.filter.all": "All",
|
||||
"notifications.filter.boosts": "Boosts",
|
||||
"notifications.filter.favourites": "Favourites",
|
||||
"notifications.filter.follows": "Follows",
|
||||
"notifications.filter.mentions": "Mentions",
|
||||
"notifications.filter.polls": "Poll results",
|
||||
"notifications.group": "{count} notifications",
|
||||
"poll.closed": "Closed",
|
||||
"poll.refresh": "Refresh",
|
||||
"poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
|
||||
"poll.vote": "Vote",
|
||||
"poll_button.add_poll": "Add a poll",
|
||||
"poll_button.remove_poll": "Remove poll",
|
||||
"privacy.change": "Adjust status privacy",
|
||||
"privacy.direct.long": "Post to mentioned users only",
|
||||
"privacy.direct.short": "Direct",
|
||||
"privacy.private.long": "Post to followers only",
|
||||
"privacy.private.short": "Followers-only",
|
||||
"privacy.public.long": "Post to public timelines",
|
||||
"privacy.public.short": "Public",
|
||||
"privacy.unlisted.long": "Do not show in public timelines",
|
||||
"privacy.unlisted.short": "Unlisted",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "now",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Cancel",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||
"report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.placeholder": "Additional comments",
|
||||
"report.submit": "Submit",
|
||||
"report.target": "Report {target}",
|
||||
"search.placeholder": "Search",
|
||||
"search_popout.search_format": "Advanced search format",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
||||
"search_popout.tips.user": "user",
|
||||
"search_results.accounts": "People",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.copy": "Copy link to status",
|
||||
"status.delete": "Delete",
|
||||
"status.detailed_status": "Detailed conversation view",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Embed",
|
||||
"status.favourite": "Favourite",
|
||||
"status.filtered": "Filtered",
|
||||
"status.load_more": "Load more",
|
||||
"status.media_hidden": "Media hidden",
|
||||
"status.mention": "Mention @{name}",
|
||||
"status.more": "More",
|
||||
"status.mute": "Mute @{name}",
|
||||
"status.mute_conversation": "Mute conversation",
|
||||
"status.open": "Expand this status",
|
||||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.read_more": "Read more",
|
||||
"status.reblog": "Boost",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "{name} boosted",
|
||||
"status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Reply",
|
||||
"status.replyAll": "Reply to thread",
|
||||
"status.report": "Report @{name}",
|
||||
"status.sensitive_warning": "Sensitive content",
|
||||
"status.share": "Share",
|
||||
"status.show_less": "Show less",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_more": "Show more",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_thread": "Show thread",
|
||||
"status.uncached_media_warning": "Not available",
|
||||
"status.unmute_conversation": "Unmute conversation",
|
||||
"status.unpin": "Unpin from profile",
|
||||
"suggestions.dismiss": "Dismiss suggestion",
|
||||
"suggestions.header": "You might be interested in…",
|
||||
"tabs_bar.federated_timeline": "Federated",
|
||||
"tabs_bar.home": "Home",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"time_remaining.days": "{number, plural, one {# day} other {# days}} left",
|
||||
"time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
|
||||
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
|
||||
"time_remaining.moments": "Moments remaining",
|
||||
"time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"trends.trending_now": "Trending now",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media ({formats})",
|
||||
"upload_error.limit": "File upload limit exceeded.",
|
||||
"upload_error.poll": "File upload not allowed with polls.",
|
||||
"upload_form.description": "Describe for the visually impaired",
|
||||
"upload_form.edit": "Edit",
|
||||
"upload_form.undo": "Delete",
|
||||
"upload_modal.analyzing_picture": "Analyzing picture…",
|
||||
"upload_modal.apply": "Apply",
|
||||
"upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
|
||||
"upload_modal.detect_text": "Detect text from picture",
|
||||
"upload_modal.edit_media": "Edit media",
|
||||
"upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
|
||||
"upload_modal.preview_label": "Preview ({ratio})",
|
||||
"upload_progress.label": "Uploading...",
|
||||
"video.close": "Close video",
|
||||
"video.exit_fullscreen": "Exit full screen",
|
||||
"video.expand": "Expand video",
|
||||
"video.fullscreen": "Full screen",
|
||||
"video.hide": "Hide video",
|
||||
"video.mute": "Mute sound",
|
||||
"video.pause": "Pause",
|
||||
"video.play": "Play",
|
||||
"video.unmute": "Unmute sound"
|
||||
}
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificacions",
|
||||
"column.pins": "Toots fixats",
|
||||
"column.public": "Línia de temps federada",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Enrere",
|
||||
"column_header.hide_settings": "Amaga la configuració",
|
||||
"column_header.moveLeft_settings": "Mou la columna cap a l'esquerra",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Nutificazione",
|
||||
"column.pins": "Statuti puntarulati",
|
||||
"column.public": "Linea pubblica glubale",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Ritornu",
|
||||
"column_header.hide_settings": "Piattà i parametri",
|
||||
"column_header.moveLeft_settings": "Spiazzà à manca",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Oznámení",
|
||||
"column.pins": "Připnuté tooty",
|
||||
"column.public": "Federovaná časová osa",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Zpět",
|
||||
"column_header.hide_settings": "Skrýt nastavení",
|
||||
"column_header.moveLeft_settings": "Posunout sloupec doleva",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Hysbysiadau",
|
||||
"column.pins": "Tŵtiau wedi eu pinio",
|
||||
"column.public": "Ffrwd y ffederasiwn",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Nôl",
|
||||
"column_header.hide_settings": "Cuddio dewisiadau",
|
||||
"column_header.moveLeft_settings": "Symud y golofn i'r chwith",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifikationer",
|
||||
"column.pins": "Fastgjorte trut",
|
||||
"column.public": "Fælles tidslinje",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tilbage",
|
||||
"column_header.hide_settings": "Skjul indstillinger",
|
||||
"column_header.moveLeft_settings": "Flyt kolonne til venstre",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Mitteilungen",
|
||||
"column.pins": "Angeheftete Beiträge",
|
||||
"column.public": "Föderierte Zeitleiste",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Zurück",
|
||||
"column_header.hide_settings": "Einstellungen verbergen",
|
||||
"column_header.moveLeft_settings": "Spalte nach links verschieben",
|
||||
|
|
|
@ -1129,6 +1129,15 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/features/compose/components/upload_form.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Uploading...",
|
||||
"id": "upload_progress.label"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/compose/components/upload_progress.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
@ -1155,19 +1164,6 @@
|
|||
],
|
||||
"path": "app/javascript/mastodon/features/compose/containers/navigation_container.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to log out?",
|
||||
"id": "confirmations.logout.message"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Log out",
|
||||
"id": "confirmations.logout.confirm"
|
||||
}
|
||||
],
|
||||
"path": "app/javascript/mastodon/features/compose/containers/navigation_container.json"
|
||||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
|
@ -1584,10 +1580,6 @@
|
|||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "Basic",
|
||||
"id": "home.column_settings.basic"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Show boosts",
|
||||
"id": "home.column_settings.show_reblogs"
|
||||
|
@ -1969,6 +1961,14 @@
|
|||
"defaultMessage": "Push notifications",
|
||||
"id": "notifications.column_settings.push"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Basic",
|
||||
"id": "home.column_settings.basic"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Update in real-time",
|
||||
"id": "home.column_settings.update_live"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Quick filter bar",
|
||||
"id": "notifications.column_settings.filter_bar.category"
|
||||
|
@ -2027,6 +2027,10 @@
|
|||
},
|
||||
{
|
||||
"descriptors": [
|
||||
{
|
||||
"defaultMessage": "and {count, plural, one {# other} other {# others}}",
|
||||
"id": "notification.and_n_others"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "{name} followed you",
|
||||
"id": "notification.follow"
|
||||
|
@ -2283,6 +2287,10 @@
|
|||
"defaultMessage": "Block & Report",
|
||||
"id": "confirmations.block.block_and_report"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Toot",
|
||||
"id": "column.status"
|
||||
},
|
||||
{
|
||||
"defaultMessage": "Are you sure you want to block {name}?",
|
||||
"id": "confirmations.block.message"
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Ειδοποιήσεις",
|
||||
"column.pins": "Καρφιτσωμένα τουτ",
|
||||
"column.public": "Ομοσπονδιακή ροή",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Πίσω",
|
||||
"column_header.hide_settings": "Απόκρυψη ρυθμίσεων",
|
||||
"column_header.moveLeft_settings": "Μεταφορά κολώνας αριστερά",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toots",
|
||||
"column.public": "Federated timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
@ -173,6 +174,7 @@
|
|||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.show_reblogs": "Show boosts",
|
||||
"home.column_settings.show_replies": "Show replies",
|
||||
"home.column_settings.update_live": "Update in real-time",
|
||||
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
|
||||
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
|
||||
|
@ -267,6 +269,7 @@
|
|||
"navigation_bar.preferences": "Preferences",
|
||||
"navigation_bar.public_timeline": "Federated timeline",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
|
||||
"notification.favourite": "{name} favourited your status",
|
||||
"notification.follow": "{name} followed you",
|
||||
"notification.mention": "{name} mentioned you",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Sciigoj",
|
||||
"column.pins": "Alpinglitaj mesaĝoj",
|
||||
"column.public": "Fratara tempolinio",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Reveni",
|
||||
"column_header.hide_settings": "Kaŝi agordojn",
|
||||
"column_header.moveLeft_settings": "Movi kolumnon maldekstren",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"account.block": "Bloquear a @{name}",
|
||||
"account.block_domain": "Ocultar todo de {domain}",
|
||||
"account.blocked": "Bloqueado",
|
||||
"account.cancel_follow_request": "Cancel follow request",
|
||||
"account.cancel_follow_request": "Cancelar la solicitud de seguimiento",
|
||||
"account.direct": "Mensaje directo a @{name}",
|
||||
"account.domain_blocked": "Dominio oculto",
|
||||
"account.edit_profile": "Editar perfil",
|
||||
|
@ -16,7 +16,7 @@
|
|||
"account.follows.empty": "Este usuario todavía no sigue a nadie.",
|
||||
"account.follows_you": "Te sigue",
|
||||
"account.hide_reblogs": "Ocultar retoots de @{name}",
|
||||
"account.last_status": "Last active",
|
||||
"account.last_status": "Última actividad",
|
||||
"account.link_verified_on": "El proprietario de este link fue comprobado el {date}",
|
||||
"account.locked_info": "El estado de privacidad de esta cuenta està configurado como bloqueado. El proprietario debe revisar manualmente quien puede seguirle.",
|
||||
"account.media": "Multimedia",
|
||||
|
@ -25,7 +25,7 @@
|
|||
"account.mute": "Silenciar a @{name}",
|
||||
"account.mute_notifications": "Silenciar notificaciones de @{name}",
|
||||
"account.muted": "Silenciado",
|
||||
"account.never_active": "Never",
|
||||
"account.never_active": "Nunca",
|
||||
"account.posts": "Toots",
|
||||
"account.posts_with_replies": "Toots con respuestas",
|
||||
"account.report": "Reportar a @{name}",
|
||||
|
@ -39,7 +39,7 @@
|
|||
"account.unmute": "Dejar de silenciar a @{name}",
|
||||
"account.unmute_notifications": "Dejar de silenciar las notificaciones de @{name}",
|
||||
"alert.rate_limited.message": "Please retry after {retry_time, time, medium}.",
|
||||
"alert.rate_limited.title": "Rate limited",
|
||||
"alert.rate_limited.title": "Tarifa limitada",
|
||||
"alert.unexpected.message": "Hubo un error inesperado.",
|
||||
"alert.unexpected.title": "¡Ups!",
|
||||
"autosuggest_hashtag.per_week": "{count} per week",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"column.blocks": "Usuarios bloqueados",
|
||||
"column.community": "Línea de tiempo local",
|
||||
"column.direct": "Mensajes directos",
|
||||
"column.directory": "Browse profiles",
|
||||
"column.directory": "Buscar perfiles",
|
||||
"column.domain_blocks": "Dominios ocultados",
|
||||
"column.favourites": "Favoritos",
|
||||
"column.follow_requests": "Solicitudes de seguimiento",
|
||||
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificaciones",
|
||||
"column.pins": "Toots fijados",
|
||||
"column.public": "Línea de tiempo federada",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Atrás",
|
||||
"column_header.hide_settings": "Ocultar configuración",
|
||||
"column_header.moveLeft_settings": "Mover columna a la izquierda",
|
||||
|
@ -100,8 +101,8 @@
|
|||
"confirmations.delete_list.message": "¿Seguro que quieres borrar esta lista permanentemente?",
|
||||
"confirmations.domain_block.confirm": "Ocultar dominio entero",
|
||||
"confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio {domain} entero? En general unos cuantos bloqueos y silenciados concretos es suficiente y preferible.",
|
||||
"confirmations.logout.confirm": "Log out",
|
||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||
"confirmations.logout.confirm": "Cerrar sesión",
|
||||
"confirmations.logout.message": "¿Estás seguro de querer cerrar la sesión?",
|
||||
"confirmations.mute.confirm": "Silenciar",
|
||||
"confirmations.mute.message": "¿Estás seguro de que quieres silenciar a {name}?",
|
||||
"confirmations.redraft.confirm": "Borrar y volver a borrador",
|
||||
|
@ -110,10 +111,10 @@
|
|||
"confirmations.reply.message": "Responder sobrescribirá el mensaje que estás escribiendo. ¿Estás seguro de que deseas continuar?",
|
||||
"confirmations.unfollow.confirm": "Dejar de seguir",
|
||||
"confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
|
||||
"directory.federated": "From known fediverse",
|
||||
"directory.local": "From {domain} only",
|
||||
"directory.new_arrivals": "New arrivals",
|
||||
"directory.recently_active": "Recently active",
|
||||
"directory.federated": "Desde el fediverso conocido",
|
||||
"directory.local": "Sólo de {domain}",
|
||||
"directory.new_arrivals": "Recién llegados",
|
||||
"directory.recently_active": "Recientemente activo",
|
||||
"embed.instructions": "Añade este toot a tu sitio web con el siguiente código.",
|
||||
"embed.preview": "Así es como se verá:",
|
||||
"emoji_button.activity": "Actividad",
|
||||
|
@ -368,7 +369,7 @@
|
|||
"status.show_more": "Mostrar más",
|
||||
"status.show_more_all": "Mostrar más para todo",
|
||||
"status.show_thread": "Ver hilo",
|
||||
"status.uncached_media_warning": "Not available",
|
||||
"status.uncached_media_warning": "No disponible",
|
||||
"status.unmute_conversation": "Dejar de silenciar conversación",
|
||||
"status.unpin": "Dejar de fijar",
|
||||
"suggestions.dismiss": "Descartar sugerencia",
|
||||
|
@ -384,21 +385,21 @@
|
|||
"time_remaining.moments": "Momentos restantes",
|
||||
"time_remaining.seconds": "{number, plural, one {# segundo restante} other {# segundos restantes}}",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {persona} other {personas}} hablando",
|
||||
"trends.trending_now": "Trending now",
|
||||
"trends.trending_now": "Tendencia ahora",
|
||||
"ui.beforeunload": "Tu borrador se perderá si sales de Mastodon.",
|
||||
"upload_area.title": "Arrastra y suelta para subir",
|
||||
"upload_button.label": "Subir multimedia (JPEG, PNG, GIF, WebM, MP4, MOV)",
|
||||
"upload_error.limit": "Límite de subida de archivos excedido.",
|
||||
"upload_error.poll": "Subida de archivos no permitida con encuestas.",
|
||||
"upload_form.description": "Describir para los usuarios con dificultad visual",
|
||||
"upload_form.edit": "Edit",
|
||||
"upload_form.edit": "Editar",
|
||||
"upload_form.undo": "Borrar",
|
||||
"upload_modal.analyzing_picture": "Analyzing picture…",
|
||||
"upload_modal.apply": "Apply",
|
||||
"upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
|
||||
"upload_modal.detect_text": "Detect text from picture",
|
||||
"upload_modal.edit_media": "Edit media",
|
||||
"upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
|
||||
"upload_modal.analyzing_picture": "Analizando imagen…",
|
||||
"upload_modal.apply": "Aplicar",
|
||||
"upload_modal.description_placeholder": "Un rápido zorro marrón salta sobre el perro perezoso",
|
||||
"upload_modal.detect_text": "Detectar texto de la imagen",
|
||||
"upload_modal.edit_media": "Editar multimedia",
|
||||
"upload_modal.hint": "Haga clic o arrastre el círculo en la vista previa para elegir el punto focal que siempre estará a la vista en todas las miniaturas.",
|
||||
"upload_modal.preview_label": "Preview ({ratio})",
|
||||
"upload_progress.label": "Subiendo…",
|
||||
"video.close": "Cerrar video",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Teated",
|
||||
"column.pins": "Kinnitatud upitused",
|
||||
"column.public": "Föderatiivne ajajoon",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tagasi",
|
||||
"column_header.hide_settings": "Peida sätted",
|
||||
"column_header.moveLeft_settings": "Liiguta tulp vasakule",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Jakinarazpenak",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federatutako denbora-lerroa",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Atzera",
|
||||
"column_header.hide_settings": "Ezkutatu ezarpenak",
|
||||
"column_header.moveLeft_settings": "Eraman zutabea ezkerrera",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "اعلانها",
|
||||
"column.pins": "نوشتههای ثابت",
|
||||
"column.public": "نوشتههای همهجا",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "بازگشت",
|
||||
"column_header.hide_settings": "نهفتن تنظیمات",
|
||||
"column_header.moveLeft_settings": "انتقال ستون به راست",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Ilmoitukset",
|
||||
"column.pins": "Kiinnitetty tuuttaus",
|
||||
"column.public": "Yleinen aikajana",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Takaisin",
|
||||
"column_header.hide_settings": "Piilota asetukset",
|
||||
"column_header.moveLeft_settings": "Siirrä saraketta vasemmalle",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pouets épinglés",
|
||||
"column.public": "Fil public global",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Retour",
|
||||
"column_header.hide_settings": "Masquer les paramètres",
|
||||
"column_header.moveLeft_settings": "Déplacer la colonne vers la gauche",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificacións",
|
||||
"column.pins": "Mensaxes fixadas",
|
||||
"column.public": "Liña temporal federada",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Atrás",
|
||||
"column_header.hide_settings": "Agochar axustes",
|
||||
"column_header.moveLeft_settings": "Mover a columna hacia a esquerda",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "התראות",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "בפרהסיה",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "חזרה",
|
||||
"column_header.hide_settings": "הסתרת העדפות",
|
||||
"column_header.moveLeft_settings": "הזחת טור לשמאל",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federated timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifikacije",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federalni timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Natrag",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Értesítések",
|
||||
"column.pins": "Kitűzött tülkök",
|
||||
"column.public": "Nyilvános idővonal",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Vissza",
|
||||
"column_header.hide_settings": "Beállítások elrejtése",
|
||||
"column_header.moveLeft_settings": "Oszlop elmozdítása balra",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Ծանուցումներ",
|
||||
"column.pins": "Ամրացված թթեր",
|
||||
"column.public": "Դաշնային հոսք",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Ետ",
|
||||
"column_header.hide_settings": "Թաքցնել կարգավորումները",
|
||||
"column_header.moveLeft_settings": "Տեղաշարժել սյունը ձախ",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifikasi",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Linimasa gabungan",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Kembali",
|
||||
"column_header.hide_settings": "Sembunyikan pengaturan",
|
||||
"column_header.moveLeft_settings": "Pindahkan kolom ke kiri",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Savigi",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federata tempolineo",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Retro",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifiche",
|
||||
"column.pins": "Toot fissati in cima",
|
||||
"column.public": "Timeline federata",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Indietro",
|
||||
"column_header.hide_settings": "Nascondi impostazioni",
|
||||
"column_header.moveLeft_settings": "Sposta colonna a sinistra",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "通知",
|
||||
"column.pins": "固定されたトゥート",
|
||||
"column.public": "連合タイムライン",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "戻る",
|
||||
"column_header.hide_settings": "設定を隠す",
|
||||
"column_header.moveLeft_settings": "カラムを左に移動する",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "შეტყობინებები",
|
||||
"column.pins": "აპინული ტუტები",
|
||||
"column.public": "ფედერალური თაიმლაინი",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "უკან",
|
||||
"column_header.hide_settings": "პარამეტრების დამალვა",
|
||||
"column_header.moveLeft_settings": "სვეტის მარცხნივ გადატანა",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Ескертпелер",
|
||||
"column.pins": "Жабыстырылған жазбалар",
|
||||
"column.public": "Жаһандық желі",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Артқа",
|
||||
"column_header.hide_settings": "Баптауларды жасыр",
|
||||
"column_header.moveLeft_settings": "Бағананы солға жылжыту",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "알림",
|
||||
"column.pins": "고정된 툿",
|
||||
"column.public": "연합 타임라인",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "돌아가기",
|
||||
"column_header.hide_settings": "설정 숨기기",
|
||||
"column_header.moveLeft_settings": "왼쪽으로 이동",
|
||||
|
@ -292,7 +293,7 @@
|
|||
"notifications.group": "{count} 개의 알림",
|
||||
"poll.closed": "마감됨",
|
||||
"poll.refresh": "새로고침",
|
||||
"poll.total_votes": "{count} 명 참여",
|
||||
"poll.total_votes": "{count} 표",
|
||||
"poll.vote": "투표",
|
||||
"poll_button.add_poll": "투표 추가",
|
||||
"poll_button.remove_poll": "투표 삭제",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federated timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Paziņojumi",
|
||||
"column.pins": "Piespraustie ziņojumi",
|
||||
"column.public": "Federatīvā laika līnija",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Atpakaļ",
|
||||
"column_header.hide_settings": "Paslēpt iestatījumus",
|
||||
"column_header.moveLeft_settings": "Pārvietot kolonu pa kreisi",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Federated timeline",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Back",
|
||||
"column_header.hide_settings": "Hide settings",
|
||||
"column_header.moveLeft_settings": "Move column to the left",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Meldingen",
|
||||
"column.pins": "Vastgezette toots",
|
||||
"column.public": "Globale tijdlijn",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Terug",
|
||||
"column_header.hide_settings": "Instellingen verbergen",
|
||||
"column_header.moveLeft_settings": "Kolom naar links verplaatsen",
|
||||
|
|
|
@ -0,0 +1,414 @@
|
|||
{
|
||||
"account.add_or_remove_from_list": "Legg til eller ta vekk fra liste",
|
||||
"account.badges.bot": "Robot",
|
||||
"account.block": "Blokkér @{name}",
|
||||
"account.block_domain": "Gøyme alt innhald for domenet {domain}",
|
||||
"account.blocked": "Blokkert",
|
||||
"account.cancel_follow_request": "Avslutt føljar-førespurnad",
|
||||
"account.direct": "Direkte meld @{name}",
|
||||
"account.domain_blocked": "Domenet er gøymt",
|
||||
"account.edit_profile": "Rediger profil",
|
||||
"account.endorse": "Framhev på profilen din",
|
||||
"account.follow": "Følj",
|
||||
"account.followers": "Føljare",
|
||||
"account.followers.empty": "Er ikkje nokon som føljar denne brukaren ennå.",
|
||||
"account.follows": "Føljingar",
|
||||
"account.follows.empty": "Denne brukaren foljer ikkje nokon ennå.",
|
||||
"account.follows_you": "Føljar deg",
|
||||
"account.hide_reblogs": "Gøym robotar for @{name}",
|
||||
"account.last_status": "Sist aktiv",
|
||||
"account.link_verified_on": "Eigerskap for denne linken er sist sjekket den {date}",
|
||||
"account.locked_info": "Brukarens privat-status er satt til lukka. Eigaren må manuelt døme kvem som kan følje honom.",
|
||||
"account.media": "Media",
|
||||
"account.mention": "Nemne @{name}",
|
||||
"account.moved_to": "{name} har flytta til:",
|
||||
"account.mute": "Målbind @{name}",
|
||||
"account.mute_notifications": "Målbind notifikasjoner ifrå @{name}",
|
||||
"account.muted": "Målbindt",
|
||||
"account.never_active": "Aldri",
|
||||
"account.posts": "Tutar",
|
||||
"account.posts_with_replies": "Tutar og svar",
|
||||
"account.report": "Rapporter @{name}",
|
||||
"account.requested": "Venter på samtykke. Klikk for å avbryte føljar-førespurnad",
|
||||
"account.share": "Del @{name} sin profil",
|
||||
"account.show_reblogs": "Sjå framhevingar ifrå @{name}",
|
||||
"account.unblock": "Avblokker @{name}",
|
||||
"account.unblock_domain": "Vis {domain}",
|
||||
"account.unendorse": "Ikkje framhev på profil",
|
||||
"account.unfollow": "Avfølja",
|
||||
"account.unmute": "Av-demp @{name}",
|
||||
"account.unmute_notifications": "Av-demp notifikasjoner ifrå @{name}",
|
||||
"alert.rate_limited.message": "Ver vennlig og prøv igjen {retry_time, time, medium}.",
|
||||
"alert.rate_limited.title": "Bregrensa rate",
|
||||
"alert.unexpected.message": "Eit uforventa problem har hendt.",
|
||||
"alert.unexpected.title": "Oops!",
|
||||
"autosuggest_hashtag.per_week": "{count} per veke",
|
||||
"boost_modal.combo": "Du kan trykke {combo} for å hoppe over dette neste gong",
|
||||
"bundle_column_error.body": "Noko gikk gale mens komponent ble nedlasta.",
|
||||
"bundle_column_error.retry": "Prøv igjen",
|
||||
"bundle_column_error.title": "Tenarmaskin feil",
|
||||
"bundle_modal_error.close": "Lukk",
|
||||
"bundle_modal_error.message": "Noko gikk gale mens komponent var i ferd med å bli nedlasta.",
|
||||
"bundle_modal_error.retry": "Prøv igjen",
|
||||
"column.blocks": "Blokka brukare",
|
||||
"column.community": "Lokal samtid",
|
||||
"column.direct": "Direkte meldingar",
|
||||
"column.directory": "Sjå gjennom profiler",
|
||||
"column.domain_blocks": "Gøymte domener",
|
||||
"column.favourites": "Favorittar",
|
||||
"column.follow_requests": "Føljarførespurnad",
|
||||
"column.home": "Heim",
|
||||
"column.lists": "Lister",
|
||||
"column.mutes": "Målbindte brukare",
|
||||
"column.notifications": "Varslinger",
|
||||
"column.pins": "Festa tuter",
|
||||
"column.public": "Federert samtid",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tilbake",
|
||||
"column_header.hide_settings": "Skjul innstillingar",
|
||||
"column_header.moveLeft_settings": "Flytt feltet til venstre",
|
||||
"column_header.moveRight_settings": "Flytt feltet til høgre",
|
||||
"column_header.pin": "Fest",
|
||||
"column_header.show_settings": "Vis innstillingar",
|
||||
"column_header.unpin": "Løys",
|
||||
"column_subheading.settings": "Innstillingar",
|
||||
"community.column_settings.media_only": "Kun medie",
|
||||
"compose_form.direct_message_warning": "Denne tuten vil kun verte synleg for nemnde brukarar.",
|
||||
"compose_form.direct_message_warning_learn_more": "Lær meir",
|
||||
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.",
|
||||
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
|
||||
"compose_form.lock_disclaimer.lock": "locked",
|
||||
"compose_form.placeholder": "What is on your mind?",
|
||||
"compose_form.poll.add_option": "Add a choice",
|
||||
"compose_form.poll.duration": "Poll duration",
|
||||
"compose_form.poll.option_placeholder": "Choice {number}",
|
||||
"compose_form.poll.remove_option": "Remove this choice",
|
||||
"compose_form.publish": "Toot",
|
||||
"compose_form.publish_loud": "{publish}!",
|
||||
"compose_form.sensitive.hide": "Mark media as sensitive",
|
||||
"compose_form.sensitive.marked": "Media is marked as sensitive",
|
||||
"compose_form.sensitive.unmarked": "Media is not marked as sensitive",
|
||||
"compose_form.spoiler.marked": "Text is hidden behind warning",
|
||||
"compose_form.spoiler.unmarked": "Text is not hidden",
|
||||
"compose_form.spoiler_placeholder": "Write your warning here",
|
||||
"confirmation_modal.cancel": "Cancel",
|
||||
"confirmations.block.block_and_report": "Block & Report",
|
||||
"confirmations.block.confirm": "Block",
|
||||
"confirmations.block.message": "Are you sure you want to block {name}?",
|
||||
"confirmations.delete.confirm": "Delete",
|
||||
"confirmations.delete.message": "Are you sure you want to delete this status?",
|
||||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.domain_block.confirm": "Hide entire domain",
|
||||
"confirmations.domain_block.message": "Er du ordentleg, ordentleg sikker på at du vill blokkere heile {domain}? I dei tilfeller er det bedre med ein målretta blokkering eller demping av individuelle brukare.",
|
||||
"confirmations.logout.confirm": "Logg ut",
|
||||
"confirmations.logout.message": "Er du sikker på at du vill logge ut?",
|
||||
"confirmations.mute.confirm": "Målbind",
|
||||
"confirmations.mute.message": "Er du sikker på at d vill målbinde {name}?",
|
||||
"confirmations.redraft.confirm": "Slett & gjennopprett",
|
||||
"confirmations.redraft.message": "Er du sikker på at du vill slette statusen og gjennoprette den? Favoritter og framhevinger vill bli borte, og svar til den originale posten vill bli einstøing.",
|
||||
"confirmations.reply.confirm": "Svar",
|
||||
"confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"directory.federated": "From known fediverse",
|
||||
"directory.local": "From {domain} only",
|
||||
"directory.new_arrivals": "New arrivals",
|
||||
"directory.recently_active": "Recently active",
|
||||
"embed.instructions": "Embed this status on your website by copying the code below.",
|
||||
"embed.preview": "Here is what it will look like:",
|
||||
"emoji_button.activity": "Activity",
|
||||
"emoji_button.custom": "Custom",
|
||||
"emoji_button.flags": "Flags",
|
||||
"emoji_button.food": "Food & Drink",
|
||||
"emoji_button.label": "Insert emoji",
|
||||
"emoji_button.nature": "Nature",
|
||||
"emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻",
|
||||
"emoji_button.objects": "Objects",
|
||||
"emoji_button.people": "People",
|
||||
"emoji_button.recent": "Frequently used",
|
||||
"emoji_button.search": "Search...",
|
||||
"emoji_button.search_results": "Search results",
|
||||
"emoji_button.symbols": "Symbols",
|
||||
"emoji_button.travel": "Travel & Places",
|
||||
"empty_column.account_timeline": "No toots here!",
|
||||
"empty_column.account_unavailable": "Profile unavailable",
|
||||
"empty_column.blocks": "You haven't blocked any users yet.",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.domain_blocks": "There are no hidden domains yet.",
|
||||
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.",
|
||||
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.",
|
||||
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
|
||||
"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.public_timeline": "the public timeline",
|
||||
"empty_column.list": "There is nothing in this list yet. When members of this list post new statuses, they will appear here.",
|
||||
"empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
|
||||
"empty_column.mutes": "You haven't muted any users yet.",
|
||||
"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 servers to fill it up",
|
||||
"follow_request.authorize": "Authorize",
|
||||
"follow_request.reject": "Reject",
|
||||
"getting_started.developers": "Developers",
|
||||
"getting_started.directory": "Profile directory",
|
||||
"getting_started.documentation": "Documentation",
|
||||
"getting_started.heading": "Getting started",
|
||||
"getting_started.invite": "Invite people",
|
||||
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
|
||||
"getting_started.security": "Security",
|
||||
"getting_started.terms": "Terms of service",
|
||||
"hashtag.column_header.tag_mode.all": "and {additional}",
|
||||
"hashtag.column_header.tag_mode.any": "or {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "without {additional}",
|
||||
"hashtag.column_settings.select.no_options_message": "No suggestions found",
|
||||
"hashtag.column_settings.select.placeholder": "Enter hashtags…",
|
||||
"hashtag.column_settings.tag_mode.all": "All of these",
|
||||
"hashtag.column_settings.tag_mode.any": "Any of these",
|
||||
"hashtag.column_settings.tag_mode.none": "None of these",
|
||||
"hashtag.column_settings.tag_toggle": "Include additional tags in this column",
|
||||
"home.column_settings.basic": "Basic",
|
||||
"home.column_settings.show_reblogs": "Show boosts",
|
||||
"home.column_settings.show_replies": "Show replies",
|
||||
"home.column_settings.update_live": "Update in real-time",
|
||||
"intervals.full.days": "{number, plural, one {# day} other {# days}}",
|
||||
"intervals.full.hours": "{number, plural, one {# hour} other {# hours}}",
|
||||
"intervals.full.minutes": "{number, plural, one {# minute} other {# minutes}}",
|
||||
"introduction.federation.action": "Next",
|
||||
"introduction.federation.federated.headline": "Federated",
|
||||
"introduction.federation.federated.text": "Public posts from other servers of the fediverse will appear in the federated timeline.",
|
||||
"introduction.federation.home.headline": "Home",
|
||||
"introduction.federation.home.text": "Posts from people you follow will appear in your home feed. You can follow anyone on any server!",
|
||||
"introduction.federation.local.headline": "Local",
|
||||
"introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
|
||||
"introduction.interactions.action": "Finish toot-orial!",
|
||||
"introduction.interactions.favourite.headline": "Favourite",
|
||||
"introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
|
||||
"introduction.interactions.reblog.headline": "Boost",
|
||||
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.",
|
||||
"introduction.interactions.reply.headline": "Reply",
|
||||
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
|
||||
"introduction.welcome.action": "Let's go!",
|
||||
"introduction.welcome.headline": "First steps",
|
||||
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
|
||||
"keyboard_shortcuts.back": "to navigate back",
|
||||
"keyboard_shortcuts.blocked": "to open blocked users list",
|
||||
"keyboard_shortcuts.boost": "to boost",
|
||||
"keyboard_shortcuts.column": "to focus a status in one of the columns",
|
||||
"keyboard_shortcuts.compose": "to focus the compose textarea",
|
||||
"keyboard_shortcuts.description": "Description",
|
||||
"keyboard_shortcuts.direct": "to open direct messages column",
|
||||
"keyboard_shortcuts.down": "to move down in the list",
|
||||
"keyboard_shortcuts.enter": "to open status",
|
||||
"keyboard_shortcuts.favourite": "to favourite",
|
||||
"keyboard_shortcuts.favourites": "to open favourites list",
|
||||
"keyboard_shortcuts.federated": "to open federated timeline",
|
||||
"keyboard_shortcuts.heading": "Keyboard Shortcuts",
|
||||
"keyboard_shortcuts.home": "to open home timeline",
|
||||
"keyboard_shortcuts.hotkey": "Hotkey",
|
||||
"keyboard_shortcuts.legend": "to display this legend",
|
||||
"keyboard_shortcuts.local": "to open local timeline",
|
||||
"keyboard_shortcuts.mention": "to mention author",
|
||||
"keyboard_shortcuts.muted": "to open muted users list",
|
||||
"keyboard_shortcuts.my_profile": "to open your profile",
|
||||
"keyboard_shortcuts.notifications": "to open notifications column",
|
||||
"keyboard_shortcuts.pinned": "to open pinned toots list",
|
||||
"keyboard_shortcuts.profile": "to open author's profile",
|
||||
"keyboard_shortcuts.reply": "to reply",
|
||||
"keyboard_shortcuts.requests": "to open follow requests list",
|
||||
"keyboard_shortcuts.search": "to focus search",
|
||||
"keyboard_shortcuts.start": "to open \"get started\" column",
|
||||
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
|
||||
"keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
|
||||
"keyboard_shortcuts.toot": "to start a brand new toot",
|
||||
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
|
||||
"keyboard_shortcuts.up": "to move up in the list",
|
||||
"lightbox.close": "Close",
|
||||
"lightbox.next": "Next",
|
||||
"lightbox.previous": "Previous",
|
||||
"lightbox.view_context": "View context",
|
||||
"lists.account.add": "Add to list",
|
||||
"lists.account.remove": "Remove from list",
|
||||
"lists.delete": "Delete list",
|
||||
"lists.edit": "Edit list",
|
||||
"lists.edit.submit": "Change title",
|
||||
"lists.new.create": "Add list",
|
||||
"lists.new.title_placeholder": "New list title",
|
||||
"lists.search": "Search among people you follow",
|
||||
"lists.subheading": "Your lists",
|
||||
"load_pending": "{count, plural, one {# new item} other {# new items}}",
|
||||
"loading_indicator.label": "Loading...",
|
||||
"media_gallery.toggle_visible": "Toggle visibility",
|
||||
"missing_indicator.label": "Not found",
|
||||
"missing_indicator.sublabel": "This resource could not be found",
|
||||
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||
"navigation_bar.apps": "Mobile apps",
|
||||
"navigation_bar.blocks": "Blocked users",
|
||||
"navigation_bar.community_timeline": "Local timeline",
|
||||
"navigation_bar.compose": "Compose new toot",
|
||||
"navigation_bar.direct": "Direct messages",
|
||||
"navigation_bar.discover": "Discover",
|
||||
"navigation_bar.domain_blocks": "Hidden domains",
|
||||
"navigation_bar.edit_profile": "Edit profile",
|
||||
"navigation_bar.favourites": "Favourites",
|
||||
"navigation_bar.filters": "Muted words",
|
||||
"navigation_bar.follow_requests": "Follow requests",
|
||||
"navigation_bar.follows_and_followers": "Follows and followers",
|
||||
"navigation_bar.info": "About this server",
|
||||
"navigation_bar.keyboard_shortcuts": "Hotkeys",
|
||||
"navigation_bar.lists": "Lists",
|
||||
"navigation_bar.logout": "Logout",
|
||||
"navigation_bar.mutes": "Muted users",
|
||||
"navigation_bar.personal": "Personal",
|
||||
"navigation_bar.pins": "Pinned toots",
|
||||
"navigation_bar.preferences": "Preferences",
|
||||
"navigation_bar.public_timeline": "Federated timeline",
|
||||
"navigation_bar.security": "Security",
|
||||
"notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
|
||||
"notification.favourite": "{name} favourited your status",
|
||||
"notification.follow": "{name} followed you",
|
||||
"notification.mention": "{name} mentioned you",
|
||||
"notification.poll": "A poll you have voted in has ended",
|
||||
"notification.reblog": "{name} boosted your status",
|
||||
"notifications.clear": "Clear notifications",
|
||||
"notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
|
||||
"notifications.column_settings.alert": "Desktop notifications",
|
||||
"notifications.column_settings.favourite": "Favourites:",
|
||||
"notifications.column_settings.filter_bar.advanced": "Display all categories",
|
||||
"notifications.column_settings.filter_bar.category": "Quick filter bar",
|
||||
"notifications.column_settings.filter_bar.show": "Show",
|
||||
"notifications.column_settings.follow": "New followers:",
|
||||
"notifications.column_settings.mention": "Mentions:",
|
||||
"notifications.column_settings.poll": "Poll results:",
|
||||
"notifications.column_settings.push": "Push notifications",
|
||||
"notifications.column_settings.reblog": "Boosts:",
|
||||
"notifications.column_settings.show": "Show in column",
|
||||
"notifications.column_settings.sound": "Play sound",
|
||||
"notifications.filter.all": "All",
|
||||
"notifications.filter.boosts": "Boosts",
|
||||
"notifications.filter.favourites": "Favourites",
|
||||
"notifications.filter.follows": "Follows",
|
||||
"notifications.filter.mentions": "Mentions",
|
||||
"notifications.filter.polls": "Poll results",
|
||||
"notifications.group": "{count} notifications",
|
||||
"poll.closed": "Closed",
|
||||
"poll.refresh": "Refresh",
|
||||
"poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
|
||||
"poll.vote": "Vote",
|
||||
"poll_button.add_poll": "Add a poll",
|
||||
"poll_button.remove_poll": "Remove poll",
|
||||
"privacy.change": "Adjust status privacy",
|
||||
"privacy.direct.long": "Post to mentioned users only",
|
||||
"privacy.direct.short": "Direct",
|
||||
"privacy.private.long": "Post to followers only",
|
||||
"privacy.private.short": "Followers-only",
|
||||
"privacy.public.long": "Post to public timelines",
|
||||
"privacy.public.short": "Public",
|
||||
"privacy.unlisted.long": "Do not show in public timelines",
|
||||
"privacy.unlisted.short": "Unlisted",
|
||||
"regeneration_indicator.label": "Loading…",
|
||||
"regeneration_indicator.sublabel": "Your home feed is being prepared!",
|
||||
"relative_time.days": "{number}d",
|
||||
"relative_time.hours": "{number}h",
|
||||
"relative_time.just_now": "now",
|
||||
"relative_time.minutes": "{number}m",
|
||||
"relative_time.seconds": "{number}s",
|
||||
"reply_indicator.cancel": "Cancel",
|
||||
"report.forward": "Forward to {target}",
|
||||
"report.forward_hint": "The account is from another server. Send an anonymized copy of the report there as well?",
|
||||
"report.hint": "The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:",
|
||||
"report.placeholder": "Additional comments",
|
||||
"report.submit": "Submit",
|
||||
"report.target": "Report {target}",
|
||||
"search.placeholder": "Search",
|
||||
"search_popout.search_format": "Advanced search format",
|
||||
"search_popout.tips.full_text": "Simple text returns statuses you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
|
||||
"search_popout.tips.hashtag": "hashtag",
|
||||
"search_popout.tips.status": "status",
|
||||
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
|
||||
"search_popout.tips.user": "user",
|
||||
"search_results.accounts": "People",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.statuses": "Toots",
|
||||
"search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.",
|
||||
"search_results.total": "{count, number} {count, plural, one {result} other {results}}",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
"status.admin_status": "Open this status in the moderation interface",
|
||||
"status.block": "Block @{name}",
|
||||
"status.cancel_reblog_private": "Unboost",
|
||||
"status.cannot_reblog": "This post cannot be boosted",
|
||||
"status.copy": "Copy link to status",
|
||||
"status.delete": "Delete",
|
||||
"status.detailed_status": "Detailed conversation view",
|
||||
"status.direct": "Direct message @{name}",
|
||||
"status.embed": "Embed",
|
||||
"status.favourite": "Favourite",
|
||||
"status.filtered": "Filtered",
|
||||
"status.load_more": "Load more",
|
||||
"status.media_hidden": "Media hidden",
|
||||
"status.mention": "Mention @{name}",
|
||||
"status.more": "More",
|
||||
"status.mute": "Mute @{name}",
|
||||
"status.mute_conversation": "Mute conversation",
|
||||
"status.open": "Expand this status",
|
||||
"status.pin": "Pin on profile",
|
||||
"status.pinned": "Pinned toot",
|
||||
"status.read_more": "Read more",
|
||||
"status.reblog": "Boost",
|
||||
"status.reblog_private": "Boost to original audience",
|
||||
"status.reblogged_by": "{name} boosted",
|
||||
"status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.",
|
||||
"status.redraft": "Delete & re-draft",
|
||||
"status.reply": "Reply",
|
||||
"status.replyAll": "Reply to thread",
|
||||
"status.report": "Report @{name}",
|
||||
"status.sensitive_warning": "Sensitive content",
|
||||
"status.share": "Share",
|
||||
"status.show_less": "Show less",
|
||||
"status.show_less_all": "Show less for all",
|
||||
"status.show_more": "Show more",
|
||||
"status.show_more_all": "Show more for all",
|
||||
"status.show_thread": "Show thread",
|
||||
"status.uncached_media_warning": "Not available",
|
||||
"status.unmute_conversation": "Unmute conversation",
|
||||
"status.unpin": "Unpin from profile",
|
||||
"suggestions.dismiss": "Dismiss suggestion",
|
||||
"suggestions.header": "You might be interested in…",
|
||||
"tabs_bar.federated_timeline": "Federated",
|
||||
"tabs_bar.home": "Home",
|
||||
"tabs_bar.local_timeline": "Local",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.search": "Search",
|
||||
"time_remaining.days": "{number, plural, one {# day} other {# days}} left",
|
||||
"time_remaining.hours": "{number, plural, one {# hour} other {# hours}} left",
|
||||
"time_remaining.minutes": "{number, plural, one {# minute} other {# minutes}} left",
|
||||
"time_remaining.moments": "Moments remaining",
|
||||
"time_remaining.seconds": "{number, plural, one {# second} other {# seconds}} left",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {person} other {people}} talking",
|
||||
"trends.trending_now": "Trending now",
|
||||
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.",
|
||||
"upload_area.title": "Drag & drop to upload",
|
||||
"upload_button.label": "Add media ({formats})",
|
||||
"upload_error.limit": "File upload limit exceeded.",
|
||||
"upload_error.poll": "File upload not allowed with polls.",
|
||||
"upload_form.description": "Describe for the visually impaired",
|
||||
"upload_form.edit": "Edit",
|
||||
"upload_form.undo": "Delete",
|
||||
"upload_modal.analyzing_picture": "Analyzing picture…",
|
||||
"upload_modal.apply": "Apply",
|
||||
"upload_modal.description_placeholder": "A quick brown fox jumps over the lazy dog",
|
||||
"upload_modal.detect_text": "Detect text from picture",
|
||||
"upload_modal.edit_media": "Edit media",
|
||||
"upload_modal.hint": "Click or drag the circle on the preview to choose the focal point which will always be in view on all thumbnails.",
|
||||
"upload_modal.preview_label": "Preview ({ratio})",
|
||||
"upload_progress.label": "Uploading...",
|
||||
"video.close": "Close video",
|
||||
"video.exit_fullscreen": "Exit full screen",
|
||||
"video.expand": "Expand video",
|
||||
"video.fullscreen": "Full screen",
|
||||
"video.hide": "Hide video",
|
||||
"video.mute": "Mute sound",
|
||||
"video.pause": "Pause",
|
||||
"video.play": "Play",
|
||||
"video.unmute": "Unmute sound"
|
||||
}
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Varsler",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "Felles tidslinje",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tilbake",
|
||||
"column_header.hide_settings": "Gjem innstillinger",
|
||||
"column_header.moveLeft_settings": "Flytt feltet til venstre",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificacions",
|
||||
"column.pins": "Tuts penjats",
|
||||
"column.public": "Flux public global",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tornar",
|
||||
"column_header.hide_settings": "Amagar los paramètres",
|
||||
"column_header.moveLeft_settings": "Desplaçar la colomna a man drecha",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Powiadomienia",
|
||||
"column.pins": "Przypięte wpisy",
|
||||
"column.public": "Globalna oś czasu",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Wróć",
|
||||
"column_header.hide_settings": "Ukryj ustawienia",
|
||||
"column_header.moveLeft_settings": "Przesuń kolumnę w lewo",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificações",
|
||||
"column.pins": "Postagens fixadas",
|
||||
"column.public": "Global",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Voltar",
|
||||
"column_header.hide_settings": "Esconder configurações",
|
||||
"column_header.moveLeft_settings": "Mover coluna para a esquerda",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificações",
|
||||
"column.pins": "Publicações fixas",
|
||||
"column.public": "Cronologia federada",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Voltar",
|
||||
"column_header.hide_settings": "Esconder configurações",
|
||||
"column_header.moveLeft_settings": "Mover coluna para a esquerda",
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notificări",
|
||||
"column.pins": "Postări fixate",
|
||||
"column.public": "Flux global",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Înapoi",
|
||||
"column_header.hide_settings": "Ascunde setările",
|
||||
"column_header.moveLeft_settings": "Mută coloana la stânga",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Уведомления",
|
||||
"column.pins": "Закреплённый пост",
|
||||
"column.public": "Глобальная лента",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Назад",
|
||||
"column_header.hide_settings": "Скрыть настройки",
|
||||
"column_header.moveLeft_settings": "Передвинуть колонку влево",
|
||||
|
@ -260,7 +261,7 @@
|
|||
"navigation_bar.mutes": "Список скрытых пользователей",
|
||||
"navigation_bar.personal": "Личное",
|
||||
"navigation_bar.pins": "Закреплённые посты",
|
||||
"navigation_bar.preferences": "Опции",
|
||||
"navigation_bar.preferences": "Настройки",
|
||||
"navigation_bar.public_timeline": "Глобальная лента",
|
||||
"navigation_bar.security": "Безопасность",
|
||||
"notification.and_n_others": "and {count, plural, one {# other} other {# others}}",
|
||||
|
@ -383,8 +384,8 @@
|
|||
"time_remaining.minutes": "{number, plural, one {осталась # минута} few {осталось # минуты} many {осталось # минут} other {осталось # минут}}",
|
||||
"time_remaining.moments": "остались считанные мгновения",
|
||||
"time_remaining.seconds": "{number, plural, one {осталась # секунду} few {осталось # секунды} many {осталось # секунд} other {осталось # секунд}}",
|
||||
"trends.count_by_accounts": "Популярно у {count} {rawCount, plural, one {человека} few {человек} many {человек} other {человек}}",
|
||||
"trends.trending_now": "Trending now",
|
||||
"trends.count_by_accounts": "{count} {rawCount, plural, one {человек говорит} few {человека говорят} other {человек говорят}} про это",
|
||||
"trends.trending_now": "Самое актуальное",
|
||||
"ui.beforeunload": "Ваш черновик будет утерян, если вы покинете Mastodon.",
|
||||
"upload_area.title": "Перетащите сюда, чтобы загрузить",
|
||||
"upload_button.label": "Добавить медиаконтент",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Oboznámenia",
|
||||
"column.pins": "Pripnuté príspevky",
|
||||
"column.public": "Federovaná časová os",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Späť",
|
||||
"column_header.hide_settings": "Skryť nastavenia",
|
||||
"column_header.moveLeft_settings": "Presuň stĺpec doľava",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Obvestila",
|
||||
"column.pins": "Pripeti tuti",
|
||||
"column.public": "Združena časovnica",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Nazaj",
|
||||
"column_header.hide_settings": "Skrij nastavitve",
|
||||
"column_header.moveLeft_settings": "Premakni stolpec na levo",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Njoftime",
|
||||
"column.pins": "Mesazhe të fiksuar",
|
||||
"column.public": "Rrjedhë kohore e federuar",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Mbrapsht",
|
||||
"column_header.hide_settings": "Fshihi rregullimet",
|
||||
"column_header.moveLeft_settings": "Shpjere shtyllën majtas",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Obaveštenja",
|
||||
"column.pins": "Prikačeni tutovi",
|
||||
"column.public": "Federisana lajna",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Nazad",
|
||||
"column_header.hide_settings": "Sakrij postavke",
|
||||
"column_header.moveLeft_settings": "Pomeri kolonu ulevo",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Обавештења",
|
||||
"column.pins": "Прикачене трубе",
|
||||
"column.public": "Здружена временска линија",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Назад",
|
||||
"column_header.hide_settings": "Сакриј поставке",
|
||||
"column_header.moveLeft_settings": "Помери колону улево",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Meddelanden",
|
||||
"column.pins": "Nålade toots",
|
||||
"column.public": "Förenad tidslinje",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Tillbaka",
|
||||
"column_header.hide_settings": "Dölj inställningar",
|
||||
"column_header.moveLeft_settings": "Flytta kolumnen till vänster",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Notifications",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "கூட்டாட்சி காலக்கெடு",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "ஆதரி",
|
||||
"column_header.hide_settings": "அமைப்புகளை மறை",
|
||||
"column_header.moveLeft_settings": "நெடுவரிசையை இடதுபுறமாக நகர்த்தவும்",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "ప్రకటనలు",
|
||||
"column.pins": "Pinned toot",
|
||||
"column.public": "సమాఖ్య కాలక్రమం",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "వెనక్కి",
|
||||
"column_header.hide_settings": "అమర్పులను దాచిపెట్టు",
|
||||
"column_header.moveLeft_settings": "నిలువు వరుసను ఎడమకి తరలించు",
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"account.follows.empty": "ผู้ใช้นี้ยังไม่ได้ติดตามใคร",
|
||||
"account.follows_you": "ติดตามคุณ",
|
||||
"account.hide_reblogs": "ซ่อนการดันจาก @{name}",
|
||||
"account.last_status": "Last active",
|
||||
"account.last_status": "ใช้งานล่าสุด",
|
||||
"account.link_verified_on": "ตรวจสอบความเป็นเจ้าของของลิงก์นี้เมื่อ {date}",
|
||||
"account.locked_info": "มีการตั้งสถานะความเป็นส่วนตัวของบัญชีนี้เป็นล็อคอยู่ เจ้าของตรวจทานผู้ที่สามารถติดตามเขาด้วยตนเอง",
|
||||
"account.media": "สื่อ",
|
||||
|
@ -25,7 +25,7 @@
|
|||
"account.mute": "ปิดเสียง @{name}",
|
||||
"account.mute_notifications": "ปิดเสียงการแจ้งเตือนจาก @{name}",
|
||||
"account.muted": "ปิดเสียงอยู่",
|
||||
"account.never_active": "Never",
|
||||
"account.never_active": "ไม่เลย",
|
||||
"account.posts": "โพสต์",
|
||||
"account.posts_with_replies": "โพสต์และการตอบกลับ",
|
||||
"account.report": "รายงาน @{name}",
|
||||
|
@ -53,7 +53,7 @@
|
|||
"column.blocks": "ผู้ใช้ที่ปิดกั้นอยู่",
|
||||
"column.community": "เส้นเวลาในเว็บ",
|
||||
"column.direct": "ข้อความโดยตรง",
|
||||
"column.directory": "Browse profiles",
|
||||
"column.directory": "เรียกดูโปรไฟล์",
|
||||
"column.domain_blocks": "โดเมนที่ซ่อนอยู่",
|
||||
"column.favourites": "รายการโปรด",
|
||||
"column.follow_requests": "คำขอติดตาม",
|
||||
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "การแจ้งเตือน",
|
||||
"column.pins": "โพสต์ที่ปักหมุด",
|
||||
"column.public": "เส้นเวลาที่ติดต่อกับภายนอก",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "ย้อนกลับ",
|
||||
"column_header.hide_settings": "ซ่อนการตั้งค่า",
|
||||
"column_header.moveLeft_settings": "ย้ายคอลัมน์ไปทางซ้าย",
|
||||
|
@ -100,8 +101,8 @@
|
|||
"confirmations.delete_list.message": "คุณแน่ใจหรือไม่ว่าต้องการลบรายการนี้อย่างถาวร?",
|
||||
"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.logout.confirm": "Log out",
|
||||
"confirmations.logout.message": "Are you sure you want to log out?",
|
||||
"confirmations.logout.confirm": "ออกจากระบบ",
|
||||
"confirmations.logout.message": "คุณแน่ใจหรือไม่ว่าต้องการออกจากระบบ?",
|
||||
"confirmations.mute.confirm": "ปิดเสียง",
|
||||
"confirmations.mute.message": "คุณแน่ใจหรือไม่ว่าต้องการปิดเสียง {name}?",
|
||||
"confirmations.redraft.confirm": "ลบแล้วร่างใหม่",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Bildirimler",
|
||||
"column.pins": "Sabitlenmiş gönderi",
|
||||
"column.public": "Federe zaman tüneli",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Geri",
|
||||
"column_header.hide_settings": "Ayarları gizle",
|
||||
"column_header.moveLeft_settings": "Sütunu sola taşı",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "Сповіщення",
|
||||
"column.pins": "Закріплені дмухи",
|
||||
"column.public": "Глобальна стрічка",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "Назад",
|
||||
"column_header.hide_settings": "Приховати налаштування",
|
||||
"column_header.moveLeft_settings": "Змістити колонку вліво",
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
|
@ -0,0 +1,2 @@
|
|||
[
|
||||
]
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "通知",
|
||||
"column.pins": "置顶嘟文",
|
||||
"column.public": "跨站公共时间轴",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "返回",
|
||||
"column_header.hide_settings": "隐藏设置",
|
||||
"column_header.moveLeft_settings": "将此栏左移",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "通知",
|
||||
"column.pins": "置頂文章",
|
||||
"column.public": "跨站時間軸",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "返回",
|
||||
"column_header.hide_settings": "隱藏設定",
|
||||
"column_header.moveLeft_settings": "將欄左移",
|
||||
|
|
|
@ -63,6 +63,7 @@
|
|||
"column.notifications": "通知",
|
||||
"column.pins": "釘選的嘟文",
|
||||
"column.public": "聯邦時間軸",
|
||||
"column.status": "Toot",
|
||||
"column_back_button.label": "上一頁",
|
||||
"column_header.hide_settings": "隱藏設定",
|
||||
"column_header.moveLeft_settings": "將欄位向左移動",
|
||||
|
|
|
@ -35,12 +35,12 @@ const notificationToMap = notification => ImmutableMap({
|
|||
});
|
||||
|
||||
const normalizeNotification = (state, notification, usePendingItems) => {
|
||||
if (usePendingItems) {
|
||||
return state.update('pendingItems', list => list.unshift(notificationToMap(notification)));
|
||||
}
|
||||
|
||||
const top = state.get('top');
|
||||
|
||||
if (usePendingItems || !top || !state.get('pendingItems').isEmpty()) {
|
||||
return state.update('pendingItems', list => list.unshift(notificationToMap(notification))).update('unread', unread => unread + 1);
|
||||
}
|
||||
|
||||
if (!top) {
|
||||
state = state.update('unread', unread => unread + 1);
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ const normalizeNotification = (state, notification, usePendingItems) => {
|
|||
});
|
||||
};
|
||||
|
||||
const expandNormalizedNotifications = (state, notifications, next, usePendingItems) => {
|
||||
const expandNormalizedNotifications = (state, notifications, next, isLoadingRecent, usePendingItems) => {
|
||||
let items = ImmutableList();
|
||||
|
||||
notifications.forEach((n, i) => {
|
||||
|
@ -63,6 +63,8 @@ const expandNormalizedNotifications = (state, notifications, next, usePendingIte
|
|||
|
||||
return state.withMutations(mutable => {
|
||||
if (!items.isEmpty()) {
|
||||
usePendingItems = isLoadingRecent && (usePendingItems || !mutable.get('top') || !mutable.get('pendingItems').isEmpty());
|
||||
|
||||
mutable.update(usePendingItems ? 'pendingItems' : 'items', list => {
|
||||
const lastIndex = 1 + list.findLastIndex(
|
||||
item => item !== null && (compareId(item.get('id'), items.last().get('id')) > 0 || item.get('id') === items.last().get('id'))
|
||||
|
@ -91,7 +93,7 @@ const filterNotifications = (state, accountIds) => {
|
|||
|
||||
const updateTop = (state, top) => {
|
||||
if (top) {
|
||||
state = state.set('unread', 0);
|
||||
state = state.set('unread', state.get('pendingItems').size);
|
||||
}
|
||||
|
||||
return state.set('top', top);
|
||||
|
@ -117,7 +119,7 @@ export default function notifications(state = initialState, action) {
|
|||
case NOTIFICATIONS_UPDATE:
|
||||
return normalizeNotification(state, action.notification, action.usePendingItems);
|
||||
case NOTIFICATIONS_EXPAND_SUCCESS:
|
||||
return expandNormalizedNotifications(state, action.notifications, action.next, action.usePendingItems);
|
||||
return expandNormalizedNotifications(state, action.notifications, action.next, action.isLoadingRecent, action.usePendingItems);
|
||||
case ACCOUNT_BLOCK_SUCCESS:
|
||||
return filterNotifications(state, [action.relationship.id]);
|
||||
case ACCOUNT_MUTE_SUCCESS:
|
||||
|
|
|
@ -40,6 +40,7 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
|
|||
if (timeline.endsWith(':pinned')) {
|
||||
mMap.set('items', statuses.map(status => status.get('id')));
|
||||
} else if (!statuses.isEmpty()) {
|
||||
usePendingItems = isLoadingRecent && (usePendingItems || !mMap.get('top') || !mMap.get('pendingItems').isEmpty());
|
||||
mMap.update(usePendingItems ? 'pendingItems' : 'items', ImmutableList(), oldIds => {
|
||||
const newIds = statuses.map(status => status.get('id'));
|
||||
|
||||
|
@ -60,15 +61,16 @@ const expandNormalizedTimeline = (state, timeline, statuses, next, isPartial, is
|
|||
};
|
||||
|
||||
const updateTimeline = (state, timeline, status, usePendingItems) => {
|
||||
if (usePendingItems) {
|
||||
const top = state.getIn([timeline, 'top']);
|
||||
|
||||
if (usePendingItems || !top || !state.getIn([timeline, 'pendingItems']).isEmpty()) {
|
||||
if (state.getIn([timeline, 'pendingItems'], ImmutableList()).includes(status.get('id')) || state.getIn([timeline, 'items'], ImmutableList()).includes(status.get('id'))) {
|
||||
return state;
|
||||
}
|
||||
|
||||
return state.update(timeline, initialTimeline, map => map.update('pendingItems', list => list.unshift(status.get('id'))));
|
||||
return state.update(timeline, initialTimeline, map => map.update('pendingItems', list => list.unshift(status.get('id'))).update('unread', unread => unread + 1));
|
||||
}
|
||||
|
||||
const top = state.getIn([timeline, 'top']);
|
||||
const ids = state.getIn([timeline, 'items'], ImmutableList());
|
||||
const includesId = ids.includes(status.get('id'));
|
||||
const unread = state.getIn([timeline, 'unread'], 0);
|
||||
|
@ -128,7 +130,7 @@ const filterTimeline = (timeline, state, relationship, statuses) => {
|
|||
|
||||
const updateTop = (state, timeline, top) => {
|
||||
return state.update(timeline, initialTimeline, map => map.withMutations(mMap => {
|
||||
if (top) mMap.set('unread', 0);
|
||||
if (top) mMap.set('unread', mMap.get('pendingItems').size);
|
||||
mMap.set('top', top);
|
||||
}));
|
||||
};
|
||||
|
|
|
@ -14,10 +14,10 @@ function main() {
|
|||
const React = require('react');
|
||||
const ReactDOM = require('react-dom');
|
||||
const Rellax = require('rellax');
|
||||
const createHistory = require('history').createBrowserHistory;
|
||||
const { createBrowserHistory } = require('history');
|
||||
|
||||
const scrollToDetailedStatus = () => {
|
||||
const history = createHistory();
|
||||
const history = createBrowserHistory();
|
||||
const detailedStatuses = document.querySelectorAll('.public-layout .detailed-status');
|
||||
const location = history.location;
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@
|
|||
}
|
||||
|
||||
.account__header__fields {
|
||||
max-width: 100vw;
|
||||
padding: 0;
|
||||
margin: 15px -15px -15px;
|
||||
border: 0 none;
|
||||
|
|
|
@ -79,6 +79,9 @@
|
|||
top: -1px;
|
||||
border-radius: 50%;
|
||||
vertical-align: middle;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
flex: 0 0 18px;
|
||||
|
||||
&.checkbox {
|
||||
border-radius: 4px;
|
||||
|
|
|
@ -408,15 +408,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
|
|||
end
|
||||
|
||||
def check_for_spam
|
||||
spam_check = SpamCheck.new(@status)
|
||||
|
||||
return if spam_check.skip?
|
||||
|
||||
if spam_check.spam?
|
||||
spam_check.flag!
|
||||
else
|
||||
spam_check.remember!
|
||||
end
|
||||
SpamCheck.perform(@status)
|
||||
end
|
||||
|
||||
def forward_for_reply
|
||||
|
|
|
@ -10,10 +10,13 @@ class ActivityPub::Activity::Move < ActivityPub::Activity
|
|||
|
||||
target_account = ActivityPub::FetchRemoteAccountService.new.call(target_uri)
|
||||
|
||||
return if target_account.nil? || !target_account.also_known_as.include?(origin_account.uri)
|
||||
if target_account.nil? || target_account.suspended? || !target_account.also_known_as.include?(origin_account.uri)
|
||||
unmark_as_processing!
|
||||
return
|
||||
end
|
||||
|
||||
# In case for some reason we didn't have a redirect for the profile already, set it
|
||||
origin_account.update(moved_to_account: target_account) if origin_account.moved_to_account_id.nil?
|
||||
origin_account.update(moved_to_account: target_account)
|
||||
|
||||
# Initiate a re-follow for each follower
|
||||
origin_account.followers.local.select(:id).find_in_batches do |follower_accounts|
|
||||
|
@ -40,4 +43,8 @@ class ActivityPub::Activity::Move < ActivityPub::Activity
|
|||
def mark_as_processing!
|
||||
redis.setex("move_in_progress:#{@account.id}", PROCESSING_COOLDOWN, true)
|
||||
end
|
||||
|
||||
def unmark_as_processing!
|
||||
redis.del("move_in_progress:#{@account.id}")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,10 +4,26 @@ class SpamCheck
|
|||
include Redisable
|
||||
include ActionView::Helpers::TextHelper
|
||||
|
||||
# Threshold over which two Nilsimsa values are considered
|
||||
# to refer to the same text
|
||||
NILSIMSA_COMPARE_THRESHOLD = 95
|
||||
|
||||
# Nilsimsa doesn't work well on small inputs, so below
|
||||
# this size, we check only for exact matches with MD5
|
||||
NILSIMSA_MIN_SIZE = 10
|
||||
|
||||
# How long to keep the trail of digests between updates,
|
||||
# there is no reason to store it forever
|
||||
EXPIRE_SET_AFTER = 1.week.seconds
|
||||
|
||||
# How many digests to keep in an account's trail. If it's
|
||||
# too small, spam could rotate around different message templates
|
||||
MAX_TRAIL_SIZE = 10
|
||||
|
||||
# How many detected duplicates to allow through before
|
||||
# considering the message as spam
|
||||
THRESHOLD = 5
|
||||
|
||||
def initialize(status)
|
||||
@account = status.account
|
||||
@status = status
|
||||
|
@ -21,9 +37,9 @@ class SpamCheck
|
|||
if insufficient_data?
|
||||
false
|
||||
elsif nilsimsa?
|
||||
any_other_digest?('nilsimsa') { |_, other_digest| nilsimsa_compare_value(digest, other_digest) >= NILSIMSA_COMPARE_THRESHOLD }
|
||||
digests_over_threshold?('nilsimsa') { |_, other_digest| nilsimsa_compare_value(digest, other_digest) >= NILSIMSA_COMPARE_THRESHOLD }
|
||||
else
|
||||
any_other_digest?('md5') { |_, other_digest| other_digest == digest }
|
||||
digests_over_threshold?('md5') { |_, other_digest| other_digest == digest }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,7 +54,7 @@ class SpamCheck
|
|||
# get the correct status ID back, we have to save it in the string value
|
||||
|
||||
redis.zadd(redis_key, @status.id, digest_with_algorithm)
|
||||
redis.zremrangebyrank(redis_key, '0', '-10')
|
||||
redis.zremrangebyrank(redis_key, 0, -(MAX_TRAIL_SIZE + 1))
|
||||
redis.expire(redis_key, EXPIRE_SET_AFTER)
|
||||
end
|
||||
|
||||
|
@ -78,6 +94,20 @@ class SpamCheck
|
|||
end
|
||||
end
|
||||
|
||||
class << self
|
||||
def perform(status)
|
||||
spam_check = new(status)
|
||||
|
||||
return if spam_check.skip?
|
||||
|
||||
if spam_check.spam?
|
||||
spam_check.flag!
|
||||
else
|
||||
spam_check.remember!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def disabled?
|
||||
|
@ -149,14 +179,14 @@ class SpamCheck
|
|||
redis.zrange(redis_key, 0, -1)
|
||||
end
|
||||
|
||||
def any_other_digest?(filter_algorithm)
|
||||
other_digests.any? do |record|
|
||||
def digests_over_threshold?(filter_algorithm)
|
||||
other_digests.select do |record|
|
||||
algorithm, other_digest, status_id = record.split(':')
|
||||
|
||||
next unless algorithm == filter_algorithm
|
||||
|
||||
yield algorithm, other_digest, status_id
|
||||
end
|
||||
end.size >= THRESHOLD
|
||||
end
|
||||
|
||||
def matching_status_ids
|
||||
|
|
|
@ -4,7 +4,7 @@ module Omniauthable
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
TEMP_EMAIL_PREFIX = 'change@me'
|
||||
TEMP_EMAIL_REGEX = /\Achange@me/
|
||||
TEMP_EMAIL_REGEX = /\A#{TEMP_EMAIL_PREFIX}/.freeze
|
||||
|
||||
included do
|
||||
devise :omniauthable
|
||||
|
@ -29,7 +29,7 @@ module Omniauthable
|
|||
# Note that this may leave zombie accounts (with no associated identity) which
|
||||
# can be cleaned up at a later date.
|
||||
user = signed_in_resource || identity.user
|
||||
user = create_for_oauth(auth) if user.nil?
|
||||
user ||= create_for_oauth(auth)
|
||||
|
||||
if identity.user.nil?
|
||||
identity.user = user
|
||||
|
@ -45,7 +45,18 @@ module Omniauthable
|
|||
# exists, we assign a temporary email and ask the user to verify it on
|
||||
# the next step via Auth::SetupController.show
|
||||
|
||||
user = User.new(user_params_from_auth(auth))
|
||||
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
|
||||
assume_verified = strategy&.security&.assume_email_is_verified
|
||||
email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified
|
||||
email = auth.info.verified_email || auth.info.email
|
||||
email = nil unless email_is_verified
|
||||
|
||||
user = User.find_by(email: email) if email_is_verified
|
||||
|
||||
return user unless user.nil?
|
||||
|
||||
user = User.new(user_params_from_auth(email, auth))
|
||||
|
||||
user.account.avatar_remote_url = auth.info.image if auth.info.image =~ /\A#{URI.regexp(%w(http https))}\z/
|
||||
user.skip_confirmation!
|
||||
user.save!
|
||||
|
@ -54,14 +65,7 @@ module Omniauthable
|
|||
|
||||
private
|
||||
|
||||
def user_params_from_auth(auth)
|
||||
strategy = Devise.omniauth_configs[auth.provider.to_sym].strategy
|
||||
assume_verified = strategy.try(:security).try(:assume_email_is_verified)
|
||||
email_is_verified = auth.info.verified || auth.info.verified_email || assume_verified
|
||||
email = auth.info.verified_email || auth.info.email
|
||||
email = email_is_verified && !User.exists?(email: auth.info.email) && email
|
||||
display_name = auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' ')
|
||||
|
||||
def user_params_from_auth(email, auth)
|
||||
{
|
||||
email: email || "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
|
||||
password: Devise.friendly_token[0, 20],
|
||||
|
@ -69,7 +73,7 @@ module Omniauthable
|
|||
external: true,
|
||||
account_attributes: {
|
||||
username: ensure_unique_username(auth.uid),
|
||||
display_name: display_name,
|
||||
display_name: auth.info.full_name || [auth.info.first_name, auth.info.last_name].join(' '),
|
||||
},
|
||||
}
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ class CustomEmoji < ApplicationRecord
|
|||
def copy!
|
||||
copy = self.class.find_or_initialize_by(domain: nil, shortcode: shortcode)
|
||||
copy.image = image
|
||||
copy.save!
|
||||
copy.tap(&:save!)
|
||||
end
|
||||
|
||||
class << self
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
class Form::DeleteConfirmation
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :password
|
||||
attr_accessor :password, :username
|
||||
end
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
class Form::TwoFactorConfirmation
|
||||
include ActiveModel::Model
|
||||
|
||||
attr_accessor :code
|
||||
attr_accessor :otp_attempt
|
||||
end
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
class Tag < ApplicationRecord
|
||||
has_and_belongs_to_many :statuses
|
||||
has_and_belongs_to_many :accounts
|
||||
has_and_belongs_to_many :sample_accounts, -> { searchable.discoverable.popular.limit(3) }, class_name: 'Account'
|
||||
has_and_belongs_to_many :sample_accounts, -> { local.discoverable.popular.limit(3) }, class_name: 'Account'
|
||||
|
||||
has_many :featured_tags, dependent: :destroy, inverse_of: :tag
|
||||
has_one :account_tag_stat, dependent: :destroy
|
||||
|
@ -39,6 +39,7 @@ class Tag < ApplicationRecord
|
|||
scope :listable, -> { where(listable: [true, nil]) }
|
||||
scope :discoverable, -> { listable.joins(:account_tag_stat).where(AccountTagStat.arel_table[:accounts_count].gt(0)).order(Arel.sql('account_tag_stats.accounts_count desc')) }
|
||||
scope :most_used, ->(account) { joins(:statuses).where(statuses: { account: account }).group(:id).order(Arel.sql('count(*) desc')) }
|
||||
scope :matches_name, ->(value) { where(arel_table[:name].matches("#{value}%")) }
|
||||
|
||||
delegate :accounts_count,
|
||||
:accounts_count=,
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TagFilter
|
||||
attr_reader :params
|
||||
|
||||
def initialize(params)
|
||||
@params = params
|
||||
end
|
||||
|
||||
def results
|
||||
scope = Tag.unscoped
|
||||
|
||||
params.each do |key, value|
|
||||
next if key.to_s == 'page'
|
||||
|
||||
scope.merge!(scope_for(key, value.to_s.strip)) if value.present?
|
||||
end
|
||||
|
||||
scope.order(id: :desc)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scope_for(key, value)
|
||||
case key.to_s
|
||||
when 'directory'
|
||||
Tag.discoverable
|
||||
when 'reviewed'
|
||||
Tag.reviewed.order(reviewed_at: :desc)
|
||||
when 'unreviewed'
|
||||
Tag.unreviewed
|
||||
when 'pending_review'
|
||||
Tag.pending_review.order(requested_review_at: :desc)
|
||||
when 'popular'
|
||||
Tag.order('max_score DESC NULLS LAST')
|
||||
when 'active'
|
||||
Tag.order('last_status_at DESC NULLS LAST')
|
||||
when 'name'
|
||||
Tag.matches_name(value)
|
||||
else
|
||||
raise "Unknown filter: #{key}"
|
||||
end
|
||||
end
|
||||
end
|
|
@ -33,7 +33,7 @@ class InstancePresenter
|
|||
end
|
||||
|
||||
def sample_accounts
|
||||
Rails.cache.fetch('sample_accounts', expires_in: 12.hours) { Account.discoverable.popular.limit(3) }
|
||||
Rails.cache.fetch('sample_accounts', expires_in: 12.hours) { Account.local.discoverable.popular.limit(3) }
|
||||
end
|
||||
|
||||
def version_number
|
||||
|
|
|
@ -33,6 +33,7 @@ class ProcessMentionsService < BaseService
|
|||
end
|
||||
|
||||
status.save!
|
||||
check_for_spam(status)
|
||||
|
||||
mentions.each { |mention| create_notification(mention) }
|
||||
end
|
||||
|
@ -61,4 +62,8 @@ class ProcessMentionsService < BaseService
|
|||
def resolve_account_service
|
||||
ResolveAccountService.new
|
||||
end
|
||||
|
||||
def check_for_spam(status)
|
||||
SpamCheck.perform(status)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,9 +6,12 @@ class UnfollowService < BaseService
|
|||
# Unfollow and notify the remote user
|
||||
# @param [Account] source_account Where to unfollow from
|
||||
# @param [Account] target_account Which to unfollow
|
||||
def call(source_account, target_account)
|
||||
# @param [Hash] options
|
||||
# @option [Boolean] :skip_unmerge
|
||||
def call(source_account, target_account, options = {})
|
||||
@source_account = source_account
|
||||
@target_account = target_account
|
||||
@options = options
|
||||
|
||||
unfollow! || undo_follow_request!
|
||||
end
|
||||
|
@ -21,9 +24,11 @@ class UnfollowService < BaseService
|
|||
return unless follow
|
||||
|
||||
follow.destroy!
|
||||
|
||||
create_notification(follow) if !@target_account.local? && @target_account.activitypub?
|
||||
create_reject_notification(follow) if @target_account.local? && !@source_account.local? && @source_account.activitypub?
|
||||
UnmergeWorker.perform_async(@target_account.id, @source_account.id)
|
||||
UnmergeWorker.perform_async(@target_account.id, @source_account.id) unless @options[:skip_unmerge]
|
||||
|
||||
follow
|
||||
end
|
||||
|
||||
|
@ -33,7 +38,9 @@ class UnfollowService < BaseService
|
|||
return unless follow_request
|
||||
|
||||
follow_request.destroy!
|
||||
|
||||
create_notification(follow_request) unless @target_account.local?
|
||||
|
||||
follow_request
|
||||
end
|
||||
|
||||
|
|
|
@ -4,35 +4,35 @@
|
|||
.dashboard__counters
|
||||
%div
|
||||
= link_to admin_accounts_url(local: 1, recent: 1) do
|
||||
.dashboard__counters__num= number_with_delimiter @users_count
|
||||
.dashboard__counters__num= number_to_human @users_count, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.total_users'
|
||||
%div
|
||||
%div
|
||||
.dashboard__counters__num= number_with_delimiter @registrations_week
|
||||
.dashboard__counters__num= number_to_human @registrations_week, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.week_users_new'
|
||||
%div
|
||||
%div
|
||||
.dashboard__counters__num= number_with_delimiter @logins_week
|
||||
.dashboard__counters__num= number_to_human @logins_week, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.week_users_active'
|
||||
%div
|
||||
= link_to admin_pending_accounts_path do
|
||||
.dashboard__counters__num= number_with_delimiter @pending_users_count
|
||||
.dashboard__counters__num= number_to_human @pending_users_count, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.pending_users'
|
||||
%div
|
||||
= link_to admin_reports_url do
|
||||
.dashboard__counters__num= number_with_delimiter @reports_count
|
||||
.dashboard__counters__num= number_to_human @reports_count, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.open_reports'
|
||||
%div
|
||||
= link_to admin_tags_path(review: 'pending_review') do
|
||||
.dashboard__counters__num= number_with_delimiter @pending_tags_count
|
||||
= link_to admin_tags_path(pending_review: '1') do
|
||||
.dashboard__counters__num= number_to_human @pending_tags_count, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.pending_tags'
|
||||
%div
|
||||
%div
|
||||
.dashboard__counters__num= number_with_delimiter @interactions_week
|
||||
.dashboard__counters__num= number_to_human @interactions_week, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.week_interactions'
|
||||
%div
|
||||
= link_to sidekiq_url do
|
||||
.dashboard__counters__num= number_with_delimiter @queue_backlog
|
||||
.dashboard__counters__num= number_to_human @queue_backlog, strip_insignificant_zeros: true
|
||||
.dashboard__counters__label= t 'admin.dashboard.backlog'
|
||||
|
||||
.dashboard__widgets
|
||||
|
|
|
@ -5,16 +5,36 @@
|
|||
.filter-subset
|
||||
%strong= t('admin.tags.context')
|
||||
%ul
|
||||
%li= filter_link_to t('generic.all'), context: nil
|
||||
%li= filter_link_to t('admin.tags.directory'), context: 'directory'
|
||||
%li= filter_link_to t('generic.all'), directory: nil
|
||||
%li= filter_link_to t('admin.tags.directory'), directory: '1'
|
||||
|
||||
.filter-subset
|
||||
%strong= t('admin.tags.review')
|
||||
%ul
|
||||
%li= filter_link_to t('generic.all'), review: nil
|
||||
%li= filter_link_to t('admin.tags.unreviewed'), review: 'unreviewed'
|
||||
%li= filter_link_to t('admin.tags.reviewed'), review: 'reviewed'
|
||||
%li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), review: 'pending_review'
|
||||
%li= filter_link_to t('generic.all'), reviewed: nil, unreviewed: nil, pending_review: nil
|
||||
%li= filter_link_to t('admin.tags.unreviewed'), unreviewed: '1', reviewed: nil, pending_review: nil
|
||||
%li= filter_link_to t('admin.tags.reviewed'), reviewed: '1', unreviewed: nil, pending_review: nil
|
||||
%li= filter_link_to safe_join([t('admin.accounts.moderation.pending'), "(#{Tag.pending_review.count})"], ' '), pending_review: '1', reviewed: nil, unreviewed: nil
|
||||
|
||||
.filter-subset
|
||||
%strong= t('generic.order_by')
|
||||
%ul
|
||||
%li= filter_link_to t('admin.tags.most_recent'), popular: nil, active: nil
|
||||
%li= filter_link_to t('admin.tags.most_popular'), popular: '1', active: nil
|
||||
%li= filter_link_to t('admin.tags.last_active'), active: '1', popular: nil
|
||||
|
||||
= form_tag admin_tags_url, method: 'GET', class: 'simple_form' do
|
||||
.fields-group
|
||||
- Admin::FilterHelper::TAGS_FILTERS.each do |key|
|
||||
= hidden_field_tag key, params[key] if params[key].present?
|
||||
|
||||
- %i(name).each do |key|
|
||||
.input.string.optional
|
||||
= text_field_tag key, params[key], class: 'string optional', placeholder: I18n.t("admin.tags.#{key}")
|
||||
|
||||
.actions
|
||||
%button= t('admin.accounts.search')
|
||||
= link_to t('admin.accounts.reset'), admin_tags_path, class: 'button negative'
|
||||
|
||||
%hr.spacer/
|
||||
|
||||
|
@ -43,7 +63,7 @@
|
|||
|
||||
= paginate @tags
|
||||
|
||||
- if params[:review] == 'pending_review'
|
||||
- if params[:pending_review] == '1'
|
||||
%hr.spacer/
|
||||
|
||||
%div{ style: 'overflow: hidden' }
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
.dashboard__counters
|
||||
%div
|
||||
= link_to web_url("timelines/tag/#{@tag.name}") do
|
||||
= link_to tag_url(@tag), target: '_blank', rel: 'noopener' do
|
||||
.dashboard__counters__num= number_with_delimiter @accounts_today
|
||||
.dashboard__counters__label= t 'admin.tags.accounts_today'
|
||||
%div
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue