Merge remote-tracking branch 'glitch/main'

pull/59/head
kouhai dev 2023-04-23 23:23:28 -07:00
commit e7ef14a4d7
132 changed files with 1184 additions and 590 deletions

View File

@ -9,6 +9,8 @@ on:
- '.nvmrc' - '.nvmrc'
- '**/*.js' - '**/*.js'
- '**/*.jsx' - '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.snap' - '**/*.snap'
- '.github/workflows/test-js.yml' - '.github/workflows/test-js.yml'
@ -19,6 +21,8 @@ on:
- '.nvmrc' - '.nvmrc'
- '**/*.js' - '**/*.js'
- '**/*.jsx' - '**/*.jsx'
- '**/*.ts'
- '**/*.tsx'
- '**/*.snap' - '**/*.snap'
- '.github/workflows/test-js.yml' - '.github/workflows/test-js.yml'

View File

@ -120,7 +120,7 @@ end
group :test do group :test do
gem 'capybara', '~> 3.39' gem 'capybara', '~> 3.39'
gem 'climate_control' gem 'climate_control'
gem 'faker', '~> 3.1' gem 'faker', '~> 3.2'
gem 'json-schema', '~> 3.0' gem 'json-schema', '~> 3.0'
gem 'rack-test', '~> 2.1' gem 'rack-test', '~> 2.1'
gem 'rails-controller-testing', '~> 1.0' gem 'rails-controller-testing', '~> 1.0'

View File

@ -243,7 +243,7 @@ GEM
tzinfo tzinfo
excon (0.95.0) excon (0.95.0)
fabrication (2.30.0) fabrication (2.30.0)
faker (3.1.1) faker (3.2.0)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
faraday (1.10.3) faraday (1.10.3)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
@ -349,19 +349,19 @@ GEM
ipaddress (0.8.3) ipaddress (0.8.3)
jmespath (1.6.2) jmespath (1.6.2)
json (2.6.3) json (2.6.3)
json-canonicalization (0.3.0) json-canonicalization (0.3.1)
json-jwt (1.15.3) json-jwt (1.15.3)
activesupport (>= 4.2) activesupport (>= 4.2)
aes_key_wrap aes_key_wrap
bindata bindata
httpclient httpclient
json-ld (3.2.3) json-ld (3.2.4)
htmlentities (~> 4.3) htmlentities (~> 4.3)
json-canonicalization (~> 0.3) json-canonicalization (~> 0.3)
link_header (~> 0.0, >= 0.0.8) link_header (~> 0.0, >= 0.0.8)
multi_json (~> 1.15) multi_json (~> 1.15)
rack (~> 2.2) rack (>= 2.2, < 4)
rdf (~> 3.2, >= 3.2.9) rdf (~> 3.2, >= 3.2.10)
json-ld-preloaded (3.2.2) json-ld-preloaded (3.2.2)
json-ld (~> 3.2) json-ld (~> 3.2)
rdf (~> 3.2) rdf (~> 3.2)
@ -480,7 +480,7 @@ GEM
openssl-signature_algorithm (1.3.0) openssl-signature_algorithm (1.3.0)
openssl (> 2.0) openssl (> 2.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
ox (2.14.14) ox (2.14.16)
parallel (1.22.1) parallel (1.22.1)
parser (3.2.2.0) parser (3.2.2.0)
ast (~> 2.4.1) ast (~> 2.4.1)
@ -488,7 +488,7 @@ GEM
pastel (0.8.0) pastel (0.8.0)
tty-color (~> 0.5) tty-color (~> 0.5)
pg (1.4.6) pg (1.4.6)
pghero (3.3.1) pghero (3.3.2)
activerecord (>= 6) activerecord (>= 6)
pkg-config (1.5.1) pkg-config (1.5.1)
posix-spawn (0.3.15) posix-spawn (0.3.15)
@ -558,7 +558,7 @@ GEM
thor (~> 1.0) thor (~> 1.0)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.0.6) rake (13.0.6)
rdf (3.2.9) rdf (3.2.10)
link_header (~> 0.0, >= 0.0.8) link_header (~> 0.0, >= 0.0.8)
rdf-normalize (0.5.1) rdf-normalize (0.5.1)
rdf (~> 3.2) rdf (~> 3.2)
@ -800,7 +800,7 @@ DEPENDENCIES
dotenv-rails (~> 2.8) dotenv-rails (~> 2.8)
ed25519 (~> 1.3) ed25519 (~> 1.3)
fabrication (~> 2.30) fabrication (~> 2.30)
faker (~> 3.1) faker (~> 3.2)
fast_blank (~> 1.0) fast_blank (~> 1.0)
fastimage fastimage
fog-core (<= 2.4.0) fog-core (<= 2.4.0)

View File

@ -0,0 +1,72 @@
# frozen_string_literal: true
class Api::V1::Admin::Trends::Links::PreviewCardProvidersController < Api::BaseController
include Authorization
LIMIT = 100
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
before_action :set_providers, only: :index
after_action :verify_authorized
after_action :insert_pagination_headers, only: :index
PAGINATION_PARAMS = %i(limit).freeze
def index
authorize :preview_card_provider, :index?
render json: @providers, each_serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
end
def approve
authorize :preview_card_provider, :review?
provider = PreviewCardProvider.find(params[:id])
provider.update(trendable: true, reviewed_at: Time.now.utc)
render json: provider, serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
end
def reject
authorize :preview_card_provider, :review?
provider = PreviewCardProvider.find(params[:id])
provider.update(trendable: false, reviewed_at: Time.now.utc)
render json: provider, serializer: REST::Admin::Trends::Links::PreviewCardProviderSerializer
end
private
def set_providers
@providers = PreviewCardProvider.all.to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
end
def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
def next_path
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(max_id: pagination_max_id)) if records_continue?
end
def prev_path
api_v1_admin_trends_links_preview_card_providers_url(pagination_params(min_id: pagination_since_id)) unless @providers.empty?
end
def pagination_max_id
@providers.last.id
end
def pagination_since_id
@providers.first.id
end
def records_continue?
@providers.size == limit_param(LIMIT)
end
def pagination_params(core_params)
params.slice(*PAGINATION_PARAMS).permit(*PAGINATION_PARAMS).merge(core_params)
end
end

View File

@ -1,7 +1,36 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Admin::Trends::LinksController < Api::V1::Trends::LinksController class Api::V1::Admin::Trends::LinksController < Api::V1::Trends::LinksController
before_action -> { authorize_if_got_token! :'admin:read' } include Authorization
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
after_action :verify_authorized, except: :index
def index
if current_user&.can?(:manage_taxonomies)
render json: @links, each_serializer: REST::Admin::Trends::LinkSerializer
else
super
end
end
def approve
authorize :preview_card, :review?
link = PreviewCard.find(params[:id])
link.update(trendable: true)
render json: link, serializer: REST::Admin::Trends::LinkSerializer
end
def reject
authorize :preview_card, :review?
link = PreviewCard.find(params[:id])
link.update(trendable: false)
render json: link, serializer: REST::Admin::Trends::LinkSerializer
end
private private

View File

@ -1,7 +1,36 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Admin::Trends::StatusesController < Api::V1::Trends::StatusesController class Api::V1::Admin::Trends::StatusesController < Api::V1::Trends::StatusesController
before_action -> { authorize_if_got_token! :'admin:read' } include Authorization
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
after_action :verify_authorized, except: :index
def index
if current_user&.can?(:manage_taxonomies)
render json: @statuses, each_serializer: REST::Admin::Trends::StatusSerializer
else
super
end
end
def approve
authorize [:admin, :status], :review?
status = Status.find(params[:id])
status.update(trendable: true)
render json: status, serializer: REST::Admin::Trends::StatusSerializer
end
def reject
authorize [:admin, :status], :review?
status = Status.find(params[:id])
status.update(trendable: false)
render json: status, serializer: REST::Admin::Trends::StatusSerializer
end
private private

View File

@ -1,7 +1,12 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
before_action -> { authorize_if_got_token! :'admin:read' } include Authorization
before_action -> { authorize_if_got_token! :'admin:read' }, only: :index
before_action -> { authorize_if_got_token! :'admin:write' }, except: :index
after_action :verify_authorized, except: :index
def index def index
if current_user&.can?(:manage_taxonomies) if current_user&.can?(:manage_taxonomies)
@ -11,6 +16,22 @@ class Api::V1::Admin::Trends::TagsController < Api::V1::Trends::TagsController
end end
end end
def approve
authorize :tag, :review?
tag = Tag.find(params[:id])
tag.update(trendable: true, reviewed_at: Time.now.utc)
render json: tag, serializer: REST::Admin::TagSerializer
end
def reject
authorize :tag, :review?
tag = Tag.find(params[:id])
tag.update(trendable: false, reviewed_at: Time.now.utc)
render json: tag, serializer: REST::Admin::TagSerializer
end
private private
def enabled? def enabled?

View File

@ -11,15 +11,7 @@ class Auth::SetupController < ApplicationController
skip_before_action :require_functional! skip_before_action :require_functional!
def show def show; end
flash.now[:notice] = begin
if @user.pending?
I18n.t('devise.registrations.signed_up_but_pending')
else
I18n.t('devise.registrations.signed_up_but_unconfirmed')
end
end
end
def update def update
# This allows updating the e-mail without entering a password as is required # This allows updating the e-mail without entering a password as is required
@ -27,14 +19,13 @@ class Auth::SetupController < ApplicationController
# that were not confirmed yet # that were not confirmed yet
if @user.update(user_params) if @user.update(user_params)
redirect_to auth_setup_path, notice: I18n.t('devise.confirmations.send_instructions') @user.resend_confirmation_instructions unless @user.confirmed?
redirect_to auth_setup_path, notice: I18n.t('auth.setup.new_confirmation_instructions_sent')
else else
render :show render :show
end end
end end
helper_method :missing_email?
private private
def require_unconfirmed_or_pending! def require_unconfirmed_or_pending!
@ -53,10 +44,6 @@ class Auth::SetupController < ApplicationController
params.require(:user).permit(:email) params.require(:user).permit(:email)
end end
def missing_email?
truthy_param?(:missing_email)
end
def set_pack def set_pack
use_pack 'auth' use_pack 'auth'
end end

View File

@ -117,6 +117,10 @@ module ApplicationHelper
content_tag(:i, nil, attributes.merge(class: class_names.join(' '))) content_tag(:i, nil, attributes.merge(class: class_names.join(' ')))
end end
def check_icon
content_tag(:svg, tag(:path, 'fill-rule': 'evenodd', 'clip-rule': 'evenodd', d: 'M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'), xmlns: 'http://www.w3.org/2000/svg', viewBox: '0 0 20 20', fill: 'currentColor')
end
def visibility_icon(status) def visibility_icon(status)
if status.public_visibility? if status.public_visibility?
fa_icon('globe', title: I18n.t('statuses.visibilities.public')) fa_icon('globe', title: I18n.t('statuses.visibilities.public'))

View File

@ -1,76 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import ShortNumber from 'mastodon/components/short_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
import { reduceMotion } from 'flavours/glitch/initial_state';
const obfuscatedCount = count => {
if (count < 0) {
return 0;
} else if (count <= 1) {
return count;
} else {
return '1+';
}
};
export default class AnimatedNumber extends React.PureComponent {
static propTypes = {
value: PropTypes.number.isRequired,
obfuscate: PropTypes.bool,
};
state = {
direction: 1,
};
componentWillReceiveProps (nextProps) {
if (nextProps.value > this.props.value) {
this.setState({ direction: 1 });
} else if (nextProps.value < this.props.value) {
this.setState({ direction: -1 });
}
}
willEnter = () => {
const { direction } = this.state;
return { y: -1 * direction };
};
willLeave = () => {
const { direction } = this.state;
return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
};
render () {
const { value, obfuscate } = this.props;
const { direction } = this.state;
if (reduceMotion) {
return obfuscate ? obfuscatedCount(value) : <ShortNumber value={value} />;
}
const styles = [{
key: `${value}`,
data: value,
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
}];
return (
<TransitionMotion styles={styles} willEnter={this.willEnter} willLeave={this.willLeave}>
{items => (
<span className='animated-number'>
{items.map(({ key, data, style }) => (
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
))}
</span>
)}
</TransitionMotion>
);
}
}

View File

@ -0,0 +1,58 @@
import React, { useCallback, useState } from 'react';
import ShortNumber from './short_number';
import { TransitionMotion, spring } from 'react-motion';
import { reduceMotion } from '../initial_state';
const obfuscatedCount = (count: number) => {
if (count < 0) {
return 0;
} else if (count <= 1) {
return count;
} else {
return '1+';
}
};
type Props = {
value: number;
obfuscate?: boolean;
}
export const AnimatedNumber: React.FC<Props> = ({
value,
obfuscate,
})=> {
const [previousValue, setPreviousValue] = useState(value);
const [direction, setDirection] = useState<1|-1>(1);
if (previousValue !== value) {
setPreviousValue(value);
setDirection(value > previousValue ? 1 : -1);
}
const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]);
if (reduceMotion) {
return obfuscate ? <>{obfuscatedCount(value)}</> : <ShortNumber value={value} />;
}
const styles = [{
key: `${value}`,
data: value,
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
}];
return (
<TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
{items => (
<span className='animated-number'>
{items.map(({ key, data, style }) => (
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
))}
</span>
)}
</TransitionMotion>
);
};
export default AnimatedNumber;

View File

@ -1,76 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
export default class GIFV extends React.PureComponent {
static propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string,
lang: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
};
state = {
loading: true,
};
handleLoadedData = () => {
this.setState({ loading: false });
};
componentWillReceiveProps (nextProps) {
if (nextProps.src !== this.props.src) {
this.setState({ loading: true });
}
}
handleClick = e => {
const { onClick } = this.props;
if (onClick) {
e.stopPropagation();
onClick();
}
};
render () {
const { src, width, height, alt, lang } = this.props;
const { loading } = this.state;
return (
<div className='gifv' style={{ position: 'relative' }}>
{loading && (
<canvas
width={width}
height={height}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
onClick={this.handleClick}
/>
)}
<video
src={src}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
muted
loop
autoPlay
playsInline
onClick={this.handleClick}
onLoadedData={this.handleLoadedData}
style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
/>
</div>
);
}
}

View File

@ -0,0 +1,68 @@
import React, { useCallback, useState } from 'react';
type Props = {
src: string;
key: string;
alt?: string;
lang?: string;
width: number;
height: number;
onClick?: () => void;
}
export const GIFV: React.FC<Props> = ({
src,
alt,
lang,
width,
height,
onClick,
})=> {
const [loading, setLoading] = useState(true);
const handleLoadedData: React.ReactEventHandler<HTMLVideoElement> = useCallback(() => {
setLoading(false);
}, [setLoading]);
const handleClick: React.MouseEventHandler = useCallback((e) => {
if (onClick) {
e.stopPropagation();
onClick();
}
}, [onClick]);
return (
<div className='gifv' style={{ position: 'relative' }}>
{loading && (
<canvas
width={width}
height={height}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
onClick={handleClick}
/>
)}
<video
src={src}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
muted
loop
autoPlay
playsInline
onClick={handleClick}
onLoadedData={handleLoadedData}
style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
/>
</div>
);
};
export default GIFV;

View File

@ -203,7 +203,7 @@ class Conversation extends ImmutablePureComponent {
parseClick={this.parseClick} parseClick={this.parseClick}
expanded={isExpanded} expanded={isExpanded}
onExpandedToggle={this.handleShowMore} onExpandedToggle={this.handleShowMore}
collapsable collapsible
media={media} media={media}
/> />

View File

@ -64,6 +64,7 @@ const messages = defineMessages({
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' }, redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: 'Are you sure you want to delete this status and re-draft it? You will lose all replies, boosts and favourites to it.' },
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' }, revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' }, hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
statusTitleWithAttachments: { id: 'status.title.with_attachments', defaultMessage: '{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}' },
detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' }, detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
@ -162,13 +163,14 @@ const truncate = (str, num) => {
} }
}; };
const titleFromStatus = status => { const titleFromStatus = (intl, status) => {
const displayName = status.getIn(['account', 'display_name']); const displayName = status.getIn(['account', 'display_name']);
const username = status.getIn(['account', 'username']); const username = status.getIn(['account', 'username']);
const prefix = displayName.trim().length === 0 ? username : displayName; const user = displayName.trim().length === 0 ? username : displayName;
const text = status.get('search_index'); const text = status.get('search_index');
const attachmentCount = status.get('media_attachments').size;
return `${prefix}: "${truncate(text, 30)}"`; return text ? `${user}: "${truncate(text, 30)}"` : intl.formatMessage(messages.statusTitleWithAttachments, { user, attachmentCount });
}; };
class Status extends ImmutablePureComponent { class Status extends ImmutablePureComponent {
@ -727,7 +729,7 @@ class Status extends ImmutablePureComponent {
</ScrollContainer> </ScrollContainer>
<Helmet> <Helmet>
<title>{titleFromStatus(status)}</title> <title>{titleFromStatus(intl, status)}</title>
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
</Helmet> </Helmet>
</Column> </Column>

View File

@ -131,4 +131,4 @@ class FilterModal extends ImmutablePureComponent {
} }
export default connect(injectIntl(FilterModal)); export default connect()(injectIntl(FilterModal));

View File

@ -371,7 +371,7 @@ class FocalPointModal extends ImmutablePureComponent {
{focals && ( {focals && (
<div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}> <div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}>
{media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />} {media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />}
{media.get('type') === 'gifv' && <GIFV src={media.get('url')} width={width} height={height} />} {media.get('type') === 'gifv' && <GIFV src={media.get('url')} key={media.get('url')} width={width} height={height} />}
<div className='focal-point__preview'> <div className='focal-point__preview'>
<strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong> <strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong>

View File

@ -188,7 +188,7 @@ class MediaModal extends ImmutablePureComponent {
src={image.get('url')} src={image.get('url')}
width={width} width={width}
height={height} height={height}
key={image.get('preview_url')} key={image.get('url')}
alt={image.get('description')} alt={image.get('description')}
lang={language} lang={language}
onClick={this.toggleNavigation} onClick={this.toggleNavigation}

View File

@ -96,11 +96,13 @@ const element = document.getElementById('initial-state');
const initialState = element?.textContent && JSON.parse(element.textContent); const initialState = element?.textContent && JSON.parse(element.textContent);
// Glitch-soc-specific “local settings” // Glitch-soc-specific “local settings”
if (initialState) {
try { try {
initialState.local_settings = JSON.parse(localStorage.getItem('mastodon-settings')); initialState.local_settings = JSON.parse(localStorage.getItem('mastodon-settings'));
} catch (e) { } catch (e) {
initialState.local_settings = {}; initialState.local_settings = {};
} }
}
/** /**
* @template {keyof InitialStateMeta} K * @template {keyof InitialStateMeta} K

View File

@ -2,6 +2,15 @@ import 'packs/public-path';
import loadPolyfills from 'flavours/glitch/load_polyfills'; import loadPolyfills from 'flavours/glitch/load_polyfills';
import ready from 'flavours/glitch/ready'; import ready from 'flavours/glitch/ready';
import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions'; import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions';
import axios from 'axios';
import { throttle } from 'lodash';
import { defineMessages } from 'react-intl';
const messages = defineMessages({
usernameTaken: { id: 'username.taken', defaultMessage: 'That username is taken. Try another' },
passwordExceedsLength: { id: 'password_confirmation.exceeds_maxlength', defaultMessage: 'Password confirmation exceeds the maximum password length' },
passwordDoesNotMatch: { id: 'password_confirmation.mismatching', defaultMessage: 'Password confirmation does not match' },
});
function main() { function main() {
const IntlMessageFormat = require('intl-messageformat').default; const IntlMessageFormat = require('intl-messageformat').default;
@ -9,7 +18,7 @@ function main() {
const { delegate } = require('@rails/ujs'); const { delegate } = require('@rails/ujs');
const emojify = require('flavours/glitch/features/emoji/emoji').default; const emojify = require('flavours/glitch/features/emoji/emoji').default;
const { getLocale } = require('locales'); const { getLocale } = require('locales');
const { messages } = getLocale(); const { localeData } = getLocale();
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
const { createBrowserHistory } = require('history'); const { createBrowserHistory } = require('history');
@ -54,6 +63,11 @@ function main() {
hour12: false, hour12: false,
}); });
const formatMessage = ({ id, defaultMessage }, values) => {
const messageFormat = new IntlMessageFormat(localeData[id] || defaultMessage, locale);
return messageFormat.format(values);
};
[].forEach.call(document.querySelectorAll('.emojify'), (content) => { [].forEach.call(document.querySelectorAll('.emojify'), (content) => {
content.innerHTML = emojify(content.innerHTML); content.innerHTML = emojify(content.innerHTML);
}); });
@ -73,7 +87,7 @@ function main() {
date.getMonth() === today.getMonth() && date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear(); date.getFullYear() === today.getFullYear();
}; };
const todayFormat = new IntlMessageFormat(messages['relative_format.today'] || 'Today at {time}', locale); const todayFormat = new IntlMessageFormat(localeData['relative_format.today'] || 'Today at {time}', locale);
[].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => { [].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => {
const datetime = new Date(content.getAttribute('datetime')); const datetime = new Date(content.getAttribute('datetime'));
@ -99,7 +113,7 @@ function main() {
const timeGiven = content.getAttribute('datetime').includes('T'); const timeGiven = content.getAttribute('datetime').includes('T');
content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime); content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime);
content.textContent = timeAgoString({ content.textContent = timeAgoString({
formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values), formatMessage,
formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date), formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date),
}, datetime, now, now.getFullYear(), timeGiven); }, datetime, now, now.getFullYear(), timeGiven);
}); });
@ -128,17 +142,19 @@ function main() {
scrollToDetailedStatus(); scrollToDetailedStatus();
} }
delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => { delegate(document, '#user_account_attributes_username', 'input', throttle(() => {
const password = document.getElementById('registration_user_password'); const username = document.getElementById('user_account_attributes_username');
const confirmation = document.getElementById('registration_user_password_confirmation');
if (confirmation.value && confirmation.value.length > password.maxLength) { if (username.value && username.value.length > 0) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format()); axios.get('/api/v1/accounts/lookup', { params: { acct: username.value } }).then(() => {
} else if (password.value && password.value !== confirmation.value) { username.setCustomValidity(formatMessage(messages.usernameTaken));
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format()); }).catch(() => {
} else { username.setCustomValidity('');
confirmation.setCustomValidity('');
}
}); });
} else {
username.setCustomValidity('');
}
}, 500, { leading: false, trailing: true }));
delegate(document, '#user_password,#user_password_confirmation', 'input', () => { delegate(document, '#user_password,#user_password_confirmation', 'input', () => {
const password = document.getElementById('user_password'); const password = document.getElementById('user_password');
@ -146,9 +162,9 @@ function main() {
if (!confirmation) return; if (!confirmation) return;
if (confirmation.value && confirmation.value.length > password.maxLength) { if (confirmation.value && confirmation.value.length > password.maxLength) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format()); confirmation.setCustomValidity(formatMessage(messages.passwordExceedsLength));
} else if (password.value && password.value !== confirmation.value) { } else if (password.value && password.value !== confirmation.value) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format()); confirmation.setCustomValidity(formatMessage(messages.passwordDoesNotMatch));
} else { } else {
confirmation.setCustomValidity(''); confirmation.setCustomValidity('');
} }
@ -162,10 +178,10 @@ function main() {
if (statusEl.dataset.spoiler === 'expanded') { if (statusEl.dataset.spoiler === 'expanded') {
statusEl.dataset.spoiler = 'folded'; statusEl.dataset.spoiler = 'folded';
this.textContent = (new IntlMessageFormat(messages['status.show_more'] || 'Show more', locale)).format(); this.textContent = (new IntlMessageFormat(localeData['status.show_more'] || 'Show more', locale)).format();
} else { } else {
statusEl.dataset.spoiler = 'expanded'; statusEl.dataset.spoiler = 'expanded';
this.textContent = (new IntlMessageFormat(messages['status.show_less'] || 'Show less', locale)).format(); this.textContent = (new IntlMessageFormat(localeData['status.show_less'] || 'Show less', locale)).format();
} }
return false; return false;
@ -173,7 +189,7 @@ function main() {
[].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => { [].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => {
const statusEl = spoilerLink.parentNode.parentNode; const statusEl = spoilerLink.parentNode.parentNode;
const message = (statusEl.dataset.spoiler === 'expanded') ? (messages['status.show_less'] || 'Show less') : (messages['status.show_more'] || 'Show more'); const message = (statusEl.dataset.spoiler === 'expanded') ? (localeData['status.show_less'] || 'Show less') : (localeData['status.show_more'] || 'Show more');
spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format(); spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format();
}); });
}); });

View File

@ -1118,3 +1118,89 @@ code {
white-space: nowrap; white-space: nowrap;
} }
} }
.progress-tracker {
display: flex;
align-items: center;
padding-bottom: 30px;
margin-bottom: 30px;
li {
flex: 0 0 auto;
position: relative;
}
.separator {
height: 2px;
background: $ui-base-lighter-color;
flex: 1 1 auto;
&.completed {
background: $highlight-text-color;
}
}
.circle {
box-sizing: border-box;
position: relative;
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid $ui-base-lighter-color;
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 16px;
}
}
.label {
position: absolute;
font-size: 14px;
font-weight: 500;
color: $secondary-text-color;
padding-top: 10px;
text-align: center;
width: 100px;
left: 50%;
transform: translateX(-50%);
}
li:first-child .label {
left: auto;
inset-inline-start: 0;
text-align: start;
transform: none;
}
li:last-child .label {
left: auto;
inset-inline-end: 0;
text-align: end;
transform: none;
}
.active .circle {
border-color: $highlight-text-color;
&::before {
content: '';
width: 10px;
height: 10px;
border-radius: 50%;
background: $highlight-text-color;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.completed .circle {
border-color: $highlight-text-color;
background: $highlight-text-color;
}
}

View File

@ -3,6 +3,8 @@
exports[`<AvatarOverlay renders a overlay avatar 1`] = ` exports[`<AvatarOverlay renders a overlay avatar 1`] = `
<div <div
className="account__avatar-overlay" className="account__avatar-overlay"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
style={ style={
{ {
"height": 46, "height": 46,
@ -15,8 +17,6 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = `
> >
<div <div
className="account__avatar" className="account__avatar"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
style={ style={
{ {
"height": "36px", "height": "36px",
@ -35,8 +35,6 @@ exports[`<AvatarOverlay renders a overlay avatar 1`] = `
> >
<div <div
className="account__avatar" className="account__avatar"
onMouseEnter={[Function]}
onMouseLeave={[Function]}
style={ style={
{ {
"height": "24px", "height": "24px",

View File

@ -1,76 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import ShortNumber from 'mastodon/components/short_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring';
import { reduceMotion } from 'mastodon/initial_state';
const obfuscatedCount = count => {
if (count < 0) {
return 0;
} else if (count <= 1) {
return count;
} else {
return '1+';
}
};
export default class AnimatedNumber extends React.PureComponent {
static propTypes = {
value: PropTypes.number.isRequired,
obfuscate: PropTypes.bool,
};
state = {
direction: 1,
};
componentWillReceiveProps (nextProps) {
if (nextProps.value > this.props.value) {
this.setState({ direction: 1 });
} else if (nextProps.value < this.props.value) {
this.setState({ direction: -1 });
}
}
willEnter = () => {
const { direction } = this.state;
return { y: -1 * direction };
};
willLeave = () => {
const { direction } = this.state;
return { y: spring(1 * direction, { damping: 35, stiffness: 400 }) };
};
render () {
const { value, obfuscate } = this.props;
const { direction } = this.state;
if (reduceMotion) {
return obfuscate ? obfuscatedCount(value) : <ShortNumber value={value} />;
}
const styles = [{
key: `${value}`,
data: value,
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
}];
return (
<TransitionMotion styles={styles} willEnter={this.willEnter} willLeave={this.willLeave}>
{items => (
<span className='animated-number'>
{items.map(({ key, data, style }) => (
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
))}
</span>
)}
</TransitionMotion>
);
}
}

View File

@ -0,0 +1,58 @@
import React, { useCallback, useState } from 'react';
import ShortNumber from './short_number';
import { TransitionMotion, spring } from 'react-motion';
import { reduceMotion } from '../initial_state';
const obfuscatedCount = (count: number) => {
if (count < 0) {
return 0;
} else if (count <= 1) {
return count;
} else {
return '1+';
}
};
type Props = {
value: number;
obfuscate?: boolean;
}
export const AnimatedNumber: React.FC<Props> = ({
value,
obfuscate,
})=> {
const [previousValue, setPreviousValue] = useState(value);
const [direction, setDirection] = useState<1|-1>(1);
if (previousValue !== value) {
setPreviousValue(value);
setDirection(value > previousValue ? 1 : -1);
}
const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
const willLeave = useCallback(() => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }), [direction]);
if (reduceMotion) {
return obfuscate ? <>{obfuscatedCount(value)}</> : <ShortNumber value={value} />;
}
const styles = [{
key: `${value}`,
data: value,
style: { y: spring(0, { damping: 35, stiffness: 400 }) },
}];
return (
<TransitionMotion styles={styles} willEnter={willEnter} willLeave={willLeave}>
{items => (
<span className='animated-number'>
{items.map(({ key, data, style }) => (
<span key={key} style={{ position: (direction * style.y) > 0 ? 'absolute' : 'static', transform: `translateY(${style.y * 100}%)` }}>{obfuscate ? obfuscatedCount(data) : <ShortNumber value={data} />}</span>
))}
</span>
)}
</TransitionMotion>
);
};
export default AnimatedNumber;

View File

@ -1,51 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { autoPlayGif } from '../initial_state';
import Avatar from './avatar';
export default class AvatarOverlay extends React.PureComponent {
static propTypes = {
account: ImmutablePropTypes.map.isRequired,
friend: ImmutablePropTypes.map.isRequired,
animate: PropTypes.bool,
size: PropTypes.number,
baseSize: PropTypes.number,
overlaySize: PropTypes.number,
};
static defaultProps = {
animate: autoPlayGif,
size: 46,
baseSize: 36,
overlaySize: 24,
};
state = {
hovering: false,
};
handleMouseEnter = () => {
if (this.props.animate) return;
this.setState({ hovering: true });
};
handleMouseLeave = () => {
if (this.props.animate) return;
this.setState({ hovering: false });
};
render() {
const { account, friend, animate, size, baseSize, overlaySize } = this.props;
const { hovering } = this.state;
return (
<div className='account__avatar-overlay' style={{ width: size, height: size }}>
<div className='account__avatar-overlay-base'><Avatar animate={hovering || animate} account={account} size={baseSize} /></div>
<div className='account__avatar-overlay-overlay'><Avatar animate={hovering || animate} account={friend} size={overlaySize} /></div>
</div>
);
}
}

View File

@ -0,0 +1,51 @@
import React from 'react';
import type { Account } from '../../types/resources';
import { useHovering } from '../../hooks/useHovering';
import { autoPlayGif } from '../initial_state';
type Props = {
account: Account;
friend: Account;
size?: number;
baseSize?: number;
overlaySize?: number;
};
export const AvatarOverlay: React.FC<Props> = ({
account,
friend,
size = 46,
baseSize = 36,
overlaySize = 24,
}) => {
const { hovering, handleMouseEnter, handleMouseLeave } = useHovering(autoPlayGif);
const accountSrc = hovering ? account?.get('avatar') : account?.get('avatar_static');
const friendSrc = hovering ? friend?.get('avatar') : friend?.get('avatar_static');
return (
<div
className='account__avatar-overlay' style={{ width: size, height: size }}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className='account__avatar-overlay-base'>
<div
className='account__avatar'
style={{ width: `${baseSize}px`, height: `${baseSize}px` }}
>
{accountSrc && <img src={accountSrc} alt={account?.get('acct')} />}
</div>
</div>
<div className='account__avatar-overlay-overlay'>
<div
className='account__avatar'
style={{ width: `${overlaySize}px`, height: `${overlaySize}px` }}
>
{friendSrc && <img src={friendSrc} alt={friend?.get('acct')} />}
</div>
</div>
</div>
);
};
export default AvatarOverlay;

View File

@ -1,76 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
export default class GIFV extends React.PureComponent {
static propTypes = {
src: PropTypes.string.isRequired,
alt: PropTypes.string,
lang: PropTypes.string,
width: PropTypes.number,
height: PropTypes.number,
onClick: PropTypes.func,
};
state = {
loading: true,
};
handleLoadedData = () => {
this.setState({ loading: false });
};
componentWillReceiveProps (nextProps) {
if (nextProps.src !== this.props.src) {
this.setState({ loading: true });
}
}
handleClick = e => {
const { onClick } = this.props;
if (onClick) {
e.stopPropagation();
onClick();
}
};
render () {
const { src, width, height, alt, lang } = this.props;
const { loading } = this.state;
return (
<div className='gifv' style={{ position: 'relative' }}>
{loading && (
<canvas
width={width}
height={height}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
onClick={this.handleClick}
/>
)}
<video
src={src}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
muted
loop
autoPlay
playsInline
onClick={this.handleClick}
onLoadedData={this.handleLoadedData}
style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
/>
</div>
);
}
}

View File

@ -0,0 +1,68 @@
import React, { useCallback, useState } from 'react';
type Props = {
src: string;
key: string;
alt?: string;
lang?: string;
width: number;
height: number;
onClick?: () => void;
}
export const GIFV: React.FC<Props> = ({
src,
alt,
lang,
width,
height,
onClick,
})=> {
const [loading, setLoading] = useState(true);
const handleLoadedData: React.ReactEventHandler<HTMLVideoElement> = useCallback(() => {
setLoading(false);
}, [setLoading]);
const handleClick: React.MouseEventHandler = useCallback((e) => {
if (onClick) {
e.stopPropagation();
onClick();
}
}, [onClick]);
return (
<div className='gifv' style={{ position: 'relative' }}>
{loading && (
<canvas
width={width}
height={height}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
onClick={handleClick}
/>
)}
<video
src={src}
role='button'
tabIndex={0}
aria-label={alt}
title={alt}
lang={lang}
muted
loop
autoPlay
playsInline
onClick={handleClick}
onLoadedData={handleLoadedData}
style={{ position: loading ? 'absolute' : 'static', top: 0, left: 0 }}
/>
</div>
);
};
export default GIFV;

View File

@ -541,7 +541,7 @@ class Status extends ImmutablePureComponent {
expanded={!status.get('hidden')} expanded={!status.get('hidden')}
onExpandedToggle={this.handleExpandedToggle} onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate} onTranslate={this.handleTranslate}
collapsable collapsible
onCollapsedToggle={this.handleCollapsedToggle} onCollapsedToggle={this.handleCollapsedToggle}
/> />

View File

@ -65,7 +65,7 @@ class StatusContent extends React.PureComponent {
onExpandedToggle: PropTypes.func, onExpandedToggle: PropTypes.func,
onTranslate: PropTypes.func, onTranslate: PropTypes.func,
onClick: PropTypes.func, onClick: PropTypes.func,
collapsable: PropTypes.bool, collapsible: PropTypes.bool,
onCollapsedToggle: PropTypes.func, onCollapsedToggle: PropTypes.func,
languages: ImmutablePropTypes.map, languages: ImmutablePropTypes.map,
intl: PropTypes.object, intl: PropTypes.object,
@ -112,10 +112,10 @@ class StatusContent extends React.PureComponent {
} }
if (status.get('collapsed', null) === null && onCollapsedToggle) { if (status.get('collapsed', null) === null && onCollapsedToggle) {
const { collapsable, onClick } = this.props; const { collapsible, onClick } = this.props;
const collapsed = const collapsed =
collapsable collapsible
&& onClick && onClick
&& node.clientHeight > MAX_HEIGHT && node.clientHeight > MAX_HEIGHT
&& status.get('spoiler_text').length === 0; && status.get('spoiler_text').length === 0;

View File

@ -165,7 +165,7 @@ class Conversation extends ImmutablePureComponent {
onClick={this.handleClick} onClick={this.handleClick}
expanded={!lastStatus.get('hidden')} expanded={!lastStatus.get('hidden')}
onExpandedToggle={this.handleShowMore} onExpandedToggle={this.handleShowMore}
collapsable collapsible
/> />
{lastStatus.get('media_attachments').size > 0 && ( {lastStatus.get('media_attachments').size > 0 && (

View File

@ -69,6 +69,7 @@ const messages = defineMessages({
redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' }, redraftMessage: { id: 'confirmations.redraft.message', defaultMessage: '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.' },
revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' }, revealAll: { id: 'status.show_more_all', defaultMessage: 'Show more for all' },
hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' }, hideAll: { id: 'status.show_less_all', defaultMessage: 'Show less for all' },
statusTitleWithAttachments: { id: 'status.title.with_attachments', defaultMessage: '{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}' },
detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' }, detailedStatus: { id: 'status.detailed_status', defaultMessage: 'Detailed conversation view' },
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' }, replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' }, replyMessage: { id: 'confirmations.reply.message', defaultMessage: 'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?' },
@ -166,13 +167,14 @@ const truncate = (str, num) => {
} }
}; };
const titleFromStatus = status => { const titleFromStatus = (intl, status) => {
const displayName = status.getIn(['account', 'display_name']); const displayName = status.getIn(['account', 'display_name']);
const username = status.getIn(['account', 'username']); const username = status.getIn(['account', 'username']);
const prefix = displayName.trim().length === 0 ? username : displayName; const user = displayName.trim().length === 0 ? username : displayName;
const text = status.get('search_index'); const text = status.get('search_index');
const attachmentCount = status.get('media_attachments').size;
return `${prefix}: "${truncate(text, 30)}"`; return text ? `${user}: "${truncate(text, 30)}"` : intl.formatMessage(messages.statusTitleWithAttachments, { user, attachmentCount });
}; };
class Status extends ImmutablePureComponent { class Status extends ImmutablePureComponent {
@ -670,7 +672,7 @@ class Status extends ImmutablePureComponent {
</ScrollContainer> </ScrollContainer>
<Helmet> <Helmet>
<title>{titleFromStatus(status)}</title> <title>{titleFromStatus(intl, status)}</title>
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} /> <meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
</Helmet> </Helmet>
</Column> </Column>

View File

@ -131,4 +131,4 @@ class FilterModal extends ImmutablePureComponent {
} }
export default connect(injectIntl(FilterModal)); export default connect()(injectIntl(FilterModal));

View File

@ -383,7 +383,7 @@ class FocalPointModal extends ImmutablePureComponent {
{focals && ( {focals && (
<div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}> <div className={classNames('focal-point', { dragging })} ref={this.setRef} onMouseDown={this.handleMouseDown} onTouchStart={this.handleTouchStart}>
{media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />} {media.get('type') === 'image' && <ImageLoader src={media.get('url')} width={width} height={height} alt='' />}
{media.get('type') === 'gifv' && <GIFV src={media.get('url')} width={width} height={height} />} {media.get('type') === 'gifv' && <GIFV src={media.get('url')} key={media.get('url')} width={width} height={height} />}
<div className='focal-point__preview'> <div className='focal-point__preview'>
<strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong> <strong><FormattedMessage id='upload_modal.preview_label' defaultMessage='Preview ({ratio})' values={{ ratio: '16:9' }} /></strong>

View File

@ -186,7 +186,7 @@ class MediaModal extends ImmutablePureComponent {
src={image.get('url')} src={image.get('url')}
width={width} width={width}
height={height} height={height}
key={image.get('preview_url')} key={image.get('url')}
alt={image.get('description')} alt={image.get('description')}
lang={language} lang={language}
onClick={this.toggleNavigation} onClick={this.toggleNavigation}

View File

@ -3732,6 +3732,10 @@
"defaultMessage": "Show less for all", "defaultMessage": "Show less for all",
"id": "status.show_less_all" "id": "status.show_less_all"
}, },
{
"defaultMessage": "{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}",
"id": "status.title.with_attachments"
},
{ {
"defaultMessage": "Detailed conversation view", "defaultMessage": "Detailed conversation view",
"id": "status.detailed_status" "id": "status.detailed_status"
@ -4354,5 +4358,22 @@
} }
], ],
"path": "app/javascript/mastodon/features/video/index.json" "path": "app/javascript/mastodon/features/video/index.json"
},
{
"descriptors": [
{
"defaultMessage": "That username is taken. Try another",
"id": "username.taken"
},
{
"defaultMessage": "Password confirmation exceeds the maximum password length",
"id": "password_confirmation.exceeds_maxlength"
},
{
"defaultMessage": "Password confirmation does not match",
"id": "password_confirmation.mismatching"
}
],
"path": "app/javascript/packs/public.json"
} }
] ]

View File

@ -443,6 +443,8 @@
"notifications_permission_banner.enable": "Enable desktop notifications", "notifications_permission_banner.enable": "Enable desktop notifications",
"notifications_permission_banner.how_to_control": "To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled.", "notifications_permission_banner.how_to_control": "To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled.",
"notifications_permission_banner.title": "Never miss a thing", "notifications_permission_banner.title": "Never miss a thing",
"password_confirmation.exceeds_maxlength": "Password confirmation exceeds the maximum password length",
"password_confirmation.mismatching": "Password confirmation does not match",
"picture_in_picture.restore": "Put it back", "picture_in_picture.restore": "Put it back",
"poll.closed": "Closed", "poll.closed": "Closed",
"poll.refresh": "Refresh", "poll.refresh": "Refresh",
@ -598,6 +600,7 @@
"status.show_more": "Show more", "status.show_more": "Show more",
"status.show_more_all": "Show more for all", "status.show_more_all": "Show more for all",
"status.show_original": "Show original", "status.show_original": "Show original",
"status.title.with_attachments": "{user} posted {attachmentCount, plural, one {an attachment} other {{attachmentCount} attachments}}",
"status.translate": "Translate", "status.translate": "Translate",
"status.translated_from_with": "Translated from {lang} using {provider}", "status.translated_from_with": "Translated from {lang} using {provider}",
"status.uncached_media_warning": "Not available", "status.uncached_media_warning": "Not available",
@ -650,6 +653,7 @@
"upload_modal.preview_label": "Preview ({ratio})", "upload_modal.preview_label": "Preview ({ratio})",
"upload_progress.label": "Uploading...", "upload_progress.label": "Uploading...",
"upload_progress.processing": "Processing…", "upload_progress.processing": "Processing…",
"username.taken": "That username is taken. Try another",
"video.close": "Close video", "video.close": "Close video",
"video.download": "Download file", "video.download": "Download file",
"video.exit_fullscreen": "Exit full screen", "video.exit_fullscreen": "Exit full screen",

View File

@ -597,6 +597,7 @@
"status.show_more": "Mostrar más", "status.show_more": "Mostrar más",
"status.show_more_all": "Mostrar más para todo", "status.show_more_all": "Mostrar más para todo",
"status.show_original": "Mostrar original", "status.show_original": "Mostrar original",
"status.title.with_attachments": "{user} publicó {attachmentCount, plural, one {un archivo adjunto} other {{attachmentCount} archivos adjuntos}}",
"status.translate": "Traducir", "status.translate": "Traducir",
"status.translated_from_with": "Traducido del {lang} usando {provider}", "status.translated_from_with": "Traducido del {lang} usando {provider}",
"status.uncached_media_warning": "No disponible", "status.uncached_media_warning": "No disponible",

View File

@ -4,6 +4,15 @@ import ready from '../mastodon/ready';
import { start } from '../mastodon/common'; import { start } from '../mastodon/common';
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions'; import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
import 'cocoon-js-vanilla'; import 'cocoon-js-vanilla';
import axios from 'axios';
import { throttle } from 'lodash';
import { defineMessages } from 'react-intl';
const messages = defineMessages({
usernameTaken: { id: 'username.taken', defaultMessage: 'That username is taken. Try another' },
passwordExceedsLength: { id: 'password_confirmation.exceeds_maxlength', defaultMessage: 'Password confirmation exceeds the maximum password length' },
passwordDoesNotMatch: { id: 'password_confirmation.mismatching', defaultMessage: 'Password confirmation does not match' },
});
start(); start();
@ -13,7 +22,7 @@ function main() {
const { delegate } = require('@rails/ujs'); const { delegate } = require('@rails/ujs');
const emojify = require('../mastodon/features/emoji/emoji').default; const emojify = require('../mastodon/features/emoji/emoji').default;
const { getLocale } = require('../mastodon/locales'); const { getLocale } = require('../mastodon/locales');
const { messages } = getLocale(); const { localeData } = getLocale();
const React = require('react'); const React = require('react');
const ReactDOM = require('react-dom'); const ReactDOM = require('react-dom');
const { createBrowserHistory } = require('history'); const { createBrowserHistory } = require('history');
@ -58,6 +67,11 @@ function main() {
hour12: false, hour12: false,
}); });
const formatMessage = ({ id, defaultMessage }, values) => {
const messageFormat = new IntlMessageFormat(localeData[id] || defaultMessage, locale);
return messageFormat.format(values);
};
[].forEach.call(document.querySelectorAll('.emojify'), (content) => { [].forEach.call(document.querySelectorAll('.emojify'), (content) => {
content.innerHTML = emojify(content.innerHTML); content.innerHTML = emojify(content.innerHTML);
}); });
@ -77,7 +91,7 @@ function main() {
date.getMonth() === today.getMonth() && date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear(); date.getFullYear() === today.getFullYear();
}; };
const todayFormat = new IntlMessageFormat(messages['relative_format.today'] || 'Today at {time}', locale); const todayFormat = new IntlMessageFormat(localeData['relative_format.today'] || 'Today at {time}', locale);
[].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => { [].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => {
const datetime = new Date(content.getAttribute('datetime')); const datetime = new Date(content.getAttribute('datetime'));
@ -103,7 +117,7 @@ function main() {
const timeGiven = content.getAttribute('datetime').includes('T'); const timeGiven = content.getAttribute('datetime').includes('T');
content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime); content.title = timeGiven ? dateTimeFormat.format(datetime) : dateFormat.format(datetime);
content.textContent = timeAgoString({ content.textContent = timeAgoString({
formatMessage: ({ id, defaultMessage }, values) => (new IntlMessageFormat(messages[id] || defaultMessage, locale)).format(values), formatMessage,
formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date), formatDate: (date, options) => (new Intl.DateTimeFormat(locale, options)).format(date),
}, datetime, now, now.getFullYear(), timeGiven); }, datetime, now, now.getFullYear(), timeGiven);
}); });
@ -133,17 +147,19 @@ function main() {
scrollToDetailedStatus(); scrollToDetailedStatus();
} }
delegate(document, '#registration_user_password_confirmation,#registration_user_password', 'input', () => { delegate(document, '#user_account_attributes_username', 'input', throttle(() => {
const password = document.getElementById('registration_user_password'); const username = document.getElementById('user_account_attributes_username');
const confirmation = document.getElementById('registration_user_password_confirmation');
if (confirmation.value && confirmation.value.length > password.maxLength) { if (username.value && username.value.length > 0) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format()); axios.get('/api/v1/accounts/lookup', { params: { acct: username.value } }).then(() => {
} else if (password.value && password.value !== confirmation.value) { username.setCustomValidity(formatMessage(messages.usernameTaken));
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format()); }).catch(() => {
} else { username.setCustomValidity('');
confirmation.setCustomValidity('');
}
}); });
} else {
username.setCustomValidity('');
}
}, 500, { leading: false, trailing: true }));
delegate(document, '#user_password,#user_password_confirmation', 'input', () => { delegate(document, '#user_password,#user_password_confirmation', 'input', () => {
const password = document.getElementById('user_password'); const password = document.getElementById('user_password');
@ -151,9 +167,9 @@ function main() {
if (!confirmation) return; if (!confirmation) return;
if (confirmation.value && confirmation.value.length > password.maxLength) { if (confirmation.value && confirmation.value.length > password.maxLength) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.exceeds_maxlength'] || 'Password confirmation exceeds the maximum password length', locale)).format()); confirmation.setCustomValidity(formatMessage(messages.passwordExceedsLength));
} else if (password.value && password.value !== confirmation.value) { } else if (password.value && password.value !== confirmation.value) {
confirmation.setCustomValidity((new IntlMessageFormat(messages['password_confirmation.mismatching'] || 'Password confirmation does not match', locale)).format()); confirmation.setCustomValidity(formatMessage(messages.passwordDoesNotMatch));
} else { } else {
confirmation.setCustomValidity(''); confirmation.setCustomValidity('');
} }
@ -167,10 +183,10 @@ function main() {
if (statusEl.dataset.spoiler === 'expanded') { if (statusEl.dataset.spoiler === 'expanded') {
statusEl.dataset.spoiler = 'folded'; statusEl.dataset.spoiler = 'folded';
this.textContent = (new IntlMessageFormat(messages['status.show_more'] || 'Show more', locale)).format(); this.textContent = (new IntlMessageFormat(localeData['status.show_more'] || 'Show more', locale)).format();
} else { } else {
statusEl.dataset.spoiler = 'expanded'; statusEl.dataset.spoiler = 'expanded';
this.textContent = (new IntlMessageFormat(messages['status.show_less'] || 'Show less', locale)).format(); this.textContent = (new IntlMessageFormat(localeData['status.show_less'] || 'Show less', locale)).format();
} }
return false; return false;
@ -178,7 +194,7 @@ function main() {
[].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => { [].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => {
const statusEl = spoilerLink.parentNode.parentNode; const statusEl = spoilerLink.parentNode.parentNode;
const message = (statusEl.dataset.spoiler === 'expanded') ? (messages['status.show_less'] || 'Show less') : (messages['status.show_more'] || 'Show more'); const message = (statusEl.dataset.spoiler === 'expanded') ? (localeData['status.show_less'] || 'Show less') : (localeData['status.show_more'] || 'Show more');
spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format(); spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format();
}); });
}); });

View File

@ -1112,3 +1112,89 @@ code {
white-space: nowrap; white-space: nowrap;
} }
} }
.progress-tracker {
display: flex;
align-items: center;
padding-bottom: 30px;
margin-bottom: 30px;
li {
flex: 0 0 auto;
position: relative;
}
.separator {
height: 2px;
background: $ui-base-lighter-color;
flex: 1 1 auto;
&.completed {
background: $highlight-text-color;
}
}
.circle {
box-sizing: border-box;
position: relative;
width: 30px;
height: 30px;
border-radius: 50%;
border: 2px solid $ui-base-lighter-color;
flex: 0 0 auto;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 16px;
}
}
.label {
position: absolute;
font-size: 14px;
font-weight: 500;
color: $secondary-text-color;
padding-top: 10px;
text-align: center;
width: 100px;
left: 50%;
transform: translateX(-50%);
}
li:first-child .label {
left: auto;
inset-inline-start: 0;
text-align: start;
transform: none;
}
li:last-child .label {
left: auto;
inset-inline-end: 0;
text-align: end;
transform: none;
}
.active .circle {
border-color: $highlight-text-color;
&::before {
content: '';
width: 10px;
height: 10px;
border-radius: 50%;
background: $highlight-text-color;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
.completed .circle {
border-color: $highlight-text-color;
background: $highlight-text-color;
}
}

View File

@ -14,7 +14,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do locale_for_account(@me) do
thread_by_conversation(@status.conversation) thread_by_conversation(@status.conversation)
mail to: @me.user.email, subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct) mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.mention.subject', name: @status.account.acct)
end end
end end
@ -25,7 +25,7 @@ class NotificationMailer < ApplicationMailer
return unless @me.user.functional? return unless @me.user.functional?
locale_for_account(@me) do locale_for_account(@me) do
mail to: @me.user.email, subject: I18n.t('notification_mailer.follow.subject', name: @account.acct) mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow.subject', name: @account.acct)
end end
end end
@ -38,7 +38,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do locale_for_account(@me) do
thread_by_conversation(@status.conversation) thread_by_conversation(@status.conversation)
mail to: @me.user.email, subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct) mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.favourite.subject', name: @account.acct)
end end
end end
@ -51,7 +51,7 @@ class NotificationMailer < ApplicationMailer
locale_for_account(@me) do locale_for_account(@me) do
thread_by_conversation(@status.conversation) thread_by_conversation(@status.conversation)
mail to: @me.user.email, subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct) mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.reblog.subject', name: @account.acct)
end end
end end
@ -62,7 +62,7 @@ class NotificationMailer < ApplicationMailer
return unless @me.user.functional? return unless @me.user.functional?
locale_for_account(@me) do locale_for_account(@me) do
mail to: @me.user.email, subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct) mail to: email_address_with_name(@me.user.email, @me.user.account.username), subject: I18n.t('notification_mailer.follow_request.subject', name: @account.acct)
end end
end end

View File

@ -55,7 +55,7 @@ class AccountFilter
when 'by_domain' when 'by_domain'
Account.where(domain: value.to_s.strip) Account.where(domain: value.to_s.strip)
when 'username' when 'username'
Account.matches_username(value.to_s.strip) Account.matches_username(value.to_s.strip.delete_prefix('@'))
when 'display_name' when 'display_name'
Account.matches_display_name(value.to_s.strip) Account.matches_display_name(value.to_s.strip)
when 'email' when 'email'

View File

@ -18,6 +18,7 @@
# #
class PreviewCardProvider < ApplicationRecord class PreviewCardProvider < ApplicationRecord
include Paginable
include DomainNormalizable include DomainNormalizable
include Attachmentable include Attachmentable

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class REST::Admin::Trends::LinkSerializer < REST::Trends::LinkSerializer
attributes :id, :requires_review
def requires_review
object.requires_review?
end
end

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
class REST::Admin::Trends::Links::PreviewCardProviderSerializer < ActiveModel::Serializer
attributes :id, :domain, :trendable, :reviewed_at,
:requested_review_at, :requires_review
def requires_review
object.requires_review?
end
end

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
class REST::Admin::Trends::StatusSerializer < REST::StatusSerializer
attributes :requires_review
def requires_review
object.requires_review?
end
end

View File

@ -7,6 +7,7 @@ class NotifyService < BaseService
admin.report admin.report
admin.sign_up admin.sign_up
update update
poll
).freeze ).freeze
def call(recipient, type, activity) def call(recipient, type, activity)

View File

@ -5,6 +5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up } = render partial: 'shared/og', locals: { description: description_for_sign_up }
= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { novalidate: false }) do |f| = simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { novalidate: false }) do |f|
= render 'auth/shared/progress', stage: 'details'
%h1.title= t('auth.sign_up.title', domain: site_hostname) %h1.title= t('auth.sign_up.title', domain: site_hostname)
%p.lead= t('auth.sign_up.preamble') %p.lead= t('auth.sign_up.preamble')
@ -18,7 +20,7 @@
.fields-group .fields-group
= f.simple_fields_for :account do |ff| = f.simple_fields_for :account do |ff|
= ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') } = ff.input :display_name, wrapper: :with_label, label: false, required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.display_name'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.display_name') }
= ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}", hint: false = ff.input :username, wrapper: :with_label, label: false, required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.username'), autocomplete: 'off', placeholder: t('simple_form.labels.defaults.username'), pattern: '[a-zA-Z0-9_]+', maxlength: 30 }, append: "@#{site_hostname}"
= f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false = f.input :email, placeholder: t('simple_form.labels.defaults.email'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'username' }, hint: false
= f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false = f.input :password, placeholder: t('simple_form.labels.defaults.password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.password'), autocomplete: 'new-password', minlength: User.password_length.first, maxlength: User.password_length.last }, hint: false
= f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false = f.input :password_confirmation, placeholder: t('simple_form.labels.defaults.confirm_password'), required: true, input_html: { 'aria-label': t('simple_form.labels.defaults.confirm_password'), autocomplete: 'new-password' }, hint: false
@ -26,9 +28,11 @@
= f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' } = f.input :website, as: :url, wrapper: :with_label, label: t('simple_form.labels.defaults.honeypot', label: 'Website'), required: false, input_html: { 'aria-label': t('simple_form.labels.defaults.honeypot', label: 'Website'), autocomplete: 'off' }
- if approved_registrations? && !@invite.present? - if approved_registrations? && !@invite.present?
%p.lead= t('auth.sign_up.manual_review', domain: site_hostname)
.fields-group .fields-group
= f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields| = f.simple_fields_for :invite_request, resource.invite_request || resource.build_invite_request do |invite_request_fields|
= invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text = invite_request_fields.input :text, as: :text, wrapper: :with_block_label, required: Setting.require_invite_text, label: false, hint: false
= hidden_field_tag :accept, params[:accept] = hidden_field_tag :accept, params[:accept]

View File

@ -5,6 +5,8 @@
= render partial: 'shared/og', locals: { description: description_for_sign_up } = render partial: 'shared/og', locals: { description: description_for_sign_up }
.simple_form .simple_form
= render 'auth/shared/progress', stage: 'rules'
%h1.title= t('auth.rules.title') %h1.title= t('auth.rules.title')
%p.lead= t('auth.rules.preamble', domain: site_hostname) %p.lead= t('auth.rules.preamble', domain: site_hostname)

View File

@ -1,20 +1,22 @@
- content_for :page_title do - content_for :page_title do
= t('auth.setup.title') = t('auth.setup.title')
- if missing_email?
= simple_form_for(@user, url: auth_setup_path) do |f| = simple_form_for(@user, url: auth_setup_path) do |f|
= render 'auth/shared/progress', stage: 'confirm'
%h1.title= t('auth.setup.title')
%p.lead= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))
= render 'shared/error_messages', object: @user = render 'shared/error_messages', object: @user
.fields-group %p.lead
%p.hint= t('auth.setup.email_below_hint_html') %strong= t('auth.setup.link_not_received')
%p.lead= t('auth.setup.email_below_hint_html')
.fields-group .fields-group
= f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' } = f.input :email, required: true, hint: false, input_html: { 'aria-label': t('simple_form.labels.defaults.email'), autocomplete: 'off' }
.actions .actions
= f.submit t('admin.accounts.change_email.label'), class: 'button' = f.submit t('auth.resend_confirmation'), class: 'button'
- else
.simple_form
%p.hint= t('auth.setup.email_settings_hint_html', email: content_tag(:strong, @user.email))
.form-footer= render 'auth/shared/links' .form-footer= render 'auth/shared/links'

View File

@ -14,5 +14,5 @@
- if controller_name != 'confirmations' && (!user_signed_in? || !current_user.confirmed? || current_user.unconfirmed_email.present?) - if controller_name != 'confirmations' && (!user_signed_in? || !current_user.confirmed? || current_user.unconfirmed_email.present?)
%li= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path %li= link_to t('auth.didnt_get_confirmation'), new_user_confirmation_path
- if user_signed_in? && controller_name != 'setup' - if user_signed_in?
%li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete } %li= link_to t('auth.logout'), destroy_user_session_path, data: { method: :delete }

View File

@ -0,0 +1,25 @@
- progress_index = { rules: 0, details: 1, confirm: 2 }[stage.to_sym]
%ol.progress-tracker
%li{ class: progress_index.positive? ? 'completed' : 'active' }
.circle
- if progress_index.positive?
= check_icon
.label= t('auth.progress.rules')
%li.separator{ class: progress_index.positive? ? 'completed' : nil }
%li{ class: [progress_index > 1 && 'completed', progress_index == 1 && 'active'] }
.circle
- if progress_index > 1
= check_icon
.label= t('auth.progress.details')
%li.separator{ class: progress_index > 1 ? 'completed' : nil }
%li{ class: [progress_index > 2 && 'completed', progress_index == 2 && 'active'] }
.circle
- if progress_index > 2
= check_icon
.label= t('auth.progress.confirm')
- if approved_registrations?
%li.separator{ class: progress_index > 2 ? 'completed' : nil }
%li
.circle
.label= t('auth.progress.review')

View File

@ -125,8 +125,8 @@ en:
removed_header_msg: Successfully removed %{username}'s header image removed_header_msg: Successfully removed %{username}'s header image
resend_confirmation: resend_confirmation:
already_confirmed: This user is already confirmed already_confirmed: This user is already confirmed
send: Resend confirmation email send: Resend confirmation link
success: Confirmation email successfully sent! success: Confirmation link successfully sent!
reset: Reset reset: Reset
reset_password: Reset password reset_password: Reset password
resubscribe: Resubscribe resubscribe: Resubscribe
@ -988,7 +988,7 @@ en:
prefix_invited_by_user: "@%{name} invites you to join this server of Mastodon!" prefix_invited_by_user: "@%{name} invites you to join this server of Mastodon!"
prefix_sign_up: Sign up on Mastodon today! prefix_sign_up: Sign up on Mastodon today!
suffix: With an account, you will be able to follow people, post updates and exchange messages with users from any Mastodon server and more! suffix: With an account, you will be able to follow people, post updates and exchange messages with users from any Mastodon server and more!
didnt_get_confirmation: Didn't receive confirmation instructions? didnt_get_confirmation: Didn't receive a confirmation link?
dont_have_your_security_key: Don't have your security key? dont_have_your_security_key: Don't have your security key?
forgot_password: Forgot your password? forgot_password: Forgot your password?
invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one. invalid_reset_password_token: Password reset token is invalid or expired. Please request a new one.
@ -1001,12 +1001,17 @@ en:
migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>. migrate_account_html: If you wish to redirect this account to a different one, you can <a href="%{path}">configure it here</a>.
or_log_in_with: Or log in with or_log_in_with: Or log in with
privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a> privacy_policy_agreement_html: I have read and agree to the <a href="%{privacy_policy_path}" target="_blank">privacy policy</a>
progress:
confirm: Confirm e-mail
details: Your details
review: Our review
rules: Accept rules
providers: providers:
cas: CAS cas: CAS
saml: SAML saml: SAML
register: Sign up register: Sign up
registration_closed: "%{instance} is not accepting new members" registration_closed: "%{instance} is not accepting new members"
resend_confirmation: Resend confirmation instructions resend_confirmation: Resend confirmation link
reset_password: Reset password reset_password: Reset password
rules: rules:
accept: Accept accept: Accept
@ -1016,13 +1021,16 @@ en:
security: Security security: Security
set_new_password: Set new password set_new_password: Set new password
setup: setup:
email_below_hint_html: If the below e-mail address is incorrect, you can change it here and receive a new confirmation e-mail. email_below_hint_html: Check your spam folder, or request another one. You can correct your e-mail address if it's wrong.
email_settings_hint_html: The confirmation e-mail was sent to %{email}. If that e-mail address is not correct, you can change it in account settings. email_settings_hint_html: Click the link we sent you to verify %{email}. We'll wait right here.
title: Setup link_not_received: Didn't get a link?
new_confirmation_instructions_sent: You will receive a new e-mail with the confirmation link in a few minutes!
title: Check your inbox
sign_in: sign_in:
preamble_html: Sign in with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here. preamble_html: Sign in with your <strong>%{domain}</strong> credentials. If your account is hosted on a different server, you will not be able to log in here.
title: Sign in to %{domain} title: Sign in to %{domain}
sign_up: sign_up:
manual_review: Sign-ups on %{domain} go through manual review by our moderators. To help us process your registration, write a bit about yourself and why you want an account on %{domain}.
preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted. preamble: With an account on this Mastodon server, you'll be able to follow any other person on the network, regardless of where their account is hosted.
title: Let's get you set up on %{domain}. title: Let's get you set up on %{domain}.
status: status:

View File

@ -59,7 +59,6 @@ an:
setting_show_application: L'aplicación que utiliza vusté pa publicar publicacions s'amostrará en a vista detallada d'as suyas publicacions setting_show_application: L'aplicación que utiliza vusté pa publicar publicacions s'amostrará en a vista detallada d'as suyas publicacions
setting_use_blurhash: Los gradientes se basan en as colors d'as imachens amagadas pero fendo borrosos los detalles setting_use_blurhash: Los gradientes se basan en as colors d'as imachens amagadas pero fendo borrosos los detalles
setting_use_pending_items: Amagar nuevos estaus dezaga d'un clic en cuenta de desplazar automaticament lo feed setting_use_pending_items: Amagar nuevos estaus dezaga d'un clic en cuenta de desplazar automaticament lo feed
username: Lo tuyo nombre d'usuario será solo en %{domain}
whole_word: Quan la parola clau u frase ye nomás alfanumerica, nomás será aplicau si concuerda con tota la parola whole_word: Quan la parola clau u frase ye nomás alfanumerica, nomás será aplicau si concuerda con tota la parola
domain_allow: domain_allow:
domain: Este dominio podrá obtener datos d'este servidor y los datos dentrants serán procesaus y archivados domain: Este dominio podrá obtener datos d'este servidor y los datos dentrants serán procesaus y archivados

View File

@ -59,7 +59,6 @@ ar:
setting_show_application: سيُعرَض اسم التطبيق الذي تستخدمه عند النشر في العرض المفصّل لمنشوراتك setting_show_application: سيُعرَض اسم التطبيق الذي تستخدمه عند النشر في العرض المفصّل لمنشوراتك
setting_use_blurhash: الألوان التدرّجية مبنية على ألوان المرئيات المخفية ولكنها تحجب كافة التفاصيل setting_use_blurhash: الألوان التدرّجية مبنية على ألوان المرئيات المخفية ولكنها تحجب كافة التفاصيل
setting_use_pending_items: إخفاء تحديثات الخط وراء نقرة بدلًا مِن التمرير التلقائي للتدفق setting_use_pending_items: إخفاء تحديثات الخط وراء نقرة بدلًا مِن التمرير التلقائي للتدفق
username: اسم المستخدم الخاص بك سوف يكون فريدا مِن نوعه على %{domain}
whole_word: إذا كانت الكلمة أو العبارة مكونة من أرقام وحروف فقط سوف يتم تطبيقها فقط عند مطابقة الكلمة ككل whole_word: إذا كانت الكلمة أو العبارة مكونة من أرقام وحروف فقط سوف يتم تطبيقها فقط عند مطابقة الكلمة ككل
domain_allow: domain_allow:
domain: سيكون بإمكان هذا النطاق جلب البيانات من هذا الخادم ومعالجة وتخزين البيانات الواردة منه domain: سيكون بإمكان هذا النطاق جلب البيانات من هذا الخادم ومعالجة وتخزين البيانات الواردة منه

View File

@ -35,7 +35,6 @@ ast:
setting_noindex: Afeuta al perfil públicu ya a les páxines de los artículos setting_noindex: Afeuta al perfil públicu ya a les páxines de los artículos
setting_show_application: L'aplicación qu'uses pa espublizar apaez na vista detallada de los tos artículos setting_show_application: L'aplicación qu'uses pa espublizar apaez na vista detallada de los tos artículos
setting_use_blurhash: Los dilíos básense nos colores del conteníu multimedia anubríu mas desenfonca los detalles setting_use_blurhash: Los dilíos básense nos colores del conteníu multimedia anubríu mas desenfonca los detalles
username: 'El nome d''usuariu va ser únicu en: %{domain}'
featured_tag: featured_tag:
name: 'Equí tán dalgunes de les etiquetes qu''usesti apocayá:' name: 'Equí tán dalgunes de les etiquetes qu''usesti apocayá:'
form_admin_settings: form_admin_settings:

View File

@ -59,7 +59,6 @@ be:
setting_show_application: Праграма, праз якую вы ствараеце допісы, будзе паказвацца ў падрабязнасцях пра допісы setting_show_application: Праграма, праз якую вы ствараеце допісы, будзе паказвацца ў падрабязнасцях пра допісы
setting_use_blurhash: Градыенты заснаваны на колерах схаваных выяў, але размываюць дэталі setting_use_blurhash: Градыенты заснаваны на колерах схаваных выяў, але размываюць дэталі
setting_use_pending_items: Схаваць абнаўленні стужкі за клікам замест аўтаматычнага пракручвання стужкі setting_use_pending_items: Схаваць абнаўленні стужкі за клікам замест аўтаматычнага пракручвання стужкі
username: Ваша імя карыстальніка будзе ўнікальным на %{domain}
whole_word: Калі ключавое слова ці фраза складаецца толькі з літар і лічбаў, яно будзе ўжытае толькі калі супадае з усім словам whole_word: Калі ключавое слова ці фраза складаецца толькі з літар і лічбаў, яно будзе ўжытае толькі калі супадае з усім словам
domain_allow: domain_allow:
domain: Гэты дамен зможа атрымліваць даныя з гэтага сервера. Даныя з гэтага дамену будуць апрацаваныя ды захаваныя domain: Гэты дамен зможа атрымліваць даныя з гэтага сервера. Даныя з гэтага дамену будуць апрацаваныя ды захаваныя

View File

@ -59,7 +59,6 @@ bg:
setting_show_application: Приложението, което ползвате за публикуване, ще се показва в подробностите на публикацията ви setting_show_application: Приложението, което ползвате за публикуване, ще се показва в подробностите на публикацията ви
setting_use_blurhash: Преливането е въз основа на цветовете на скритите визуализации, но се замъгляват подробностите setting_use_blurhash: Преливането е въз основа на цветовете на скритите визуализации, но се замъгляват подробностите
setting_use_pending_items: Да се показват обновявания на часовата ос само след щракване вместо автоматично превъртане на инфоканала setting_use_pending_items: Да се показват обновявания на часовата ос само след щракване вместо автоматично превъртане на инфоканала
username: Вашето потребителско име ще е неповторимо в %{domain}
whole_word: Ако ключовата дума или фраза е само буквеноцифрена, то ще се приложи само, ако съвпадне с цялата дума whole_word: Ако ключовата дума или фраза е само буквеноцифрена, то ще се приложи само, ако съвпадне с цялата дума
domain_allow: domain_allow:
domain: Домейнът ще може да извлича данни от този сървър и входящите данни от него ще се обработят и съхранят domain: Домейнът ще може да извлича данни от този сървър и входящите данни от него ще се обработят и съхранят

View File

@ -59,7 +59,6 @@ ca:
setting_show_application: L'aplicació que fas servir per a publicar es mostrarà a la vista detallada dels teus tuts setting_show_application: L'aplicació que fas servir per a publicar es mostrarà a la vista detallada dels teus tuts
setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls
setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament
username: El teu nom d'usuari serà únic a %{domain}
whole_word: Quan la paraula clau o la frase sigui només alfanumèrica, s'aplicarà si coincideix amb la paraula sencera whole_word: Quan la paraula clau o la frase sigui només alfanumèrica, s'aplicarà si coincideix amb la paraula sencera
domain_allow: domain_allow:
domain: Aquest domini podrà obtenir dades daquest servidor i les dades entrants daquests seran processades i emmagatzemades domain: Aquest domini podrà obtenir dades daquest servidor i les dades entrants daquests seran processades i emmagatzemades

View File

@ -51,7 +51,6 @@ ckb:
setting_show_application: بەرنامەیەک کە بە یارمەتیت توت دەکەیت، لە دیمەنی وردی توتەکان پیشان دەدرێت setting_show_application: بەرنامەیەک کە بە یارمەتیت توت دەکەیت، لە دیمەنی وردی توتەکان پیشان دەدرێت
setting_use_blurhash: سێبەرەکان لە سەر بنەمای ڕەنگەکانی بەکارهاتوو لە وێنە داشاراوەکان دروست دەبن بەڵام وردەزانیاری وێنە تێیدا ڕوون نییە setting_use_blurhash: سێبەرەکان لە سەر بنەمای ڕەنگەکانی بەکارهاتوو لە وێنە داشاراوەکان دروست دەبن بەڵام وردەزانیاری وێنە تێیدا ڕوون نییە
setting_use_pending_items: لەجیاتی ئەوەی بە خۆکارانە کێشان هەبێت لە نووسراوەکان بە کرتەیەک بەڕۆژبوونی پێرستی نووسراوەکان بشارەوە setting_use_pending_items: لەجیاتی ئەوەی بە خۆکارانە کێشان هەبێت لە نووسراوەکان بە کرتەیەک بەڕۆژبوونی پێرستی نووسراوەکان بشارەوە
username: ناوی بەکارهێنەری ئێوە لەسەر %{domain} یەکتا دەبێت
whole_word: کاتێک کلیل‌وشە بریتییە لە ژمارە و پیت، تنەها کاتێک پەیدا دەبێت کە لەگەڵ گشتی وشە لە نێو دەقەکە هاوئاهەنگ بێت، نە تەنها لەگەڵ بەشێک لە وشە whole_word: کاتێک کلیل‌وشە بریتییە لە ژمارە و پیت، تنەها کاتێک پەیدا دەبێت کە لەگەڵ گشتی وشە لە نێو دەقەکە هاوئاهەنگ بێت، نە تەنها لەگەڵ بەشێک لە وشە
domain_allow: domain_allow:
domain: ئەم دۆمەینە دەتوانێت دراوە لە ئەم ڕاژە وەربگرێت و دراوەی ئەم دۆمەینە لێرە ڕێکدەخرین و پاشکەوت دەکرێن domain: ئەم دۆمەینە دەتوانێت دراوە لە ئەم ڕاژە وەربگرێت و دراوەی ئەم دۆمەینە لێرە ڕێکدەخرین و پاشکەوت دەکرێن

View File

@ -49,7 +49,6 @@ co:
setting_show_application: L'applicazione chì voi utilizate per mandà statuti sarà affissata indè a vista ditagliata di quelli setting_show_application: L'applicazione chì voi utilizate per mandà statuti sarà affissata indè a vista ditagliata di quelli
setting_use_blurhash: I digradati blurhash sò basati nant'à i culori di u ritrattu piattatu ma senza i ditagli setting_use_blurhash: I digradati blurhash sò basati nant'à i culori di u ritrattu piattatu ma senza i ditagli
setting_use_pending_items: Clicchi per messe à ghjornu i statuti invece di fà sfilà a linea autumaticamente setting_use_pending_items: Clicchi per messe à ghjornu i statuti invece di fà sfilà a linea autumaticamente
username: U vostru cugnome sarà unicu nant'à %{domain}
whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana whole_word: Quandu a parolla o a frasa sana hè alfanumerica, sarà applicata solu s'ella currisponde à a parolla sana
domain_allow: domain_allow:
domain: Stu duminiu puderà ricuperà i dati di stu servore è i dati ch'affaccanu da quallà saranu trattati è cunservati domain: Stu duminiu puderà ricuperà i dati di stu servore è i dati ch'affaccanu da quallà saranu trattati è cunservati

View File

@ -59,7 +59,6 @@ cs:
setting_show_application: Aplikace, kterou používáte k odeslání příspěvků, bude zobrazena jejich detailním zobrazení setting_show_application: Aplikace, kterou používáte k odeslání příspěvků, bude zobrazena jejich detailním zobrazení
setting_use_blurhash: Gradienty jsou založeny na barvách skryté grafiky, ale zakrývají jakékoliv detaily setting_use_blurhash: Gradienty jsou založeny na barvách skryté grafiky, ale zakrývají jakékoliv detaily
setting_use_pending_items: Aktualizovat časovou osu až po kliknutí namísto automatického rolování kanálu setting_use_pending_items: Aktualizovat časovou osu až po kliknutí namísto automatického rolování kanálu
username: Vaše uživatelské jméno bude na serveru %{domain} unikátní
whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikován pouze, pokud se shoduje s celým slovem whole_word: Je-li klíčové slovo či fráze pouze alfanumerická, bude aplikován pouze, pokud se shoduje s celým slovem
domain_allow: domain_allow:
domain: Tato doména bude moci stahovat data z tohoto serveru a příchozí data z ní budou zpracována a uložena domain: Tato doména bude moci stahovat data z tohoto serveru a příchozí data z ní budou zpracována a uložena

View File

@ -59,7 +59,6 @@ cy:
setting_show_application: Bydd y cymhwysiad a ddefnyddiwch i bostio yn cael ei arddangos yng ngolwg fanwl eich postiadau setting_show_application: Bydd y cymhwysiad a ddefnyddiwch i bostio yn cael ei arddangos yng ngolwg fanwl eich postiadau
setting_use_blurhash: Mae graddiannau wedi'u seilio ar liwiau'r delweddau cudd ond maen nhw'n cuddio unrhyw fanylion setting_use_blurhash: Mae graddiannau wedi'u seilio ar liwiau'r delweddau cudd ond maen nhw'n cuddio unrhyw fanylion
setting_use_pending_items: Cuddio diweddariadau llinell amser y tu ôl i glic yn lle sgrolio'n awtomatig setting_use_pending_items: Cuddio diweddariadau llinell amser y tu ôl i glic yn lle sgrolio'n awtomatig
username: Bydd eich enw defnyddiwr yn unigryw ar %{domain}
whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan whole_word: Os yw'r allweddair neu'r ymadrodd yn alffaniwmerig yn unig, mi fydd ond yn cael ei osod os yw'n cyfateb a'r gair cyfan
domain_allow: domain_allow:
domain: Bydd y parth hwn yn gallu nôl data o'r gweinydd hwn a bydd data sy'n dod i mewn ohono yn cael ei brosesu a'i storio domain: Bydd y parth hwn yn gallu nôl data o'r gweinydd hwn a bydd data sy'n dod i mewn ohono yn cael ei brosesu a'i storio

View File

@ -59,7 +59,6 @@ da:
setting_show_application: Applikationen, hvormed der postes, vil fremgå af detailvisningen af dine indlæg setting_show_application: Applikationen, hvormed der postes, vil fremgå af detailvisningen af dine indlæg
setting_use_blurhash: Gradienter er baseret på de skjulte grafikelementers farver, men slører alle detaljer setting_use_blurhash: Gradienter er baseret på de skjulte grafikelementers farver, men slører alle detaljer
setting_use_pending_items: Skjul tidslinjeopdateringer bag et klik i stedet for brug af auto-feedrulning setting_use_pending_items: Skjul tidslinjeopdateringer bag et klik i stedet for brug af auto-feedrulning
username: Dit brugernavn vil være unikt på %{domain}
whole_word: Ved rent alfanumeriske nøgleord/-sætning, forudsætter brugen matchning af hele ordet whole_word: Ved rent alfanumeriske nøgleord/-sætning, forudsætter brugen matchning af hele ordet
domain_allow: domain_allow:
domain: Dette domæne vil kunne hente data, som efterfølgende behandles og gemmes, fra denne server domain: Dette domæne vil kunne hente data, som efterfølgende behandles og gemmes, fra denne server

View File

@ -59,7 +59,6 @@ de:
setting_show_application: Die Anwendung die du nutzt wird in der detaillierten Ansicht deiner Beiträge angezeigt setting_show_application: Die Anwendung die du nutzt wird in der detaillierten Ansicht deiner Beiträge angezeigt
setting_use_blurhash: Die Farbverläufe basieren auf den Farben der verborgenen Medien, verschleiern aber jegliche Details setting_use_blurhash: Die Farbverläufe basieren auf den Farben der verborgenen Medien, verschleiern aber jegliche Details
setting_use_pending_items: Neue Beiträge hinter einem Klick verstecken, anstatt des automatischen Bildlaufs setting_use_pending_items: Neue Beiträge hinter einem Klick verstecken, anstatt des automatischen Bildlaufs
username: Dein Profilname wird auf %{domain} einmalig sein
whole_word: Wenn das Wort oder die Formulierung nur aus Buchstaben oder Zahlen besteht, tritt der Filter nur dann in Kraft, wenn er exakt dieser Zeichenfolge entspricht whole_word: Wenn das Wort oder die Formulierung nur aus Buchstaben oder Zahlen besteht, tritt der Filter nur dann in Kraft, wenn er exakt dieser Zeichenfolge entspricht
domain_allow: domain_allow:
domain: Diese Domain kann Daten von diesem Server abrufen, und eingehende Daten werden verarbeitet und gespeichert domain: Diese Domain kann Daten von diesem Server abrufen, und eingehende Daten werden verarbeitet und gespeichert

View File

@ -59,7 +59,6 @@ el:
setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους setting_show_application: Η εφαρμογή που χρησιμοποιείς για να στέλνεις τα τουτ σου θα εμφανίζεται στις αναλυτικές λεπτομέρειες τους
setting_use_blurhash: Οι χρωματισμοί βασίζονται στα χρώματα του κρυμμένου πολυμέσου αλλά θολώνουν τις λεπτομέρειες setting_use_blurhash: Οι χρωματισμοί βασίζονται στα χρώματα του κρυμμένου πολυμέσου αλλά θολώνουν τις λεπτομέρειες
setting_use_pending_items: Εμφάνιση ενημερώσεων ροής μετά από κλικ αντί για αυτόματη κύλισή τους setting_use_pending_items: Εμφάνιση ενημερώσεων ροής μετά από κλικ αντί για αυτόματη κύλισή τους
username: Το όνομα χρήστη σου θα είναι μοναδικό στο %{domain}
whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη whole_word: Όταν η λέξη ή η φράση κλειδί είναι μόνο αλφαριθμητική, θα εφαρμοστεί μόνο αν ταιριάζει με ολόκληρη τη λέξη
domain_allow: domain_allow:
domain: Ο τομέας αυτός θα επιτρέπεται να ανακτά δεδομένα από αυτό τον διακομιστή και τα εισερχόμενα δεδομένα θα επεξεργάζονται και θα αποθηκεύονται domain: Ο τομέας αυτός θα επιτρέπεται να ανακτά δεδομένα από αυτό τον διακομιστή και τα εισερχόμενα δεδομένα θα επεξεργάζονται και θα αποθηκεύονται

View File

@ -59,7 +59,6 @@ en-GB:
setting_show_application: The application you use to post will be displayed in the detailed view of your posts setting_show_application: The application you use to post will be displayed in the detailed view of your posts
setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details
setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
username: Your username will be unique on %{domain}
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
domain_allow: domain_allow:
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored

View File

@ -59,7 +59,7 @@ en:
setting_show_application: The application you use to post will be displayed in the detailed view of your posts setting_show_application: The application you use to post will be displayed in the detailed view of your posts
setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details setting_use_blurhash: Gradients are based on the colors of the hidden visuals but obfuscate any details
setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed
username: Your username will be unique on %{domain} username: You can use letters, numbers, and underscores
whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word
domain_allow: domain_allow:
domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored

View File

@ -59,7 +59,6 @@ eo:
setting_show_application: La aplikaĵo, kiun vi uzas por afiŝi, estos montrita en la detala vido de viaj afiŝoj setting_show_application: La aplikaĵo, kiun vi uzas por afiŝi, estos montrita en la detala vido de viaj afiŝoj
setting_use_blurhash: Transirojn estas bazita sur la koloroj de la kaŝitaj aŭdovidaĵoj sed ne montri iun ajn detalon setting_use_blurhash: Transirojn estas bazita sur la koloroj de la kaŝitaj aŭdovidaĵoj sed ne montri iun ajn detalon
setting_use_pending_items: Kaŝi tempoliniajn ĝisdatigojn malantaŭ klako anstataŭ aŭtomate rulumi la fluon setting_use_pending_items: Kaŝi tempoliniajn ĝisdatigojn malantaŭ klako anstataŭ aŭtomate rulumi la fluon
username: Via uzantnomo estos unika en %{domain}
whole_word: Kiam la vorto aŭ frazo estas nur litera aŭ cifera, ĝi estos uzata nur se ĝi kongruas kun la tuta vorto whole_word: Kiam la vorto aŭ frazo estas nur litera aŭ cifera, ĝi estos uzata nur se ĝi kongruas kun la tuta vorto
domain_allow: domain_allow:
domain: Ĉi tiu domajno povos akiri datumon de ĉi tiu servilo kaj envenanta datumo estos prilaborita kaj konservita domain: Ĉi tiu domajno povos akiri datumon de ĉi tiu servilo kaj envenanta datumo estos prilaborita kaj konservita

View File

@ -59,7 +59,6 @@ es-AR:
setting_show_application: La aplicación que usás para enviar mensajes se mostrará en la vista detallada de tus mensajes setting_show_application: La aplicación que usás para enviar mensajes se mostrará en la vista detallada de tus mensajes
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar actualizaciones de la línea temporal detrás de un clic en lugar de desplazar automáticamente el flujo setting_use_pending_items: Ocultar actualizaciones de la línea temporal detrás de un clic en lugar de desplazar automáticamente el flujo
username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es sólo alfanumérica, sólo será aplicado si coincide con toda la palabra whole_word: Cuando la palabra clave o frase es sólo alfanumérica, sólo será aplicado si coincide con toda la palabra
domain_allow: domain_allow:
domain: Este dominio podrá recolectar datos de este servidor, y los datos entrantes serán procesados y archivados domain: Este dominio podrá recolectar datos de este servidor, y los datos entrantes serán procesados y archivados

View File

@ -59,7 +59,6 @@ es-MX:
setting_show_application: La aplicación que utiliza usted para publicar toots se mostrará en la vista detallada de sus toots setting_show_application: La aplicación que utiliza usted para publicar toots se mostrará en la vista detallada de sus toots
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed
username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra
domain_allow: domain_allow:
domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados

View File

@ -59,7 +59,6 @@ es:
setting_show_application: La aplicación que utiliza usted para publicar publicaciones se mostrará en la vista detallada de sus publicaciones setting_show_application: La aplicación que utiliza usted para publicar publicaciones se mostrará en la vista detallada de sus publicaciones
setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles setting_use_blurhash: Los gradientes se basan en los colores de las imágenes ocultas pero haciendo borrosos los detalles
setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed setting_use_pending_items: Ocultar nuevos estados detrás de un clic en lugar de desplazar automáticamente el feed
username: Tu nombre de usuario será único en %{domain}
whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra whole_word: Cuando la palabra clave o frase es solo alfanumérica, solo será aplicado si concuerda con toda la palabra
domain_allow: domain_allow:
domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados domain: Este dominio podrá obtener datos de este servidor y los datos entrantes serán procesados y archivados

View File

@ -59,7 +59,6 @@ et:
setting_show_application: Postitamiseks kasutatud rakenduse infot kuvatakse postituse üksikasjavaates setting_show_application: Postitamiseks kasutatud rakenduse infot kuvatakse postituse üksikasjavaates
setting_use_blurhash: Värvid põhinevad peidetud visuaalidel, kuid hägustavad igasuguseid detaile setting_use_blurhash: Värvid põhinevad peidetud visuaalidel, kuid hägustavad igasuguseid detaile
setting_use_pending_items: Voo automaatse kerimise asemel peida ajajoone uuendused kliki taha setting_use_pending_items: Voo automaatse kerimise asemel peida ajajoone uuendused kliki taha
username: Sinu kasutajanimi on %{domain}-il unikaalne
whole_word: Kui võtmesõna või fraas on ainult tähtnumbriline, rakendub see ainult siis, kui see kattub terve sõnaga whole_word: Kui võtmesõna või fraas on ainult tähtnumbriline, rakendub see ainult siis, kui see kattub terve sõnaga
domain_allow: domain_allow:
domain: See domeen saab tõmmata andmeid sellelt serverilt ning sissetulevad andmed sellelt domeenilt töödeldakse ning salvestatakse domain: See domeen saab tõmmata andmeid sellelt serverilt ning sissetulevad andmed sellelt domeenilt töödeldakse ning salvestatakse

View File

@ -59,7 +59,6 @@ eu:
setting_show_application: Tootak bidaltzeko erabiltzen duzun aplikazioa zure tooten ikuspegi xehetsuan bistaratuko da setting_show_application: Tootak bidaltzeko erabiltzen duzun aplikazioa zure tooten ikuspegi xehetsuan bistaratuko da
setting_use_blurhash: Gradienteak ezkutatutakoaren koloreetan oinarritzen dira, baina xehetasunak ezkutatzen dituzte setting_use_blurhash: Gradienteak ezkutatutakoaren koloreetan oinarritzen dira, baina xehetasunak ezkutatzen dituzte
setting_use_pending_items: Ezkutatu denbora-lerroko eguneraketak klik baten atzean jarioa automatikoki korritu ordez setting_use_pending_items: Ezkutatu denbora-lerroko eguneraketak klik baten atzean jarioa automatikoki korritu ordez
username: Zure erabiltzaile-izena bakana izango da %{domain} domeinuan
whole_word: Hitz eta esaldi gakoa alfanumerikoa denean, hitz osoarekin bat datorrenean besterik ez da aplikatuko whole_word: Hitz eta esaldi gakoa alfanumerikoa denean, hitz osoarekin bat datorrenean besterik ez da aplikatuko
domain_allow: domain_allow:
domain: Domeinu honek zerbitzari honetatik datuak hartu ahal izango ditu eta bertatik jasotako informazioa prozesatu eta gordeko da domain: Domeinu honek zerbitzari honetatik datuak hartu ahal izango ditu eta bertatik jasotako informazioa prozesatu eta gordeko da

View File

@ -59,7 +59,6 @@ fa:
setting_show_application: برنامه‌ای که به کمک آن فرسته می‌زنید، در جزئیات فرسته شما نمایش خواهد یافت setting_show_application: برنامه‌ای که به کمک آن فرسته می‌زنید، در جزئیات فرسته شما نمایش خواهد یافت
setting_use_blurhash: سایه‌ها بر اساس رنگ‌های به‌کاررفته در تصویر پنهان‌شده ساخته می‌شوند ولی جزئیات تصویر در آن‌ها آشکار نیست setting_use_blurhash: سایه‌ها بر اساس رنگ‌های به‌کاررفته در تصویر پنهان‌شده ساخته می‌شوند ولی جزئیات تصویر در آن‌ها آشکار نیست
setting_use_pending_items: به جای پیش‌رفتن خودکار در فهرست، به‌روزرسانی فهرست نوشته‌ها را پشت یک کلیک پنهان کن setting_use_pending_items: به جای پیش‌رفتن خودکار در فهرست، به‌روزرسانی فهرست نوشته‌ها را پشت یک کلیک پنهان کن
username: نام کاربری شما روی %{domain} یکتا خواهد بود
whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه whole_word: اگر کلیدواژه فقط دارای حروف و اعداد باشد، تنها وقتی پیدا می‌شود که با کل یک واژه در متن منطبق باشد، نه با بخشی از یک واژه
domain_allow: domain_allow:
domain: این دامین خواهد توانست داده‌ها از این سرور را دریافت کند و داده‌های از این دامین در این‌جا پردازش و ذخیره خواهند شد domain: این دامین خواهد توانست داده‌ها از این سرور را دریافت کند و داده‌های از این دامین در این‌جا پردازش و ذخیره خواهند شد

View File

@ -59,7 +59,6 @@ fi:
setting_show_application: Viestittelyyn käyttämäsi sovellus näkyy viestiesi yksityiskohtaisessa näkymässä setting_show_application: Viestittelyyn käyttämäsi sovellus näkyy viestiesi yksityiskohtaisessa näkymässä
setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat setting_use_blurhash: Liukuvärit perustuvat piilotettujen kuvien väreihin, mutta sumentavat yksityiskohdat
setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse sen sijaan, että vierittäisi syötettä automaattisesti setting_use_pending_items: Piilota aikajanan päivitykset napsautuksen taakse sen sijaan, että vierittäisi syötettä automaattisesti
username: Käyttäjänimesi tulee olemaan yksilöllinen %{domain}
whole_word: Kun avainsana tai lause on vain aakkosnumeerinen, se otetaan käyttöön, jos se vastaa koko sanaa whole_word: Kun avainsana tai lause on vain aakkosnumeerinen, se otetaan käyttöön, jos se vastaa koko sanaa
domain_allow: domain_allow:
domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan domain: Tämä verkkotunnus voi noutaa tietoja tältä palvelimelta ja sieltä saapuvat tiedot käsitellään ja tallennetaan

View File

@ -59,7 +59,6 @@ fo:
setting_show_application: Nýtsluskipanin, sum tú brúkar at posta við, verður víst í nágreinligu vísingini av postum tínum setting_show_application: Nýtsluskipanin, sum tú brúkar at posta við, verður víst í nágreinligu vísingini av postum tínum
setting_use_blurhash: Gradientar eru grundaðir á litirnar av fjaldu myndunum, men grugga allar smálutir setting_use_blurhash: Gradientar eru grundaðir á litirnar av fjaldu myndunum, men grugga allar smálutir
setting_use_pending_items: Fjal tíðarlinjudagføringar aftan fyri eitt klikk heldur enn at skrulla tilføringina sjálvvirkandi setting_use_pending_items: Fjal tíðarlinjudagføringar aftan fyri eitt klikk heldur enn at skrulla tilføringina sjálvvirkandi
username: Brúkaranavnið hjá tær verður eindømi á %{domain}
whole_word: Tá lyklaorðið ella frasan einans hevur bókstavir og tøl, so verður hon einans nýtt, um tú samsvarar við alt orðið whole_word: Tá lyklaorðið ella frasan einans hevur bókstavir og tøl, so verður hon einans nýtt, um tú samsvarar við alt orðið
domain_allow: domain_allow:
domain: Økisnavnið kann heinta dátur frá hesum ambætaranum og inngangandi dátur frá honum verða viðgjørdar og goymdar domain: Økisnavnið kann heinta dátur frá hesum ambætaranum og inngangandi dátur frá honum verða viðgjørdar og goymdar

View File

@ -59,7 +59,6 @@ fr-QC:
setting_show_application: Le nom de lapplication que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages setting_show_application: Le nom de lapplication que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages
setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais nen montrent pas les détails setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais nen montrent pas les détails
setting_use_pending_items: Cacher les mises à jour des fils dactualités derrière un clic, au lieu de les afficher automatiquement setting_use_pending_items: Cacher les mises à jour des fils dactualités derrière un clic, au lieu de les afficher automatiquement
username: Votre nom dutilisateur sera unique sur %{domain}
whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que sil correspond au mot entier whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que sil correspond au mot entier
domain_allow: domain_allow:
domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées

View File

@ -59,7 +59,6 @@ fr:
setting_show_application: Le nom de lapplication que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages setting_show_application: Le nom de lapplication que vous utilisez pour publier sera affichée dans la vue détaillée de vos messages
setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais nen montrent pas les détails setting_use_blurhash: Les dégradés sont basés sur les couleurs des images cachées mais nen montrent pas les détails
setting_use_pending_items: Cacher les mises à jour des fils dactualités derrière un clic, au lieu de les afficher automatiquement setting_use_pending_items: Cacher les mises à jour des fils dactualités derrière un clic, au lieu de les afficher automatiquement
username: Votre identifiant sera unique sur %{domain}
whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que sil correspond au mot entier whole_word: Si le mot-clé ou la phrase est alphanumérique, alors le filtre ne sera appliqué que sil correspond au mot entier
domain_allow: domain_allow:
domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées domain: Ce domaine pourra récupérer des données de ce serveur et les données entrantes seront traitées et stockées

View File

@ -59,7 +59,6 @@ fy:
setting_show_application: De tapassing dyt jo brûke om berjochten te pleatsen, wurdt yn de detaillearre werjefte fan it berjocht toand setting_show_application: De tapassing dyt jo brûke om berjochten te pleatsen, wurdt yn de detaillearre werjefte fan it berjocht toand
setting_use_blurhash: Dizige kleuroergongen binne basearre op de kleuren fan de ferstoppe media, wêrmei elk detail ferdwynt setting_use_blurhash: Dizige kleuroergongen binne basearre op de kleuren fan de ferstoppe media, wêrmei elk detail ferdwynt
setting_use_pending_items: De tiidline wurdt bywurke troch op it oantal nije items te klikken, yn stee fan dat dizze automatysk bywurke wurdt setting_use_pending_items: De tiidline wurdt bywurke troch op it oantal nije items te klikken, yn stee fan dat dizze automatysk bywurke wurdt
username: Jo brûkersnamme is unyk op %{domain}
whole_word: Wannear it trefwurd of part fan de sin alfanumeryk is, wurdt it allinnich filtere wanneart it hiele wurd oerienkomt whole_word: Wannear it trefwurd of part fan de sin alfanumeryk is, wurdt it allinnich filtere wanneart it hiele wurd oerienkomt
domain_allow: domain_allow:
domain: Dit domein is yn steat om gegevens fan dizze server op te heljen, en ynkommende gegevens wurde ferwurke en bewarre domain: Dit domein is yn steat om gegevens fan dizze server op te heljen, en ynkommende gegevens wurde ferwurke en bewarre

View File

@ -59,7 +59,6 @@ gd:
setting_show_application: Chithear cò an aplacaid a chleachd thu airson post a sgrìobhadh ann an seallaidhean mionaideach nam postaichean agad setting_show_application: Chithear cò an aplacaid a chleachd thu airson post a sgrìobhadh ann an seallaidhean mionaideach nam postaichean agad
setting_use_blurhash: Tha caiseadan stèidhichte air dathan nan nithean lèirsinneach a chaidh fhalach ach chan fhaicear am mion-fhiosrachadh setting_use_blurhash: Tha caiseadan stèidhichte air dathan nan nithean lèirsinneach a chaidh fhalach ach chan fhaicear am mion-fhiosrachadh
setting_use_pending_items: Falaich ùrachaidhean na loidhne-ama air cùlaibh briogaidh seach a bhith a sgroladh nam postaichean gu fèin-obrachail setting_use_pending_items: Falaich ùrachaidhean na loidhne-ama air cùlaibh briogaidh seach a bhith a sgroladh nam postaichean gu fèin-obrachail
username: Bidh ainm-cleachdaiche àraidh agad air %{domain}
whole_word: Mur eil ach litrichean is àireamhan san fhacal-luirg, cha dèid a chur an sàs ach ma bhios e a maidseadh an fhacail shlàin whole_word: Mur eil ach litrichean is àireamhan san fhacal-luirg, cha dèid a chur an sàs ach ma bhios e a maidseadh an fhacail shlàin
domain_allow: domain_allow:
domain: "S urrainn dhan àrainn seo dàta fhaighinn on fhrithealaiche seo agus thèid an dàta a thig a-steach uaithe a phròiseasadh s a stòradh" domain: "S urrainn dhan àrainn seo dàta fhaighinn on fhrithealaiche seo agus thèid an dàta a thig a-steach uaithe a phròiseasadh s a stòradh"

View File

@ -59,7 +59,6 @@ gl:
setting_show_application: A aplicación que estás a utilizar para enviar publicacións mostrarase na vista detallada da publicación setting_show_application: A aplicación que estás a utilizar para enviar publicacións mostrarase na vista detallada da publicación
setting_use_blurhash: Os gradientes toman as cores da imaxe oculta pero esvaecendo tódolos detalles setting_use_blurhash: Os gradientes toman as cores da imaxe oculta pero esvaecendo tódolos detalles
setting_use_pending_items: Agochar actualizacións da cronoloxía tras un click no lugar de desprazar automáticamente os comentarios setting_use_pending_items: Agochar actualizacións da cronoloxía tras un click no lugar de desprazar automáticamente os comentarios
username: O teu nome de usuaria será único en %{domain}
whole_word: Se a chave ou frase de paso é só alfanumérica, só se aplicará se concorda a palabra completa whole_word: Se a chave ou frase de paso é só alfanumérica, só se aplicará se concorda a palabra completa
domain_allow: domain_allow:
domain: Este dominio estará en disposición de obter datos desde este servidor e datos de entrada a el poderán ser procesados e gardados domain: Este dominio estará en disposición de obter datos desde este servidor e datos de entrada a el poderán ser procesados e gardados

View File

@ -59,7 +59,6 @@ he:
setting_show_application: היישום בו נעשה שימוש כדי לחצרץ יופיע בתצוגה המפורטת של החצרוץ setting_show_application: היישום בו נעשה שימוש כדי לחצרץ יופיע בתצוגה המפורטת של החצרוץ
setting_use_blurhash: הגראדיינטים מבוססים על תוכן התמונה המוסתרת, אבל מסתירים את כל הפרטים setting_use_blurhash: הגראדיינטים מבוססים על תוכן התמונה המוסתרת, אבל מסתירים את כל הפרטים
setting_use_pending_items: הסתר עדכוני פיד מאחורי קליק במקום לגלול את הפיד אוטומטית setting_use_pending_items: הסתר עדכוני פיד מאחורי קליק במקום לגלול את הפיד אוטומטית
username: שם המשתמש שלך יהיה ייחודי ב- %{domain}
whole_word: אם מילת מפתח או ביטוי הם אלפאנומריים בלבד, הם יופעלו רק אם נמצאה התאמה למילה שלמה whole_word: אם מילת מפתח או ביטוי הם אלפאנומריים בלבד, הם יופעלו רק אם נמצאה התאמה למילה שלמה
domain_allow: domain_allow:
domain: דומיין זה יוכל לייבא מידע משרת זה והמידע המגיע ממנו יעובד ויאופסן domain: דומיין זה יוכל לייבא מידע משרת זה והמידע המגיע ממנו יעובד ויאופסן

View File

@ -59,7 +59,6 @@ hu:
setting_show_application: A bejegyzések részletes nézetében látszani fog, milyen alkalmazást használtál a bejegyzés közzétételéhez setting_show_application: A bejegyzések részletes nézetében látszani fog, milyen alkalmazást használtál a bejegyzés közzétételéhez
setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt
setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett
username: A felhasználói neved egyedi lesz a %{domain} domainen
whole_word: Ha a kulcsszó alfanumerikus, csak akkor minősül majd találatnak, ha teljes szóra illeszkedik whole_word: Ha a kulcsszó alfanumerikus, csak akkor minősül majd találatnak, ha teljes szóra illeszkedik
domain_allow: domain_allow:
domain: Ez a domain adatokat kérhet le erről a kiszolgálóról, és a bejövő adatok fel lesznek dolgozva és tárolva lesznek domain: Ez a domain adatokat kérhet le erről a kiszolgálóról, és a bejövő adatok fel lesznek dolgozva és tárolva lesznek

View File

@ -49,7 +49,6 @@ hy:
setting_show_application: Գրառման մանրամասներում կերեւայ թէ որ ծրագրով ես հրապարակել այն setting_show_application: Գրառման մանրամասներում կերեւայ թէ որ ծրագրով ես հրապարակել այն
setting_use_blurhash: Կտորները հիմնուում են թաքցուած վիզուալի վրայ՝ խամրեցնելով դետալները setting_use_blurhash: Կտորները հիմնուում են թաքցուած վիզուալի վրայ՝ խամրեցնելով դետալները
setting_use_pending_items: Թաքցնել հոսքի թարմացումները կտտոի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն setting_use_pending_items: Թաքցնել հոսքի թարմացումները կտտոի ետեւում՝ աւտօմատ թարմացուող հոսքի փոխարէն
username: Քո օգտանունը պէտք է եզակի լինի %{domain}-ում։
whole_word: Եթէ բանալի բառը կամ արտայայտութիւնը պարունակում է միայն այբբենական նիշեր եւ թուեր, ապա այն կիրառուելու է ամբողջ բառի հետ համընկնելու դէպքում միայն whole_word: Եթէ բանալի բառը կամ արտայայտութիւնը պարունակում է միայն այբբենական նիշեր եւ թուեր, ապա այն կիրառուելու է ամբողջ բառի հետ համընկնելու դէպքում միայն
domain_allow: domain_allow:
domain: Այս տիրոյթը կարող է ստանալ տուեալներ այս սպասարկչից եւ ստացուող տուեալները կարող են օգտագործուել եւ պահուել domain: Այս տիրոյթը կարող է ստանալ տուեալներ այս սպասարկչից եւ ստացուող տուեալները կարող են օգտագործուել եւ պահուել

View File

@ -57,7 +57,6 @@ id:
setting_show_application: Aplikasi yang Anda pakai untuk men-toot akan ditampilkan di tampilan detail toot setting_show_application: Aplikasi yang Anda pakai untuk men-toot akan ditampilkan di tampilan detail toot
setting_use_blurhash: Gradien didasarkan pada warna visual yang tersembunyi tetapi mengaburkan setiap detail setting_use_blurhash: Gradien didasarkan pada warna visual yang tersembunyi tetapi mengaburkan setiap detail
setting_use_pending_items: Sembunyikan pembaruan linimasa di balik klik alih-alih bergulir secara otomatis setting_use_pending_items: Sembunyikan pembaruan linimasa di balik klik alih-alih bergulir secara otomatis
username: Nama pengguna Anda unik di %{domain}
whole_word: Ketika kata kunci/frasa hanya alfanumerik, maka itu hanya akan diterapkan jika cocok dengan semua kata whole_word: Ketika kata kunci/frasa hanya alfanumerik, maka itu hanya akan diterapkan jika cocok dengan semua kata
domain_allow: domain_allow:
domain: Domain ini dapat mengambil data dari server ini dan data yang diterima akan diproses dan disimpan domain: Domain ini dapat mengambil data dari server ini dan data yang diterima akan diproses dan disimpan

View File

@ -57,7 +57,6 @@ io:
setting_show_application: Softwaro quon vu uzar por postigar montresos che detala vidajo di vua posti setting_show_application: Softwaro quon vu uzar por postigar montresos che detala vidajo di vua posti
setting_use_blurhash: Inklini esas segun kolori di celesis vidaji ma kovras irga detali setting_use_blurhash: Inklini esas segun kolori di celesis vidaji ma kovras irga detali
setting_use_pending_items: Celez tempolineonovi dop kliktar e ne automatike movigar niuzeto setting_use_pending_items: Celez tempolineonovi dop kliktar e ne automatike movigar niuzeto
username: Vua uzantonomo esos nura che %{domain}
whole_word: Kande klefvorto o fraz esas nur litera e nombra, ol nur aplikesos se ol parigesas la tota vorto whole_word: Kande klefvorto o fraz esas nur litera e nombra, ol nur aplikesos se ol parigesas la tota vorto
domain_allow: domain_allow:
domain: Ca domeno povas ganar informi de ca servilo e venanta informo de ol procedagesos e sparesos domain: Ca domeno povas ganar informi de ca servilo e venanta informo de ol procedagesos e sparesos

View File

@ -59,7 +59,6 @@ is:
setting_show_application: Nafnið á forritinu sem þú notar til að senda færslur mun birtast í ítarlegri sýn á færslunum þínum setting_show_application: Nafnið á forritinu sem þú notar til að senda færslur mun birtast í ítarlegri sýn á færslunum þínum
setting_use_blurhash: Litstiglarnir byggja á litunum í földu myndunum, en gera öll smáatriði óskýr setting_use_blurhash: Litstiglarnir byggja á litunum í földu myndunum, en gera öll smáatriði óskýr
setting_use_pending_items: Fela uppfærslur tímalínu þar til smellt er, í stað þess að hún skruni streyminu sjálfvirkt setting_use_pending_items: Fela uppfærslur tímalínu þar til smellt er, í stað þess að hún skruni streyminu sjálfvirkt
username: Notandanafnið þitt verður einstakt á %{domain}
whole_word: Þegar stikkorð eða setning er einungis tölur og bókstafir, verður það aðeins notað ef það samsvarar heilu orði whole_word: Þegar stikkorð eða setning er einungis tölur og bókstafir, verður það aðeins notað ef það samsvarar heilu orði
domain_allow: domain_allow:
domain: Þetta lén mun geta sótt gögn af þessum vefþjóni og tekið verður á móti innsendum gögnum frá léninu til vinnslu og geymslu domain: Þetta lén mun geta sótt gögn af þessum vefþjóni og tekið verður á móti innsendum gögnum frá léninu til vinnslu og geymslu

View File

@ -59,7 +59,6 @@ it:
setting_show_application: L'applicazione che usi per pubblicare i toot sarà mostrata nella vista di dettaglio dei tuoi toot setting_show_application: L'applicazione che usi per pubblicare i toot sarà mostrata nella vista di dettaglio dei tuoi toot
setting_use_blurhash: I gradienti sono basati sui colori delle immagini nascoste ma offuscano tutti i dettagli setting_use_blurhash: I gradienti sono basati sui colori delle immagini nascoste ma offuscano tutti i dettagli
setting_use_pending_items: Fare clic per mostrare i nuovi messaggi invece di aggiornare la timeline automaticamente setting_use_pending_items: Fare clic per mostrare i nuovi messaggi invece di aggiornare la timeline automaticamente
username: Il tuo nome utente sarà unico su %{domain}
whole_word: Quando la parola chiave o la frase è solo alfanumerica, si applica solo se corrisponde alla parola intera whole_word: Quando la parola chiave o la frase è solo alfanumerica, si applica solo se corrisponde alla parola intera
domain_allow: domain_allow:
domain: Questo dominio potrà recuperare i dati da questo server e i dati in arrivo da esso verranno elaborati e memorizzati domain: Questo dominio potrà recuperare i dati da questo server e i dati in arrivo da esso verranno elaborati e memorizzati

View File

@ -59,7 +59,6 @@ ja:
setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります setting_show_application: 投稿するのに使用したアプリが投稿の詳細ビューに表示されるようになります
setting_use_blurhash: ぼかしはメディアの色を元に生成されますが、細部は見えにくくなっています setting_use_blurhash: ぼかしはメディアの色を元に生成されますが、細部は見えにくくなっています
setting_use_pending_items: 新着があってもタイムラインを自動的にスクロールしないようにします setting_use_pending_items: 新着があってもタイムラインを自動的にスクロールしないようにします
username: あなたのユーザー名は%{domain}の中で重複していない必要があります
whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります whole_word: キーワードまたはフレーズが英数字のみの場合、単語全体と一致する場合のみ適用されるようになります
domain_allow: domain_allow:
domain: 登録するとこのサーバーからデータを受信したり、このドメインから受信するデータを処理して保存できるようになります domain: 登録するとこのサーバーからデータを受信したり、このドメインから受信するデータを処理して保存できるようになります

View File

@ -20,7 +20,6 @@ kab:
setting_display_media_hide_all: Ffer yal tikkelt akk taywalt setting_display_media_hide_all: Ffer yal tikkelt akk taywalt
setting_display_media_show_all: Ffer yal tikkelt teywalt yettwacreḍ d tanafrit setting_display_media_show_all: Ffer yal tikkelt teywalt yettwacreḍ d tanafrit
setting_hide_network: Wid i teṭṭafaṛeḍ d wid i k-yeṭṭafaṛen ur d-ttwaseknen ara deg umaγnu-inek setting_hide_network: Wid i teṭṭafaṛeḍ d wid i k-yeṭṭafaṛen ur d-ttwaseknen ara deg umaγnu-inek
username: Isem-ik n umseqdac ad yili d ayiwen, ulac am netta deg %{domain}
imports: imports:
data: Afaylu CSV id yusan seg uqeddac-nniḍen n Maṣṭudun data: Afaylu CSV id yusan seg uqeddac-nniḍen n Maṣṭudun
ip_block: ip_block:

View File

@ -59,7 +59,6 @@ ko:
setting_show_application: 당신이 게시물을 작성하는데에 사용한 앱이 게시물의 상세정보에 표시 됩니다 setting_show_application: 당신이 게시물을 작성하는데에 사용한 앱이 게시물의 상세정보에 표시 됩니다
setting_use_blurhash: 그라디언트는 숨겨진 내용의 색상을 기반으로 하지만 상세 내용은 보이지 않게 합니다 setting_use_blurhash: 그라디언트는 숨겨진 내용의 색상을 기반으로 하지만 상세 내용은 보이지 않게 합니다
setting_use_pending_items: 타임라인의 새 게시물을 자동으로 보여 주는 대신, 클릭해서 나타내도록 합니다 setting_use_pending_items: 타임라인의 새 게시물을 자동으로 보여 주는 대신, 클릭해서 나타내도록 합니다
username: 당신의 사용자명은 %{domain} 안에서 유일해야 합니다
whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다 whole_word: 키워드가 영문과 숫자로만 이루어 진 경우, 단어 전체에 매칭 되었을 때에만 작동하게 합니다
domain_allow: domain_allow:
domain: 이 도메인은 이 서버에서 데이터를 가져갈 수 있고 이 도메인에서 보내진 데이터는 처리되고 저장 됩니다 domain: 이 도메인은 이 서버에서 데이터를 가져갈 수 있고 이 도메인에서 보내진 데이터는 처리되고 저장 됩니다

View File

@ -59,7 +59,6 @@ ku:
setting_show_application: Navê sepana ku tu ji bo şandinê wê bi kar tîne dê di dîtinê berferh ên di şandiyên te de were xuyakirin setting_show_application: Navê sepana ku tu ji bo şandinê wê bi kar tîne dê di dîtinê berferh ên di şandiyên te de were xuyakirin
setting_use_blurhash: Gradyen xwe bi rengên dîtbarîyên veşartî ve radigire, lê belê hûrgilîyan diveşêre setting_use_blurhash: Gradyen xwe bi rengên dîtbarîyên veşartî ve radigire, lê belê hûrgilîyan diveşêre
setting_use_pending_items: Li şûna ku herkê wek bixweber bizivirînî nûvekirina demnameyê li paş tikandinekî veşêre setting_use_pending_items: Li şûna ku herkê wek bixweber bizivirînî nûvekirina demnameyê li paş tikandinekî veşêre
username: Navê te yê bikarhênerî li ser %{domain} de bêhempa be
whole_word: Dema peyvkilîd an jî hevok bi tenê alfahejmarî çêbe, bi tenê hemû bêjeyê re li hev bike wê pêk bê whole_word: Dema peyvkilîd an jî hevok bi tenê alfahejmarî çêbe, bi tenê hemû bêjeyê re li hev bike wê pêk bê
domain_allow: domain_allow:
domain: Ev navê navperê, ji vê rajekarê wê daneyan bistîne û daneyên ku jê bê wê were sazkirin û veşartin domain: Ev navê navperê, ji vê rajekarê wê daneyan bistîne û daneyên ku jê bê wê were sazkirin û veşartin

View File

@ -59,7 +59,6 @@ lv:
setting_show_application: Lietojumprogramma, ko tu izmanto publicēšanai, tiks parādīta tavu ziņu detalizētajā skatā setting_show_application: Lietojumprogramma, ko tu izmanto publicēšanai, tiks parādīta tavu ziņu detalizētajā skatā
setting_use_blurhash: Gradientu pamatā ir paslēpto vizuālo attēlu krāsas, bet neskaidras visas detaļas setting_use_blurhash: Gradientu pamatā ir paslēpto vizuālo attēlu krāsas, bet neskaidras visas detaļas
setting_use_pending_items: Paslēpt laika skalas atjauninājumus aiz klikšķa, nevis automātiski ritini plūsmu setting_use_pending_items: Paslēpt laika skalas atjauninājumus aiz klikšķa, nevis automātiski ritini plūsmu
username: Tavs lietotājvārds %{domain} būs unikāls
whole_word: Ja atslēgvārds vai frāze ir tikai burtciparu, tas tiks lietots tikai tad, ja tas atbilst visam vārdam whole_word: Ja atslēgvārds vai frāze ir tikai burtciparu, tas tiks lietots tikai tad, ja tas atbilst visam vārdam
domain_allow: domain_allow:
domain: Šis domēns varēs izgūt datus no šī servera, un no tā ienākošie dati tiks apstrādāti un saglabāti domain: Šis domēns varēs izgūt datus no šī servera, un no tā ienākošie dati tiks apstrādāti un saglabāti

View File

@ -59,7 +59,6 @@ my:
setting_show_application: ပို့စ်တင်ရန်အတွက် သင်အသုံးပြုသည့် အက်ပလီကေးရှင်းကို သင့်ပို့စ်များ၏ အသေးစိတ်ကြည့်ရှုမှုတွင် ပြသမည်ဖြစ်သည် setting_show_application: ပို့စ်တင်ရန်အတွက် သင်အသုံးပြုသည့် အက်ပလီကေးရှင်းကို သင့်ပို့စ်များ၏ အသေးစိတ်ကြည့်ရှုမှုတွင် ပြသမည်ဖြစ်သည်
setting_use_blurhash: Gradients မှာ ဖျောက်ထားသောရုပ်ပုံများ၏ အရောင်များကိုအခြေခံသော်လည်း မည်သည့်အသေးစိတ်အချက်အလက်ကိုမဆို ရှုပ်ထွေးစေနိုင်ပါသည်။ setting_use_blurhash: Gradients မှာ ဖျောက်ထားသောရုပ်ပုံများ၏ အရောင်များကိုအခြေခံသော်လည်း မည်သည့်အသေးစိတ်အချက်အလက်ကိုမဆို ရှုပ်ထွေးစေနိုင်ပါသည်။
setting_use_pending_items: အပေါ်အောက်လှိမ့်မည့်အစား ကလစ်တစ်ခုနောက်တွင် စာမျက်နှာအပ်ဒိတ်များကို ဖျောက်ထားပါ။ setting_use_pending_items: အပေါ်အောက်လှိမ့်မည့်အစား ကလစ်တစ်ခုနောက်တွင် စာမျက်နှာအပ်ဒိတ်များကို ဖျောက်ထားပါ။
username: "%{domain} ရှိ သင့်အသုံးပြုသူအမည်မှာ တူညီ၍မရပါ"
whole_word: အဓိကစကားလုံး သို့မဟုတ် စကားစုသည် အက္ခရာဂဏန်းများသာဖြစ်ပါကစကားလုံးတစ်ခုလုံးနှင့် ကိုက်ညီမှသာ အသုံးပြုနိုင်မည်ဖြစ်သည် whole_word: အဓိကစကားလုံး သို့မဟုတ် စကားစုသည် အက္ခရာဂဏန်းများသာဖြစ်ပါကစကားလုံးတစ်ခုလုံးနှင့် ကိုက်ညီမှသာ အသုံးပြုနိုင်မည်ဖြစ်သည်
domain_allow: domain_allow:
domain: ဤဒိုမိန်းသည် ဤဆာဗာမှ အချက်အလက်များကို ရယူနိုင်မည်ဖြစ်ပြီး ဝင်လာသောအချက်အလက်များကို စီမံဆောင်ရွက်ပေးပြီး သိမ်းဆည်းသွားမည်ဖြစ်သည် domain: ဤဒိုမိန်းသည် ဤဆာဗာမှ အချက်အလက်များကို ရယူနိုင်မည်ဖြစ်ပြီး ဝင်လာသောအချက်အလက်များကို စီမံဆောင်ရွက်ပေးပြီး သိမ်းဆည်းသွားမည်ဖြစ်သည်

View File

@ -59,7 +59,6 @@ nl:
setting_show_application: De toepassing de je gebruikt om berichten te plaatsen wordt in de gedetailleerde weergave van het bericht getoond setting_show_application: De toepassing de je gebruikt om berichten te plaatsen wordt in de gedetailleerde weergave van het bericht getoond
setting_use_blurhash: Wazige kleurovergangen zijn gebaseerd op de kleuren van de verborgen media, waarmee elk detail verdwijnt setting_use_blurhash: Wazige kleurovergangen zijn gebaseerd op de kleuren van de verborgen media, waarmee elk detail verdwijnt
setting_use_pending_items: De tijdlijn wordt bijgewerkt door op het aantal nieuwe items te klikken, in plaats van dat deze automatisch wordt bijgewerkt setting_use_pending_items: De tijdlijn wordt bijgewerkt door op het aantal nieuwe items te klikken, in plaats van dat deze automatisch wordt bijgewerkt
username: Jouw gebruikersnaam is uniek op %{domain}
whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt whole_word: Wanneer het trefwoord of zinsdeel alfanumeriek is, wordt het alleen gefilterd wanneer het hele woord overeenkomt
domain_allow: domain_allow:
domain: Dit domein is in staat om gegevens van deze server op te halen, en binnenkomende gegevens worden verwerkt en opgeslagen domain: Dit domein is in staat om gegevens van deze server op te halen, en binnenkomende gegevens worden verwerkt en opgeslagen

View File

@ -57,7 +57,6 @@ nn:
setting_show_application: Programmet du brukar for å tuta blir vist i den detaljerte visninga av tuta dine setting_show_application: Programmet du brukar for å tuta blir vist i den detaljerte visninga av tuta dine
setting_use_blurhash: Overgangar er basert på fargane til skjulte grafikkelement, men gjer detaljar utydelege setting_use_blurhash: Overgangar er basert på fargane til skjulte grafikkelement, men gjer detaljar utydelege
setting_use_pending_items: Gøym tidslineoppdateringar bak eit klikk, i staden for å rulla ned automatisk setting_use_pending_items: Gøym tidslineoppdateringar bak eit klikk, i staden for å rulla ned automatisk
username: Brukarnamnet ditt vert unikt på %{domain}
whole_word: Når søkjeordet eller setninga berre er alfanumerisk, nyttast det berre om det samsvarar med heile ordet whole_word: Når søkjeordet eller setninga berre er alfanumerisk, nyttast det berre om det samsvarar med heile ordet
domain_allow: domain_allow:
domain: Dette domenet er i stand til å henta data frå denne tenaren og innkomande data vert handsama og lagra domain: Dette domenet er i stand til å henta data frå denne tenaren og innkomande data vert handsama og lagra

View File

@ -57,7 +57,6 @@
setting_show_application: Appen du bruker til å publisere innlegg vil bli vist i den detaljerte visningen til innleggene dine setting_show_application: Appen du bruker til å publisere innlegg vil bli vist i den detaljerte visningen til innleggene dine
setting_use_blurhash: Gradientene er basert på fargene til de skjulte visualitetene, men gjør alle detaljer uklare setting_use_blurhash: Gradientene er basert på fargene til de skjulte visualitetene, men gjør alle detaljer uklare
setting_use_pending_items: Skjul tidslinjeoppdateringer bak et klikk, i stedet for å automatisk la strømmen skrolle setting_use_pending_items: Skjul tidslinjeoppdateringer bak et klikk, i stedet for å automatisk la strømmen skrolle
username: Brukernavnet ditt vil være unikt på %{domain}
whole_word: Når søkeordet eller setningen bare er alfanumerisk, aktiveres det bare hvis det samsvarer med hele ordet whole_word: Når søkeordet eller setningen bare er alfanumerisk, aktiveres det bare hvis det samsvarer med hele ordet
domain_allow: domain_allow:
domain: Dette domenet vil være i stand til å hente data fra denne serveren og dets innkommende data vil bli prosessert og lagret domain: Dette domenet vil være i stand til å hente data fra denne serveren og dets innkommende data vil bli prosessert og lagret

View File

@ -52,7 +52,6 @@ oc:
setting_show_application: Lo nom de laplicacion quutilizatz per publicar serà mostrat dins la vista detalhada de vòstres tuts setting_show_application: Lo nom de laplicacion quutilizatz per publicar serà mostrat dins la vista detalhada de vòstres tuts
setting_use_blurhash: Los degradats venon de las colors de limatge rescondut en enfoscar los detalhs setting_use_blurhash: Los degradats venon de las colors de limatge rescondut en enfoscar los detalhs
setting_use_pending_items: Rescondre las actualizacions del flux dactualitat aprèp un clic allòc de desfilar lo flux automaticament setting_use_pending_items: Rescondre las actualizacions del flux dactualitat aprèp un clic allòc de desfilar lo flux automaticament
username: Vòstre nom dutilizaire serà unic sus %{domain}
whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas quaplicat se correspond al mot complèt whole_word: Quand lo mot-clau o frasa es solament alfranumeric, serà pas quaplicat se correspond al mot complèt
domain_allow: domain_allow:
domain: Aqueste domeni poirà recuperar las donadas daqueste servidor estant e las donadas venent daqueste domeni seràn tractadas e gardadas domain: Aqueste domeni poirà recuperar las donadas daqueste servidor estant e las donadas venent daqueste domeni seràn tractadas e gardadas

View File

@ -59,7 +59,6 @@ pl:
setting_show_application: W informacjach o wpisie będzie widoczna informacja o aplikacji, z której został wysłany setting_show_application: W informacjach o wpisie będzie widoczna informacja o aplikacji, z której został wysłany
setting_use_blurhash: Gradienty są oparte na kolorach ukrywanej zawartości, ale uniewidaczniają wszystkie szczegóły setting_use_blurhash: Gradienty są oparte na kolorach ukrywanej zawartości, ale uniewidaczniają wszystkie szczegóły
setting_use_pending_items: Ukryj aktualizacje osi czasu za kliknięciem, zamiast automatycznego przewijania strumienia setting_use_pending_items: Ukryj aktualizacje osi czasu za kliknięciem, zamiast automatycznego przewijania strumienia
username: Twoja nazwa użytkownika będzie niepowtarzalna na %{domain}
whole_word: Jeśli słowo lub fraza składa się jedynie z liter lub cyfr, filtr będzie zastosowany tylko do pełnych wystąpień whole_word: Jeśli słowo lub fraza składa się jedynie z liter lub cyfr, filtr będzie zastosowany tylko do pełnych wystąpień
domain_allow: domain_allow:
domain: Ta domena będzie mogła pobierać dane z serwera, a dane przychodzące z niej będą przetwarzane i przechowywane domain: Ta domena będzie mogła pobierać dane z serwera, a dane przychodzące z niej będą przetwarzane i przechowywane

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