mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Merge pull request #3136 from ClearlyClaire/glitch-soc/merge-upstream
Merge upstream changes up to 19626ad89f
This commit is contained in:
@@ -1 +1 @@
|
||||
3.4.4
|
||||
3.4.5
|
||||
|
||||
@@ -13,7 +13,7 @@ ARG BASE_REGISTRY="docker.io"
|
||||
|
||||
# Ruby image to use for base image, change with [--build-arg RUBY_VERSION="3.4.x"]
|
||||
# renovate: datasource=docker depName=docker.io/ruby
|
||||
ARG RUBY_VERSION="3.4.4"
|
||||
ARG RUBY_VERSION="3.4.5"
|
||||
# # Node.js version to use in base image, change with [--build-arg NODE_MAJOR_VERSION="20"]
|
||||
# renovate: datasource=node-version depName=node
|
||||
ARG NODE_MAJOR_VERSION="22"
|
||||
|
||||
11
Gemfile.lock
11
Gemfile.lock
@@ -224,7 +224,7 @@ GEM
|
||||
mail (~> 2.7)
|
||||
email_validator (2.2.4)
|
||||
activemodel
|
||||
erb (5.0.1)
|
||||
erb (5.0.2)
|
||||
erubi (1.13.1)
|
||||
et-orbi (1.2.11)
|
||||
tzinfo
|
||||
@@ -315,7 +315,7 @@ GEM
|
||||
http_accept_language (2.1.1)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
httplog (1.7.0)
|
||||
httplog (1.7.1)
|
||||
rack (>= 2.0)
|
||||
rainbow (>= 2.0.0)
|
||||
i18n (1.14.7)
|
||||
@@ -335,7 +335,7 @@ GEM
|
||||
inline_svg (1.10.0)
|
||||
activesupport (>= 3.0)
|
||||
nokogiri (>= 1.6)
|
||||
io-console (0.8.0)
|
||||
io-console (0.8.1)
|
||||
irb (1.15.2)
|
||||
pp (>= 0.6.0)
|
||||
rdoc (>= 4.0.0)
|
||||
@@ -627,11 +627,10 @@ GEM
|
||||
prism (1.4.0)
|
||||
prometheus_exporter (2.2.0)
|
||||
webrick
|
||||
propshaft (1.1.0)
|
||||
propshaft (1.2.0)
|
||||
actionpack (>= 7.0.0)
|
||||
activesupport (>= 7.0.0)
|
||||
rack
|
||||
railties (>= 7.0.0)
|
||||
psych (5.2.6)
|
||||
date
|
||||
stringio
|
||||
@@ -708,7 +707,7 @@ GEM
|
||||
link_header (~> 0.0, >= 0.0.8)
|
||||
rdf-normalize (0.7.0)
|
||||
rdf (~> 3.3)
|
||||
rdoc (6.14.1)
|
||||
rdoc (6.14.2)
|
||||
erb
|
||||
psych (>= 4.0.0)
|
||||
redcarpet (3.6.1)
|
||||
|
||||
@@ -122,98 +122,93 @@ export const PolicyControls: React.FC = () => {
|
||||
value={notificationPolicy.for_not_following}
|
||||
onChange={handleFilterNotFollowing}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_following_title'
|
||||
defaultMessage="People you don't follow"
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_following_hint'
|
||||
defaultMessage='Until you manually approve them'
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_not_followers}
|
||||
onChange={handleFilterNotFollowers}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_followers_title'
|
||||
defaultMessage='People not following you'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_followers_hint'
|
||||
defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}'
|
||||
values={{ days: 3 }}
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_new_accounts}
|
||||
onChange={handleFilterNewAccounts}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_new_accounts_title'
|
||||
defaultMessage='New accounts'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_new_accounts.hint'
|
||||
defaultMessage='Created within the past {days, plural, one {one day} other {# days}}'
|
||||
values={{ days: 30 }}
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_private_mentions}
|
||||
onChange={handleFilterPrivateMentions}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_private_mentions_title'
|
||||
defaultMessage='Unsolicited private mentions'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_private_mentions_hint'
|
||||
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_limited_accounts}
|
||||
onChange={handleFilterLimitedAccounts}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_limited_accounts_title'
|
||||
defaultMessage='Moderated accounts'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_limited_accounts_hint'
|
||||
defaultMessage='Limited by server moderators'
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useCallback, useState, useRef } from 'react';
|
||||
import { useCallback, useState, useRef, useId } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -16,6 +16,8 @@ interface DropdownProps {
|
||||
options: SelectItem[];
|
||||
disabled?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
'aria-labelledby': string;
|
||||
'aria-describedby'?: string;
|
||||
placement?: Placement;
|
||||
}
|
||||
|
||||
@@ -24,51 +26,33 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
options,
|
||||
disabled,
|
||||
onChange,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
'aria-describedby': ariaDescribedBy,
|
||||
placement: initialPlacement = 'bottom-end',
|
||||
}) => {
|
||||
const activeElementRef = useRef<Element | null>(null);
|
||||
const containerRef = useRef(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [isOpen, setOpen] = useState<boolean>(false);
|
||||
const [placement, setPlacement] = useState<Placement>(initialPlacement);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
activeElementRef.current &&
|
||||
activeElementRef.current instanceof HTMLElement
|
||||
) {
|
||||
activeElementRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
setOpen(!isOpen);
|
||||
}, [isOpen, setOpen]);
|
||||
|
||||
const handleMouseDown = useCallback(() => {
|
||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
||||
}, [isOpen]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
||||
break;
|
||||
}
|
||||
},
|
||||
[isOpen],
|
||||
);
|
||||
const uniqueId = useId();
|
||||
const menuId = `${uniqueId}-menu`;
|
||||
const buttonLabelId = `${uniqueId}-button`;
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
activeElementRef.current &&
|
||||
activeElementRef.current instanceof HTMLElement
|
||||
)
|
||||
activeElementRef.current.focus({ preventScroll: true });
|
||||
if (isOpen && buttonRef.current) {
|
||||
buttonRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
setOpen(false);
|
||||
}, [isOpen]);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
if (isOpen) {
|
||||
handleClose();
|
||||
} else {
|
||||
setOpen(true);
|
||||
}
|
||||
}, [isOpen, handleClose]);
|
||||
|
||||
const handleOverlayEnter = useCallback(
|
||||
(state: Partial<PopperState>) => {
|
||||
if (state.placement) setPlacement(state.placement);
|
||||
@@ -82,13 +66,18 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
<div ref={containerRef}>
|
||||
<button
|
||||
type='button'
|
||||
ref={buttonRef}
|
||||
onClick={handleToggle}
|
||||
onMouseDown={handleMouseDown}
|
||||
onKeyDown={handleKeyDown}
|
||||
disabled={disabled}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={menuId}
|
||||
aria-labelledby={`${ariaLabelledBy} ${buttonLabelId}`}
|
||||
aria-describedby={ariaDescribedBy}
|
||||
className={classNames('dropdown-button', { active: isOpen })}
|
||||
>
|
||||
<span className='dropdown-button__label'>{valueOption?.text}</span>
|
||||
<span id={buttonLabelId} className='dropdown-button__label'>
|
||||
{valueOption?.text}
|
||||
</span>
|
||||
<Icon id='down' icon={ArrowDropDownIcon} />
|
||||
</button>
|
||||
|
||||
@@ -101,7 +90,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }}
|
||||
>
|
||||
{({ props, placement }) => (
|
||||
<div {...props}>
|
||||
<div {...props} id={menuId}>
|
||||
<div
|
||||
className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}
|
||||
>
|
||||
@@ -123,6 +112,8 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
interface Props {
|
||||
value: string;
|
||||
options: SelectItem[];
|
||||
label: string | React.ReactElement;
|
||||
hint: string | React.ReactElement;
|
||||
disabled?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
@@ -130,13 +121,26 @@ interface Props {
|
||||
export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||
value,
|
||||
options,
|
||||
label,
|
||||
hint,
|
||||
disabled,
|
||||
children,
|
||||
onChange,
|
||||
}) => {
|
||||
const uniqueId = useId();
|
||||
const labelId = `${uniqueId}-label`;
|
||||
const descId = `${uniqueId}-desc`;
|
||||
|
||||
return (
|
||||
// This label is only used for its click-forwarding behaviour,
|
||||
// accessible names are assigned manually
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||
<label className='app-form__toggle'>
|
||||
<div className='app-form__toggle__label'>{children}</div>
|
||||
<div className='app-form__toggle__label'>
|
||||
<strong id={labelId}>{label}</strong>
|
||||
<span className='hint' id={descId}>
|
||||
{hint}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='app-form__toggle__toggle'>
|
||||
<div>
|
||||
@@ -144,6 +148,8 @@ export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
aria-labelledby={labelId}
|
||||
aria-describedby={descId}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -122,98 +122,93 @@ export const PolicyControls: React.FC = () => {
|
||||
value={notificationPolicy.for_not_following}
|
||||
onChange={handleFilterNotFollowing}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_following_title'
|
||||
defaultMessage="People you don't follow"
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_following_hint'
|
||||
defaultMessage='Until you manually approve them'
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_not_followers}
|
||||
onChange={handleFilterNotFollowers}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_followers_title'
|
||||
defaultMessage='People not following you'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_not_followers_hint'
|
||||
defaultMessage='Including people who have been following you fewer than {days, plural, one {one day} other {# days}}'
|
||||
values={{ days: 3 }}
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_new_accounts}
|
||||
onChange={handleFilterNewAccounts}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_new_accounts_title'
|
||||
defaultMessage='New accounts'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_new_accounts.hint'
|
||||
defaultMessage='Created within the past {days, plural, one {one day} other {# days}}'
|
||||
values={{ days: 30 }}
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_private_mentions}
|
||||
onChange={handleFilterPrivateMentions}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_private_mentions_title'
|
||||
defaultMessage='Unsolicited private mentions'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_private_mentions_hint'
|
||||
defaultMessage="Filtered unless it's in reply to your own mention or if you follow the sender"
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
|
||||
<SelectWithLabel
|
||||
value={notificationPolicy.for_limited_accounts}
|
||||
onChange={handleFilterLimitedAccounts}
|
||||
options={options}
|
||||
>
|
||||
<strong>
|
||||
label={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_limited_accounts_title'
|
||||
defaultMessage='Moderated accounts'
|
||||
/>
|
||||
</strong>
|
||||
<span className='hint'>
|
||||
}
|
||||
hint={
|
||||
<FormattedMessage
|
||||
id='notifications.policy.filter_limited_accounts_hint'
|
||||
defaultMessage='Limited by server moderators'
|
||||
/>
|
||||
</span>
|
||||
</SelectWithLabel>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useCallback, useState, useRef } from 'react';
|
||||
import { useCallback, useState, useRef, useId } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
@@ -16,6 +16,8 @@ interface DropdownProps {
|
||||
options: SelectItem[];
|
||||
disabled?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
'aria-labelledby': string;
|
||||
'aria-describedby'?: string;
|
||||
placement?: Placement;
|
||||
}
|
||||
|
||||
@@ -24,51 +26,33 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
options,
|
||||
disabled,
|
||||
onChange,
|
||||
'aria-labelledby': ariaLabelledBy,
|
||||
'aria-describedby': ariaDescribedBy,
|
||||
placement: initialPlacement = 'bottom-end',
|
||||
}) => {
|
||||
const activeElementRef = useRef<Element | null>(null);
|
||||
const containerRef = useRef(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const [isOpen, setOpen] = useState<boolean>(false);
|
||||
const [placement, setPlacement] = useState<Placement>(initialPlacement);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
activeElementRef.current &&
|
||||
activeElementRef.current instanceof HTMLElement
|
||||
) {
|
||||
activeElementRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
setOpen(!isOpen);
|
||||
}, [isOpen, setOpen]);
|
||||
|
||||
const handleMouseDown = useCallback(() => {
|
||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
||||
}, [isOpen]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(e: React.KeyboardEvent) => {
|
||||
switch (e.key) {
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
if (!isOpen) activeElementRef.current = document.activeElement;
|
||||
break;
|
||||
}
|
||||
},
|
||||
[isOpen],
|
||||
);
|
||||
const uniqueId = useId();
|
||||
const menuId = `${uniqueId}-menu`;
|
||||
const buttonLabelId = `${uniqueId}-button`;
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
if (
|
||||
isOpen &&
|
||||
activeElementRef.current &&
|
||||
activeElementRef.current instanceof HTMLElement
|
||||
)
|
||||
activeElementRef.current.focus({ preventScroll: true });
|
||||
if (isOpen && buttonRef.current) {
|
||||
buttonRef.current.focus({ preventScroll: true });
|
||||
}
|
||||
setOpen(false);
|
||||
}, [isOpen]);
|
||||
|
||||
const handleToggle = useCallback(() => {
|
||||
if (isOpen) {
|
||||
handleClose();
|
||||
} else {
|
||||
setOpen(true);
|
||||
}
|
||||
}, [isOpen, handleClose]);
|
||||
|
||||
const handleOverlayEnter = useCallback(
|
||||
(state: Partial<PopperState>) => {
|
||||
if (state.placement) setPlacement(state.placement);
|
||||
@@ -82,13 +66,18 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
<div ref={containerRef}>
|
||||
<button
|
||||
type='button'
|
||||
ref={buttonRef}
|
||||
onClick={handleToggle}
|
||||
onMouseDown={handleMouseDown}
|
||||
onKeyDown={handleKeyDown}
|
||||
disabled={disabled}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={menuId}
|
||||
aria-labelledby={`${ariaLabelledBy} ${buttonLabelId}`}
|
||||
aria-describedby={ariaDescribedBy}
|
||||
className={classNames('dropdown-button', { active: isOpen })}
|
||||
>
|
||||
<span className='dropdown-button__label'>{valueOption?.text}</span>
|
||||
<span id={buttonLabelId} className='dropdown-button__label'>
|
||||
{valueOption?.text}
|
||||
</span>
|
||||
<Icon id='down' icon={ArrowDropDownIcon} />
|
||||
</button>
|
||||
|
||||
@@ -101,7 +90,7 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
popperConfig={{ strategy: 'fixed', onFirstUpdate: handleOverlayEnter }}
|
||||
>
|
||||
{({ props, placement }) => (
|
||||
<div {...props}>
|
||||
<div {...props} id={menuId}>
|
||||
<div
|
||||
className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}
|
||||
>
|
||||
@@ -123,6 +112,8 @@ const Dropdown: React.FC<DropdownProps> = ({
|
||||
interface Props {
|
||||
value: string;
|
||||
options: SelectItem[];
|
||||
label: string | React.ReactElement;
|
||||
hint: string | React.ReactElement;
|
||||
disabled?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
}
|
||||
@@ -130,13 +121,26 @@ interface Props {
|
||||
export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||
value,
|
||||
options,
|
||||
label,
|
||||
hint,
|
||||
disabled,
|
||||
children,
|
||||
onChange,
|
||||
}) => {
|
||||
const uniqueId = useId();
|
||||
const labelId = `${uniqueId}-label`;
|
||||
const descId = `${uniqueId}-desc`;
|
||||
|
||||
return (
|
||||
// This label is only used for its click-forwarding behaviour,
|
||||
// accessible names are assigned manually
|
||||
// eslint-disable-next-line jsx-a11y/label-has-associated-control
|
||||
<label className='app-form__toggle'>
|
||||
<div className='app-form__toggle__label'>{children}</div>
|
||||
<div className='app-form__toggle__label'>
|
||||
<strong id={labelId}>{label}</strong>
|
||||
<span className='hint' id={descId}>
|
||||
{hint}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className='app-form__toggle__toggle'>
|
||||
<div>
|
||||
@@ -144,6 +148,8 @@ export const SelectWithLabel: React.FC<PropsWithChildren<Props>> = ({
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
aria-labelledby={labelId}
|
||||
aria-describedby={descId}
|
||||
options={options}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -617,7 +617,7 @@
|
||||
"notification.reblog": "{name} продвинул(а) ваш пост",
|
||||
"notification.reblog.name_and_others_with_link": "{name} и ещё <a>{count, plural, one {# пользователь} few {# пользователя} other {# пользователей}}</a> продвинули ваш пост",
|
||||
"notification.relationships_severance_event": "Разорвана связь с {name}",
|
||||
"notification.relationships_severance_event.account_suspension": "Администратор сервера {from} заблокировал сервер {target}, поэтому вы больше не сможете получать обновления от людей с этого сервера или взаимодействовать с ними.",
|
||||
"notification.relationships_severance_event.account_suspension": "Администратор сервера {from} заблокировал сервер {target}, поэтому вы больше не сможете получать обновления от людей с этого сервера и взаимодействовать с ними.",
|
||||
"notification.relationships_severance_event.domain_block": "Администратор сервера {from} заблокировал сервер {target}, где размещены учётные записи {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
||||
"notification.relationships_severance_event.learn_more": "Узнать больше",
|
||||
"notification.relationships_severance_event.user_domain_block": "Вы заблокировали сервер {target}, где размещены учётные записи {followersCount} ваших подписчиков и {followingCount, plural, one {# пользователя, на которого вы подписаны} other {# пользователей, на которых вы подписаны}}.",
|
||||
@@ -707,7 +707,7 @@
|
||||
"onboarding.profile.display_name": "Отображаемое имя",
|
||||
"onboarding.profile.display_name_hint": "Ваше полное имя или псевдоним…",
|
||||
"onboarding.profile.note": "О себе",
|
||||
"onboarding.profile.note_hint": "Вы можете @упоминать других людей или использовать #хештеги…",
|
||||
"onboarding.profile.note_hint": "Вы можете @упоминать других людей, а также использовать #хештеги…",
|
||||
"onboarding.profile.save_and_continue": "Сохранить и продолжить",
|
||||
"onboarding.profile.title": "Создайте свой профиль",
|
||||
"onboarding.profile.upload_avatar": "Загрузить фото профиля",
|
||||
@@ -741,16 +741,16 @@
|
||||
"refresh": "Обновить",
|
||||
"regeneration_indicator.please_stand_by": "Пожалуйста, подождите.",
|
||||
"regeneration_indicator.preparing_your_home_feed": "Готовим вашу ленту…",
|
||||
"relative_time.days": "{number} д",
|
||||
"relative_time.days": "{number} д.",
|
||||
"relative_time.full.days": "{number, plural, one {# день} many {# дней} other {# дня}} назад",
|
||||
"relative_time.full.hours": "{number, plural, one {# час} many {# часов} other {# часа}} назад",
|
||||
"relative_time.full.just_now": "только что",
|
||||
"relative_time.full.minutes": "{number, plural, one {# минуту} many {# минут} other {# минуты}} назад",
|
||||
"relative_time.full.seconds": "{number, plural, one {# секунду} many {# секунд} other {# секунды}} назад",
|
||||
"relative_time.hours": "{number} ч",
|
||||
"relative_time.hours": "{number} ч.",
|
||||
"relative_time.just_now": "только что",
|
||||
"relative_time.minutes": "{number} мин",
|
||||
"relative_time.seconds": "{number} с",
|
||||
"relative_time.minutes": "{number} мин.",
|
||||
"relative_time.seconds": "{number} с.",
|
||||
"relative_time.today": "сегодня",
|
||||
"reply_indicator.attachments": "{count, plural, one {# вложение} few {# вложения} other {# вложений}}",
|
||||
"reply_indicator.cancel": "Отмена",
|
||||
@@ -836,7 +836,7 @@
|
||||
"server_banner.is_one_of_many": "{domain} — это один из многих независимых серверов Mastodon, которые вы можете использовать, чтобы присоединиться к сети Fediverse.",
|
||||
"server_banner.server_stats": "Статистика сервера:",
|
||||
"sign_in_banner.create_account": "Зарегистрироваться",
|
||||
"sign_in_banner.follow_anyone": "Подписывайтесь на кого угодно в федивёрсе и читайте ленту в хронологическом порядке. Никаких алгоритмов, рекламы или кликбейта.",
|
||||
"sign_in_banner.follow_anyone": "Подписывайтесь на кого угодно в федивёрсе и читайте ленту в хронологическом порядке. Никаких алгоритмов, рекламы и кликбейта.",
|
||||
"sign_in_banner.mastodon_is": "Mastodon — лучший способ быть в курсе всего происходящего.",
|
||||
"sign_in_banner.sign_in": "Войти",
|
||||
"sign_in_banner.sso_redirect": "Вход/Регистрация",
|
||||
|
||||
@@ -1349,6 +1349,8 @@ fa:
|
||||
basic_information: اطلاعات پایه
|
||||
hint_html: "<strong>شخصیسازی آن چه مردم روی نمایهٔ عمومیتان و کنار فرستههایتان میبینند.</strong> هنگامی که نمایهای کامل و یک تصویر نمایه داشته باشید، احتمال پیگیری متقابل و تعامل با شما بیشتر است."
|
||||
other: سایر
|
||||
emoji_styles:
|
||||
auto: خودکار
|
||||
errors:
|
||||
'400': درخواستی که فرستادید نامعتبر یا اشتباه بود.
|
||||
'403': شما اجازهٔ دیدن این صفحه را ندارید.
|
||||
|
||||
@@ -354,7 +354,7 @@ ru:
|
||||
enable: Включить
|
||||
enabled: Включён
|
||||
enabled_msg: Эмодзи включён
|
||||
image_hint: Поддерживаются файлы PNG или GIF размером не более %{size}
|
||||
image_hint: Поддерживаются файлы PNG и GIF размером не более %{size}
|
||||
list: В список
|
||||
listed: В списке
|
||||
new:
|
||||
@@ -1280,7 +1280,7 @@ ru:
|
||||
confirm: Продолжить
|
||||
hint_html: "<strong>Подсказка:</strong> В течение часа вам не придётся снова вводить свой пароль."
|
||||
invalid_password: Неверный пароль
|
||||
prompt: Введите пароль для продолжения
|
||||
prompt: Введите пароль, чтобы продолжить
|
||||
crypto:
|
||||
errors:
|
||||
invalid_key: должен быть действительным Ed25519- или Curve25519-ключом
|
||||
@@ -1290,35 +1290,35 @@ ru:
|
||||
with_month_name: "%d %B %Y"
|
||||
datetime:
|
||||
distance_in_words:
|
||||
about_x_hours: "%{count}ч"
|
||||
about_x_months: "%{count}мес"
|
||||
about_x_years: "%{count}г"
|
||||
almost_x_years: "%{count}г"
|
||||
about_x_hours: "%{count} ч."
|
||||
about_x_months: "%{count} мес."
|
||||
about_x_years: "%{count} г."
|
||||
almost_x_years: "%{count} г."
|
||||
half_a_minute: Только что
|
||||
less_than_x_minutes: "%{count}мин"
|
||||
less_than_x_minutes: "%{count} мин."
|
||||
less_than_x_seconds: Только что
|
||||
over_x_years: "%{count}г"
|
||||
x_days: "%{count}д"
|
||||
x_minutes: "%{count}мин"
|
||||
x_months: "%{count}мес"
|
||||
x_seconds: "%{count}сек"
|
||||
over_x_years: "%{count} г."
|
||||
x_days: "%{count} д."
|
||||
x_minutes: "%{count} мин."
|
||||
x_months: "%{count} мес."
|
||||
x_seconds: "%{count} с."
|
||||
deletes:
|
||||
challenge_not_passed: Введённая вами информация некорректна
|
||||
confirm_password: Введите свой пароль, чтобы подтвердить, что вы — это вы, и никто другой
|
||||
challenge_not_passed: Данные введены неверно
|
||||
confirm_password: Введите свой пароль, чтобы подтвердить, что это ваша учётная запись
|
||||
confirm_username: Введите своё имя пользователя для подтверждения
|
||||
proceed: Удалить учётную запись
|
||||
success_msg: Ваша учётная запись была успешно удалена
|
||||
success_msg: Ваша учётная запись удалена
|
||||
warning:
|
||||
before: 'Внимательно прочитайте следующую информацию перед началом:'
|
||||
caches: Некоторые данные, обработанные другими узлами, однако, могут храниться ещё какое-то время
|
||||
data_removal: Все ваши золотые посты, шикарный профиль и прочие данные будут безвозвратно уничтожены
|
||||
before: 'Внимательно ознакомьтесь со следующими замечаниями перед тем как продолжить:'
|
||||
caches: На других серверах могут остаться сохранённые в кэше данные
|
||||
data_removal: Все ваши посты и другие ваши данные будут безвозвратно уничтожены
|
||||
email_change_html: Вы можете <a href="%{path}">изменить свой адрес электронной почты</a>, не удаляя свою учетную запись
|
||||
email_contact_html: Если оно все еще не пришло, вы можете обратиться за помощью по электронной почте <a href="mailto:%{email}">%{email}</a>
|
||||
email_reconfirmation_html: Если вы не получили подтверждение по электронной почте, вы можете <a href="%{path}">запросить его снова</a>
|
||||
irreversible: После удаления восстановить или повторно активировать учётную запись не получится
|
||||
more_details_html: За всеми подробностями, изучите <a href="%{terms_path}">политику конфиденциальности</a>.
|
||||
irreversible: После удаления вы больше не сможете ни восстановить, ни повторно активировать свою учётную запись
|
||||
more_details_html: За более подробной информацией вы можете обратиться к <a href="%{terms_path}">политике конфиденциальности</a>.
|
||||
username_available: Ваше имя пользователя снова станет доступным
|
||||
username_unavailable: Ваше имя пользователя останется недоступным для использования
|
||||
username_unavailable: Зарегистрироваться с вашим именем пользователя будет невозможно
|
||||
disputes:
|
||||
strikes:
|
||||
action_taken: Предпринятые меры
|
||||
@@ -1353,6 +1353,10 @@ ru:
|
||||
basic_information: Основная информация
|
||||
hint_html: "<strong>Настройте то, что люди видят в вашем публичном профиле и рядом с вашими сообщениями.</strong> Другие люди с большей вероятностью подпишутся на Вас и будут взаимодействовать с вами, если у Вас заполнен профиль и добавлено изображение."
|
||||
other: Прочее
|
||||
emoji_styles:
|
||||
auto: Автоматически
|
||||
native: Как в системе
|
||||
twemoji: Twemoji
|
||||
errors:
|
||||
'400': Ваш запрос был недействительным или неправильным.
|
||||
'403': У Вас нет доступа к просмотру этой страницы.
|
||||
@@ -2136,17 +2140,17 @@ ru:
|
||||
webauthn_credentials:
|
||||
add: Добавить новый электронный ключ
|
||||
create:
|
||||
error: Возникла проблема с добавлением ключа безопасности. Пожалуйста, попробуйте еще раз.
|
||||
error: При добавлении электронного ключа произошла ошибка. Попробуйте ещё раз.
|
||||
success: Ваш электронный ключ добавлен.
|
||||
delete: Удалить
|
||||
delete_confirmation: Вы действительно хотите удалить этот электронный ключ?
|
||||
description_html: Если вы включите <strong>аутентификацию по электронным ключам</strong>, для входа в учётную запись вам будет предложено использовать один из ваших ключей.
|
||||
destroy:
|
||||
error: Произошла ошибка при удалении ключа безопасности. Пожалуйста, попробуйте еще раз.
|
||||
error: При удалении электронного ключа произошла ошибка. Попробуйте ещё раз.
|
||||
success: Ваш электронный ключ удалён.
|
||||
invalid_credential: Неверный электронный ключ
|
||||
nickname_hint: Введите название для нового электронного ключа
|
||||
not_enabled: Вы еще не включили WebAuthn
|
||||
not_supported: Этот браузер не поддерживает ключи безопасности
|
||||
otp_required: Чтобы использовать ключи безопасности, сначала включите двухфакторную аутентификацию.
|
||||
not_supported: В этом браузере отсутствует поддержка электронных ключей
|
||||
otp_required: Чтобы использовать электронные ключи, сначала включите двухфакторную аутентификацию.
|
||||
registered_on: Зарегистрирован %{date}
|
||||
|
||||
@@ -149,6 +149,9 @@ ca:
|
||||
min_age: No hauria de ser inferior a l'edat mínima exigida per la llei de la vostra jurisdicció.
|
||||
user:
|
||||
chosen_languages: Quan estigui marcat, només es mostraran els tuts de les llengües seleccionades en les línies de temps públiques
|
||||
date_of_birth:
|
||||
one: Ens hem d'assegurar que teniu com a mínim %{count} any per a fer servir %{domain}. No ho desarem.
|
||||
other: Ens hem d'assegurar que teniu com a mínim %{count} anys per a fer servir %{domain}. No ho desarem.
|
||||
role: El rol controla quins permisos té l'usuari.
|
||||
user_role:
|
||||
color: Color que s'usarà per al rol a tota la interfície d'usuari, com a RGB en format hexadecimal
|
||||
|
||||
@@ -150,6 +150,11 @@ cs:
|
||||
min_age: Neměla by být pod minimálním věkem požadovaným zákony vaší jurisdikce.
|
||||
user:
|
||||
chosen_languages: Po zaškrtnutí budou ve veřejných časových osách zobrazeny pouze příspěvky ve zvolených jazycích
|
||||
date_of_birth:
|
||||
few: Musíme se ujistit, že je Vám alespoň %{count}, abyste mohli používat %{domain}. Nebudeme to ukládat.
|
||||
many: Musíme se ujistit, že je Vám alespoň %{count} let, abyste mohli používat %{domain}. Nebudeme to ukládat.
|
||||
one: Musíme se ujistit, že je Vám alespoň %{count} rok, abyste mohli používat %{domain}. Nebudeme to ukládat.
|
||||
other: Musíme se ujistit, že je Vám alespoň %{count}, abyste mohli používat %{domain}. Nebudeme to ukládat.
|
||||
role: Role určuje, která oprávnění uživatel má.
|
||||
user_role:
|
||||
color: Barva, která má být použita pro roli v celém UI, jako RGB v hex formátu
|
||||
|
||||
@@ -151,8 +151,8 @@ da:
|
||||
user:
|
||||
chosen_languages: Når markeret, vil kun indlæg på de valgte sprog fremgå på offentlige tidslinjer
|
||||
date_of_birth:
|
||||
one: Vi skal sikre os, at du er mindst %{count} for at kunne bruge %{domain}. Vi gemmer ikke dette.
|
||||
other: Vi skal sikre os, at du er mindst %{count} for at kunne bruge %{domain}. Vi gemmer ikke dette.
|
||||
one: Vi skal sikre os, at du er mindst %{count} for at kunne bruge %{domain}. Informationen gemmes ikke.
|
||||
other: Vi skal sikre os, at du er mindst %{count} for at kunne bruge %{domain}. Informationen gemmes ikke.
|
||||
role: Rollen styrer, hvilke tilladelser brugeren er tildelt.
|
||||
user_role:
|
||||
color: Farven, i RGB hex-format, der skal bruges til rollen i hele UI'en
|
||||
|
||||
@@ -150,6 +150,9 @@ fo:
|
||||
min_age: Eigur ikki at vera undir lægsta aldri, sum lógirnar í tínum rættarøki krevja.
|
||||
user:
|
||||
chosen_languages: Tá hetta er valt, verða einans postar í valdum málum vístir á almennum tíðarlinjum
|
||||
date_of_birth:
|
||||
one: Vit mugu tryggja okkum, at tú er í minsta lagi %{count} fyri at brúka %{domain}. Vit goyma ikki hesar upplýsingar.
|
||||
other: Vit mugu tryggja okkum, at tú er í minsta lagi %{count} ár fyri at brúka %{domain}. Vit goyma ikki hesar upplýsingar.
|
||||
role: Leikluturin stýrir hvørji rættindi, brúkarin hevur.
|
||||
user_role:
|
||||
color: Litur, sum leikluturin hevur í øllum brúkaramarkamótinum, sum RGB og upplýst sum sekstandatal
|
||||
|
||||
@@ -150,6 +150,9 @@ fy:
|
||||
min_age: Mei net leger wêze as de minimale fereaske leeftiid neffens de wetten fan jo jurisdiksje.
|
||||
user:
|
||||
chosen_languages: Allinnich berjochten yn de selektearre talen wurde op de iepenbiere tiidline toand
|
||||
date_of_birth:
|
||||
one: Wy moatte derfoar soargje dat jo op syn minst %{count} binne om %{domain} brûke te meien. Dit wurdt net bewarre.
|
||||
other: Wy moatte derfoar soargje dat jo op syn minst %{count} binne om %{domain} brûke te meien. Dit wurdt net bewarre.
|
||||
role: De rol bepaalt hokker rjochten in brûker hat.
|
||||
user_role:
|
||||
color: Kleur dy’t brûkt wurdt foar de rol yn de UI, as RGB yn heksadesimaal formaat
|
||||
|
||||
@@ -150,6 +150,9 @@ gl:
|
||||
min_age: Non debería ser inferior á idade mínima requerida polas leis da túa xurisdición.
|
||||
user:
|
||||
chosen_languages: Se ten marca, só as publicacións nos idiomas seleccionados serán mostrados en cronoloxías públicas
|
||||
date_of_birth:
|
||||
one: Temos que confirmar que tes %{count} anos polo menos para usar %{domain}. Non gardamos este dato.
|
||||
other: Temos que confirmar que tes %{count} anos polo menos para usar %{domain}. Non gardamos este dato.
|
||||
role: Os roles establecen os permisos que ten a usuaria.
|
||||
user_role:
|
||||
color: Cor que se usará para o rol a través da IU, como RGB en formato hex
|
||||
|
||||
@@ -150,6 +150,9 @@ is:
|
||||
min_age: Ætti ekki að vera lægri en sá lágmarksaldur sek kveðið er á um í lögum þíns lögsagnarumdæmis.
|
||||
user:
|
||||
chosen_languages: Þegar merkt er við þetta, birtast einungis færslur á völdum tungumálum á opinberum tímalínum
|
||||
date_of_birth:
|
||||
one: Við verðum að ganga úr skugga um að þú hafir náð %{count} aldri til að nota %{domain}. Við munum ekki geyma þessar upplýsingar.
|
||||
other: Við verðum að ganga úr skugga um að þú hafir náð %{count} aldri til að nota %{domain}. Við munum ekki geyma þessar upplýsingar.
|
||||
role: Hlutverk stýrir hvaða heimildir notandinn hefur.
|
||||
user_role:
|
||||
color: Litur sem notaður er fyrir hlutverkið allsstaðar í viðmótinu, sem RGB-gildi á hex-sniði
|
||||
|
||||
@@ -150,6 +150,9 @@ it:
|
||||
min_age: Non si dovrebbe avere un'età inferiore a quella minima richiesta, dalle leggi della tua giurisdizione.
|
||||
user:
|
||||
chosen_languages: Quando una o più lingue sono contrassegnate, nelle timeline pubbliche vengono mostrati solo i toot nelle lingue selezionate
|
||||
date_of_birth:
|
||||
one: Dobbiamo assicurarci che tu abbia almeno %{count} anni per utilizzare %{domain}. Non memorizzeremo questo dato.
|
||||
other: Dobbiamo assicurarci che tu abbia almeno %{count} anni per utilizzare %{domain}. Non memorizzeremo questo dato.
|
||||
role: Il ruolo controlla quali permessi ha l'utente.
|
||||
user_role:
|
||||
color: Colore da usare per il ruolo in tutta l'UI, come RGB in formato esadecimale
|
||||
|
||||
@@ -8,7 +8,7 @@ ru:
|
||||
display_name: Ваше полное имя или псевдоним.
|
||||
fields: Домашняя страница, местоимения, возраст — всё что угодно.
|
||||
indexable: Отметьте флажок, чтобы ваши публичные посты могли быть найдены при помощи поиска в Mastodon. Люди, которые взаимодействовали с вашими постами, смогут их найти вне зависимости от этой настройки.
|
||||
note: 'Вы можете @упоминать других людей или использовать #хештеги.'
|
||||
note: 'Вы можете @упоминать других людей, а также использовать #хештеги.'
|
||||
show_collections: Отметьте флажок, чтобы кто угодно мог просматривать списки ваших подписок и подписчиков. Люди, на которых вы подписаны, будут знать о том, что вы на них подписаны, вне зависимости от этой настройки.
|
||||
unlocked: 'Отметьте флажок, чтобы на вас можно было подписаться, не запрашивая подтверждения. Снимите флажок, чтобы вы могли просматривать запросы на подписку и выбирать: принять или отклонить новых подписчиков.'
|
||||
account_alias:
|
||||
|
||||
Reference in New Issue
Block a user