Merge commit '7af5ba271d6f04831f000e9b815914375e42abeb' into glitch-soc/merge-upstream

This commit is contained in:
Claire 2026-01-27 18:03:27 +01:00
commit 5a45a3203a
96 changed files with 959 additions and 505 deletions

View File

@ -305,8 +305,8 @@ GEM
highline (3.1.2) highline (3.1.2)
reline reline
hiredis (0.6.3) hiredis (0.6.3)
hiredis-client (0.26.3) hiredis-client (0.26.4)
redis-client (= 0.26.3) redis-client (= 0.26.4)
hkdf (0.3.0) hkdf (0.3.0)
htmlentities (4.3.4) htmlentities (4.3.4)
http (5.3.1) http (5.3.1)
@ -708,7 +708,7 @@ GEM
reline reline
redcarpet (3.6.1) redcarpet (3.6.1)
redis (4.8.1) redis (4.8.1)
redis-client (0.26.3) redis-client (0.26.4)
connection_pool connection_pool
regexp_parser (2.11.3) regexp_parser (2.11.3)
reline (0.6.3) reline (0.6.3)

View File

@ -36,6 +36,7 @@ export interface CalloutProps {
secondaryLabel?: string; secondaryLabel?: string;
onClose?: () => void; onClose?: () => void;
id?: string; id?: string;
extraContent?: ReactNode;
} }
const variantClasses = { const variantClasses = {
@ -59,6 +60,7 @@ export const Callout: FC<CalloutProps> = ({
onSecondary: secondaryAction, onSecondary: secondaryAction,
secondaryLabel, secondaryLabel,
onClose, onClose,
extraContent,
id, id,
}) => { }) => {
const intl = useIntl(); const intl = useIntl();
@ -105,6 +107,8 @@ export const Callout: FC<CalloutProps> = ({
)} )}
</div> </div>
{extraContent}
{onClose && ( {onClose && (
<IconButton <IconButton
icon='close' icon='close'

View File

@ -13,6 +13,7 @@
border-radius: 9999px; border-radius: 9999px;
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
margin-top: -2px;
} }
.content { .content {
@ -28,16 +29,12 @@
} }
} }
.icon + .content,
.wrapper:has(.close) .content {
margin-top: 2px;
}
.body { .body {
flex-grow: 1; flex-grow: 1;
h3 { h3 {
font-weight: 500; font-weight: 500;
margin-bottom: 5px;
} }
} }
@ -62,6 +59,12 @@
} }
} }
@media (prefers-reduced-motion: reduce) {
.action {
transition: none;
}
}
.close { .close {
color: inherit; color: inherit;

View File

@ -13,6 +13,7 @@ interface Props extends React.SVGProps<SVGSVGElement> {
children?: never; children?: never;
id: string; id: string;
icon: IconProp; icon: IconProp;
noFill?: boolean;
} }
export const Icon: React.FC<Props> = ({ export const Icon: React.FC<Props> = ({
@ -20,6 +21,7 @@ export const Icon: React.FC<Props> = ({
icon: IconComponent, icon: IconComponent,
className, className,
'aria-label': ariaLabel, 'aria-label': ariaLabel,
noFill = false,
...other ...other
}) => { }) => {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
@ -42,7 +44,12 @@ export const Icon: React.FC<Props> = ({
return ( return (
<IconComponent <IconComponent
className={classNames('icon', `icon-${id}`, className)} className={classNames(
'icon',
`icon-${id}`,
noFill && 'icon--no-fill',
className,
)}
title={title} title={title}
aria-hidden={ariaHidden} aria-hidden={ariaHidden}
aria-label={ariaLabel} aria-label={ariaLabel}

View File

@ -44,8 +44,7 @@ export const DomainPill: React.FC<{
aria-controls={accessibilityId} aria-controls={accessibilityId}
type='button' type='button'
> >
{domain} {children ?? domain}
{children}
</button> </button>
<Overlay <Overlay

View File

@ -24,6 +24,7 @@ import { AccountHeaderFields } from './fields';
import { AccountInfo } from './info'; import { AccountInfo } from './info';
import { MemorialNote } from './memorial_note'; import { MemorialNote } from './memorial_note';
import { MovedNote } from './moved_note'; import { MovedNote } from './moved_note';
import { AccountNote as AccountNoteRedesign } from './note';
import { AccountNumberFields } from './number_fields'; import { AccountNumberFields } from './number_fields';
import redesignClasses from './redesign.module.scss'; import redesignClasses from './redesign.module.scss';
import { AccountTabs } from './tabs'; import { AccountTabs } from './tabs';
@ -142,12 +143,7 @@ export const AccountHeader: React.FC<{
isRedesignEnabled() && redesignClasses.nameWrapper, isRedesignEnabled() && redesignClasses.nameWrapper,
)} )}
> >
<AccountName <AccountName accountId={accountId} />
accountId={accountId}
className={classNames(
isRedesignEnabled() && redesignClasses.name,
)}
/>
{isRedesignEnabled() && <AccountButtons accountId={accountId} />} {isRedesignEnabled() && <AccountButtons accountId={accountId} />}
</div> </div>
@ -166,7 +162,9 @@ export const AccountHeader: React.FC<{
{!suspendedOrHidden && ( {!suspendedOrHidden && (
<div className='account__header__extra'> <div className='account__header__extra'>
<div className='account__header__bio'> <div className='account__header__bio'>
{me && account.id !== me && ( {me && account.id !== me && isRedesignEnabled() ? (
<AccountNoteRedesign accountId={accountId} />
) : (
<AccountNote accountId={accountId} /> <AccountNote accountId={accountId} />
)} )}

View File

@ -6,7 +6,7 @@ import { DisplayName } from '@/mastodon/components/display_name';
import { Icon } from '@/mastodon/components/icon'; import { Icon } from '@/mastodon/components/icon';
import { useAccount } from '@/mastodon/hooks/useAccount'; import { useAccount } from '@/mastodon/hooks/useAccount';
import { useAppSelector } from '@/mastodon/store'; import { useAppSelector } from '@/mastodon/store';
import InfoIcon from '@/material-icons/400-24px/info.svg?react'; import HelpIcon from '@/material-icons/400-24px/help.svg?react';
import LockIcon from '@/material-icons/400-24px/lock.svg?react'; import LockIcon from '@/material-icons/400-24px/lock.svg?react';
import { DomainPill } from '../../account/components/domain_pill'; import { DomainPill } from '../../account/components/domain_pill';
@ -14,10 +14,7 @@ import { isRedesignEnabled } from '../common';
import classes from './redesign.module.scss'; import classes from './redesign.module.scss';
export const AccountName: FC<{ accountId: string; className?: string }> = ({ export const AccountName: FC<{ accountId: string }> = ({ accountId }) => {
accountId,
className,
}) => {
const intl = useIntl(); const intl = useIntl();
const account = useAccount(accountId); const account = useAccount(accountId);
const me = useAppSelector((state) => state.meta.get('me') as string); const me = useAppSelector((state) => state.meta.get('me') as string);
@ -31,38 +28,52 @@ export const AccountName: FC<{ accountId: string; className?: string }> = ({
const [username = '', domain = localDomain] = account.acct.split('@'); const [username = '', domain = localDomain] = account.acct.split('@');
return ( if (!isRedesignEnabled()) {
<h1 className={className}> return (
<DisplayName account={account} variant='simple' /> <h1>
<small> <DisplayName account={account} variant='simple' />
<span> <small>
@{username} <span>
{isRedesignEnabled() && '@'} @{username}
<span className='invisible'> <span className='invisible'>@{domain}</span>
{!isRedesignEnabled() && '@'}
{domain}
</span> </span>
</span> <DomainPill
username={username}
domain={domain}
isSelf={me === account.id}
/>
{account.locked && (
<Icon
id='lock'
icon={LockIcon}
aria-label={intl.formatMessage({
id: 'account.locked_info',
defaultMessage:
'This account privacy status is set to locked. The owner manually reviews who can follow them.',
})}
/>
)}
</small>
</h1>
);
}
return (
<div className={classes.name}>
<h1>
<DisplayName account={account} variant='simple' />
</h1>
<p className={classes.username}>
@{username}@{domain}
<DomainPill <DomainPill
username={username} username={username}
domain={domain} domain={domain}
isSelf={me === account.id} isSelf={me === account.id}
className={(isRedesignEnabled() && classes.domainPill) || ''} className={classes.domainPill}
> >
{isRedesignEnabled() && <Icon id='info' icon={InfoIcon} />} <Icon id='help' icon={HelpIcon} />
</DomainPill> </DomainPill>
{!isRedesignEnabled() && account.locked && ( </p>
<Icon </div>
id='lock'
icon={LockIcon}
aria-label={intl.formatMessage({
id: 'account.locked_info',
defaultMessage:
'This account privacy status is set to locked. The owner manually reviews who can follow them.',
})}
/>
)}
</small>
</h1>
); );
}; };

View File

@ -37,7 +37,12 @@ export const AccountBadges: FC<{ accountId: string }> = ({ accountId }) => {
let icon: ReactNode = undefined; let icon: ReactNode = undefined;
if (isAdminBadge(role)) { if (isAdminBadge(role)) {
icon = ( icon = (
<Icon icon={IconAdmin} id='badge-admin' className={classes.badgeIcon} /> <Icon
icon={IconAdmin}
id='badge-admin'
className={classes.badgeIcon}
noFill
/>
); );
} }
badges.push( badges.push(

View File

@ -76,6 +76,7 @@ const RedesignAccountHeaderFields: FC<{ account: Account }> = ({ account }) => {
id='verified' id='verified'
icon={IconVerified} icon={IconVerified}
className={classes.fieldIconVerified} className={classes.fieldIconVerified}
noFill
/> />
)} )}
</> </>

View File

@ -81,6 +81,7 @@ export const AccountFieldsModal: FC<{
id='verified' id='verified'
icon={IconVerified} icon={IconVerified}
className={classes.fieldIconVerified} className={classes.fieldIconVerified}
noFill
/> />
)} )}
</dd> </dd>

View File

@ -31,6 +31,8 @@ import {
import { useAppDispatch, useAppSelector } from '@/mastodon/store'; import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react'; import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { isRedesignEnabled } from '../common';
const messages = defineMessages({ const messages = defineMessages({
unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' }, mention: { id: 'account.mention', defaultMessage: 'Mention @{name}' },
@ -55,6 +57,14 @@ const messages = defineMessages({
id: 'account.show_reblogs', id: 'account.show_reblogs',
defaultMessage: 'Show boosts from @{name}', defaultMessage: 'Show boosts from @{name}',
}, },
addNote: {
id: 'account.add_note',
defaultMessage: 'Add a personal note',
},
editNote: {
id: 'account.edit_note',
defaultMessage: 'Edit personal note',
},
endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' },
unendorse: { unendorse: {
id: 'account.unendorse', id: 'account.unendorse',
@ -187,7 +197,30 @@ export const AccountMenu: FC<{ accountId: string }> = ({ accountId }) => {
}); });
arr.push(null); arr.push(null);
} }
}
if (isRedesignEnabled()) {
arr.push({
text: intl.formatMessage(
relationship?.note ? messages.editNote : messages.addNote,
),
action: () => {
dispatch(
openModal({
modalType: 'ACCOUNT_NOTE',
modalProps: {
accountId: account.id,
},
}),
);
},
});
if (!relationship?.following) {
arr.push(null);
}
}
if (relationship?.following) {
arr.push({ arr.push({
text: intl.formatMessage( text: intl.formatMessage(
relationship.endorsed ? messages.unendorse : messages.endorse, relationship.endorsed ? messages.unendorse : messages.endorse,

View File

@ -0,0 +1,69 @@
import { useCallback, useEffect } from 'react';
import type { FC } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { fetchRelationships } from '@/mastodon/actions/accounts';
import { openModal } from '@/mastodon/actions/modal';
import { Callout } from '@/mastodon/components/callout';
import { IconButton } from '@/mastodon/components/icon_button';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import EditIcon from '@/material-icons/400-24px/edit_square.svg?react';
import classes from './redesign.module.scss';
const messages = defineMessages({
title: {
id: 'account.note.title',
defaultMessage: 'Personal note (visible only to you)',
},
editButton: {
id: 'account.note.edit_button',
defaultMessage: 'Edit',
},
});
export const AccountNote: FC<{ accountId: string }> = ({ accountId }) => {
const intl = useIntl();
const relationship = useAppSelector((state) =>
state.relationships.get(accountId),
);
const dispatch = useAppDispatch();
useEffect(() => {
if (!relationship) {
dispatch(fetchRelationships([accountId]));
}
}, [accountId, dispatch, relationship]);
const handleEdit = useCallback(() => {
dispatch(
openModal({
modalType: 'ACCOUNT_NOTE',
modalProps: { accountId },
}),
);
}, [accountId, dispatch]);
if (!relationship?.note) {
return null;
}
return (
<Callout
icon={false}
title={intl.formatMessage(messages.title)}
className={classes.note}
extraContent={
<IconButton
icon='edit'
iconComponent={EditIcon}
title={intl.formatMessage(messages.editButton)}
className={classes.noteEditButton}
onClick={handleEdit}
/>
}
>
{relationship.note}
</Callout>
);
};

View File

@ -7,20 +7,16 @@
flex-grow: 1; flex-grow: 1;
font-size: 22px; font-size: 22px;
white-space: initial; white-space: initial;
text-overflow: initial;
line-height: normal; line-height: normal;
:global(.icon-info) {
margin-left: 2px;
width: 1em;
height: 1em;
align-self: center;
}
} }
// Overrides .account__header__tabs__name h1 small .username {
h1.name > small { display: flex;
gap: 0; font-size: 13px;
color: var(--color-text-secondary);
align-items: center;
user-select: all;
margin-top: 4px;
} }
.domainPill { .domainPill {
@ -32,10 +28,20 @@ h1.name > small {
color: inherit; color: inherit;
font-size: 1em; font-size: 1em;
font-weight: initial; font-weight: initial;
margin-left: 2px;
width: 16px;
height: 16px;
transition: color 0.2s ease-in-out;
> svg {
width: 100%;
height: 100%;
}
&:hover,
&:global(.active) { &:global(.active) {
background: none; background: none;
color: inherit; color: var(--color-text-brand-soft);
} }
} }
@ -53,10 +59,18 @@ h1.name > small {
svg.badgeIcon { svg.badgeIcon {
opacity: 1; opacity: 1;
fill: revert-layer; }
path { .note {
fill: revert-layer; margin-bottom: 16px;
}
.noteEditButton {
color: inherit;
svg {
width: 20px;
height: 20px;
} }
} }
@ -90,11 +104,6 @@ svg.badgeIcon {
.fieldIconVerified { .fieldIconVerified {
width: 1rem; width: 1rem;
height: 1rem; height: 1rem;
// Need to override .icon path.
path {
fill: revert-layer;
}
} }
.fieldNumbersWrapper { .fieldNumbersWrapper {

View File

@ -0,0 +1,21 @@
.noteCallout {
margin-bottom: 16px;
}
.noteInput {
min-height: 70px;
width: 100%;
padding: 8px;
border-radius: 8px;
box-sizing: border-box;
background: var(--color-bg-primary);
border: 1px solid var(--color-border-primary);
appearance: none;
resize: none;
margin-top: 4px;
}
.noteInput:focus-visible {
outline: var(--outline-focus-default);
outline-offset: 2px;
}

View File

@ -0,0 +1,160 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import type { ChangeEventHandler, FC } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { submitAccountNote } from '@/mastodon/actions/account_notes';
import { fetchRelationships } from '@/mastodon/actions/accounts';
import { Callout } from '@/mastodon/components/callout';
import { TextAreaField } from '@/mastodon/components/form_fields';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import type { Relationship } from '@/mastodon/models/relationship';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { ConfirmationModal } from '../../ui/components/confirmation_modals';
import classes from './modals.module.css';
const messages = defineMessages({
newTitle: {
id: 'account.node_modal.title',
defaultMessage: 'Add a personal note',
},
editTitle: {
id: 'account.node_modal.edit_title',
defaultMessage: 'Edit personal note',
},
save: {
id: 'account.node_modal.save',
defaultMessage: 'Save',
},
fieldLabel: {
id: 'account.node_modal.field_label',
defaultMessage: 'Personal Note',
},
errorUnknown: {
id: 'account.node_modal.error_unknown',
defaultMessage: 'Could not save the note',
},
});
export const AccountNoteModal: FC<{
accountId: string;
onClose: () => void;
}> = ({ accountId, onClose }) => {
const relationship = useAppSelector((state) =>
state.relationships.get(accountId),
);
const dispatch = useAppDispatch();
useEffect(() => {
if (!relationship) {
dispatch(fetchRelationships([accountId]));
}
}, [accountId, dispatch, relationship]);
if (!relationship) {
return <LoadingIndicator />;
}
return (
<InnerNodeModal
relationship={relationship}
accountId={accountId}
onClose={onClose}
/>
);
};
const InnerNodeModal: FC<{
relationship: Relationship;
accountId: string;
onClose: () => void;
}> = ({ relationship, accountId, onClose }) => {
// Set up the state.
const initialContents = relationship.note;
const [note, setNote] = useState(initialContents);
const [errorText, setErrorText] = useState('');
const [state, setState] = useState<'idle' | 'saving' | 'error'>('idle');
const isDirty = note !== initialContents;
const handleChange: ChangeEventHandler<HTMLTextAreaElement> = useCallback(
(e) => {
if (state !== 'saving') {
setNote(e.target.value);
}
},
[state],
);
const intl = useIntl();
// Create an abort controller to cancel the request if the modal is closed.
const abortController = useRef(new AbortController());
const dispatch = useAppDispatch();
const handleSave = useCallback(() => {
if (state === 'saving' || !isDirty) {
return;
}
setState('saving');
dispatch(
submitAccountNote(
{ accountId, note },
{ signal: abortController.current.signal },
),
)
.then(() => {
setState('idle');
onClose();
})
.catch((err: unknown) => {
setState('error');
if (err instanceof Error) {
setErrorText(err.message);
} else {
setErrorText(intl.formatMessage(messages.errorUnknown));
}
});
}, [accountId, dispatch, intl, isDirty, note, onClose, state]);
const handleCancel = useCallback(() => {
abortController.current.abort();
onClose();
}, [onClose]);
return (
<ConfirmationModal
title={
initialContents
? intl.formatMessage(messages.editTitle)
: intl.formatMessage(messages.newTitle)
}
extraContent={
<>
<Callout className={classes.noteCallout}>
<FormattedMessage
id='account.node_modal.callout'
defaultMessage='Personal notes are visible only to you.'
/>
</Callout>
<TextAreaField
value={note}
onChange={handleChange}
label={intl.formatMessage(messages.fieldLabel)}
className={classes.noteInput}
hasError={state === 'error'}
hint={errorText}
// eslint-disable-next-line jsx-a11y/no-autofocus -- We want to focus here as it's a modal.
autoFocus
/>
</>
}
onClose={handleCancel}
confirm={intl.formatMessage(messages.save)}
onConfirm={handleSave}
updating={state === 'saving'}
disabled={!isDirty}
closeWhenConfirm={false}
noFocusButton
/>
);
};

View File

@ -19,6 +19,9 @@ export const ConfirmationModal: React.FC<
onConfirm: () => void; onConfirm: () => void;
closeWhenConfirm?: boolean; closeWhenConfirm?: boolean;
extraContent?: React.ReactNode; extraContent?: React.ReactNode;
updating?: boolean;
disabled?: boolean;
noFocusButton?: boolean;
} & BaseConfirmationModalProps } & BaseConfirmationModalProps
> = ({ > = ({
title, title,
@ -31,6 +34,9 @@ export const ConfirmationModal: React.FC<
onSecondary, onSecondary,
closeWhenConfirm = true, closeWhenConfirm = true,
extraContent, extraContent,
updating,
disabled,
noFocusButton = false,
}) => { }) => {
const handleClick = useCallback(() => { const handleClick = useCallback(() => {
if (closeWhenConfirm) { if (closeWhenConfirm) {
@ -74,16 +80,23 @@ export const ConfirmationModal: React.FC<
onClick={handleSecondary} onClick={handleSecondary}
className='link-button' className='link-button'
type='button' type='button'
disabled={disabled}
> >
{secondary} {secondary}
</button> </button>
</> </>
)} )}
{/* eslint-disable-next-line jsx-a11y/no-autofocus -- we are in a modal and thus autofocusing is justified */} {/* eslint-disable jsx-a11y/no-autofocus -- we are in a modal and thus autofocusing is justified */}
<Button onClick={handleClick} autoFocus> <Button
onClick={handleClick}
loading={updating}
disabled={disabled}
autoFocus={!noFocusButton}
>
{confirm} {confirm}
</Button> </Button>
{/* eslint-enable */}
</div> </div>
</div> </div>
</div> </div>

View File

@ -85,6 +85,7 @@ export const MODAL_COMPONENTS = {
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal, 'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
'ANNUAL_REPORT': AnnualReportModal, 'ANNUAL_REPORT': AnnualReportModal,
'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }), 'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }),
'ACCOUNT_NOTE': () => import('@/mastodon/features/account_timeline/modals/note_modal').then(module => ({ default: module.AccountNoteModal })),
'ACCOUNT_FIELDS': () => import('mastodon/features/account_timeline/components/fields_modal.tsx').then(module => ({ default: module.AccountFieldsModal })), 'ACCOUNT_FIELDS': () => import('mastodon/features/account_timeline/components/fields_modal.tsx').then(module => ({ default: module.AccountFieldsModal })),
}; };

View File

@ -714,7 +714,6 @@
"privacy.private.short": "للمتابِعين", "privacy.private.short": "للمتابِعين",
"privacy.public.long": "أي شخص على أو خارج ماستدون", "privacy.public.long": "أي شخص على أو خارج ماستدون",
"privacy.public.short": "للعامة", "privacy.public.short": "للعامة",
"privacy.quote.anyone": "{visibility}، يمكن لأي شخص الاقتباس",
"privacy.quote.disabled": "{visibility}، الاقتباس معطل", "privacy.quote.disabled": "{visibility}، الاقتباس معطل",
"privacy.quote.limited": "{visibility}، الاقتباسات محدودة", "privacy.quote.limited": "{visibility}، الاقتباسات محدودة",
"privacy.unlisted.additional": "هذا يتصرف بالضبط مثل النشر للعامة، باستثناء أن المنشور لن يظهر في الموجزات الحية أو في الوسوم أو في الإستكشاف، أو في نتائج بحث ماستدون، حتى وإن قمت بتفعيله على مستوى الحساب.", "privacy.unlisted.additional": "هذا يتصرف بالضبط مثل النشر للعامة، باستثناء أن المنشور لن يظهر في الموجزات الحية أو في الوسوم أو في الإستكشاف، أو في نتائج بحث ماستدون، حتى وإن قمت بتفعيله على مستوى الحساب.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Падпісчыкі", "privacy.private.short": "Падпісчыкі",
"privacy.public.long": "Усе, хто ёсць і каго няма ў Mastodon", "privacy.public.long": "Усе, хто ёсць і каго няма ў Mastodon",
"privacy.public.short": "Публічны", "privacy.public.short": "Публічны",
"privacy.quote.anyone": "{visibility}, усе могуць цытаваць", "privacy.quote.anyone": "{visibility}, цытаты дазволеныя",
"privacy.quote.disabled": "{visibility}, цытаты адключаныя", "privacy.quote.disabled": "{visibility}, цытаты адключаныя",
"privacy.quote.limited": "{visibility}, абмежаваныя цытаты", "privacy.quote.limited": "{visibility}, абмежаваныя цытаты",
"privacy.unlisted.additional": "Паводзіць сябе гэтак жа, як і публічны, за выключэннем таго, што допіс не будзе адлюстроўвацца ў жывой стужцы, хэштэгах, аглядзе або ў пошуку Mastodon, нават калі Вы ўключылі бачнасць у пошуку ў наладах.", "privacy.unlisted.additional": "Паводзіць сябе гэтак жа, як і публічны, за выключэннем таго, што допіс не будзе адлюстроўвацца ў жывой стужцы, хэштэгах, аглядзе або ў пошуку Mastodon, нават калі Вы ўключылі бачнасць у пошуку ў наладах.",

View File

@ -714,7 +714,6 @@
"privacy.private.short": "Последователи", "privacy.private.short": "Последователи",
"privacy.public.long": "Всеки във и извън Mastodon", "privacy.public.long": "Всеки във и извън Mastodon",
"privacy.public.short": "Публично", "privacy.public.short": "Публично",
"privacy.quote.anyone": "{visibility}, всеки може да цитира",
"privacy.quote.disabled": "{visibility}, цитатите са изключени", "privacy.quote.disabled": "{visibility}, цитатите са изключени",
"privacy.quote.limited": "{visibility}, цитатите са ограничени", "privacy.quote.limited": "{visibility}, цитатите са ограничени",
"privacy.unlisted.additional": "Това действие е точно като публичното, с изключение на това, че публикацията няма да се появява в каналите на живо, хаштаговете, разглеждането или търсенето в Mastodon, дори ако сте избрали да се публично видими на ниво акаунт.", "privacy.unlisted.additional": "Това действие е точно като публичното, с изключение на това, че публикацията няма да се появява в каналите на живо, хаштаговете, разглеждането или търсенето в Mastodon, дори ако сте избрали да се публично видими на ниво акаунт.",

View File

@ -559,7 +559,6 @@
"privacy.private.long": "Hoc'h heulierien·ezed hepken", "privacy.private.long": "Hoc'h heulierien·ezed hepken",
"privacy.private.short": "Heulierien", "privacy.private.short": "Heulierien",
"privacy.public.short": "Publik", "privacy.public.short": "Publik",
"privacy.quote.anyone": "{visibility}, n'eus forzh piv a c'hall menegiñ",
"privacy.quote.disabled": "{visibility}, menegoù diweredekaet", "privacy.quote.disabled": "{visibility}, menegoù diweredekaet",
"privacy_policy.last_updated": "Hizivadenn ziwezhañ {date}", "privacy_policy.last_updated": "Hizivadenn ziwezhañ {date}",
"privacy_policy.title": "Reolennoù Prevezded", "privacy_policy.title": "Reolennoù Prevezded",

View File

@ -772,7 +772,6 @@
"privacy.private.short": "Seguidors", "privacy.private.short": "Seguidors",
"privacy.public.long": "Tothom dins o fora Mastodon", "privacy.public.long": "Tothom dins o fora Mastodon",
"privacy.public.short": "Públic", "privacy.public.short": "Públic",
"privacy.quote.anyone": "{visibility}, qualsevol pot citar",
"privacy.quote.disabled": "{visibility}, cites desactivades", "privacy.quote.disabled": "{visibility}, cites desactivades",
"privacy.quote.limited": "{visibility}, cites limitades", "privacy.quote.limited": "{visibility}, cites limitades",
"privacy.unlisted.additional": "Es comporta igual que públic, excepte que la publicació no apareixerà als canals en directe o etiquetes, l'explora o a la cerca de Mastodon, fins i tot si ho heu activat a nivell de compte.", "privacy.unlisted.additional": "Es comporta igual que públic, excepte que la publicació no apareixerà als canals en directe o etiquetes, l'explora o a la cerca de Mastodon, fins i tot si ho heu activat a nivell de compte.",

View File

@ -790,7 +790,6 @@
"privacy.private.short": "Sledující", "privacy.private.short": "Sledující",
"privacy.public.long": "Kdokoliv na Mastodonu i mimo něj", "privacy.public.long": "Kdokoliv na Mastodonu i mimo něj",
"privacy.public.short": "Veřejné", "privacy.public.short": "Veřejné",
"privacy.quote.anyone": "{visibility}, kdokoliv může citovat",
"privacy.quote.disabled": "{visibility}, citování je zakázáno", "privacy.quote.disabled": "{visibility}, citování je zakázáno",
"privacy.quote.limited": "{visibility}, citování je omezené", "privacy.quote.limited": "{visibility}, citování je omezené",
"privacy.unlisted.additional": "Chová se stejně jako veřejný, až na to, že se příspěvek neobjeví v živých kanálech nebo hashtazích, v objevování nebo vyhledávání na Mastodonu, a to i když je účet nastaven tak, aby se zde všude tyto příspěvky zobrazovaly.", "privacy.unlisted.additional": "Chová se stejně jako veřejný, až na to, že se příspěvek neobjeví v živých kanálech nebo hashtazích, v objevování nebo vyhledávání na Mastodonu, a to i když je účet nastaven tak, aby se zde všude tyto příspěvky zobrazovaly.",

View File

@ -785,7 +785,6 @@
"privacy.private.short": "Dilynwyr", "privacy.private.short": "Dilynwyr",
"privacy.public.long": "Unrhyw un ar ac oddi ar Mastodon", "privacy.public.long": "Unrhyw un ar ac oddi ar Mastodon",
"privacy.public.short": "Cyhoeddus", "privacy.public.short": "Cyhoeddus",
"privacy.quote.anyone": "{visibility}, gall unrhyw un ddyfynnu",
"privacy.quote.disabled": "{visibility}, dyfyniadau wedi'u hanalluogi", "privacy.quote.disabled": "{visibility}, dyfyniadau wedi'u hanalluogi",
"privacy.quote.limited": "{visibility}, dyfyniadau wedi'u cyfyngu", "privacy.quote.limited": "{visibility}, dyfyniadau wedi'u cyfyngu",
"privacy.unlisted.additional": "Mae hwn yn ymddwyn yn union fel y cyhoeddus, ac eithrio na fydd y postiad yn ymddangos mewn ffrydiau byw neu hashnodau, archwilio, neu chwiliad Mastodon, hyd yn oed os ydych wedi eich cynnwys ar draws y cyfrif.", "privacy.unlisted.additional": "Mae hwn yn ymddwyn yn union fel y cyhoeddus, ac eithrio na fydd y postiad yn ymddangos mewn ffrydiau byw neu hashnodau, archwilio, neu chwiliad Mastodon, hyd yn oed os ydych wedi eich cynnwys ar draws y cyfrif.",

View File

@ -577,7 +577,7 @@
"lists.add_to_list": "Føj til liste", "lists.add_to_list": "Føj til liste",
"lists.add_to_lists": "Føj {name} til lister", "lists.add_to_lists": "Føj {name} til lister",
"lists.create": "Opret", "lists.create": "Opret",
"lists.create_a_list_to_organize": "Opret en ny liste til organisering af hjemmefeed", "lists.create_a_list_to_organize": "Opret en ny liste til organisering af dit Hjem-feed",
"lists.create_list": "Opret liste", "lists.create_list": "Opret liste",
"lists.delete": "Slet liste", "lists.delete": "Slet liste",
"lists.done": "Færdig", "lists.done": "Færdig",
@ -799,7 +799,7 @@
"privacy.private.short": "Følgere", "privacy.private.short": "Følgere",
"privacy.public.long": "Alle på og udenfor Mastodon", "privacy.public.long": "Alle på og udenfor Mastodon",
"privacy.public.short": "Offentlig", "privacy.public.short": "Offentlig",
"privacy.quote.anyone": "{visibility}, alle kan citere", "privacy.quote.anyone": "{visibility}, citering tilladt",
"privacy.quote.disabled": "{visibility}, citering deaktiveret", "privacy.quote.disabled": "{visibility}, citering deaktiveret",
"privacy.quote.limited": "{visibility}, citering begrænset", "privacy.quote.limited": "{visibility}, citering begrænset",
"privacy.unlisted.additional": "Dette svarer til offentlig, bortset fra at indlægget ikke vises i live-feeds eller hashtags, udforsk eller Mastodon-søgning, selvom du har tilvalgt dette for kontoen.", "privacy.unlisted.additional": "Dette svarer til offentlig, bortset fra at indlægget ikke vises i live-feeds eller hashtags, udforsk eller Mastodon-søgning, selvom du har tilvalgt dette for kontoen.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Follower", "privacy.private.short": "Follower",
"privacy.public.long": "Alle innerhalb und außerhalb von Mastodon", "privacy.public.long": "Alle innerhalb und außerhalb von Mastodon",
"privacy.public.short": "Öffentlich", "privacy.public.short": "Öffentlich",
"privacy.quote.anyone": "{visibility} alle dürfen zitieren", "privacy.quote.anyone": "{visibility}, zitierte Beiträge erlaubt",
"privacy.quote.disabled": "{visibility} Zitieren deaktiviert", "privacy.quote.disabled": "{visibility} Zitieren deaktiviert",
"privacy.quote.limited": "{visibility} nur Follower", "privacy.quote.limited": "{visibility} nur Follower",
"privacy.unlisted.additional": "Das Verhalten ist wie bei „Öffentlich“, jedoch gibt es einige Einschränkungen. Der Beitrag wird nicht in „Live-Feeds“, „Erkunden“, Hashtags oder über die Mastodon-Suchfunktion auffindbar sein selbst wenn die zugehörige Einstellung aktiviert wurde.", "privacy.unlisted.additional": "Das Verhalten ist wie bei „Öffentlich“, jedoch gibt es einige Einschränkungen. Der Beitrag wird nicht in „Live-Feeds“, „Erkunden“, Hashtags oder über die Mastodon-Suchfunktion auffindbar sein selbst wenn die zugehörige Einstellung aktiviert wurde.",

View File

@ -60,7 +60,7 @@
"account.joined_long": "Έγινε μέλος {date}", "account.joined_long": "Έγινε μέλος {date}",
"account.joined_short": "Έγινε μέλος", "account.joined_short": "Έγινε μέλος",
"account.languages": "Αλλαγή εγγεγραμμένων γλωσσών", "account.languages": "Αλλαγή εγγεγραμμένων γλωσσών",
"account.link_verified_on": "Η ιδιοκτησία αυτού του συνδέσμου ελέχθηκε στις {date}", "account.link_verified_on": "Η ιδιοκτησία αυτού του συνδέσμου ελέγχθηκε στις {date}",
"account.locked_info": "Η κατάσταση απορρήτου αυτού του λογαριασμού έχει ρυθμιστεί σε κλειδωμένη. Ο ιδιοκτήτης αξιολογεί χειροκίνητα ποιος μπορεί να τον ακολουθήσει.", "account.locked_info": "Η κατάσταση απορρήτου αυτού του λογαριασμού έχει ρυθμιστεί σε κλειδωμένη. Ο ιδιοκτήτης αξιολογεί χειροκίνητα ποιος μπορεί να τον ακολουθήσει.",
"account.media": "Πολυμέσα", "account.media": "Πολυμέσα",
"account.mention": "Επισήμανε @{name}", "account.mention": "Επισήμανε @{name}",
@ -799,7 +799,7 @@
"privacy.private.short": "Ακόλουθοι", "privacy.private.short": "Ακόλουθοι",
"privacy.public.long": "Όλοι εντός και εκτός του Mastodon", "privacy.public.long": "Όλοι εντός και εκτός του Mastodon",
"privacy.public.short": "Δημόσια", "privacy.public.short": "Δημόσια",
"privacy.quote.anyone": "{visibility}, ο καθένας μπορεί να παραθέσει", "privacy.quote.anyone": "{visibility}, παραθέσεις επιτρεπτές",
"privacy.quote.disabled": "{visibility}, παραθέσεις απενεργοποιημένες", "privacy.quote.disabled": "{visibility}, παραθέσεις απενεργοποιημένες",
"privacy.quote.limited": "{visibility}, παραθέσεις περιορισμένες", "privacy.quote.limited": "{visibility}, παραθέσεις περιορισμένες",
"privacy.unlisted.additional": "Αυτό συμπεριφέρεται ακριβώς όπως το δημόσιο, εκτός από το ότι η ανάρτηση δεν θα εμφανιστεί σε ζωντανές ροές ή ετικέτες, εξερεύνηση ή αναζήτηση στο Mastodon, ακόμη και αν το έχεις επιλέξει για τον λογαριασμό σου.", "privacy.unlisted.additional": "Αυτό συμπεριφέρεται ακριβώς όπως το δημόσιο, εκτός από το ότι η ανάρτηση δεν θα εμφανιστεί σε ζωντανές ροές ή ετικέτες, εξερεύνηση ή αναζήτηση στο Mastodon, ακόμη και αν το έχεις επιλέξει για τον λογαριασμό σου.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Followers", "privacy.private.short": "Followers",
"privacy.public.long": "Anyone on and off Mastodon", "privacy.public.long": "Anyone on and off Mastodon",
"privacy.public.short": "Public", "privacy.public.short": "Public",
"privacy.quote.anyone": "{visibility}, anyone can quote", "privacy.quote.anyone": "{visibility}, quotes allowed",
"privacy.quote.disabled": "{visibility}, quotes disabled", "privacy.quote.disabled": "{visibility}, quotes disabled",
"privacy.quote.limited": "{visibility}, quotes limited", "privacy.quote.limited": "{visibility}, quotes limited",
"privacy.unlisted.additional": "This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.", "privacy.unlisted.additional": "This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.",

View File

@ -14,6 +14,7 @@
"about.powered_by": "Decentralized social media powered by {mastodon}", "about.powered_by": "Decentralized social media powered by {mastodon}",
"about.rules": "Server rules", "about.rules": "Server rules",
"account.account_note_header": "Personal note", "account.account_note_header": "Personal note",
"account.add_note": "Add a personal note",
"account.add_or_remove_from_list": "Add or Remove from lists", "account.add_or_remove_from_list": "Add or Remove from lists",
"account.badges.bot": "Automated", "account.badges.bot": "Automated",
"account.badges.group": "Group", "account.badges.group": "Group",
@ -27,6 +28,7 @@
"account.direct": "Privately mention @{name}", "account.direct": "Privately mention @{name}",
"account.disable_notifications": "Stop notifying me when @{name} posts", "account.disable_notifications": "Stop notifying me when @{name} posts",
"account.domain_blocking": "Blocking domain", "account.domain_blocking": "Blocking domain",
"account.edit_note": "Edit personal note",
"account.edit_profile": "Edit profile", "account.edit_profile": "Edit profile",
"account.edit_profile_short": "Edit", "account.edit_profile_short": "Edit",
"account.enable_notifications": "Notify me when @{name} posts", "account.enable_notifications": "Notify me when @{name} posts",
@ -72,6 +74,14 @@
"account.muting": "Muting", "account.muting": "Muting",
"account.mutual": "You follow each other", "account.mutual": "You follow each other",
"account.no_bio": "No description provided.", "account.no_bio": "No description provided.",
"account.node_modal.callout": "Personal notes are visible only to you.",
"account.node_modal.edit_title": "Edit personal note",
"account.node_modal.error_unknown": "Could not save the note",
"account.node_modal.field_label": "Personal Note",
"account.node_modal.save": "Save",
"account.node_modal.title": "Add a personal note",
"account.note.edit_button": "Edit",
"account.note.title": "Personal note (visible only to you)",
"account.open_original_page": "Open original page", "account.open_original_page": "Open original page",
"account.posts": "Posts", "account.posts": "Posts",
"account.posts_with_replies": "Posts and replies", "account.posts_with_replies": "Posts and replies",

View File

@ -86,6 +86,7 @@
"account.unmute": "Malsilentigi @{name}", "account.unmute": "Malsilentigi @{name}",
"account.unmute_notifications_short": "Malsilentigu sciigojn", "account.unmute_notifications_short": "Malsilentigu sciigojn",
"account.unmute_short": "Ne plu silentigi", "account.unmute_short": "Ne plu silentigi",
"account_fields_modal.close": "Fermi",
"account_note.placeholder": "Alklaku por aldoni noton", "account_note.placeholder": "Alklaku por aldoni noton",
"admin.dashboard.daily_retention": "Uzantoretenprocento laŭ tag post registro", "admin.dashboard.daily_retention": "Uzantoretenprocento laŭ tag post registro",
"admin.dashboard.monthly_retention": "Uzantoretenprocento laŭ monato post registro", "admin.dashboard.monthly_retention": "Uzantoretenprocento laŭ monato post registro",
@ -112,6 +113,7 @@
"annual_report.announcement.action_dismiss": "Ne, dankon", "annual_report.announcement.action_dismiss": "Ne, dankon",
"annual_report.nav_item.badge": "Nova", "annual_report.nav_item.badge": "Nova",
"annual_report.shared_page.donate": "Donaci", "annual_report.shared_page.donate": "Donaci",
"annual_report.summary.close": "Fermi",
"annual_report.summary.copy_link": "Kopii ligilon", "annual_report.summary.copy_link": "Kopii ligilon",
"annual_report.summary.highlighted_post.title": "Plej populara afiŝo", "annual_report.summary.highlighted_post.title": "Plej populara afiŝo",
"annual_report.summary.most_used_app.most_used_app": "plej uzita aplikaĵo", "annual_report.summary.most_used_app.most_used_app": "plej uzita aplikaĵo",
@ -149,6 +151,9 @@
"closed_registrations_modal.find_another_server": "Trovi alian servilon", "closed_registrations_modal.find_another_server": "Trovi alian servilon",
"closed_registrations_modal.preamble": "Mastodon estas malcentraliza, do sendepende de tio, kie vi kreas vian konton, vi povos sekvi kaj komuniki kun ĉiuj ajn el ĉi tiu servilo. Vi eĉ povas mem starigi propran servilon!", "closed_registrations_modal.preamble": "Mastodon estas malcentraliza, do sendepende de tio, kie vi kreas vian konton, vi povos sekvi kaj komuniki kun ĉiuj ajn el ĉi tiu servilo. Vi eĉ povas mem starigi propran servilon!",
"closed_registrations_modal.title": "Registriĝi en Mastodon", "closed_registrations_modal.title": "Registriĝi en Mastodon",
"collections.create_collection": "Krei kolekton",
"collections.delete_collection": "Forigi kolekton",
"collections.error_loading_collections": "Okazis eraro provante ŝargi viajn kolektojn.",
"column.about": "Pri", "column.about": "Pri",
"column.blocks": "Blokitaj uzantoj", "column.blocks": "Blokitaj uzantoj",
"column.bookmarks": "Legosignoj", "column.bookmarks": "Legosignoj",
@ -179,6 +184,7 @@
"community.column_settings.local_only": "Nur loka", "community.column_settings.local_only": "Nur loka",
"community.column_settings.media_only": "Nur aŭdovidaĵoj", "community.column_settings.media_only": "Nur aŭdovidaĵoj",
"community.column_settings.remote_only": "Nur fora", "community.column_settings.remote_only": "Nur fora",
"compose.error.blank_post": "Afiŝo ne povas esti malplena.",
"compose.language.change": "Ŝanĝi lingvon", "compose.language.change": "Ŝanĝi lingvon",
"compose.language.search": "Serĉi lingvojn...", "compose.language.search": "Serĉi lingvojn...",
"compose.published.body": "Afiŝo publikigita.", "compose.published.body": "Afiŝo publikigita.",
@ -213,6 +219,7 @@
"confirmations.delete_list.title": "Ĉu forigi liston?", "confirmations.delete_list.title": "Ĉu forigi liston?",
"confirmations.discard_draft.confirm": "Forĵetu kaj daŭrigu", "confirmations.discard_draft.confirm": "Forĵetu kaj daŭrigu",
"confirmations.discard_draft.edit.cancel": "Daŭrigi redaktadon", "confirmations.discard_draft.edit.cancel": "Daŭrigi redaktadon",
"confirmations.discard_draft.edit.message": "Daŭrigo forigos ĉiujn ŝanĝojn, kiujn vi faris al la afiŝo, kiun vi nun redaktas.",
"confirmations.discard_draft.edit.title": "Ĉu forĵeti ŝanĝojn al via afiŝo?", "confirmations.discard_draft.edit.title": "Ĉu forĵeti ŝanĝojn al via afiŝo?",
"confirmations.discard_draft.post.cancel": "Daŭrigi malneton", "confirmations.discard_draft.post.cancel": "Daŭrigi malneton",
"confirmations.discard_draft.post.message": "Daŭrigo forigos la afiŝon, kiun vi nun verkas.", "confirmations.discard_draft.post.message": "Daŭrigo forigos la afiŝon, kiun vi nun verkas.",
@ -230,6 +237,8 @@
"confirmations.missing_alt_text.secondary": "Afiŝi ĉiuokaze", "confirmations.missing_alt_text.secondary": "Afiŝi ĉiuokaze",
"confirmations.missing_alt_text.title": "Ĉu aldoni alttekston?", "confirmations.missing_alt_text.title": "Ĉu aldoni alttekston?",
"confirmations.mute.confirm": "Silentigi", "confirmations.mute.confirm": "Silentigi",
"confirmations.private_quote_notify.confirm": "Publikigi afiŝon",
"confirmations.private_quote_notify.do_not_show_again": "Ne montru al mi ĉi tiun mesaĝon denove",
"confirmations.quiet_post_quote_info.dismiss": "Ne memorigu min denove", "confirmations.quiet_post_quote_info.dismiss": "Ne memorigu min denove",
"confirmations.quiet_post_quote_info.got_it": "Komprenite", "confirmations.quiet_post_quote_info.got_it": "Komprenite",
"confirmations.redraft.confirm": "Forigi kaj reskribi", "confirmations.redraft.confirm": "Forigi kaj reskribi",
@ -336,6 +345,7 @@
"explore.trending_statuses": "Afiŝoj", "explore.trending_statuses": "Afiŝoj",
"explore.trending_tags": "Kradvortoj", "explore.trending_tags": "Kradvortoj",
"featured_carousel.header": "{count, plural, one {Alpinglita afiŝo} other {Alpinglitaj afiŝoj}}", "featured_carousel.header": "{count, plural, one {Alpinglita afiŝo} other {Alpinglitaj afiŝoj}}",
"featured_carousel.slide": "Afiŝo {current, number} de {max, number}",
"filter_modal.added.context_mismatch_explanation": "Ĉi tiu filtrilkategorio ne kongruas kun la kunteksto en kiu vi akcesis ĉi tiun afiŝon. Se vi volas ke la afiŝo estas ankaŭ filtrita en ĉi tiu kunteksto, vi devus redakti la filtrilon.", "filter_modal.added.context_mismatch_explanation": "Ĉi tiu filtrilkategorio ne kongruas kun la kunteksto en kiu vi akcesis ĉi tiun afiŝon. Se vi volas ke la afiŝo estas ankaŭ filtrita en ĉi tiu kunteksto, vi devus redakti la filtrilon.",
"filter_modal.added.context_mismatch_title": "Ne kongruas la kunteksto!", "filter_modal.added.context_mismatch_title": "Ne kongruas la kunteksto!",
"filter_modal.added.expired_explanation": "Ĉi tiu filtrilkategorio eksvalidiĝis, vu bezonos ŝanĝi la eksvaliddaton por ĝi.", "filter_modal.added.expired_explanation": "Ĉi tiu filtrilkategorio eksvalidiĝis, vu bezonos ŝanĝi la eksvaliddaton por ĝi.",
@ -378,6 +388,9 @@
"follow_suggestions.who_to_follow": "Kiun sekvi", "follow_suggestions.who_to_follow": "Kiun sekvi",
"followed_tags": "Sekvataj kradvortoj", "followed_tags": "Sekvataj kradvortoj",
"footer.about": "Pri", "footer.about": "Pri",
"footer.about_mastodon": "Pri Mastodon",
"footer.about_server": "Pri {domain}",
"footer.about_this_server": "Pri",
"footer.directory": "Profilujo", "footer.directory": "Profilujo",
"footer.get_app": "Akiri la apon", "footer.get_app": "Akiri la apon",
"footer.keyboard_shortcuts": "Fulmoklavoj", "footer.keyboard_shortcuts": "Fulmoklavoj",
@ -710,7 +723,6 @@
"privacy.private.short": "Sekvantoj", "privacy.private.short": "Sekvantoj",
"privacy.public.long": "Ĉiujn ajn ĉe kaj ekster Mastodon", "privacy.public.long": "Ĉiujn ajn ĉe kaj ekster Mastodon",
"privacy.public.short": "Publika", "privacy.public.short": "Publika",
"privacy.quote.anyone": "{visibility}, iu ajn povas citi",
"privacy.quote.disabled": "{visibility}, malŝaltitaj citaĵoj", "privacy.quote.disabled": "{visibility}, malŝaltitaj citaĵoj",
"privacy.quote.limited": "{visibility}, limigitaj citaĵoj", "privacy.quote.limited": "{visibility}, limigitaj citaĵoj",
"privacy.unlisted.additional": "Ĉi tio kondutas ekzakte kiel publika, krom ke la afiŝo ne aperos en vivaj fluoj aŭ kradvortoj, esploro aŭ Mastodon-serĉo, eĉ se vi estas enskribita en la tuta konto.", "privacy.unlisted.additional": "Ĉi tio kondutas ekzakte kiel publika, krom ke la afiŝo ne aperos en vivaj fluoj aŭ kradvortoj, esploro aŭ Mastodon-serĉo, eĉ se vi estas enskribita en la tuta konto.",
@ -835,6 +847,7 @@
"status.cancel_reblog_private": "Ne plu diskonigi", "status.cancel_reblog_private": "Ne plu diskonigi",
"status.cannot_quote": "Vi ne rajtas citi ĉi tiun afiŝon", "status.cannot_quote": "Vi ne rajtas citi ĉi tiun afiŝon",
"status.cannot_reblog": "Ĉi tiun afiŝon ne eblas diskonigi", "status.cannot_reblog": "Ĉi tiun afiŝon ne eblas diskonigi",
"status.context.show": "Montri",
"status.continued_thread": "Daŭrigis fadenon", "status.continued_thread": "Daŭrigis fadenon",
"status.copy": "Kopii la ligilon al la afiŝo", "status.copy": "Kopii la ligilon al la afiŝo",
"status.delete": "Forigi", "status.delete": "Forigi",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Seguidores", "privacy.private.short": "Seguidores",
"privacy.public.long": "Cualquier persona dentro y fuera de Mastodon", "privacy.public.long": "Cualquier persona dentro y fuera de Mastodon",
"privacy.public.short": "Público", "privacy.public.short": "Público",
"privacy.quote.anyone": "{visibility}, todos pueden citar", "privacy.quote.anyone": "{visibility}, citas permitidas",
"privacy.quote.disabled": "{visibility}, citas deshabilitadas", "privacy.quote.disabled": "{visibility}, citas deshabilitadas",
"privacy.quote.limited": "{visibility}, citas limitadas", "privacy.quote.limited": "{visibility}, citas limitadas",
"privacy.unlisted.additional": "Esto se comporta exactamente igual que con la configuración de privacidad de mensaje «Público», excepto que el mensaje no aparecerá en las líneas temporales en vivo, ni en las etiquetas, ni en la línea temporal «Explorá», ni en la búsqueda de Mastodon; incluso si optaste por hacer tu cuenta visible.", "privacy.unlisted.additional": "Esto se comporta exactamente igual que con la configuración de privacidad de mensaje «Público», excepto que el mensaje no aparecerá en las líneas temporales en vivo, ni en las etiquetas, ni en la línea temporal «Explorá», ni en la búsqueda de Mastodon; incluso si optaste por hacer tu cuenta visible.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Seguidores", "privacy.private.short": "Seguidores",
"privacy.public.long": "Cualquiera dentro y fuera de Mastodon", "privacy.public.long": "Cualquiera dentro y fuera de Mastodon",
"privacy.public.short": "Público", "privacy.public.short": "Público",
"privacy.quote.anyone": "{visibility}, cualquiera puede citar", "privacy.quote.anyone": "{visibility}, citas permitidas",
"privacy.quote.disabled": "{visibility}, citas desactivadas", "privacy.quote.disabled": "{visibility}, citas desactivadas",
"privacy.quote.limited": "{visibility}, citas limitadas", "privacy.quote.limited": "{visibility}, citas limitadas",
"privacy.unlisted.additional": "Esto se comporta exactamente igual que el público, excepto que el post no aparecerá en las cronologías en directo o en las etiquetas, la exploración o busquedas en Mastodon, incluso si está optado por activar la cuenta de usuario.", "privacy.unlisted.additional": "Esto se comporta exactamente igual que el público, excepto que el post no aparecerá en las cronologías en directo o en las etiquetas, la exploración o busquedas en Mastodon, incluso si está optado por activar la cuenta de usuario.",

View File

@ -187,6 +187,7 @@
"bundle_modal_error.close": "Cerrar", "bundle_modal_error.close": "Cerrar",
"bundle_modal_error.message": "Ha habido algún error mientras cargábamos esta pantalla.", "bundle_modal_error.message": "Ha habido algún error mientras cargábamos esta pantalla.",
"bundle_modal_error.retry": "Inténtalo de nuevo", "bundle_modal_error.retry": "Inténtalo de nuevo",
"callout.dismiss": "Descartar",
"carousel.current": "<sr>Diapositiva</sr> {current, number} / {max, number}", "carousel.current": "<sr>Diapositiva</sr> {current, number} / {max, number}",
"carousel.slide": "Diapositiva {current, number} de {max, number}", "carousel.slide": "Diapositiva {current, number} de {max, number}",
"closed_registrations.other_server_instructions": "Como Mastodon es descentralizado, puedes crear una cuenta en otro servidor y seguir interactuando con este.", "closed_registrations.other_server_instructions": "Como Mastodon es descentralizado, puedes crear una cuenta en otro servidor y seguir interactuando con este.",
@ -194,9 +195,16 @@
"closed_registrations_modal.find_another_server": "Buscar otro servidor", "closed_registrations_modal.find_another_server": "Buscar otro servidor",
"closed_registrations_modal.preamble": "Mastodon es descentralizado, por lo que no importa dónde crees tu cuenta, podrás seguir e interactuar con cualquier persona en este servidor. ¡Incluso puedes alojarlo tú mismo!", "closed_registrations_modal.preamble": "Mastodon es descentralizado, por lo que no importa dónde crees tu cuenta, podrás seguir e interactuar con cualquier persona en este servidor. ¡Incluso puedes alojarlo tú mismo!",
"closed_registrations_modal.title": "Registrarse en Mastodon", "closed_registrations_modal.title": "Registrarse en Mastodon",
"collections.create_a_collection_hint": "Crea una colección para recomendar o compartir tus cuentas favoritas con otros.",
"collections.create_collection": "Crear colección",
"collections.delete_collection": "Eliminar colección",
"collections.error_loading_collections": "Se ha producido un error al intentar cargar tus colecciones.",
"collections.no_collections_yet": "Aún no hay colecciones.",
"collections.view_collection": "Ver colección",
"column.about": "Acerca de", "column.about": "Acerca de",
"column.blocks": "Usuarios bloqueados", "column.blocks": "Usuarios bloqueados",
"column.bookmarks": "Marcadores", "column.bookmarks": "Marcadores",
"column.collections": "Mis colecciones",
"column.community": "Cronología local", "column.community": "Cronología local",
"column.create_list": "Crear lista", "column.create_list": "Crear lista",
"column.direct": "Menciones privadas", "column.direct": "Menciones privadas",
@ -791,7 +799,7 @@
"privacy.private.short": "Seguidores", "privacy.private.short": "Seguidores",
"privacy.public.long": "Visible por todo el mundo, dentro y fuera de Mastodon", "privacy.public.long": "Visible por todo el mundo, dentro y fuera de Mastodon",
"privacy.public.short": "Pública", "privacy.public.short": "Pública",
"privacy.quote.anyone": "{visibility}, cualquiera puede citar", "privacy.quote.anyone": "{visibility}, citas permitidas",
"privacy.quote.disabled": "{visibility}, citas deshabilitadas", "privacy.quote.disabled": "{visibility}, citas deshabilitadas",
"privacy.quote.limited": "{visibility}, citas limitadas", "privacy.quote.limited": "{visibility}, citas limitadas",
"privacy.unlisted.additional": "Se comporta exactamente igual que la visibilidad pública, excepto que la publicación no aparecerá en las cronologías públicas o en las etiquetas, la sección de Explorar o la búsqueda de Mastodon, incluso si has habilitado la opción de búsqueda en tu perfil.", "privacy.unlisted.additional": "Se comporta exactamente igual que la visibilidad pública, excepto que la publicación no aparecerá en las cronologías públicas o en las etiquetas, la sección de Explorar o la búsqueda de Mastodon, incluso si has habilitado la opción de búsqueda en tu perfil.",

View File

@ -791,7 +791,6 @@
"privacy.private.short": "Jälgijad", "privacy.private.short": "Jälgijad",
"privacy.public.long": "Nii kasutajad kui mittekasutajad", "privacy.public.long": "Nii kasutajad kui mittekasutajad",
"privacy.public.short": "Avalik", "privacy.public.short": "Avalik",
"privacy.quote.anyone": "{visibility}, kõik võivad tsiteerida",
"privacy.quote.disabled": "{visibility}, tsiteerimine pole lubatud", "privacy.quote.disabled": "{visibility}, tsiteerimine pole lubatud",
"privacy.quote.limited": "{visibility}, tsiteerimine on piiratud", "privacy.quote.limited": "{visibility}, tsiteerimine on piiratud",
"privacy.unlisted.additional": "See on olemuselt küll avalik, aga postitus ei ilmu voogudes ega teemaviidetes, lehitsedes ega Mastodoni otsingus, isegi kui konto on seadistustes avalik.", "privacy.unlisted.additional": "See on olemuselt küll avalik, aga postitus ei ilmu voogudes ega teemaviidetes, lehitsedes ega Mastodoni otsingus, isegi kui konto on seadistustes avalik.",

View File

@ -785,7 +785,6 @@
"privacy.private.short": "Jarraitzaileak", "privacy.private.short": "Jarraitzaileak",
"privacy.public.long": "Mastodonen dagoen edo ez dagoen edonor", "privacy.public.long": "Mastodonen dagoen edo ez dagoen edonor",
"privacy.public.short": "Publikoa", "privacy.public.short": "Publikoa",
"privacy.quote.anyone": "{visibility}, edonork aipa dezake",
"privacy.quote.disabled": "{visibility}, aipuak desgaituta", "privacy.quote.disabled": "{visibility}, aipuak desgaituta",
"privacy.quote.limited": "{visibility}, aipuak mugatuta", "privacy.quote.limited": "{visibility}, aipuak mugatuta",
"privacy.unlisted.additional": "Aukera honek publiko modua bezala funtzionatzen du, baina argitalpena ez da agertuko zuzeneko jarioetan edo traoletan, \"Arakatu\" atalean edo Mastodonen bilaketan, nahiz eta kontua zabaltzeko onartu duzun.", "privacy.unlisted.additional": "Aukera honek publiko modua bezala funtzionatzen du, baina argitalpena ez da agertuko zuzeneko jarioetan edo traoletan, \"Arakatu\" atalean edo Mastodonen bilaketan, nahiz eta kontua zabaltzeko onartu duzun.",

View File

@ -785,7 +785,6 @@
"privacy.private.short": "پی‌گیرندگان", "privacy.private.short": "پی‌گیرندگان",
"privacy.public.long": "هرکسی در و بیرون از ماستودون", "privacy.public.long": "هرکسی در و بیرون از ماستودون",
"privacy.public.short": "عمومی", "privacy.public.short": "عمومی",
"privacy.quote.anyone": "{visibility}، هرکسی می‌تواند نقل کند",
"privacy.quote.disabled": "{visibility}، نقل‌ها از کار افتاده", "privacy.quote.disabled": "{visibility}، نقل‌ها از کار افتاده",
"privacy.quote.limited": "{visibility}، نقل‌ها محدود شده", "privacy.quote.limited": "{visibility}، نقل‌ها محدود شده",
"privacy.unlisted.additional": "درست مثل عمومی رفتار می‌کند؛ جز این که فرسته در برچسب‌ها یا خوراک‌های زنده، کشف یا جست‌وجوی ماستودون ظاهر نخواهد شد. حتا اگر کلیّت نمایه‌تان اجازه داده باشد.", "privacy.unlisted.additional": "درست مثل عمومی رفتار می‌کند؛ جز این که فرسته در برچسب‌ها یا خوراک‌های زنده، کشف یا جست‌وجوی ماستودون ظاهر نخواهد شد. حتا اگر کلیّت نمایه‌تان اجازه داده باشد.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Seuraajat", "privacy.private.short": "Seuraajat",
"privacy.public.long": "Kuka tahansa Mastodonissa ja sen ulkopuolella", "privacy.public.long": "Kuka tahansa Mastodonissa ja sen ulkopuolella",
"privacy.public.short": "Julkinen", "privacy.public.short": "Julkinen",
"privacy.quote.anyone": "{visibility}, kuka tahansa voi lainata", "privacy.quote.anyone": "{visibility}, lainaukset sallittu",
"privacy.quote.disabled": "{visibility}, lainaukset poissa käytöstä", "privacy.quote.disabled": "{visibility}, lainaukset poissa käytöstä",
"privacy.quote.limited": "{visibility}, lainauksia rajoitettu", "privacy.quote.limited": "{visibility}, lainauksia rajoitettu",
"privacy.unlisted.additional": "Tämä toimii muuten kuin julkinen, mutta julkaisut eivät näy livesyöte-, aihetunniste- tai selausnäkymissä eivätkä Mastodonin hakutuloksissa, vaikka ne olisivat käyttäjätililläsi yleisesti sallittuina.", "privacy.unlisted.additional": "Tämä toimii muuten kuin julkinen, mutta julkaisut eivät näy livesyöte-, aihetunniste- tai selausnäkymissä eivätkä Mastodonin hakutuloksissa, vaikka ne olisivat käyttäjätililläsi yleisesti sallittuina.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Fylgjarar", "privacy.private.short": "Fylgjarar",
"privacy.public.long": "Øll í og uttanfyri Mastodon", "privacy.public.long": "Øll í og uttanfyri Mastodon",
"privacy.public.short": "Alment", "privacy.public.short": "Alment",
"privacy.quote.anyone": "{visibility}, øll kunnu sitera", "privacy.quote.anyone": "{visibility}, siteringar loyvdar",
"privacy.quote.disabled": "{visibility}, siteringar óvirknar", "privacy.quote.disabled": "{visibility}, siteringar óvirknar",
"privacy.quote.limited": "{visibility}, siteringar avmarkaðar", "privacy.quote.limited": "{visibility}, siteringar avmarkaðar",
"privacy.unlisted.additional": "Hetta er júst sum almenn, tó verður posturin ikki vístur í samtíðarrásum ella frámerkjum, rannsakan ella Mastodon leitingum, sjálvt um valið er galdandi fyri alla kontuna.", "privacy.unlisted.additional": "Hetta er júst sum almenn, tó verður posturin ikki vístur í samtíðarrásum ella frámerkjum, rannsakan ella Mastodon leitingum, sjálvt um valið er galdandi fyri alla kontuna.",

View File

@ -790,7 +790,6 @@
"privacy.private.short": "Leantóirí", "privacy.private.short": "Leantóirí",
"privacy.public.long": "Duine ar bith ar agus amach Mastodon", "privacy.public.long": "Duine ar bith ar agus amach Mastodon",
"privacy.public.short": "Poiblí", "privacy.public.short": "Poiblí",
"privacy.quote.anyone": "{visibility}, is féidir le duine ar bith lua",
"privacy.quote.disabled": "{visibility}, sleachta díchumasaithe", "privacy.quote.disabled": "{visibility}, sleachta díchumasaithe",
"privacy.quote.limited": "{visibility}, sleachta teoranta", "privacy.quote.limited": "{visibility}, sleachta teoranta",
"privacy.unlisted.additional": "Iompraíonn sé seo díreach mar a bheadh poiblí, ach amháin ní bheidh an postáil le feiceáil i bhfothaí beo nó i hashtags, in iniúchadh nó i gcuardach Mastodon, fiú má tá tú liostáilte ar fud an chuntais.", "privacy.unlisted.additional": "Iompraíonn sé seo díreach mar a bheadh poiblí, ach amháin ní bheidh an postáil le feiceáil i bhfothaí beo nó i hashtags, in iniúchadh nó i gcuardach Mastodon, fiú má tá tú liostáilte ar fud an chuntais.",

View File

@ -786,7 +786,6 @@
"privacy.private.short": "Luchd-leantainn", "privacy.private.short": "Luchd-leantainn",
"privacy.public.long": "Duine sam bith taobh a-staigh no a-muigh Mhastodon", "privacy.public.long": "Duine sam bith taobh a-staigh no a-muigh Mhastodon",
"privacy.public.short": "Poblach", "privacy.public.short": "Poblach",
"privacy.quote.anyone": "{visibility}, luaidh fosgailte",
"privacy.quote.disabled": "{visibility}, luaidh à comas", "privacy.quote.disabled": "{visibility}, luaidh à comas",
"privacy.quote.limited": "{visibility}, luaidh cuingichte", "privacy.quote.limited": "{visibility}, luaidh cuingichte",
"privacy.unlisted.additional": "Tha seo coltach ris an fhaicsinneachd phoblach ach cha nochd am post air loidhnichean-ama an t-saoghail phoblaich, nan tagaichean hais no an rùrachaidh no ann an toraidhean luirg Mhastodon fiù s ma thug thu ro-aonta airson sin seachad.", "privacy.unlisted.additional": "Tha seo coltach ris an fhaicsinneachd phoblach ach cha nochd am post air loidhnichean-ama an t-saoghail phoblaich, nan tagaichean hais no an rùrachaidh no ann an toraidhean luirg Mhastodon fiù s ma thug thu ro-aonta airson sin seachad.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Seguidoras", "privacy.private.short": "Seguidoras",
"privacy.public.long": "Para todas dentro e fóra de Mastodon", "privacy.public.long": "Para todas dentro e fóra de Mastodon",
"privacy.public.short": "Público", "privacy.public.short": "Público",
"privacy.quote.anyone": "{visibility}, calquera pode citar", "privacy.quote.anyone": "{visibility}, permítese citar",
"privacy.quote.disabled": "{visibility}, citas desactivadas", "privacy.quote.disabled": "{visibility}, citas desactivadas",
"privacy.quote.limited": "{visibility}, citas limitadas", "privacy.quote.limited": "{visibility}, citas limitadas",
"privacy.unlisted.additional": "Do mesmo xeito que público, menos que a publicación non aparecerá nas cronoloxías en directo ou nos cancelos, en descubrir ou nas buscas de Mastodon, incluso se estivese establecido nas opcións xerais da conta.", "privacy.unlisted.additional": "Do mesmo xeito que público, menos que a publicación non aparecerá nas cronoloxías en directo ou nos cancelos, en descubrir ou nas buscas de Mastodon, incluso se estivese establecido nas opcións xerais da conta.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "עוקבים", "privacy.private.short": "עוקבים",
"privacy.public.long": "כל הגולשים, מחוברים למסטודון או לא", "privacy.public.long": "כל הגולשים, מחוברים למסטודון או לא",
"privacy.public.short": "פומבי", "privacy.public.short": "פומבי",
"privacy.quote.anyone": "{visibility}, הציטוט מותר לכל", "privacy.quote.anyone": "{visibility}, רשות הציטוט נתונה",
"privacy.quote.disabled": "{visibility}, האפשרות לציטוט מכובה", "privacy.quote.disabled": "{visibility}, האפשרות לציטוט מכובה",
"privacy.quote.limited": "{visibility}, האפשרות לציטוט מוגבלת", "privacy.quote.limited": "{visibility}, האפשרות לציטוט מוגבלת",
"privacy.unlisted.additional": "ההתנהגות דומה להודעה ציבורית, מלבד שההודעה לא תופיע בפיד החי המקומי או בתגיות, תגליות או חיפוש מסטודון, אפילו אם ביקשת שהחשבון כולו יהיה פומבי.", "privacy.unlisted.additional": "ההתנהגות דומה להודעה ציבורית, מלבד שההודעה לא תופיע בפיד החי המקומי או בתגיות, תגליות או חיפוש מסטודון, אפילו אם ביקשת שהחשבון כולו יהיה פומבי.",

View File

@ -797,7 +797,6 @@
"privacy.private.short": "Követők", "privacy.private.short": "Követők",
"privacy.public.long": "Bárki a Mastodonon és azon kívül", "privacy.public.long": "Bárki a Mastodonon és azon kívül",
"privacy.public.short": "Nyilvános", "privacy.public.short": "Nyilvános",
"privacy.quote.anyone": "{visibility}, bárki idézheti",
"privacy.quote.disabled": "{visibility}, idézés letiltva", "privacy.quote.disabled": "{visibility}, idézés letiltva",
"privacy.quote.limited": "{visibility}, idézés korlátozva", "privacy.quote.limited": "{visibility}, idézés korlátozva",
"privacy.unlisted.additional": "Ez pontosan úgy viselkedik, mint a nyilvános, kivéve, hogy a bejegyzés nem jelenik meg élő hírfolyamokban, hashtagekben, felfedezésben vagy a Mastodonos keresésben, még akkor sem, ha ezt az egész fiókra engedélyezted.", "privacy.unlisted.additional": "Ez pontosan úgy viselkedik, mint a nyilvános, kivéve, hogy a bejegyzés nem jelenik meg élő hírfolyamokban, hashtagekben, felfedezésben vagy a Mastodonos keresésben, még akkor sem, ha ezt az egész fiókra engedélyezted.",

View File

@ -741,7 +741,6 @@
"privacy.private.short": "Sequitores", "privacy.private.short": "Sequitores",
"privacy.public.long": "Quicunque, sur Mastodon o non", "privacy.public.long": "Quicunque, sur Mastodon o non",
"privacy.public.short": "Public", "privacy.public.short": "Public",
"privacy.quote.anyone": "{visibility}, omnes pote citar",
"privacy.quote.disabled": "{visibility}, citation disactivate", "privacy.quote.disabled": "{visibility}, citation disactivate",
"privacy.quote.limited": "{visibility}, citation limitate", "privacy.quote.limited": "{visibility}, citation limitate",
"privacy.unlisted.additional": "Isto es exactemente como public, excepte que le message non apparera in fluxos in vivo, in hashtags, in Explorar, o in le recerca de Mastodon, mesmo si tu ha optate pro render tote le conto discoperibile.", "privacy.unlisted.additional": "Isto es exactemente como public, excepte que le message non apparera in fluxos in vivo, in hashtags, in Explorar, o in le recerca de Mastodon, mesmo si tu ha optate pro render tote le conto discoperibile.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Fylgjendur", "privacy.private.short": "Fylgjendur",
"privacy.public.long": "Hver sem er, á og utan Mastodon", "privacy.public.long": "Hver sem er, á og utan Mastodon",
"privacy.public.short": "Opinbert", "privacy.public.short": "Opinbert",
"privacy.quote.anyone": "{visibility}, hver sem er getur vitnað í færslu", "privacy.quote.anyone": "{visibility}, tilvitnanir leyfðar",
"privacy.quote.disabled": "{visibility}, tilvitnanir eru óvirkar", "privacy.quote.disabled": "{visibility}, tilvitnanir eru óvirkar",
"privacy.quote.limited": "{visibility}, tilvitnanir eru takmarkaðar", "privacy.quote.limited": "{visibility}, tilvitnanir eru takmarkaðar",
"privacy.unlisted.additional": "Þetta hegðar sér eins og opinber færsla, fyrir utan að færslan birtist ekki í beinum streymum eða myllumerkjum, né heldur í Mastodon-leitum jafnvel þótt þú hafir valið að falla undir slíkt í notandasniðinu þínu.", "privacy.unlisted.additional": "Þetta hegðar sér eins og opinber færsla, fyrir utan að færslan birtist ekki í beinum streymum eða myllumerkjum, né heldur í Mastodon-leitum jafnvel þótt þú hafir valið að falla undir slíkt í notandasniðinu þínu.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Follower", "privacy.private.short": "Follower",
"privacy.public.long": "Chiunque dentro e fuori Mastodon", "privacy.public.long": "Chiunque dentro e fuori Mastodon",
"privacy.public.short": "Pubblico", "privacy.public.short": "Pubblico",
"privacy.quote.anyone": "{visibility}, chiunque può citare", "privacy.quote.anyone": "{visibility}, citazioni autorizzate",
"privacy.quote.disabled": "{visibility}, citazioni disabilitate", "privacy.quote.disabled": "{visibility}, citazioni disabilitate",
"privacy.quote.limited": "{visibility}, citazioni limitate", "privacy.quote.limited": "{visibility}, citazioni limitate",
"privacy.unlisted.additional": "Si comporta esattamente come pubblico, tranne per il fatto che il post non verrà visualizzato nei feed live o negli hashtag, nell'esplorazione o nella ricerca Mastodon, anche se hai attivato l'attivazione a livello di account.", "privacy.unlisted.additional": "Si comporta esattamente come pubblico, tranne per il fatto che il post non verrà visualizzato nei feed live o negli hashtag, nell'esplorazione o nella ricerca Mastodon, anche se hai attivato l'attivazione a livello di account.",

View File

@ -729,7 +729,6 @@
"privacy.private.short": "フォロワー", "privacy.private.short": "フォロワー",
"privacy.public.long": "すべての人 (Mastodon以外も含む)", "privacy.public.long": "すべての人 (Mastodon以外も含む)",
"privacy.public.short": "公開", "privacy.public.short": "公開",
"privacy.quote.anyone": "{visibility}、誰でも引用可能",
"privacy.quote.disabled": "{visibility}、引用不可", "privacy.quote.disabled": "{visibility}、引用不可",
"privacy.quote.limited": "{visibility}、引用は制限", "privacy.quote.limited": "{visibility}、引用は制限",
"privacy.unlisted.additional": "「公開」とほとんど同じですが、リアルタイムフィードやハッシュタグ、探索機能、Mastodon検索などに投稿が表示されない点で「公開」と異なります。また、アカウント設定で投稿の検索や表示を許可している場合でも、この公開範囲を設定した投稿は前述の機能には表示されません。", "privacy.unlisted.additional": "「公開」とほとんど同じですが、リアルタイムフィードやハッシュタグ、探索機能、Mastodon検索などに投稿が表示されない点で「公開」と異なります。また、アカウント設定で投稿の検索や表示を許可している場合でも、この公開範囲を設定した投稿は前述の機能には表示されません。",

View File

@ -782,7 +782,6 @@
"privacy.private.short": "팔로워", "privacy.private.short": "팔로워",
"privacy.public.long": "마스토돈 내외 모두", "privacy.public.long": "마스토돈 내외 모두",
"privacy.public.short": "공개", "privacy.public.short": "공개",
"privacy.quote.anyone": "{visibility}, 누구나 인용 가능",
"privacy.quote.disabled": "{visibility}, 인용 비활성화", "privacy.quote.disabled": "{visibility}, 인용 비활성화",
"privacy.quote.limited": "{visibility}, 제한된 인용", "privacy.quote.limited": "{visibility}, 제한된 인용",
"privacy.unlisted.additional": "공개와 똑같지만 게시물이 실시간 피드나 해시태그, 둘러보기, (계정 설정에서 허용했더라도) 마스토돈 검색에서 제외됩니다.", "privacy.unlisted.additional": "공개와 똑같지만 게시물이 실시간 피드나 해시태그, 둘러보기, (계정 설정에서 허용했더라도) 마스토돈 검색에서 제외됩니다.",

View File

@ -747,7 +747,6 @@
"privacy.private.short": "Sekėjai", "privacy.private.short": "Sekėjai",
"privacy.public.long": "Bet kas iš Mastodon ir ne Mastodon", "privacy.public.long": "Bet kas iš Mastodon ir ne Mastodon",
"privacy.public.short": "Vieša", "privacy.public.short": "Vieša",
"privacy.quote.anyone": "{visibility}, kiekvienas gali cituoti",
"privacy.quote.disabled": "{visibility}, paminėjimai išjungti", "privacy.quote.disabled": "{visibility}, paminėjimai išjungti",
"privacy.quote.limited": "{visibility}, paminėjimai apriboti", "privacy.quote.limited": "{visibility}, paminėjimai apriboti",
"privacy.unlisted.additional": "Tai veikia lygiai taip pat, kaip ir vieša, tik įrašas nebus rodomas tiesioginiuose srautuose, grotažymėse, naršyme ar Mastodon paieškoje, net jei esi įtraukęs (-usi) visą paskyrą.", "privacy.unlisted.additional": "Tai veikia lygiai taip pat, kaip ir vieša, tik įrašas nebus rodomas tiesioginiuose srautuose, grotažymėse, naršyme ar Mastodon paieškoje, net jei esi įtraukęs (-usi) visą paskyrą.",

View File

@ -633,7 +633,6 @@
"privacy.private.short": "Sekotāji", "privacy.private.short": "Sekotāji",
"privacy.public.long": "Jebkurš Mastodon platformā un ārpus tās", "privacy.public.long": "Jebkurš Mastodon platformā un ārpus tās",
"privacy.public.short": "Publisks", "privacy.public.short": "Publisks",
"privacy.quote.anyone": "{visibility}, jebkurš var citēt",
"privacy.quote.disabled": "{visibility}, aizliegta citēšana", "privacy.quote.disabled": "{visibility}, aizliegta citēšana",
"privacy.quote.limited": "{visibility}, ierobežota citēšana", "privacy.quote.limited": "{visibility}, ierobežota citēšana",
"privacy.unlisted.additional": "Šis uzvedas tieši kā publisks, izņemot to, ka ieraksts neparādīsies tiešraides barotnēs vai tēmturos, izpētē vai Mastodon meklēšanā, pat ja esi to norādījis visa konta ietvaros.", "privacy.unlisted.additional": "Šis uzvedas tieši kā publisks, izņemot to, ka ieraksts neparādīsies tiešraides barotnēs vai tēmturos, izpētē vai Mastodon meklēšanā, pat ja esi to norādījis visa konta ietvaros.",

View File

@ -786,7 +786,6 @@
"privacy.private.short": "跟tuè lí ê", "privacy.private.short": "跟tuè lí ê",
"privacy.public.long": "逐ê lâng無論佇Mastodon以內á是以外", "privacy.public.long": "逐ê lâng無論佇Mastodon以內á是以外",
"privacy.public.short": "公開ê", "privacy.public.short": "公開ê",
"privacy.quote.anyone": "{visibility}ta̍k ê lâng lóng ē當引用",
"privacy.quote.disabled": "{visibility}停止引用PO文", "privacy.quote.disabled": "{visibility}停止引用PO文",
"privacy.quote.limited": "{visibility}PO文引用受限", "privacy.quote.limited": "{visibility}PO文引用受限",
"privacy.unlisted.additional": "Tse ê行為kap公開相siângm̄-koh 就算lí佇口座設定phah開有關ê公開功能PO文mā bē顯示佇即時ê動態、hashtag、探索kap Mastodon ê搜尋結果。", "privacy.unlisted.additional": "Tse ê行為kap公開相siângm̄-koh 就算lí佇口座設定phah開有關ê公開功能PO文mā bē顯示佇即時ê動態、hashtag、探索kap Mastodon ê搜尋結果。",

View File

@ -799,7 +799,6 @@
"privacy.private.short": "Volgers", "privacy.private.short": "Volgers",
"privacy.public.long": "Iedereen op Mastodon en daarbuiten", "privacy.public.long": "Iedereen op Mastodon en daarbuiten",
"privacy.public.short": "Openbaar", "privacy.public.short": "Openbaar",
"privacy.quote.anyone": "{visibility}, iedereen mag citeren",
"privacy.quote.disabled": "{visibility}, citeren uitgeschakeld", "privacy.quote.disabled": "{visibility}, citeren uitgeschakeld",
"privacy.quote.limited": "{visibility}, citeren beperkt", "privacy.quote.limited": "{visibility}, citeren beperkt",
"privacy.unlisted.additional": "Dit is vergelijkbaar met openbaar, behalve dat het bericht niet op openbare tijdlijnen, onder hashtags, verkennen of zoeken verschijnt, zelfs als je je account daarvoor hebt ingesteld.", "privacy.unlisted.additional": "Dit is vergelijkbaar met openbaar, behalve dat het bericht niet op openbare tijdlijnen, onder hashtags, verkennen of zoeken verschijnt, zelfs als je je account daarvoor hebt ingesteld.",

View File

@ -790,7 +790,6 @@
"privacy.private.short": "Fylgjarar", "privacy.private.short": "Fylgjarar",
"privacy.public.long": "Kven som helst på og av Mastodon", "privacy.public.long": "Kven som helst på og av Mastodon",
"privacy.public.short": "Offentleg", "privacy.public.short": "Offentleg",
"privacy.quote.anyone": "{visibility}, alle kan sitera",
"privacy.quote.disabled": "{visibility}, ingen kan sitera", "privacy.quote.disabled": "{visibility}, ingen kan sitera",
"privacy.quote.limited": "{visibility}, avgrensa sitat", "privacy.quote.limited": "{visibility}, avgrensa sitat",
"privacy.unlisted.additional": "Dette er akkurat som offentleg, bortsett frå at innlegga ikkje dukkar opp i direktestraumar eller emneknaggar, i oppdagingar eller Mastodon-søk, sjølv om du har sagt ja til at kontoen skal vera synleg.", "privacy.unlisted.additional": "Dette er akkurat som offentleg, bortsett frå at innlegga ikkje dukkar opp i direktestraumar eller emneknaggar, i oppdagingar eller Mastodon-søk, sjølv om du har sagt ja til at kontoen skal vera synleg.",

View File

@ -769,7 +769,6 @@
"privacy.private.short": "Obserwujący", "privacy.private.short": "Obserwujący",
"privacy.public.long": "Każdy na i poza Mastodon", "privacy.public.long": "Każdy na i poza Mastodon",
"privacy.public.short": "Publiczny", "privacy.public.short": "Publiczny",
"privacy.quote.anyone": "{visibility}, każdy może cytować",
"privacy.quote.disabled": "{visibility}, cytaty wyłączone", "privacy.quote.disabled": "{visibility}, cytaty wyłączone",
"privacy.quote.limited": "{visibility}, cytaty ograniczone", "privacy.quote.limited": "{visibility}, cytaty ograniczone",
"privacy.unlisted.additional": "Dostępny podobnie jak wpis publiczny, ale nie będzie widoczny w aktualnościach, hashtagach ani wyszukiwarce Mastodon, nawet jeśli twoje konto jest widoczne.", "privacy.unlisted.additional": "Dostępny podobnie jak wpis publiczny, ale nie będzie widoczny w aktualnościach, hashtagach ani wyszukiwarce Mastodon, nawet jeśli twoje konto jest widoczne.",

View File

@ -785,7 +785,6 @@
"privacy.private.short": "Seguidores", "privacy.private.short": "Seguidores",
"privacy.public.long": "Qualquer um dentro ou fora do Mastodon", "privacy.public.long": "Qualquer um dentro ou fora do Mastodon",
"privacy.public.short": "Público", "privacy.public.short": "Público",
"privacy.quote.anyone": "{visibility} Qualquer pessoa pode citar",
"privacy.quote.disabled": "{visibility} Citações desabilitadas", "privacy.quote.disabled": "{visibility} Citações desabilitadas",
"privacy.quote.limited": "{visibility} Citações limitadas", "privacy.quote.limited": "{visibility} Citações limitadas",
"privacy.unlisted.additional": "Isso se comporta exatamente como público, exceto que a publicação não aparecerá nos _feeds ao vivo_ ou nas _hashtags_, explorar, ou barra de busca, mesmo que você seja escolhido em toda a conta.", "privacy.unlisted.additional": "Isso se comporta exatamente como público, exceto que a publicação não aparecerá nos _feeds ao vivo_ ou nas _hashtags_, explorar, ou barra de busca, mesmo que você seja escolhido em toda a conta.",

View File

@ -799,7 +799,6 @@
"privacy.private.short": "Seguidores", "privacy.private.short": "Seguidores",
"privacy.public.long": "Qualquer pessoa no Mastodon ou não", "privacy.public.long": "Qualquer pessoa no Mastodon ou não",
"privacy.public.short": "Público", "privacy.public.short": "Público",
"privacy.quote.anyone": "{visibility}, qualquer pessoa pode citar",
"privacy.quote.disabled": "{visibility}, citações desativadas", "privacy.quote.disabled": "{visibility}, citações desativadas",
"privacy.quote.limited": "{visibility}, citações limitadas", "privacy.quote.limited": "{visibility}, citações limitadas",
"privacy.unlisted.additional": "Este comportamento é exatamente igual ao do público, exceto que a publicação não aparecerá em cronologias, nas etiquetas, ao explorar ou na pesquisa do Mastodon, mesmo que tenhas optado por participar em toda a tua conta.", "privacy.unlisted.additional": "Este comportamento é exatamente igual ao do público, exceto que a publicação não aparecerá em cronologias, nas etiquetas, ao explorar ou na pesquisa do Mastodon, mesmo que tenhas optado por participar em toda a tua conta.",

View File

@ -759,7 +759,6 @@
"privacy.private.short": "Для подписчиков", "privacy.private.short": "Для подписчиков",
"privacy.public.long": "Для кого угодно в интернете", "privacy.public.long": "Для кого угодно в интернете",
"privacy.public.short": "Публичный", "privacy.public.short": "Публичный",
"privacy.quote.anyone": "{visibility}, цитировать разрешено всем",
"privacy.quote.disabled": "{visibility}, без возможности цитирования", "privacy.quote.disabled": "{visibility}, без возможности цитирования",
"privacy.quote.limited": "{visibility}, с ограничениями цитирования", "privacy.quote.limited": "{visibility}, с ограничениями цитирования",
"privacy.unlisted.additional": "Похоже на «Публичный» за исключением того, что пост не появится ни в живых лентах, ни в лентах хештегов, ни в разделе «Актуальное», ни в поиске Mastodon, даже если вы разрешили поиск по своим постам в настройках профиля.", "privacy.unlisted.additional": "Похоже на «Публичный» за исключением того, что пост не появится ни в живых лентах, ни в лентах хештегов, ни в разделе «Актуальное», ни в поиске Mastodon, даже если вы разрешили поиск по своим постам в настройках профиля.",

View File

@ -665,7 +665,6 @@
"privacy.private.short": "Sledovatelia", "privacy.private.short": "Sledovatelia",
"privacy.public.long": "Ktokoľvek na Mastodone aj mimo neho", "privacy.public.long": "Ktokoľvek na Mastodone aj mimo neho",
"privacy.public.short": "Verejné", "privacy.public.short": "Verejné",
"privacy.quote.anyone": "{visibility}, hocikto môže citovať",
"privacy.quote.disabled": "{visibility}, citovanie nepovolené", "privacy.quote.disabled": "{visibility}, citovanie nepovolené",
"privacy.quote.limited": "{visibility}, citovanie obmedzené", "privacy.quote.limited": "{visibility}, citovanie obmedzené",
"privacy.unlisted.additional": "Presne ako verejné, s tým rozdielom, že sa príspevok nezobrazí v živých kanáloch, hashtagoch, objavovaní či vo vyhľadávaní na Mastodone, aj keď máte pre účet objaviteľnosť zapnutú.", "privacy.unlisted.additional": "Presne ako verejné, s tým rozdielom, že sa príspevok nezobrazí v živých kanáloch, hashtagoch, objavovaní či vo vyhľadávaní na Mastodone, aj keď máte pre účet objaviteľnosť zapnutú.",

View File

@ -797,7 +797,7 @@
"privacy.private.short": "Ndjekës", "privacy.private.short": "Ndjekës",
"privacy.public.long": "Cilido që hyn e del në Mastodon", "privacy.public.long": "Cilido që hyn e del në Mastodon",
"privacy.public.short": "Publik", "privacy.public.short": "Publik",
"privacy.quote.anyone": "{visibility}, mund të citojë cilido", "privacy.quote.anyone": "{visibility}, lejohen citimet",
"privacy.quote.disabled": "{visibility}, citimet janë çaktivizuar", "privacy.quote.disabled": "{visibility}, citimet janë çaktivizuar",
"privacy.quote.limited": "{visibility}, citime të kufizuara", "privacy.quote.limited": "{visibility}, citime të kufizuara",
"privacy.unlisted.additional": "Ky sillet saktësisht si publik, vetëm se postimi sdo të shfaqet në prurje të drejtpërdrejta, ose në hashtag-ë, te eksploroni, apo kërkim në Mastodon, edhe kur keni zgjedhur të jetë për tërë llogarinë.", "privacy.unlisted.additional": "Ky sillet saktësisht si publik, vetëm se postimi sdo të shfaqet në prurje të drejtpërdrejta, ose në hashtag-ë, te eksploroni, apo kërkim në Mastodon, edhe kur keni zgjedhur të jetë për tërë llogarinë.",

View File

@ -797,7 +797,6 @@
"privacy.private.short": "Följare", "privacy.private.short": "Följare",
"privacy.public.long": "Alla på och utanför Mastodon", "privacy.public.long": "Alla på och utanför Mastodon",
"privacy.public.short": "Offentlig", "privacy.public.short": "Offentlig",
"privacy.quote.anyone": "{visibility}, vem som helst kan citera",
"privacy.quote.disabled": "{visibility}, citat inaktiverade", "privacy.quote.disabled": "{visibility}, citat inaktiverade",
"privacy.quote.limited": "{visibility}, citat begränsade", "privacy.quote.limited": "{visibility}, citat begränsade",
"privacy.unlisted.additional": "Detta fungerar precis som offentlig, förutom att inlägget inte visas i liveflöden eller hashtaggar, utforska eller Mastodon-sökning, även om du har valt detta för hela kontot.", "privacy.unlisted.additional": "Detta fungerar precis som offentlig, förutom att inlägget inte visas i liveflöden eller hashtaggar, utforska eller Mastodon-sökning, även om du har valt detta för hela kontot.",

View File

@ -708,7 +708,6 @@
"privacy.private.short": "ผู้ติดตาม", "privacy.private.short": "ผู้ติดตาม",
"privacy.public.long": "ใครก็ตามที่อยู่ในและนอก Mastodon", "privacy.public.long": "ใครก็ตามที่อยู่ในและนอก Mastodon",
"privacy.public.short": "สาธารณะ", "privacy.public.short": "สาธารณะ",
"privacy.quote.anyone": "{visibility}, ใครก็ตามสามารถอ้างอิง",
"privacy.quote.disabled": "{visibility}, ปิดใช้งานการอ้างอิงแล้ว", "privacy.quote.disabled": "{visibility}, ปิดใช้งานการอ้างอิงแล้ว",
"privacy.quote.limited": "{visibility}, จำกัดการอ้างอิงอยู่", "privacy.quote.limited": "{visibility}, จำกัดการอ้างอิงอยู่",
"privacy.unlisted.additional": "สิ่งนี้ทำงานเหมือนกับสาธารณะทุกประการ ยกเว้นโพสต์จะไม่ปรากฏในฟีดสดหรือแฮชแท็ก, การสำรวจ หรือการค้นหา Mastodon แม้ว่าคุณได้เลือกรับทั่วทั้งบัญชีก็ตาม", "privacy.unlisted.additional": "สิ่งนี้ทำงานเหมือนกับสาธารณะทุกประการ ยกเว้นโพสต์จะไม่ปรากฏในฟีดสดหรือแฮชแท็ก, การสำรวจ หรือการค้นหา Mastodon แม้ว่าคุณได้เลือกรับทั่วทั้งบัญชีก็ตาม",

View File

@ -187,6 +187,7 @@
"bundle_modal_error.close": "Kapat", "bundle_modal_error.close": "Kapat",
"bundle_modal_error.message": "Bu ekran yüklenirken bir şeyler ters gitti.", "bundle_modal_error.message": "Bu ekran yüklenirken bir şeyler ters gitti.",
"bundle_modal_error.retry": "Tekrar deneyin", "bundle_modal_error.retry": "Tekrar deneyin",
"callout.dismiss": "Yoksay",
"carousel.current": "<sr>Slayt</sr> {current, number} / {max, number}", "carousel.current": "<sr>Slayt</sr> {current, number} / {max, number}",
"carousel.slide": "Slayt {current, number} / {max, number}", "carousel.slide": "Slayt {current, number} / {max, number}",
"closed_registrations.other_server_instructions": "Mastodon merkeziyetsiz olduğu için, başka bir sunucuda bir hesap oluşturabilir ve bu sunucuyla etkileşimde bulunmaya devam edebilirsiniz.", "closed_registrations.other_server_instructions": "Mastodon merkeziyetsiz olduğu için, başka bir sunucuda bir hesap oluşturabilir ve bu sunucuyla etkileşimde bulunmaya devam edebilirsiniz.",
@ -798,7 +799,7 @@
"privacy.private.short": "Takipçiler", "privacy.private.short": "Takipçiler",
"privacy.public.long": "Mastodon'da olan olmayan herkes", "privacy.public.long": "Mastodon'da olan olmayan herkes",
"privacy.public.short": "Herkese açık", "privacy.public.short": "Herkese açık",
"privacy.quote.anyone": "{visibility}, herkes alıntılayabilir", "privacy.quote.anyone": "{visibility}, alıntı yapılabilir",
"privacy.quote.disabled": "{visibility}, alıntı yapılamaz", "privacy.quote.disabled": "{visibility}, alıntı yapılamaz",
"privacy.quote.limited": "{visibility}, sınırlı alıntı", "privacy.quote.limited": "{visibility}, sınırlı alıntı",
"privacy.unlisted.additional": "Bu neredeyse herkese açık gibi çalışır, tek farkı gönderi canlı akışlarda veya etiketlerde, keşfette, veya Mastodon aramasında gözükmez, hesap çapında öyle seçmiş olsanız bile.", "privacy.unlisted.additional": "Bu neredeyse herkese açık gibi çalışır, tek farkı gönderi canlı akışlarda veya etiketlerde, keşfette, veya Mastodon aramasında gözükmez, hesap çapında öyle seçmiş olsanız bile.",

View File

@ -718,7 +718,6 @@
"privacy.private.short": "Підписники", "privacy.private.short": "Підписники",
"privacy.public.long": "Усі з Mastodon", "privacy.public.long": "Усі з Mastodon",
"privacy.public.short": "Публічно", "privacy.public.short": "Публічно",
"privacy.quote.anyone": "{visibility}, будь-хто може цитувати",
"privacy.quote.disabled": "{visibility}, цитування вимкнено", "privacy.quote.disabled": "{visibility}, цитування вимкнено",
"privacy.quote.limited": "{visibility}, цитування обмежено", "privacy.quote.limited": "{visibility}, цитування обмежено",
"privacy.unlisted.additional": "Має таку ж поведінку, як у людей, але повідомлення не з'являтимуться у стрічках або хештегах, оглядах, або пошуку Mastodon, навіть якщо ви використовуєте облікові записи.", "privacy.unlisted.additional": "Має таку ж поведінку, як у людей, але повідомлення не з'являтимуться у стрічках або хештегах, оглядах, або пошуку Mastodon, навіть якщо ви використовуєте облікові записи.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "Người theo dõi", "privacy.private.short": "Người theo dõi",
"privacy.public.long": "Bất cứ ai", "privacy.public.long": "Bất cứ ai",
"privacy.public.short": "Công khai", "privacy.public.short": "Công khai",
"privacy.quote.anyone": "{visibility}, mọi người có thể trích dẫn", "privacy.quote.anyone": "{visibility}, cho phép trích dẫn",
"privacy.quote.disabled": "{visibility}, tắt trích dẫn", "privacy.quote.disabled": "{visibility}, tắt trích dẫn",
"privacy.quote.limited": "{visibility}, hạn chế trích dẫn", "privacy.quote.limited": "{visibility}, hạn chế trích dẫn",
"privacy.unlisted.additional": "Công khai, nhưng tút sẽ không hiện trong bảng tin, hashtag, khám phá hoặc tìm kiếm Mastodon, kể cả trong cài đặt tài khoản bạn chọn cho phép.", "privacy.unlisted.additional": "Công khai, nhưng tút sẽ không hiện trong bảng tin, hashtag, khám phá hoặc tìm kiếm Mastodon, kể cả trong cài đặt tài khoản bạn chọn cho phép.",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "关注者", "privacy.private.short": "关注者",
"privacy.public.long": "所有 Mastodon 内外的人", "privacy.public.long": "所有 Mastodon 内外的人",
"privacy.public.short": "公开", "privacy.public.short": "公开",
"privacy.quote.anyone": "{visibility}任何人都能引用", "privacy.quote.anyone": "{visibility}允许嘟文引用",
"privacy.quote.disabled": "{visibility},禁用嘟文引用", "privacy.quote.disabled": "{visibility},禁用嘟文引用",
"privacy.quote.limited": "{visibility},嘟文引用受限", "privacy.quote.limited": "{visibility},嘟文引用受限",
"privacy.unlisted.additional": "此模式的行为与“公开”类似,只是嘟文不会出现在实时动态、话题、探索或 Mastodon 搜索页面中,即使你已全局开启了对应的发现设置。", "privacy.unlisted.additional": "此模式的行为与“公开”类似,只是嘟文不会出现在实时动态、话题、探索或 Mastodon 搜索页面中,即使你已全局开启了对应的发现设置。",

View File

@ -799,7 +799,7 @@
"privacy.private.short": "跟隨者", "privacy.private.short": "跟隨者",
"privacy.public.long": "所有人 (無論在 Mastodon 上與否)", "privacy.public.long": "所有人 (無論在 Mastodon 上與否)",
"privacy.public.short": "公開", "privacy.public.short": "公開",
"privacy.quote.anyone": "{visibility}任何人皆可引用", "privacy.quote.anyone": "{visibility}允許引用嘟文",
"privacy.quote.disabled": "{visibility},停用引用嘟文", "privacy.quote.disabled": "{visibility},停用引用嘟文",
"privacy.quote.limited": "{visibility},受限的引用嘟文", "privacy.quote.limited": "{visibility},受限的引用嘟文",
"privacy.unlisted.additional": "此與公開嘟文完全相同,但嘟文不會出現於即時內容或主題標籤、探索、及 Mastodon 搜尋中,即使您於帳戶設定中選擇加入。", "privacy.unlisted.additional": "此與公開嘟文完全相同,但嘟文不會出現於即時內容或主題標籤、探索、及 Mastodon 搜尋中,即使您於帳戶設定中選擇加入。",

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z"/></svg>

After

Width:  |  Height:  |  Size: 580 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M478-240q21 0 35.5-14.5T528-290q0-21-14.5-35.5T478-340q-21 0-35.5 14.5T428-290q0 21 14.5 35.5T478-240Zm-36-154h74q0-33 7.5-52t42.5-52q26-26 41-49.5t15-56.5q0-56-41-86t-97-30q-57 0-92.5 30T342-618l66 26q5-18 22.5-39t53.5-21q32 0 48 17.5t16 38.5q0 20-12 37.5T506-526q-44 39-54 59t-10 73Zm38 314q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

After

Width:  |  Height:  |  Size: 676 B

View File

@ -275,7 +275,7 @@
height: 24px; height: 24px;
aspect-ratio: 1; aspect-ratio: 1;
path { &:not(.icon--no-fill) path {
fill: currentColor; fill: currentColor;
} }
} }

View File

@ -20,8 +20,8 @@ module Account::Counters
to: :account_stat to: :account_stat
# @param [Symbol] key # @param [Symbol] key
def increment_count!(key) def increment_count!(key, status_created_at: nil)
update_count!(key, 1) update_count!(key, 1, status_created_at:)
end end
# @param [Symbol] key # @param [Symbol] key
@ -31,11 +31,11 @@ module Account::Counters
# @param [Symbol] key # @param [Symbol] key
# @param [Integer] value # @param [Integer] value
def update_count!(key, value) def update_count!(key, value, status_created_at: nil)
raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key) raise ArgumentError, "Invalid key #{key}" unless ALLOWED_COUNTER_KEYS.include?(key)
raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id) raise ArgumentError, 'Do not call update_count! on dirty objects' if association(:account_stat).loaded? && account_stat&.changed? && account_stat.changed_attribute_names_to_save == %w(id)
result = updated_account_stat(key, value.to_i) result = updated_account_stat(key, value.to_i, status_created_at:)
# Reload account_stat if it was loaded, taking into account newly-created unsaved records # Reload account_stat if it was loaded, taking into account newly-created unsaved records
if association(:account_stat).loaded? if association(:account_stat).loaded?
@ -50,25 +50,27 @@ module Account::Counters
private private
def updated_account_stat(key, value) def updated_account_stat(key, value, status_created_at: nil)
status_created_at = Time.now.utc if status_created_at.nil? || status_created_at > Time.now.utc
AccountStat.upsert( AccountStat.upsert(
initial_values(key, value), initial_values(key, value, status_created_at:),
on_duplicate: Arel.sql( on_duplicate: Arel.sql(
duplicate_values(key, value).join(', ') duplicate_values(key, value, status_created_at:).join(', ')
), ),
unique_by: :account_id unique_by: :account_id
) )
end end
def initial_values(key, value) def initial_values(key, value, status_created_at: nil)
{ :account_id => id, key => [value, 0].max }.tap do |values| { :account_id => id, key => [value, 0].max }.tap do |values|
values.merge!(last_status_at: Time.current) if key == :statuses_count values.merge!(last_status_at: status_created_at) if key == :statuses_count
end end
end end
def duplicate_values(key, value) def duplicate_values(key, value, status_created_at: nil)
["#{key} = (account_stats.#{key} + #{value})", 'updated_at = CURRENT_TIMESTAMP'].tap do |values| ["#{key} = (account_stats.#{key} + #{value})", 'updated_at = CURRENT_TIMESTAMP'].tap do |values|
values << 'last_status_at = CURRENT_TIMESTAMP' if key == :statuses_count && value.positive? values << AccountStat.sanitize_sql_array(['last_status_at = GREATEST(account_stats.last_status_at, ?::timestamp)', status_created_at]) if key == :statuses_count && value.positive?
end end
end end

View File

@ -539,7 +539,7 @@ class Status < ApplicationRecord
def increment_counter_caches def increment_counter_caches
return if direct_visibility? return if direct_visibility?
account&.increment_count!(:statuses_count) account&.increment_count!(:statuses_count, status_created_at: created_at)
reblog&.increment_count!(:reblogs_count) if reblog? reblog&.increment_count!(:reblogs_count) if reblog?
thread&.increment_count!(:replies_count) if in_reply_to_id.present? && distributable? thread&.increment_count!(:replies_count) if in_reply_to_id.present? && distributable?
end end

View File

@ -10,11 +10,13 @@ class ActivityPub::AddSerializer < ActivityPub::Serializer
end end
def self.serializer_for(model, options) def self.serializer_for(model, options)
case model.class.name case model
when 'Status' when Status
UriSerializer UriSerializer
when 'FeaturedTag' when FeaturedTag
ActivityPub::HashtagSerializer ActivityPub::HashtagSerializer
when Collection
ActivityPub::FeaturedCollectionSerializer
else else
super super
end end
@ -38,6 +40,16 @@ class ActivityPub::AddSerializer < ActivityPub::Serializer
end end
def target def target
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured) case object
when Status, FeaturedTag
# Technically this is not correct, as tags have their own collection.
# But sadly we do not store the collection URI for tags anywhere so cannot
# handle `Add` activities to that properly (yet). The receiving code for
# this currently looks at the type of the contained objects to do the
# right thing.
ActivityPub::TagManager.instance.collection_uri_for(object.account, :featured)
when Collection
ap_account_featured_collections_url(object.account_id)
end
end end
end end

View File

@ -204,7 +204,11 @@ class ActivityPub::ProcessStatusUpdateService < BaseService
def update_tags! def update_tags!
previous_tags = @status.tags.to_a previous_tags = @status.tags.to_a
current_tags = @status.tags = Tag.find_or_create_by_names(@raw_tags) current_tags = @status.tags = @raw_tags.flat_map do |tag|
Tag.find_or_create_by_names([tag])
rescue ActiveRecord::RecordInvalid
[]
end
return unless @status.distributable? return unless @status.distributable?

View File

@ -8,11 +8,18 @@ class CreateCollectionService
build_items build_items
@collection.save! @collection.save!
distribute_add_activity if Mastodon::Feature.collections_federation_enabled?
@collection @collection
end end
private private
def distribute_add_activity
ActivityPub::AccountRawDistributionWorker.perform_async(activity_json, @account.id)
end
def build_items def build_items
return if @accounts_to_add.empty? return if @accounts_to_add.empty?
@ -23,4 +30,8 @@ class CreateCollectionService
@collection.collection_items.build(account: account_to_add) @collection.collection_items.build(account: account_to_add)
end end
end end
def activity_json
ActiveModelSerializers::SerializableResource.new(@collection, serializer: ActivityPub::AddSerializer, adapter: ActivityPub::Adapter).to_json
end
end end

View File

@ -81,9 +81,11 @@ class FanOutOnWriteService < BaseService
end end
def notify_mentioned_accounts! def notify_mentioned_accounts!
@status.active_mentions.where.not(id: @options[:silenced_account_ids] || []).joins(:account).merge(Account.local).select(:id, :account_id).reorder(nil).find_in_batches do |mentions| @status.active_mentions.joins(:account).merge(Account.local).select(:id, :account_id).reorder(nil).find_in_batches do |mentions|
LocalNotificationWorker.push_bulk(mentions) do |mention| LocalNotificationWorker.push_bulk(mentions) do |mention|
[mention.account_id, mention.id, 'Mention', 'mention'] options = { 'silenced' => true } if @options[:silenced_account_ids]&.include?(mention.account_id)
[mention.account_id, mention.id, 'Mention', 'mention', options].compact
end end
next unless update? next unless update?

View File

@ -30,12 +30,13 @@ class NotifyService < BaseService
annual_report annual_report
).freeze ).freeze
def initialize(notification) def initialize(notification, **options)
@recipient = notification.account @recipient = notification.account
@sender = notification.from_account @sender = notification.from_account
@notification = notification @notification = notification
@policy = NotificationPolicy.find_or_initialize_by(account: @recipient) @policy = NotificationPolicy.find_or_initialize_by(account: @recipient)
@from_staff = @sender.local? && @sender.user.present? && @sender.user_role&.bypass_block?(@recipient.user_role) @from_staff = @sender.local? && @sender.user.present? && @sender.user_role&.bypass_block?(@recipient.user_role)
@options = options
end end
private private
@ -164,7 +165,7 @@ class NotifyService < BaseService
end end
def blocked_by_limited_accounts_policy? def blocked_by_limited_accounts_policy?
@policy.drop_limited_accounts? && @sender.silenced? && not_following? @policy.drop_limited_accounts? && (@options[:silenced] || @sender.silenced?) && not_following?
end end
end end
@ -200,13 +201,14 @@ class NotifyService < BaseService
end end
def filtered_by_limited_accounts_policy? def filtered_by_limited_accounts_policy?
@policy.filter_limited_accounts? && @sender.silenced? && not_following? @policy.filter_limited_accounts? && (@options[:silenced] || @sender.silenced?) && not_following?
end end
end end
def call(recipient, type, activity) def call(recipient, type, activity, **options)
return if recipient.user.nil? return if recipient.user.nil?
@options = options
@recipient = recipient @recipient = recipient
@activity = activity @activity = activity
@notification = Notification.new(account: @recipient, type: type, activity: @activity) @notification = Notification.new(account: @recipient, type: type, activity: @activity)
@ -236,11 +238,11 @@ class NotifyService < BaseService
private private
def drop? def drop?
DropCondition.new(@notification).drop? DropCondition.new(@notification, silenced: @options[:silenced]).drop?
end end
def filter? def filter?
FilterCondition.new(@notification).filter? FilterCondition.new(@notification, silenced: @options[:silenced]).filter?
end end
def update_notification_request! def update_notification_request!

View File

@ -3,14 +3,9 @@
class LocalNotificationWorker class LocalNotificationWorker
include Sidekiq::Worker include Sidekiq::Worker
def perform(receiver_account_id, activity_id = nil, activity_class_name = nil, type = nil) def perform(receiver_account_id, activity_id, activity_class_name, type = nil, options = {})
if activity_id.nil? && activity_class_name.nil? receiver = Account.find(receiver_account_id)
activity = Mention.find(receiver_account_id) activity = activity_class_name.constantize.find(activity_id)
receiver = activity.account
else
receiver = Account.find(receiver_account_id)
activity = activity_class_name.constantize.find(activity_id)
end
# For most notification types, only one notification should exist, and the older one is # For most notification types, only one notification should exist, and the older one is
# preferred. For updates, such as when a status is edited, the new notification # preferred. For updates, such as when a status is edited, the new notification
@ -23,7 +18,7 @@ class LocalNotificationWorker
return return
end end
NotifyService.new.call(receiver, type || activity_class_name.underscore, activity) NotifyService.new.call(receiver, type || activity_class_name.underscore, activity, **options.symbolize_keys)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
true true
end end

View File

@ -1473,7 +1473,7 @@ da:
other: "%{count} individuelle indlæg skjult" other: "%{count} individuelle indlæg skjult"
title: Filtre title: Filtre
new: new:
save: Gem nye filter save: Gem nyt filter
title: Tilføj nyt filter title: Tilføj nyt filter
statuses: statuses:
back_to_filter: Tilbage til filter back_to_filter: Tilbage til filter

View File

@ -241,8 +241,8 @@ el:
setting_boost_modal: Έλεγχος ορατότητας της ενίσχυσης setting_boost_modal: Έλεγχος ορατότητας της ενίσχυσης
setting_color_scheme: Λειτουργία setting_color_scheme: Λειτουργία
setting_contrast: Αντίθεση setting_contrast: Αντίθεση
setting_default_language: Γλώσσα κατά την ανάρτηση setting_default_language: Γλώσσα ανάρτησης
setting_default_privacy: Ορατότητα αναρτήσεων setting_default_privacy: Ορατότητα ανάρτησης
setting_default_quote_policy: Ποιος μπορεί να παραθέσει setting_default_quote_policy: Ποιος μπορεί να παραθέσει
setting_default_sensitive: Σημείωση όλων των πολυμέσων ως ευαίσθητου περιεχομένου setting_default_sensitive: Σημείωση όλων των πολυμέσων ως ευαίσθητου περιεχομένου
setting_delete_modal: Προειδοποίηση πριν από τη διαγραφή μιας ανάρτησης setting_delete_modal: Προειδοποίηση πριν από τη διαγραφή μιας ανάρτησης
@ -255,7 +255,7 @@ el:
setting_emoji_style: Στυλ Emoji setting_emoji_style: Στυλ Emoji
setting_expand_spoilers: Μόνιμη ανάπτυξη των τουτ με προειδοποίηση περιεχομένου setting_expand_spoilers: Μόνιμη ανάπτυξη των τουτ με προειδοποίηση περιεχομένου
setting_hide_network: Κρύψε τις διασυνδέσεις σου setting_hide_network: Κρύψε τις διασυνδέσεις σου
setting_missing_alt_text_modal: Προειδοποίηση πριν από την ανάρτηση πολυμέσων χωρίς εναλλακτικό κείμενο setting_missing_alt_text_modal: Προειδοποίηση πριν από τη δημοσίευση πολυμέσων χωρίς εναλλακτικό κείμενο
setting_quick_boosting: Ενεργοποίηση γρήγορης ενίσχυσης setting_quick_boosting: Ενεργοποίηση γρήγορης ενίσχυσης
setting_reduce_motion: Μείωση κίνησης κινουμένων στοιχείων setting_reduce_motion: Μείωση κίνησης κινουμένων στοιχείων
setting_system_font_ui: Χρήση της προεπιλεγμένης γραμματοσειράς του συστήματος setting_system_font_ui: Χρήση της προεπιλεγμένης γραμματοσειράς του συστήματος

View File

@ -884,7 +884,7 @@ sq:
types: types:
major: Hedhje e rëndësishme në qarkullim major: Hedhje e rëndësishme në qarkullim
minor: Hedhje e vockël në qarkullim minor: Hedhje e vockël në qarkullim
patch: Hedhje në qarkullim arnimesh — ndreqje të meash dhe ndryshime të lehta për tu aplikuar patch: Hedhje në qarkullim arnimesh — ndreqje të metash dhe ndryshime të lehta për tu aplikuar
version: Version version: Version
statuses: statuses:
account: Autor account: Autor

View File

@ -1,76 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe OAuth::AuthorizationsController do
render_views
let(:app) { Doorkeeper::Application.create!(name: 'test', redirect_uri: 'http://localhost/', scopes: 'read') }
describe 'GET #new' do
subject do
get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read' }
end
context 'when signed in' do
let!(:user) { Fabricate(:user) }
before do
sign_in user, scope: :user
end
it 'returns http success and private cache control headers' do
subject
expect(response)
.to have_http_status(200)
expect(response.headers['Cache-Control'])
.to include('private, no-store')
expect(response.parsed_body.at('body.modal-layout'))
.to be_present
expect(controller.stored_location_for(:user))
.to eq authorize_path_for(app)
end
context 'when app is already authorized' do
before do
Doorkeeper::AccessToken.find_or_create_for(
application: app,
resource_owner: user.id,
scopes: app.scopes,
expires_in: Doorkeeper.configuration.access_token_expires_in,
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
)
end
it 'redirects to callback' do
subject
expect(response).to redirect_to(/\A#{app.redirect_uri}/)
end
context 'with `force_login` param true' do
subject do
get :new, params: { client_id: app.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read', force_login: 'true' }
end
it { is_expected.to have_http_status(:success) }
end
end
end
context 'when not signed in' do
it 'redirects' do
subject
expect(response)
.to redirect_to '/auth/sign_in'
expect(controller.stored_location_for(:user))
.to eq authorize_path_for(app)
end
end
def authorize_path_for(app)
"/oauth/authorize?client_id=#{app.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code&scope=read"
end
end
end

View File

@ -1,71 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Settings::AliasesController do
render_views
let!(:user) { Fabricate(:user) }
let(:account) { user.account }
before do
sign_in user, scope: :user
end
describe 'GET #index' do
before do
get :index
end
it 'returns http success with private cache control headers', :aggregate_failures do
expect(response).to have_http_status(200)
expect(response.headers['Cache-Control']).to include('private, no-store')
end
end
describe 'POST #create' do
context 'with valid alias' do
before { stub_resolver }
it 'creates an alias for the user' do
expect do
post :create, params: { account_alias: { acct: 'new@example.com' } }
end.to change(AccountAlias, :count).by(1)
expect(response).to redirect_to(settings_aliases_path)
end
end
context 'with invalid alias' do
it 'does not create an alias for the user' do
expect do
post :create, params: { account_alias: { acct: 'format-wrong' } }
end.to_not change(AccountAlias, :count)
expect(response).to have_http_status(200)
end
end
end
describe 'DELETE #destroy' do
let(:account_alias) do
AccountAlias.new(account: user.account, acct: 'new@example.com').tap do |account_alias|
account_alias.save(validate: false)
end
end
it 'removes an alias' do
delete :destroy, params: { id: account_alias.id }
expect(response).to redirect_to(settings_aliases_path)
expect { account_alias.reload }.to raise_error(ActiveRecord::RecordNotFound)
end
end
private
def stub_resolver
resolver = instance_double(ResolveAccountService, call: Fabricate(:account))
allow(ResolveAccountService).to receive(:new).and_return(resolver)
end
end

View File

@ -21,6 +21,28 @@ RSpec.describe Account::Counters do
expect(account.statuses_count).to eq increment_by expect(account.statuses_count).to eq increment_by
end end
it 'updates last_status_at when discovering a new post' do
status_created_at = Time.now.utc
expect { account.increment_count!(:statuses_count, status_created_at:) }
.to(change { account.reload.last_status_at })
end
it 'does not update last_status_at when discovering an older post' do
account_stat = Fabricate(
:account_stat,
account: account,
last_status_at: 1.day.ago.utc,
statuses_count: 10
)
status_created_at = 2.days.ago.utc
expect { account.increment_count!(:statuses_count, status_created_at:) }
.to change { account_stat.reload.statuses_count }
.and(not_change { account_stat.reload.last_status_at })
end
end end
describe '#decrement_count!' do describe '#decrement_count!' do

View File

@ -119,6 +119,7 @@ RSpec.configure do |config|
config.include SignedRequestHelpers, type: :request config.include SignedRequestHelpers, type: :request
config.include CommandLineHelpers, type: :cli config.include CommandLineHelpers, type: :cli
config.include SystemHelpers, type: :system config.include SystemHelpers, type: :system
config.include Shoulda::Matchers::ActiveModel, type: :validator
# TODO: Remove when Devise fixes https://github.com/heartcombo/devise/issues/5705 # TODO: Remove when Devise fixes https://github.com/heartcombo/devise/issues/5705
config.before do config.before do

View File

@ -0,0 +1,80 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'OAuth Authorizations' do
let(:application) { Fabricate :application, name: 'test', redirect_uri: 'http://localhost/', scopes: 'read' }
let(:params) { { client_id: application.uid, response_type: 'code', redirect_uri: 'http://localhost/', scope: 'read' } }
describe 'GET #new' do
subject { get oauth_authorization_path(params) }
context 'when signed in' do
let(:user) { Fabricate(:user) }
before { sign_in user }
it 'returns http success and private cache control headers' do
subject
expect(response)
.to have_http_status(:success)
expect(response.headers['Cache-Control'])
.to include('private, no-store')
expect(response.parsed_body.at('body.modal-layout'))
.to be_present
expect(controller.stored_location_for(:user))
.to eq authorize_path_for(application)
end
context 'when app is already authorized' do
before do
Doorkeeper::AccessToken.find_or_create_for(
application: application,
resource_owner: user.id,
scopes: application.scopes,
expires_in: Doorkeeper.configuration.access_token_expires_in,
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
)
end
it 'redirects to callback' do
subject
expect(response)
.to redirect_to(/\A#{application.redirect_uri}/)
end
context 'with `force_login` param true' do
subject do
get oauth_authorization_path(params.merge(force_login: 'true'))
end
it 'renders new page with success status' do
subject
expect(response)
.to have_http_status(:success)
expect(response.parsed_body.title)
.to match(I18n.t('doorkeeper.authorizations.new.title'))
end
end
end
end
context 'when not signed in' do
it 'redirects' do
subject
expect(response)
.to redirect_to(new_user_session_path)
expect(controller.stored_location_for(:user))
.to eq authorize_path_for(application)
end
end
def authorize_path_for(application)
"/oauth/authorize?client_id=#{application.uid}&redirect_uri=http%3A%2F%2Flocalhost%2F&response_type=code&scope=read"
end
end
end

View File

@ -2,21 +2,16 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe OAuth::AuthorizedApplicationsController do RSpec.describe 'OAuth Authorized Applications' do
render_views describe 'GET /oauth/authorized_applications' do
subject { get oauth_authorized_applications_path }
describe 'GET #index' do
subject do
get :index
end
context 'when signed in' do context 'when signed in' do
before do before { sign_in Fabricate(:user) }
sign_in Fabricate(:user), scope: :user
end
it 'returns http success with private cache control headers' do it 'returns http success with private cache control headers' do
subject subject
expect(response) expect(response)
.to have_http_status(200) .to have_http_status(200)
expect(response.headers['Cache-Control']) expect(response.headers['Cache-Control'])
@ -40,29 +35,29 @@ RSpec.describe OAuth::AuthorizedApplicationsController do
end end
end end
describe 'DELETE #destroy' do describe 'DELETE /oauth/authorized_applications/:id' do
subject { delete oauth_authorized_application_path(application) }
let!(:user) { Fabricate(:user) } let!(:user) { Fabricate(:user) }
let!(:application) { Fabricate(:application) } let!(:application) { Fabricate(:application) }
let!(:access_token) { Fabricate(:accessible_access_token, application: application, resource_owner_id: user.id) } let!(:access_token) { Fabricate(:accessible_access_token, application: application, resource_owner_id: user.id) }
let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) } let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }
let(:redis_pipeline_stub) { instance_double(Redis::PipelinedConnection, publish: nil) } let(:redis_pipeline_stub) { instance_double(Redis::PipelinedConnection, publish: nil) }
before do before { allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub) }
sign_in user, scope: :user
allow(redis).to receive(:pipelined).and_yield(redis_pipeline_stub)
end
it 'revokes access tokens for the application and removes subscriptions and sends kill payload to streaming' do context 'when signed in' do
post :destroy, params: { id: application.id } before { sign_in user }
expect(Doorkeeper::AccessToken.where(application: application).first.revoked_at) it 'revokes access tokens for the application and removes subscriptions and sends kill payload to streaming' do
.to_not be_nil expect { subject }
expect(Web::PushSubscription.where(user: user).count) .to change { Doorkeeper::AccessToken.where(application:).first.reload.revoked_at }.from(nil).to(be_present)
.to eq(0) .and change { Web::PushSubscription.where(user:).reload.count }.to(0)
expect { web_push_subscription.reload } expect { web_push_subscription.reload }
.to raise_error(ActiveRecord::RecordNotFound) .to raise_error(ActiveRecord::RecordNotFound)
expect(redis_pipeline_stub) expect(redis_pipeline_stub)
.to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}') .to have_received(:publish).with("timeline:access_token:#{access_token.id}", '{"event":"kill"}')
end
end end
end end
end end

View File

@ -18,10 +18,38 @@ RSpec.describe ActivityPub::AddSerializer do
it { is_expected.to eq(ActivityPub::HashtagSerializer) } it { is_expected.to eq(ActivityPub::HashtagSerializer) }
end end
context 'with a Collection model' do
let(:model) { Collection.new }
it { is_expected.to eq(ActivityPub::FeaturedCollectionSerializer) }
end
context 'with an Array' do context 'with an Array' do
let(:model) { [] } let(:model) { [] }
it { is_expected.to eq(ActiveModel::Serializer::CollectionSerializer) } it { is_expected.to eq(ActiveModel::Serializer::CollectionSerializer) }
end end
end end
describe '#target' do
subject { described_class.new(object).target }
context 'when object is a Status' do
let(:object) { Fabricate(:status) }
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
end
context 'when object is a FeaturedTag' do
let(:object) { Fabricate(:featured_tag) }
it { is_expected.to match(%r{/#{object.account_id}/collections/featured$}) }
end
context 'when object is a Collection' do
let(:object) { Fabricate(:collection) }
it { is_expected.to match(%r{/#{object.account_id}/featured_collections$}) }
end
end
end end

View File

@ -258,6 +258,7 @@ RSpec.describe ActivityPub::ProcessStatusUpdateService do
tag: [ tag: [
{ type: 'Hashtag', name: 'foo' }, { type: 'Hashtag', name: 'foo' },
{ type: 'Hashtag', name: 'bar' }, { type: 'Hashtag', name: 'bar' },
{ type: 'Hashtag', name: '#2024' },
], ],
} }
end end

View File

@ -29,6 +29,12 @@ RSpec.describe CreateCollectionService do
expect(collection).to be_local expect(collection).to be_local
end end
it 'federates an `Add` activity', feature: :collections_federation do
subject.call(base_params, author)
expect(ActivityPub::AccountRawDistributionWorker).to have_enqueued_sidekiq_job
end
context 'when given account ids' do context 'when given account ids' do
let(:accounts) do let(:accounts) do
Fabricate.times(2, :account) Fabricate.times(2, :account)

View File

@ -45,7 +45,9 @@ RSpec.describe FanOutOnWriteService do
let(:visibility) { 'public' } let(:visibility) { 'public' }
it 'adds status to home feed of author and followers and broadcasts', :inline_jobs do it 'adds status to home feed of author and followers and broadcasts', :inline_jobs do
subject.call(status) expect { subject.call(status) }
.to change(bob.notifications, :count).by(1)
.and change(eve.notifications, :count).by(1)
expect(status.id) expect(status.id)
.to be_in(home_feed_of(alice)) .to be_in(home_feed_of(alice))
@ -58,6 +60,14 @@ RSpec.describe FanOutOnWriteService do
expect(redis).to have_received(:publish).with('timeline:public:local', anything) expect(redis).to have_received(:publish).with('timeline:public:local', anything)
expect(redis).to have_received(:publish).with('timeline:public:media', anything) expect(redis).to have_received(:publish).with('timeline:public:media', anything)
end end
context 'with silenced_account_ids' do
it 'calls LocalNotificationWorker with the expected arguments' do
expect { subject.call(status, silenced_account_ids: [eve.id]) }
.to enqueue_sidekiq_job(LocalNotificationWorker).with(bob.id, anything, 'Mention', 'mention')
.and enqueue_sidekiq_job(LocalNotificationWorker).with(eve.id, anything, 'Mention', 'mention', { 'silenced' => true })
end
end
end end
context 'when status is limited' do context 'when status is limited' do

View File

@ -224,13 +224,25 @@ RSpec.describe NotifyService do
end end
end end
context 'when sender is considered silenced through `silenced` option and recipient has a policy to ignore silenced accounts' do
subject { described_class.new(notification, silenced: true) }
before do
notification.account.create_notification_policy!(for_limited_accounts: :drop)
end
it 'returns true' do
expect(subject.drop?).to be true
end
end
context 'when sender is new and recipient has a default policy' do context 'when sender is new and recipient has a default policy' do
it 'returns false' do it 'returns false' do
expect(subject.drop?).to be false expect(subject.drop?).to be false
end end
end end
context 'when sender is new and recipient has a policy to ignore silenced accounts' do context 'when sender is new and recipient has a policy to ignore new accounts' do
before do before do
notification.account.create_notification_policy!(for_new_accounts: :drop) notification.account.create_notification_policy!(for_new_accounts: :drop)
end end
@ -240,7 +252,7 @@ RSpec.describe NotifyService do
end end
end end
context 'when sender is new and followed and recipient has a policy to ignore silenced accounts' do context 'when sender is new and followed and recipient has a policy to ignore new accounts' do
before do before do
notification.account.create_notification_policy!(for_new_accounts: :drop) notification.account.create_notification_policy!(for_new_accounts: :drop)
notification.account.follow!(notification.from_account) notification.account.follow!(notification.from_account)
@ -300,6 +312,34 @@ RSpec.describe NotifyService do
end end
end end
context 'when sender is considered silenced through the `silenced` option' do
subject { described_class.new(notification, silenced: true) }
it 'returns true' do
expect(subject.filter?).to be true
end
context 'when recipient follows sender' do
before do
notification.account.follow!(notification.from_account)
end
it 'returns false' do
expect(subject.filter?).to be false
end
end
context 'when recipient is allowing limited accounts' do
before do
notification.account.create_notification_policy!(for_limited_accounts: :accept)
end
it 'returns false' do
expect(subject.filter?).to be false
end
end
end
context 'when recipient is filtering not-followed senders' do context 'when recipient is filtering not-followed senders' do
before do before do
Fabricate(:notification_policy, account: notification.account, filter_not_following: true) Fabricate(:notification_policy, account: notification.account, filter_not_following: true)

View File

@ -0,0 +1,82 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Settings aliases page' do
let!(:user) { Fabricate(:user) }
let(:account) { user.account }
before { sign_in user }
describe 'Viewing aliases' do
it 'shows index page with private cache control headers' do
visit settings_aliases_path
# View index page
expect(page)
.to have_content(I18n.t('settings.aliases'))
.and have_private_cache_control
end
end
describe 'Creating an alias' do
context 'with valid alias value' do
before { stub_resolver }
it 'creates an alias for the user' do
visit settings_aliases_path
fill_in 'account_alias_acct',
with: 'new@host.example'
expect { submit_form }
.to change(AccountAlias, :count).by(1)
expect(page)
.to have_content(I18n.t('aliases.created_msg'))
end
end
context 'with invalid value' do
it 'does not create an alias for the user' do
visit settings_aliases_path
fill_in 'account_alias_acct',
with: 'invalid-value'
expect { submit_form }
.to not_change(AccountAlias, :count)
expect(page)
.to have_content(I18n.t('settings.aliases'))
end
end
def submit_form
click_on I18n.t('aliases.add_new')
end
end
describe 'Removing an alias' do
let!(:account_alias) do
AccountAlias.new(account: user.account, acct: 'new@example.com').tap do |account_alias|
account_alias.save(validate: false)
end
end
it 'removes an alias' do
visit settings_aliases_path
expect { click_on I18n.t('aliases.remove') }
.to change(AccountAlias, :count).by(-1)
expect(page)
.to have_content(I18n.t('settings.aliases'))
.and have_content(I18n.t('aliases.deleted_msg'))
expect { account_alias.reload }
.to raise_error(ActiveRecord::RecordNotFound)
end
end
private
def stub_resolver
resolver = instance_double(ResolveAccountService, call: Fabricate(:account))
allow(ResolveAccountService).to receive(:new).and_return(resolver)
end
end

View File

@ -3,49 +3,25 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe DateOfBirthValidator do RSpec.describe DateOfBirthValidator do
let(:record_class) do subject { Fabricate.build :user }
Class.new do
include ActiveModel::Validations
attr_accessor :date_of_birth before { Setting.min_age = 16 }
validates :date_of_birth, date_of_birth: true context 'with an invalid date' do
end let(:invalid_date) { '76.830.10' }
it { is_expected.to_not allow_values(invalid_date).for(:date_of_birth) }
end end
let(:record) { record_class.new } context 'with a date below the age limit' do
let(:too_young) { 13.years.ago }
before do it { is_expected.to_not allow_values(too_young).for(:date_of_birth).with_message(:below_limit) }
Setting.min_age = 16
end end
describe '#validate_each' do context 'with a date above the age limit' do
context 'with an invalid date' do let(:old_enough) { 16.years.ago }
it 'adds errors' do
record.date_of_birth = '76.830.10'
expect(record).to_not be_valid it { is_expected.to allow_values(old_enough).for(:date_of_birth) }
expect(record.errors.first.attribute).to eq(:date_of_birth)
expect(record.errors.first.type).to eq(:invalid)
end
end
context 'with a date below age limit' do
it 'adds errors' do
record.date_of_birth = 13.years.ago.strftime('%d.%m.%Y')
expect(record).to_not be_valid
expect(record.errors.first.attribute).to eq(:date_of_birth)
expect(record.errors.first.type).to eq(:below_limit)
end
end
context 'with a date above age limit' do
it 'does not add errors' do
record.date_of_birth = 16.years.ago.strftime('%d.%m.%Y')
expect(record).to be_valid
end
end
end end
end end

View File

@ -3,35 +3,23 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe PollExpirationValidator do RSpec.describe PollExpirationValidator do
describe '#validate' do subject { Fabricate.build :poll }
before do
validator.validate(poll)
end
let(:validator) { described_class.new } context 'when poll expires in far future' do
let(:poll) { instance_double(Poll, options: options, expires_at: expires_at, errors: errors) } let(:far_future) { 6.months.from_now }
let(:errors) { instance_double(ActiveModel::Errors, add: nil) }
let(:options) { %w(foo bar) }
let(:expires_at) { 1.day.from_now }
it 'has no errors' do it { is_expected.to_not allow_value(far_future).for(:expires_at).with_message(I18n.t('polls.errors.duration_too_long')) }
expect(errors).to_not have_received(:add) end
end
context 'when the poll expires in 5 min from now' do context 'when poll expires in far past' do
let(:expires_at) { 5.minutes.from_now } let(:past_date) { 6.days.ago }
it 'has no errors' do it { is_expected.to_not allow_value(past_date).for(:expires_at).with_message(I18n.t('polls.errors.duration_too_short')) }
expect(errors).to_not have_received(:add) end
end
end
context 'when the poll expires in the past' do context 'when poll expires in medium future' do
let(:expires_at) { 5.minutes.ago } let(:allowed_future) { 10.minutes.from_now }
it 'has errors' do it { is_expected.to allow_value(allowed_future).for(:expires_at) }
expect(errors).to have_received(:add)
end
end
end end
end end

View File

@ -214,7 +214,10 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => {
svgr(), svgr(),
// Old library types need to be converted // Old library types need to be converted
optimizeLodashImports() as PluginOption, optimizeLodashImports() as PluginOption,
!!process.env.ANALYZE_BUNDLE_SIZE && (visualizer() as PluginOption), !!process.env.ANALYZE_BUNDLE_SIZE &&
(visualizer({
template: process.env.CI ? 'raw-data' : 'treemap',
}) as PluginOption),
MastodonNameLookup(), MastodonNameLookup(),
], ],
} satisfies UserConfig; } satisfies UserConfig;

214
yarn.lock
View File

@ -1265,10 +1265,10 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/color-helpers@npm:^6.0.0": "@csstools/color-helpers@npm:^6.0.1":
version: 6.0.0 version: 6.0.1
resolution: "@csstools/color-helpers@npm:6.0.0" resolution: "@csstools/color-helpers@npm:6.0.1"
checksum: 10c0/784447fa6ba2f5fec30f8676c48f9f66bff30a7a16582e3c3b3e9aa2574df1ac4e5f8e7455dfa6d991fd84ceceb22ff4016e2ea3a8116e76772b3972dbab7bec checksum: 10c0/866844267d5aa5a02fe9d54f6db6fc18f6306595edb03664cc8ef15c99d3e6f3b42eb1a413c98bafa5b2dc0d8e0193da9b3bcc9d6a04f5de74cbd44935e74b3c
languageName: node languageName: node
linkType: hard linkType: hard
@ -1305,16 +1305,16 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/css-color-parser@npm:^4.0.0": "@csstools/css-color-parser@npm:^4.0.1":
version: 4.0.0 version: 4.0.1
resolution: "@csstools/css-color-parser@npm:4.0.0" resolution: "@csstools/css-color-parser@npm:4.0.1"
dependencies: dependencies:
"@csstools/color-helpers": "npm:^6.0.0" "@csstools/color-helpers": "npm:^6.0.1"
"@csstools/css-calc": "npm:^3.0.0" "@csstools/css-calc": "npm:^3.0.0"
peerDependencies: peerDependencies:
"@csstools/css-parser-algorithms": ^4.0.0 "@csstools/css-parser-algorithms": ^4.0.0
"@csstools/css-tokenizer": ^4.0.0 "@csstools/css-tokenizer": ^4.0.0
checksum: 10c0/bbfa3855bd53d5f31e2e9d40d8bc7b1143c7efd3dd6fa43c0ef2222a66bdc94f7ffedc8932a4eb4f10c5cbc38d1ed110fda99240037e0a2dae61c6b25527b0a2 checksum: 10c0/c46be5b9f5c0ef3cd25b47a71bd2a4d1c4856b123ecba4abe8eaa0688d3fc47f58fa67ea281d6b9efca4b9fdfa88fb045c51d0f9b8c612a56bd546d38260b138
languageName: node languageName: node
linkType: hard linkType: hard
@ -1376,18 +1376,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-alpha-function@npm:^2.0.1": "@csstools/postcss-alpha-function@npm:^2.0.2":
version: 2.0.1 version: 2.0.2
resolution: "@csstools/postcss-alpha-function@npm:2.0.1" resolution: "@csstools/postcss-alpha-function@npm:2.0.2"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/7e38e245eb4a4d76dcaafd9ee1f6d1cdfc8fceabf835dd1615fbb9fb0944224d29c8d601e55db4b3ba1dd37a541c8568fd130106171ca11b012eb512ff1ec7a9 checksum: 10c0/2ffb1d4c6db63f9b841b8de18a0baf1b37bc321632af4d8dc0bba0c9472980ffb9c3c94a4b3445eedcc986399791fd2bc5e682b676d5a021d4db3e2602ad892f
languageName: node languageName: node
linkType: hard linkType: hard
@ -1403,63 +1403,63 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-color-function-display-p3-linear@npm:^2.0.0": "@csstools/postcss-color-function-display-p3-linear@npm:^2.0.1":
version: 2.0.0 version: 2.0.1
resolution: "@csstools/postcss-color-function-display-p3-linear@npm:2.0.0" resolution: "@csstools/postcss-color-function-display-p3-linear@npm:2.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/c2d007dfa7500b6b54bca3a43f92f272cbdd8acaa9d4924eafa320c448f1cee77e7c00a229d5a6ffcc5211664b1dcfd7d54bb6622f2e7956e21ac51ea883165c checksum: 10c0/cc6b79d8a19338f930f68bf4bac31bcbf38842068ed5779193979b5e2041a7b12386e4e992065cbf898c537ac6887ac530651f2164aaf77ced92d1bc4dd4ae50
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-color-function@npm:^5.0.0": "@csstools/postcss-color-function@npm:^5.0.1":
version: 5.0.0 version: 5.0.1
resolution: "@csstools/postcss-color-function@npm:5.0.0" resolution: "@csstools/postcss-color-function@npm:5.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/b01b0e86df5cca222b9859601a4da18ee7a3bade52d6c7fada739cc6c6a4741173f0dccce05f4b307776bc8c0e156923930ce869faae9231e59aa2abab522581 checksum: 10c0/c6d28aae458a2f914367b3fa87ac300366bcf44c57ed7a6c6ebcdaec4d42901b7892a867b01d23af0edc0798035e205a7e590ccc3f288c632d8ed5ed9219455b
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-color-mix-function@npm:^4.0.0": "@csstools/postcss-color-mix-function@npm:^4.0.1":
version: 4.0.0 version: 4.0.1
resolution: "@csstools/postcss-color-mix-function@npm:4.0.0" resolution: "@csstools/postcss-color-mix-function@npm:4.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/60fa7fbc5e97dc295fd01a90e866d3923bfe47a6e2e3317f01ec8ab0aca687901ef569cdda867780b3aa37a02efa44531bfa0d0d602b90803333baa4cfbf6063 checksum: 10c0/5137bb1fe2037609366e6282000ed1305151988a6968e336e9599cfed020495f9bf523d2eab64f83d74089f15a30d26d376a49c32ae3a3df16b3846d8690e477
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-color-mix-variadic-function-arguments@npm:^2.0.0": "@csstools/postcss-color-mix-variadic-function-arguments@npm:^2.0.1":
version: 2.0.0 version: 2.0.1
resolution: "@csstools/postcss-color-mix-variadic-function-arguments@npm:2.0.0" resolution: "@csstools/postcss-color-mix-variadic-function-arguments@npm:2.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/1206543ec6472f9dd7b67d3311128b66e3be2c6f1bdf9da1b6e4b4f9d69e9388e2896128bb3d1834d825ae4de9455524d7749501a60be740c52c0f7b67287263 checksum: 10c0/b4cd04a4650ba1b3340d99e5d020e860cef481d4ba4ecf1300ffb20863778a3376742c2b1209f14f0b13f1c0c63c7f3d84d1df812ef2a26ea53934f2f676d1df
languageName: node languageName: node
linkType: hard linkType: hard
@ -1477,18 +1477,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-contrast-color-function@npm:^3.0.0": "@csstools/postcss-contrast-color-function@npm:^3.0.1":
version: 3.0.0 version: 3.0.1
resolution: "@csstools/postcss-contrast-color-function@npm:3.0.0" resolution: "@csstools/postcss-contrast-color-function@npm:3.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/7dec6e3bac9d45ae22b5dfcaec9ce8894a1ad80d1e62eb58634eebaa4a02a4f43f5b795a65224442b90b2285c0a0e1d7e80d9528fc1480348ab9a03bf9be2fe0 checksum: 10c0/00d17c77aae78953782cb51988fa76c00bb25316a59aba7a70c11142554f49ad48ce37963f10689fd908a98484d16e9531e808e5d2df60ae26aa6509a0c6b4f5
languageName: node languageName: node
linkType: hard linkType: hard
@ -1517,46 +1517,46 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-gamut-mapping@npm:^3.0.0": "@csstools/postcss-gamut-mapping@npm:^3.0.1":
version: 3.0.0 version: 3.0.1
resolution: "@csstools/postcss-gamut-mapping@npm:3.0.0" resolution: "@csstools/postcss-gamut-mapping@npm:3.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/da138bee13c3af9e25962a425c70e242581722881fa52faa090dbb62d22adeced112d3589304651c759bae5fc0060eefb7eb62114798e96d3925bb01febc5a99 checksum: 10c0/a94337b13ed0332e2a80d07424e07bd726339476ce0ac009d00238c39b007cc7f2d58aeb48fe04d366a3015d7032f41bcc6a223f2f108574dcbfff7e53f694b0
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-gradients-interpolation-method@npm:^6.0.0": "@csstools/postcss-gradients-interpolation-method@npm:^6.0.1":
version: 6.0.0 version: 6.0.1
resolution: "@csstools/postcss-gradients-interpolation-method@npm:6.0.0" resolution: "@csstools/postcss-gradients-interpolation-method@npm:6.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/33da282f65480d1a4e8a2ce336bf5e0948d47e9fdab0847d3c9e839ae640cb4af96defdcf4cb3d59e43019dec83a5e48fcd0fb96be927c43c7369e8be316fc79 checksum: 10c0/c930cfba3168d7d2016f7b30489fe3e8e6433ef2cc922635fb088946495439d7a4505ca65841897da60760c2962e0a112a15c0f67845e7f0ac9377e2736cc8c8
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-hwb-function@npm:^5.0.0": "@csstools/postcss-hwb-function@npm:^5.0.1":
version: 5.0.0 version: 5.0.1
resolution: "@csstools/postcss-hwb-function@npm:5.0.0" resolution: "@csstools/postcss-hwb-function@npm:5.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/7f3e6d46531334621cc2c525df5c76cf916a53d0d9c82008b97b4b6b42f1b07b5729b4c3a8e5ba7b77c51ca44bbd216f83549e978f1aaf75e060335f754aacb2 checksum: 10c0/3951f49fdf081133bc339011e909fd60a2e36618a2ee20acf00baa0e1ebc6d5e30e988f5d70a4017c5247ef699d77e55ea9bb32cd7eb7a3683d2fc0f202429aa
languageName: node languageName: node
linkType: hard linkType: hard
@ -1709,29 +1709,29 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-normalize-display-values@npm:^5.0.0": "@csstools/postcss-normalize-display-values@npm:^5.0.1":
version: 5.0.0 version: 5.0.1
resolution: "@csstools/postcss-normalize-display-values@npm:5.0.0" resolution: "@csstools/postcss-normalize-display-values@npm:5.0.1"
dependencies: dependencies:
postcss-value-parser: "npm:^4.2.0" postcss-value-parser: "npm:^4.2.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/d43a2658604bdd037ab1516bffadea4db3224390838f5096fccdfbae12a2db08e56ca576724a0279968e6af39419e5fe2963632754dd0956fda2d01b848cf97e checksum: 10c0/16b53d11db7ea6a48e1e43e06eb76d4d2b5c2c9af43b4f7e4d0d03345aa5f935a625d321d38a607739bfb59f6cc24b0506983dc5c599a7b795626ada33bba68f
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-oklab-function@npm:^5.0.0": "@csstools/postcss-oklab-function@npm:^5.0.1":
version: 5.0.0 version: 5.0.1
resolution: "@csstools/postcss-oklab-function@npm:5.0.0" resolution: "@csstools/postcss-oklab-function@npm:5.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/af3413b1667be101f39b15b9528a57ff764e5abcf80578590b95c27c42a493ed9dcd2927834371d211b025c5d5df103cded6f2def98c9c79301f76ca379d7dbf checksum: 10c0/ef5298c499fda9854f93d8ab1416cdb2bdb9120bca14ac7f97ea867821777aa67219c7784ffd70c793b02ba3ca3988a1c5f4fbd8be43f5d97cae822556847fe2
languageName: node languageName: node
linkType: hard linkType: hard
@ -1780,18 +1780,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-relative-color-syntax@npm:^4.0.0": "@csstools/postcss-relative-color-syntax@npm:^4.0.1":
version: 4.0.0 version: 4.0.1
resolution: "@csstools/postcss-relative-color-syntax@npm:4.0.0" resolution: "@csstools/postcss-relative-color-syntax@npm:4.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/52f21acc66a0aa591d99173b9813f0b9f375de462bc657e909916ed176590b8d530a2eff83e71da488e2c8f476f0397d4a79bb7b7ef13664176d9e744a49510a checksum: 10c0/101cb35ac950f45f21cb5aa853b57e304178d366390036e5390eda0ebcc21032f096d77863f6d978233f3b52b02c77acb6c394a965260ad41d1f49ddc0015aae
languageName: node languageName: node
linkType: hard linkType: hard
@ -1855,15 +1855,15 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@csstools/postcss-text-decoration-shorthand@npm:^5.0.0": "@csstools/postcss-text-decoration-shorthand@npm:^5.0.1":
version: 5.0.0 version: 5.0.1
resolution: "@csstools/postcss-text-decoration-shorthand@npm:5.0.0" resolution: "@csstools/postcss-text-decoration-shorthand@npm:5.0.1"
dependencies: dependencies:
"@csstools/color-helpers": "npm:^6.0.0" "@csstools/color-helpers": "npm:^6.0.1"
postcss-value-parser: "npm:^4.2.0" postcss-value-parser: "npm:^4.2.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/0d1dc47da13adc1f0863017a3448f3a79774f00f1952fc2bfc09404b00b03d125b54dedce036e0e5c73a6f2a64cdabe702e9bc03dc6b88d3b71a6424cd0cec80 checksum: 10c0/e9a6f4d02a4584bf227783296eb4016542d70345152c2c0f1012146376eaf7e3efa7e27d8eab6856857612b8d682ea1085b5d027ad6f05406e0adee7b6244c33
languageName: node languageName: node
linkType: hard linkType: hard
@ -5545,13 +5545,13 @@ __metadata:
linkType: hard linkType: hard
"axios@npm:^1.4.0": "axios@npm:^1.4.0":
version: 1.13.2 version: 1.13.3
resolution: "axios@npm:1.13.2" resolution: "axios@npm:1.13.3"
dependencies: dependencies:
follow-redirects: "npm:^1.15.6" follow-redirects: "npm:^1.15.6"
form-data: "npm:^4.0.4" form-data: "npm:^4.0.4"
proxy-from-env: "npm:^1.1.0" proxy-from-env: "npm:^1.1.0"
checksum: 10c0/e8a42e37e5568ae9c7a28c348db0e8cf3e43d06fcbef73f0048669edfe4f71219664da7b6cc991b0c0f01c28a48f037c515263cb79be1f1ae8ff034cd813867b checksum: 10c0/86f0770624d9f14a3f8f8738c8b8f7f7fbb7b0d4ad38757db1de2d71007a0311bc597661c5ff4b4a9ee6350c6956a7282e3a281fcdf7b5b32054e35a8801e2ce
languageName: node languageName: node
linkType: hard linkType: hard
@ -10683,8 +10683,8 @@ __metadata:
linkType: hard linkType: hard
"pino@npm:^10.0.0": "pino@npm:^10.0.0":
version: 10.2.1 version: 10.3.0
resolution: "pino@npm:10.2.1" resolution: "pino@npm:10.3.0"
dependencies: dependencies:
"@pinojs/redact": "npm:^0.4.0" "@pinojs/redact": "npm:^0.4.0"
atomic-sleep: "npm:^1.0.0" atomic-sleep: "npm:^1.0.0"
@ -10699,7 +10699,7 @@ __metadata:
thread-stream: "npm:^4.0.0" thread-stream: "npm:^4.0.0"
bin: bin:
pino: bin.js pino: bin.js
checksum: 10c0/2eaed48bb7fb8865e27ac6d6709383f5c117f1e59c818734c7cc22b362e9aa5846a0547e7fd9cde64088a3b48aa314e1dab07ee16da8dc3b87897970eb56843e checksum: 10c0/cfbbc7dfaa2df2aa2dce728d751aa4b5b7ab973b2cd4bfff57868567563ef0c1c021f22932769141d535c72662390e09a0190e44f4413496dbe5e3c672816308
languageName: node languageName: node
linkType: hard linkType: hard
@ -10774,18 +10774,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"postcss-color-functional-notation@npm:^8.0.0": "postcss-color-functional-notation@npm:^8.0.1":
version: 8.0.0 version: 8.0.1
resolution: "postcss-color-functional-notation@npm:8.0.0" resolution: "postcss-color-functional-notation@npm:8.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/4b23633475b57f5d0076340ab4f434506891b5a25254d077215c08d08bbdab369484488bbc249595618730afea3546329e5633cc9e119f31c756b1c224dd0300 checksum: 10c0/e5f1ec677f752344bbb9a65b011465d08d1fe5a2cf02eea2b337e472a555bf137030b96b42b833bfa07ffe9afbf76b9f5cd2ac05dbf5df7d66c785b8fb9a365a
languageName: node languageName: node
linkType: hard linkType: hard
@ -10932,18 +10932,18 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"postcss-lab-function@npm:^8.0.0": "postcss-lab-function@npm:^8.0.1":
version: 8.0.0 version: 8.0.1
resolution: "postcss-lab-function@npm:8.0.0" resolution: "postcss-lab-function@npm:8.0.1"
dependencies: dependencies:
"@csstools/css-color-parser": "npm:^4.0.0" "@csstools/css-color-parser": "npm:^4.0.1"
"@csstools/css-parser-algorithms": "npm:^4.0.0" "@csstools/css-parser-algorithms": "npm:^4.0.0"
"@csstools/css-tokenizer": "npm:^4.0.0" "@csstools/css-tokenizer": "npm:^4.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/utilities": "npm:^3.0.0" "@csstools/utilities": "npm:^3.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/8805a853016c5919afd95f7cbee9ba624f398d25c81a2a7987edc0d0031fee08732b02f64cb51f537f364b0de07fc837bb4bd375e0ea96a489860c59a94c0590 checksum: 10c0/f1fd9d7cd99c1b87247c87de9d5f462c12ad9bcfe922837f37ecf20c43893ef863aa3dc35fd90fed69a5120a1379e8f952ca3cc2112faecbc8196192d15d805b
languageName: node languageName: node
linkType: hard linkType: hard
@ -11070,22 +11070,22 @@ __metadata:
linkType: hard linkType: hard
"postcss-preset-env@npm:^11.0.0": "postcss-preset-env@npm:^11.0.0":
version: 11.1.1 version: 11.1.2
resolution: "postcss-preset-env@npm:11.1.1" resolution: "postcss-preset-env@npm:11.1.2"
dependencies: dependencies:
"@csstools/postcss-alpha-function": "npm:^2.0.1" "@csstools/postcss-alpha-function": "npm:^2.0.2"
"@csstools/postcss-cascade-layers": "npm:^6.0.0" "@csstools/postcss-cascade-layers": "npm:^6.0.0"
"@csstools/postcss-color-function": "npm:^5.0.0" "@csstools/postcss-color-function": "npm:^5.0.1"
"@csstools/postcss-color-function-display-p3-linear": "npm:^2.0.0" "@csstools/postcss-color-function-display-p3-linear": "npm:^2.0.1"
"@csstools/postcss-color-mix-function": "npm:^4.0.0" "@csstools/postcss-color-mix-function": "npm:^4.0.1"
"@csstools/postcss-color-mix-variadic-function-arguments": "npm:^2.0.0" "@csstools/postcss-color-mix-variadic-function-arguments": "npm:^2.0.1"
"@csstools/postcss-content-alt-text": "npm:^3.0.0" "@csstools/postcss-content-alt-text": "npm:^3.0.0"
"@csstools/postcss-contrast-color-function": "npm:^3.0.0" "@csstools/postcss-contrast-color-function": "npm:^3.0.1"
"@csstools/postcss-exponential-functions": "npm:^3.0.0" "@csstools/postcss-exponential-functions": "npm:^3.0.0"
"@csstools/postcss-font-format-keywords": "npm:^5.0.0" "@csstools/postcss-font-format-keywords": "npm:^5.0.0"
"@csstools/postcss-gamut-mapping": "npm:^3.0.0" "@csstools/postcss-gamut-mapping": "npm:^3.0.1"
"@csstools/postcss-gradients-interpolation-method": "npm:^6.0.0" "@csstools/postcss-gradients-interpolation-method": "npm:^6.0.1"
"@csstools/postcss-hwb-function": "npm:^5.0.0" "@csstools/postcss-hwb-function": "npm:^5.0.1"
"@csstools/postcss-ic-unit": "npm:^5.0.0" "@csstools/postcss-ic-unit": "npm:^5.0.0"
"@csstools/postcss-initial": "npm:^3.0.0" "@csstools/postcss-initial": "npm:^3.0.0"
"@csstools/postcss-is-pseudo-class": "npm:^6.0.0" "@csstools/postcss-is-pseudo-class": "npm:^6.0.0"
@ -11099,19 +11099,19 @@ __metadata:
"@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^4.0.0" "@csstools/postcss-media-queries-aspect-ratio-number-values": "npm:^4.0.0"
"@csstools/postcss-mixins": "npm:^1.0.0" "@csstools/postcss-mixins": "npm:^1.0.0"
"@csstools/postcss-nested-calc": "npm:^5.0.0" "@csstools/postcss-nested-calc": "npm:^5.0.0"
"@csstools/postcss-normalize-display-values": "npm:^5.0.0" "@csstools/postcss-normalize-display-values": "npm:^5.0.1"
"@csstools/postcss-oklab-function": "npm:^5.0.0" "@csstools/postcss-oklab-function": "npm:^5.0.1"
"@csstools/postcss-position-area-property": "npm:^2.0.0" "@csstools/postcss-position-area-property": "npm:^2.0.0"
"@csstools/postcss-progressive-custom-properties": "npm:^5.0.0" "@csstools/postcss-progressive-custom-properties": "npm:^5.0.0"
"@csstools/postcss-property-rule-prelude-list": "npm:^2.0.0" "@csstools/postcss-property-rule-prelude-list": "npm:^2.0.0"
"@csstools/postcss-random-function": "npm:^3.0.0" "@csstools/postcss-random-function": "npm:^3.0.0"
"@csstools/postcss-relative-color-syntax": "npm:^4.0.0" "@csstools/postcss-relative-color-syntax": "npm:^4.0.1"
"@csstools/postcss-scope-pseudo-class": "npm:^5.0.0" "@csstools/postcss-scope-pseudo-class": "npm:^5.0.0"
"@csstools/postcss-sign-functions": "npm:^2.0.0" "@csstools/postcss-sign-functions": "npm:^2.0.0"
"@csstools/postcss-stepped-value-functions": "npm:^5.0.0" "@csstools/postcss-stepped-value-functions": "npm:^5.0.0"
"@csstools/postcss-syntax-descriptor-syntax-production": "npm:^2.0.0" "@csstools/postcss-syntax-descriptor-syntax-production": "npm:^2.0.0"
"@csstools/postcss-system-ui-font-family": "npm:^2.0.0" "@csstools/postcss-system-ui-font-family": "npm:^2.0.0"
"@csstools/postcss-text-decoration-shorthand": "npm:^5.0.0" "@csstools/postcss-text-decoration-shorthand": "npm:^5.0.1"
"@csstools/postcss-trigonometric-functions": "npm:^5.0.0" "@csstools/postcss-trigonometric-functions": "npm:^5.0.0"
"@csstools/postcss-unset-value": "npm:^5.0.0" "@csstools/postcss-unset-value": "npm:^5.0.0"
autoprefixer: "npm:^10.4.23" autoprefixer: "npm:^10.4.23"
@ -11122,7 +11122,7 @@ __metadata:
cssdb: "npm:^8.7.0" cssdb: "npm:^8.7.0"
postcss-attribute-case-insensitive: "npm:^8.0.0" postcss-attribute-case-insensitive: "npm:^8.0.0"
postcss-clamp: "npm:^4.1.0" postcss-clamp: "npm:^4.1.0"
postcss-color-functional-notation: "npm:^8.0.0" postcss-color-functional-notation: "npm:^8.0.1"
postcss-color-hex-alpha: "npm:^11.0.0" postcss-color-hex-alpha: "npm:^11.0.0"
postcss-color-rebeccapurple: "npm:^11.0.0" postcss-color-rebeccapurple: "npm:^11.0.0"
postcss-custom-media: "npm:^12.0.0" postcss-custom-media: "npm:^12.0.0"
@ -11135,7 +11135,7 @@ __metadata:
postcss-font-variant: "npm:^5.0.0" postcss-font-variant: "npm:^5.0.0"
postcss-gap-properties: "npm:^7.0.0" postcss-gap-properties: "npm:^7.0.0"
postcss-image-set-function: "npm:^8.0.0" postcss-image-set-function: "npm:^8.0.0"
postcss-lab-function: "npm:^8.0.0" postcss-lab-function: "npm:^8.0.1"
postcss-logical: "npm:^9.0.0" postcss-logical: "npm:^9.0.0"
postcss-nesting: "npm:^14.0.0" postcss-nesting: "npm:^14.0.0"
postcss-opacity-percentage: "npm:^3.0.0" postcss-opacity-percentage: "npm:^3.0.0"
@ -11147,7 +11147,7 @@ __metadata:
postcss-selector-not: "npm:^9.0.0" postcss-selector-not: "npm:^9.0.0"
peerDependencies: peerDependencies:
postcss: ^8.4 postcss: ^8.4
checksum: 10c0/ed9e0b07c82368defe1ab7f776e8b163610c9db3a79e36cf95291f65959d912261aa8c4b94734bba047fe875fcf3eb6e0dd71dec93640dfd94578cba33833c5a checksum: 10c0/01cf7e5bc399e9c7521a8fdb6ef20763addd16c9e0fdf57ab6d3fa8da9ddfbc937db36bf6ea0d55492f2c788bb5ec3b43f40eb91ee1abf78622a30fbc812107f
languageName: node languageName: node
linkType: hard linkType: hard