Merge commit '1b664cf20dbb696cf16a42efcf59ab186cb211eb' into glitch-soc/merge-upstream

This commit is contained in:
Claire committed 2025-09-05 20:03:42 +02:00
commit 6fc9febb47
65 files changed
+903 -197

No files matched your search

@@ -13,9 +13,9 @@ import { useSelectableClick } from 'mastodon/hooks/useSelectableClick';
const offset = [0, 4] as OffsetValue;
const popperConfig = { strategy: 'fixed' } as UsePopperOptions;
export const AltTextBadge: React.FC<{
description: string;
}> = ({ description }) => {
export const AltTextBadge: React.FC<{ description: string }> = ({
description,
}) => {
const accessibilityId = useId();
const anchorRef = useRef<HTMLButtonElement>(null);
const [open, setOpen] = useState(false);
@@ -56,7 +56,7 @@ export const AltTextBadge: React.FC<{
{({ props }) => (
<div {...props} className='hover-card-controller'>
<div // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
className='media-gallery__alt__popover dropdown-animation'
className='info-tooltip dropdown-animation'
role='region'
id={accessibilityId}
onMouseDown={handleMouseDown}
@@ -8,6 +8,7 @@ const meta = {
component: Button,
args: {
secondary: false,
plain: false,
compact: false,
dangerous: false,
disabled: false,
@@ -57,6 +58,14 @@ export const Secondary: Story = {
play: buttonTest,
};
export const Plain: Story = {
args: {
plain: true,
children: 'Plain button',
},
play: buttonTest,
};
export const Compact: Story = {
args: {
compact: true,
@@ -101,6 +110,14 @@ export const SecondaryDisabled: Story = {
play: disabledButtonTest,
};
export const PlainDisabled: Story = {
args: {
...Plain.args,
disabled: true,
},
play: disabledButtonTest,
};
const loadingButtonTest: Story['play'] = async ({
args,
canvas,
@@ -9,6 +9,7 @@ interface BaseProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
block?: boolean;
secondary?: boolean;
plain?: boolean;
compact?: boolean;
dangerous?: boolean;
loading?: boolean;
@@ -35,6 +36,7 @@ export const Button: React.FC<Props> = ({
disabled,
block,
secondary,
plain,
compact,
dangerous,
loading,
@@ -62,6 +64,7 @@ export const Button: React.FC<Props> = ({
<button
className={classNames('button', className, {
'button-secondary': secondary,
'button--plain': plain,
'button--compact': compact,
'button--block': block,
'button--dangerous': dangerous,
@@ -1,8 +1,3 @@
/* eslint-disable @typescript-eslint/no-unsafe-call,
@typescript-eslint/no-unsafe-return,
@typescript-eslint/no-unsafe-assignment,
@typescript-eslint/no-unsafe-member-access
-- the settings store is not yet typed */
import type { PropsWithChildren } from 'react';
import { useCallback, useState, useEffect } from 'react';
@@ -23,31 +18,48 @@ interface Props {
id: string;
}
export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
id,
children,
}) => {
const dismissed = useAppSelector((state) =>
export function useDismissableBannerState({ id }: Props) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const dismissed: boolean = useAppSelector((state) =>
/* eslint-disable-next-line */
state.settings.getIn(['dismissed_banners', id], false),
);
const [isVisible, setIsVisible] = useState(
!bannerSettings.get(id) && !dismissed,
);
const dispatch = useAppDispatch();
const [visible, setVisible] = useState(!bannerSettings.get(id) && !dismissed);
const intl = useIntl();
const handleDismiss = useCallback(() => {
setVisible(false);
const dismiss = useCallback(() => {
setIsVisible(false);
bannerSettings.set(id, true);
dispatch(changeSetting(['dismissed_banners', id], true));
}, [id, dispatch]);
useEffect(() => {
if (!visible && !dismissed) {
// Store legacy localStorage setting on server
if (!isVisible && !dismissed) {
dispatch(changeSetting(['dismissed_banners', id], true));
}
}, [id, dispatch, visible, dismissed]);
}, [id, dispatch, isVisible, dismissed]);
if (!visible) {
return {
isVisible,
dismiss,
};
}
export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
id,
children,
}) => {
const intl = useIntl();
const { isVisible, dismiss } = useDismissableBannerState({
id,
});
if (!isVisible) {
return null;
}
@@ -58,7 +70,7 @@ export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
icon='times'
iconComponent={CloseIcon}
title={intl.formatMessage(messages.dismiss)}
onClick={handleDismiss}
onClick={dismiss}
/>
</div>
@@ -0,0 +1,81 @@
import type { ComponentProps } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { accountFactoryState } from '@/testing/factories';
import { DisplayName, LinkedDisplayName } from './index';
type PageProps = Omit<ComponentProps<typeof DisplayName>, 'account'> & {
name: string;
username: string;
loading: boolean;
};
const meta = {
title: 'Components/DisplayName',
args: {
username: 'mastodon@mastodon.social',
name: 'Test User 🧪',
loading: false,
simple: false,
noDomain: false,
localDomain: 'mastodon.social',
},
tags: [],
render({ name, username, loading, ...args }) {
const account = !loading
? accountFactoryState({
display_name: name,
acct: username,
})
: undefined;
return <DisplayName {...args} account={account} />;
},
} satisfies Meta<PageProps>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {},
};
export const Loading: Story = {
args: {
loading: true,
},
};
export const NoDomain: Story = {
args: {
noDomain: true,
},
};
export const Simple: Story = {
args: {
simple: true,
},
};
export const LocalUser: Story = {
args: {
username: 'localuser',
name: 'Local User',
localDomain: '',
},
};
export const Linked: Story = {
render({ name, username, loading, ...args }) {
const account = !loading
? accountFactoryState({
display_name: name,
acct: username,
})
: undefined;
return <LinkedDisplayName {...args} account={account} />;
},
};
@@ -0,0 +1,122 @@
import type { ComponentPropsWithoutRef, FC } from 'react';
import { useMemo } from 'react';
import classNames from 'classnames';
import type { LinkProps } from 'react-router-dom';
import { Link } from 'react-router-dom';
import { EmojiHTML } from '@/mastodon/features/emoji/emoji_html';
import type { Account } from '@/mastodon/models/account';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { Skeleton } from '../skeleton';
interface Props {
account?: Account;
localDomain?: string;
simple?: boolean;
noDomain?: boolean;
}
export const DisplayName: FC<Props & ComponentPropsWithoutRef<'span'>> = ({
account,
localDomain,
simple = false,
noDomain = false,
className,
...props
}) => {
const username = useMemo(() => {
if (!account || noDomain) {
return null;
}
let acct = account.get('acct');
if (!acct.includes('@') && localDomain) {
acct = `${acct}@${localDomain}`;
}
return `@${acct}`;
}, [account, localDomain, noDomain]);
if (!account) {
if (simple) {
return null;
}
return (
<span {...props} className={classNames('display-name', className)}>
<bdi>
<strong className='display-name__html'>
<Skeleton width='10ch' />
</strong>
</bdi>
{!noDomain && (
<span className='display-name__account'>
&nbsp;
<Skeleton width='7ch' />
</span>
)}
</span>
);
}
const accountName = isModernEmojiEnabled()
? account.get('display_name')
: account.get('display_name_html');
if (simple) {
return (
<bdi>
<EmojiHTML {...props} htmlString={accountName} shallow as='span' />
</bdi>
);
}
return (
<span {...props} className={classNames('display-name', className)}>
<bdi>
<EmojiHTML
className='display-name__html'
htmlString={accountName}
shallow
as='strong'
/>
</bdi>
{username && (
<span className='display-name__account'>&nbsp;{username}</span>
)}
</span>
);
};
export const LinkedDisplayName: FC<
Props & { asProps?: ComponentPropsWithoutRef<'span'> } & Partial<LinkProps>
> = ({
account,
asProps = {},
className,
localDomain,
simple,
noDomain,
...linkProps
}) => {
const displayProps = {
account,
className,
localDomain,
simple,
noDomain,
...asProps,
};
if (!account) {
return <DisplayName {...displayProps} />;
}
return (
<Link
to={`/@${account.acct}`}
title={`@${account.acct}`}
data-hover-card-account={account.id}
{...linkProps}
>
<DisplayName {...displayProps} />
</Link>
);
};
@@ -69,7 +69,7 @@ const messages = defineMessages({
},
reblog_private: {
id: 'status.reblog_private',
defaultMessage: 'Boost with original visibility',
defaultMessage: 'Share again with your followers',
},
reblog_cannot: {
id: 'status.cannot_reblog',
@@ -20,11 +20,12 @@ import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { Dropdown } from 'mastodon/components/dropdown_menu';
import { me } from '../initial_state';
import { me } from '../../initial_state';
import { IconButton } from './icon_button';
import { isFeatureEnabled } from '../utils/environment';
import { ReblogButton } from './status/reblog_button';
import { IconButton } from '../icon_button';
import { isFeatureEnabled } from '../../utils/environment';
import { ReblogButton } from '../status/reblog_button';
import { RemoveQuoteHint } from './remove_quote_hint';
const messages = defineMessages({
delete: { id: 'status.delete', defaultMessage: 'Delete' },
@@ -77,6 +78,7 @@ class StatusActionBar extends ImmutablePureComponent {
status: ImmutablePropTypes.map.isRequired,
relationship: ImmutablePropTypes.record,
quotedAccountId: PropTypes.string,
contextType: PropTypes.string,
onReply: PropTypes.func,
onFavourite: PropTypes.func,
onDelete: PropTypes.func,
@@ -240,7 +242,7 @@ class StatusActionBar extends ImmutablePureComponent {
};
render () {
const { status, relationship, quotedAccountId, intl, withDismiss, withCounters, scrollKey } = this.props;
const { status, relationship, quotedAccountId, contextType, intl, withDismiss, withCounters, scrollKey } = this.props;
const { signedIn, permissions } = this.props.identity;
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
@@ -249,6 +251,7 @@ class StatusActionBar extends ImmutablePureComponent {
const account = status.get('account');
const writtenByMe = status.getIn(['account', 'id']) === me;
const isRemote = status.getIn(['account', 'username']) !== status.getIn(['account', 'acct']);
const isQuotingMe = quotedAccountId === me;
let menu = [];
@@ -293,7 +296,7 @@ class StatusActionBar extends ImmutablePureComponent {
menu.push({ text: intl.formatMessage(messages.direct, { name: account.get('username') }), action: this.handleDirectClick });
menu.push(null);
if (quotedAccountId === me) {
if (isQuotingMe) {
menu.push({ text: intl.formatMessage(messages.revokeQuote, { name: account.get('username') }), action: this.handleRevokeQuoteClick, dangerous: true });
}
@@ -360,6 +363,8 @@ class StatusActionBar extends ImmutablePureComponent {
const bookmarkTitle = intl.formatMessage(status.get('bookmarked') ? messages.removeBookmark : messages.bookmark);
const favouriteTitle = intl.formatMessage(status.get('favourited') ? messages.removeFavourite : messages.favourite);
const isReply = status.get('in_reply_to_account_id') === status.getIn(['account', 'id']);
const shouldShowQuoteRemovalHint = isQuotingMe && contextType === 'notifications';
return (
<div className='status__action-bar'>
@@ -375,17 +380,23 @@ class StatusActionBar extends ImmutablePureComponent {
<div className='status__action-bar__button-wrapper'>
<IconButton className='status__action-bar__button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={bookmarkTitle} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
</div>
<div className='status__action-bar__button-wrapper'>
<Dropdown
scrollKey={scrollKey}
status={status}
items={menu}
icon='ellipsis-h'
iconComponent={MoreHorizIcon}
direction='right'
title={intl.formatMessage(messages.more)}
/>
</div>
<RemoveQuoteHint className='status__action-bar__button-wrapper' canShowHint={shouldShowQuoteRemovalHint}>
{(dismissQuoteHint) => (
<Dropdown
scrollKey={scrollKey}
status={status}
items={menu}
icon='ellipsis-h'
iconComponent={MoreHorizIcon}
direction='right'
title={intl.formatMessage(messages.more)}
onOpen={() => {
dismissQuoteHint();
return true;
}}
/>
)}
</RemoveQuoteHint>
</div>
);
}
@@ -0,0 +1,90 @@
import { useRef } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
import classNames from 'classnames';
import Overlay from 'react-overlays/Overlay';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { Button } from '../button';
import { useDismissableBannerState } from '../dismissable_banner';
import { Icon } from '../icon';
const DISMISSABLE_BANNER_ID = 'notifications/remove_quote_hint';
export const RemoveQuoteHint: React.FC<{
canShowHint: boolean;
className?: string;
children: (dismiss: () => void) => React.ReactNode;
}> = ({ canShowHint, className, children }) => {
const anchorRef = useRef<HTMLDivElement>(null);
const intl = useIntl();
const { isVisible, dismiss } = useDismissableBannerState({
id: DISMISSABLE_BANNER_ID,
});
return (
<div className={className} ref={anchorRef}>
{children(dismiss)}
{isVisible && canShowHint && (
<Overlay
show
flip
offset={[12, 10]}
placement='bottom-end'
target={anchorRef.current}
container={anchorRef.current}
>
{({ props, placement }) => (
<div
{...props}
className={classNames(
'info-tooltip info-tooltip--solid dropdown-animation',
placement,
)}
>
<h4>
<FormattedMessage
id='remove_quote_hint.title'
defaultMessage='Want to remove your quoted post?'
/>
</h4>
<FormattedMessage
id='remove_quote_hint.message'
defaultMessage='You can do so from the {icon} options menu.'
values={{
icon: (
<Icon
id='ellipsis-h'
icon={MoreHorizIcon}
aria-label={intl.formatMessage({
id: 'status.more',
defaultMessage: 'More',
})}
style={{ verticalAlign: 'middle' }}
/>
),
}}
>
{(text) => <p>{text}</p>}
</FormattedMessage>
<FormattedMessage
id='remove_quote_hint.button_label'
defaultMessage='Got it'
>
{(text) => (
<Button plain compact onClick={dismiss}>
{text}
</Button>
)}
</FormattedMessage>
</div>
)}
</Overlay>
)}
</div>
);
};
@@ -1,7 +1,5 @@
import type { ComponentPropsWithoutRef, ElementType } from 'react';
import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { useEmojify } from './hooks';
import type { CustomEmojiMapArg } from './types';
@@ -12,16 +10,21 @@ type EmojiHTMLProps<Element extends ElementType = 'div'> = Omit<
htmlString: string;
extraEmojis?: CustomEmojiMapArg;
as?: Element;
shallow?: boolean;
};
export const ModernEmojiHTML = <Element extends ElementType>({
export const EmojiHTML = ({
extraEmojis,
htmlString,
as: asElement, // Rename for syntax highlighting
as: Wrapper = 'div', // Rename for syntax highlighting
shallow,
...props
}: EmojiHTMLProps<Element>) => {
const Wrapper = asElement ?? 'div';
const emojifiedHtml = useEmojify(htmlString, extraEmojis);
}: EmojiHTMLProps<ElementType>) => {
const emojifiedHtml = useEmojify({
text: htmlString,
extraEmojis,
deep: !shallow,
});
if (emojifiedHtml === null) {
return null;
@@ -31,14 +34,3 @@ export const ModernEmojiHTML = <Element extends ElementType>({
<Wrapper {...props} dangerouslySetInnerHTML={{ __html: emojifiedHtml }} />
);
};
export const EmojiHTML = <Element extends ElementType>(
props: EmojiHTMLProps<Element>,
) => {
if (isModernEmojiEnabled()) {
return <ModernEmojiHTML {...props} />;
}
const { as: asElement, htmlString, extraEmojis, ...rest } = props;
const Wrapper = asElement ?? 'div';
return <Wrapper {...rest} dangerouslySetInnerHTML={{ __html: htmlString }} />;
};
@@ -8,6 +8,7 @@ import { isModernEmojiEnabled } from '@/mastodon/utils/environment';
import { toSupportedLocale } from './locale';
import { determineEmojiMode } from './mode';
import { emojifyElement, emojifyText } from './render';
import type {
CustomEmojiMapArg,
EmojiAppState,
@@ -15,7 +16,17 @@ import type {
} from './types';
import { stringHasAnyEmoji } from './utils';
export function useEmojify(text: string, extraEmojis?: CustomEmojiMapArg) {
interface UseEmojifyOptions {
text: string;
extraEmojis?: CustomEmojiMapArg;
deep?: boolean;
}
export function useEmojify({
text,
extraEmojis,
deep = true,
}: UseEmojifyOptions) {
const [emojifiedText, setEmojifiedText] = useState<string | null>(null);
const appState = useEmojiAppState();
@@ -36,17 +47,23 @@ export function useEmojify(text: string, extraEmojis?: CustomEmojiMapArg) {
const emojify = useCallback(
async (input: string) => {
const wrapper = document.createElement('div');
wrapper.innerHTML = input;
const { emojifyElement } = await import('./render');
const result = await emojifyElement(wrapper, appState, extra);
let result: string | null = null;
if (deep) {
const wrapper = document.createElement('div');
wrapper.innerHTML = input;
if (await emojifyElement(wrapper, appState, extra)) {
result = wrapper.innerHTML;
}
} else {
result = await emojifyText(text, appState, extra);
}
if (result) {
setEmojifiedText(result.innerHTML);
setEmojifiedText(result);
} else {
setEmojifiedText(input);
}
},
[appState, extra],
[appState, deep, extra, text],
);
useLayoutEffect(() => {
if (isModernEmojiEnabled() && !!text.trim() && stringHasAnyEmoji(text)) {
@@ -33,7 +33,7 @@ const messages = defineMessages({
reblog: { id: 'status.reblog', defaultMessage: 'Boost' },
reblog_private: {
id: 'status.reblog_private',
defaultMessage: 'Boost with original visibility',
defaultMessage: 'Share again with your followers',
},
cancel_reblog_private: {
id: 'status.cancel_reblog_private',
@@ -92,8 +92,7 @@ const messages = defineMessages({
const mapStateToProps = state => ({
layout: state.getIn(['meta', 'layout']),
isComposing: state.getIn(['compose', 'is_composing']),
hasComposingText: state.getIn(['compose', 'text']).trim().length !== 0,
hasMediaAttachments: state.getIn(['compose', 'media_attachments']).size > 0,
hasComposingContents: state.getIn(['compose', 'text']).trim().length !== 0 || state.getIn(['compose', 'media_attachments']).size > 0 || state.getIn(['compose', 'poll']) !== null || state.getIn(['compose', 'quoted_status_id']) !== null,
canUploadMore: !state.getIn(['compose', 'media_attachments']).some(x => ['audio', 'video'].includes(x.get('type'))) && state.getIn(['compose', 'media_attachments']).size < state.getIn(['server', 'server', 'configuration', 'statuses', 'max_media_attachments']),
firstLaunch: state.getIn(['settings', 'introductionVersion'], 0) < INTRODUCTION_VERSION,
newAccount: !state.getIn(['accounts', me, 'note']) && !state.getIn(['accounts', me, 'bot']) && state.getIn(['accounts', me, 'following_count'], 0) === 0 && state.getIn(['accounts', me, 'statuses_count'], 0) === 0,
@@ -241,8 +240,7 @@ class UI extends PureComponent {
dispatch: PropTypes.func.isRequired,
children: PropTypes.node,
isComposing: PropTypes.bool,
hasComposingText: PropTypes.bool,
hasMediaAttachments: PropTypes.bool,
hasComposingContents: PropTypes.bool,
canUploadMore: PropTypes.bool,
intl: PropTypes.object.isRequired,
layout: PropTypes.string.isRequired,
@@ -257,11 +255,11 @@ class UI extends PureComponent {
};
handleBeforeUnload = e => {
const { intl, dispatch, isComposing, hasComposingText, hasMediaAttachments } = this.props;
const { intl, dispatch, isComposing, hasComposingContents } = this.props;
dispatch(synchronouslySubmitMarkers());
if (isComposing && (hasComposingText || hasMediaAttachments)) {
if (isComposing && hasComposingContents) {
e.preventDefault();
// Setting returnValue to any string causes confirmation dialog.
// Many browsers no longer display this text to users,
+46 -13
View File
@@ -29,6 +29,8 @@
"account.endorse": "Lakaat war-wel war ar profil",
"account.familiar_followers_one": "Heuilhet gant {name1}",
"account.familiar_followers_two": "Heuilhet gant {name1} ha {name2}",
"account.featured.accounts": "Profiloù",
"account.featured.hashtags": "Gerioù-klik",
"account.featured_tags.last_status_at": "Toud diwezhañ : {date}",
"account.featured_tags.last_status_never": "Embannadur ebet",
"account.follow": "Heuliañ",
@@ -39,6 +41,7 @@
"account.followers_you_know_counter": "{counter} a anavezit",
"account.following": "Koumanantoù",
"account.follows.empty": "An implijer·ez-mañ na heul den ebet.",
"account.follows_you": "Ho heuilh",
"account.go_to_profile": "Gwelet ar profil",
"account.hide_reblogs": "Kuzh skignadennoù gant @{name}",
"account.in_memoriam": "E koun.",
@@ -89,7 +92,10 @@
"alt_text_modal.done": "Graet",
"announcement.announcement": "Kemennad",
"annual_report.summary.followers.followers": "heulier",
"annual_report.summary.followers.total": "{count} en holl",
"annual_report.summary.highlighted_post.possessive": "{name}",
"annual_report.summary.most_used_app.most_used_app": "arload muiañ implijet",
"annual_report.summary.most_used_hashtag.most_used_hashtag": "ar gerioù-klik implijet ar muiañ",
"annual_report.summary.most_used_hashtag.none": "Hini ebet",
"annual_report.summary.new_posts.new_posts": "toudoù nevez",
"attachments_list.unprocessed": "(ket meret)",
@@ -149,7 +155,7 @@
"compose.saved.body": "Enrollet.",
"compose_form.direct_message_warning_learn_more": "Gouzout hiroc'h",
"compose_form.encryption_warning": "Toudoù war Mastodon na vezont ket sifret penn-da-benn. Na rannit ket titouroù kizidik dre Mastodon.",
"compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
"compose_form.hashtag_warning": "Ne vo ket listennet an toud-mañ dindan gerioù-klik ebet dre m'eo anlistennet. N'eus nemet an toudoù foran a c'hall bezañ klasket dre c'her-klik.",
"compose_form.lock_disclaimer": "N'eo ket {locked} ho kont. An holl a c'hal ho heuliañ evit gwelet ho toudoù prevez.",
"compose_form.lock_disclaimer.lock": "prennet",
"compose_form.placeholder": "Petra emaoc'h o soñjal e-barzh ?",
@@ -168,6 +174,7 @@
"confirmations.block.confirm": "Stankañ",
"confirmations.delete.confirm": "Dilemel",
"confirmations.delete.message": "Ha sur oc'h e fell deoc'h dilemel an toud-mañ ?",
"confirmations.delete.title": "Dilemel an toud?",
"confirmations.delete_list.confirm": "Dilemel",
"confirmations.delete_list.message": "Ha sur eo hoc'h eus c'hoant da zilemel ar roll-mañ da vat ?",
"confirmations.delete_list.title": "Dilemel al listenn?",
@@ -176,10 +183,14 @@
"confirmations.follow_to_list.title": "Heuliañ an implijer·ez?",
"confirmations.logout.confirm": "Digevreañ",
"confirmations.logout.message": "Ha sur oc'h e fell deoc'h digevreañ ?",
"confirmations.logout.title": "Digevreañ?",
"confirmations.mute.confirm": "Kuzhat",
"confirmations.redraft.confirm": "Diverkañ ha skrivañ en-dro",
"confirmations.unfollow.confirm": "Diheuliañ",
"confirmations.unfollow.message": "Ha sur oc'h e fell deoc'h paouez da heuliañ {name} ?",
"confirmations.unfollow.title": "Paouez da heuliañ an implijer·ez?",
"content_warning.hide": "Kuzhat an embannadur",
"content_warning.show": "Diskwel memes tra",
"content_warning.show_more": "Diskouez muioc'h",
"conversation.delete": "Dilemel ar gaozeadenn",
"conversation.mark_as_read": "Merkañ evel lennet",
@@ -224,8 +235,8 @@
"empty_column.domain_blocks": "N'eus domani kuzh ebet c'hoazh.",
"empty_column.explore_statuses": "N'eus tuadur ebet evit c'hoazh. Distroit diwezhatoc'h !",
"empty_column.follow_requests": "N'ho peus reked heuliañ ebet c'hoazh. Pa vo resevet unan e teuio war wel amañ.",
"empty_column.followed_tags": "N'emaoc'h oc'h heuliañ hashtag ebet evit poent. Pa vioc'h e vo d'o gwelet amañ.",
"empty_column.hashtag": "N'eus netra en hashtag-mañ c'hoazh.",
"empty_column.followed_tags": "N'emaoc'h oc'h heuliañ ger-klik ebet evit poent. Pa vioc'h e vo d'o gwelet amañ.",
"empty_column.hashtag": "N'eus netra er ger-klik-mañ c'hoazh.",
"empty_column.home": "Goullo eo ho red-amzer degemer! Kit da weladenniñ {public} pe implijit ar c'hlask evit kregiñ ganti ha kejañ gant implijer·ien·ezed all.",
"empty_column.list": "Goullo eo al listenn-mañ evit c'hoazh. Pa vo embannet toudoù nevez gant e izili e teuint war wel amañ.",
"empty_column.mutes": "N'ho peus kuzhet implijer ebet c'hoazh.",
@@ -241,7 +252,7 @@
"explore.title": "Diouzh ar c'hiz",
"explore.trending_links": "Keleier",
"explore.trending_statuses": "Embannadurioù",
"explore.trending_tags": "Hashtagoù",
"explore.trending_tags": "Gerioù-klik",
"featured_carousel.next": "War-raok",
"featured_carousel.post": "Embannadenn",
"featured_carousel.previous": "War-gil",
@@ -269,7 +280,8 @@
"follow_suggestions.friends_of_friends_longer": "Diouzh ar c'hiz e-touez an dud heuliet ganeoc'h",
"follow_suggestions.popular_suggestion_longer": "Diouzh ar c'hiz war {domain}",
"follow_suggestions.view_all": "Gwelet pep tra",
"followed_tags": "Hashtagoù o heuliañ",
"follow_suggestions.who_to_follow": "Piv heuliañ",
"followed_tags": "Gerioù-klik o heuliañ",
"footer.about": "Diwar-benn",
"footer.directory": "Kavlec'h ar profiloù",
"footer.get_app": "Pellgargañ an arload",
@@ -281,19 +293,23 @@
"generic.saved": "Enrollet",
"getting_started.heading": "Loc'hañ",
"hashtag.admin_moderation": "Digeriñ an etrefas evezhiañ evit #{name}",
"hashtag.browse": "Furchal dre an toudoù gant #{hashtag}",
"hashtag.browse_from_account": "Furchal dre an toudoù gant @{name} gant #{hashtag}",
"hashtag.column_header.tag_mode.all": "ha(g) {additional}",
"hashtag.column_header.tag_mode.any": "pe {additional}",
"hashtag.column_header.tag_mode.none": "hep {additional}",
"hashtag.column_settings.select.no_options_message": "N'eus bet kavet ali ebet",
"hashtag.column_settings.select.placeholder": "Ouzhpennañ hashtagoù…",
"hashtag.column_settings.select.placeholder": "Ouzhpennañ gerioù-klik…",
"hashtag.column_settings.tag_mode.all": "An holl anezho",
"hashtag.column_settings.tag_mode.any": "Unan e mesk anezho",
"hashtag.column_settings.tag_mode.none": "Hini ebet anezho",
"hashtag.column_settings.tag_toggle": "Endelc'her gerioù-alc'hwez ouzhpenn evit ar bannad-mañ",
"hashtag.counter_by_uses": "{count, plural, one {{counter} embannadur} other {{counter} embannadur}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} embannadur} other {{counter} embannadur}} hiziv",
"hashtag.feature": "Lakaat war-wel war ar profil",
"hashtag.follow": "Heuliañ ar ger-klik",
"hashtag.unfollow": "Paouez heuliañ an hashtag",
"hashtag.mute": "Kuzhat #{hashtag}",
"hashtag.unfollow": "Diheuliañ ar ger-klik",
"hashtags.and_other": "…{count, plural, one {hag # all} other {ha # all}}",
"home.column_settings.show_quotes": "Diskouez an arroudennoù",
"home.column_settings.show_reblogs": "Diskouez ar skignadennoù",
@@ -302,12 +318,14 @@
"home.pending_critical_update.body": "Hizivait ho servijer Mastodon kerkent ha ma c'hallit mar plij!",
"home.pending_critical_update.link": "Gwelet an hizivadennoù",
"home.show_announcements": "Diskouez ar c'hemennoù",
"interaction_modal.go": "Mont di",
"interaction_modal.on_another_server": "War ur servijer all",
"interaction_modal.on_this_server": "War ar servijer-mañ",
"interaction_modal.title.favourite": "Ouzhpennañ embannadur {name} d'ar re vuiañ-karet",
"interaction_modal.title.follow": "Heuliañ {name}",
"interaction_modal.title.reblog": "Skignañ toud {name}",
"interaction_modal.title.reply": "Respont da doud {name}",
"interaction_modal.username_prompt": "D.s. {example}",
"intervals.full.days": "{number, plural, one {# devezh} other{# a zevezhioù}}",
"intervals.full.hours": "{number, plural, one {# eurvezh} other{# eurvezh}}",
"intervals.full.minutes": "{number, plural, one {# munut} other{# a vunutoù}}",
@@ -345,12 +363,14 @@
"keyboard_shortcuts.toot": "Kregiñ gant un toud nevez",
"keyboard_shortcuts.unfocus": "Difokus an dachenn testenn/klask",
"keyboard_shortcuts.up": "Pignat er roll",
"learn_more_link.got_it": "Mat eo",
"lightbox.close": "Serriñ",
"lightbox.next": "Da-heul",
"lightbox.previous": "A-raok",
"limited_account_hint.action": "Diskouez an aelad memes tra",
"limited_account_hint.action": "Diskouez ar profil memes tra",
"limited_account_hint.title": "Kuzhet eo bet ar profil-mañ gant an evezhierien eus {domain}.",
"link_preview.author": "Gant {name}",
"link_preview.more_from_author": "Muioc'h gant {name}",
"lists.add_member": "Ouzhpennañ",
"lists.add_to_list": "Ouzhpennañ d'al listenn",
"lists.create": "Krouiñ",
@@ -359,13 +379,19 @@
"lists.done": "Graet",
"lists.edit": "Kemmañ al listenn",
"lists.list_name": "Anv al listenn",
"lists.new_list_name": "Anv nevez al listenn",
"lists.no_lists_yet": "Listenn ebet c'hoazh.",
"lists.replies_policy.followed": "Pep implijer.ez heuliet",
"lists.replies_policy.list": "Izili ar roll",
"lists.replies_policy.none": "Den ebet",
"lists.save": "Enrollañ",
"lists.search": "Klask",
"load_pending": "{count, plural, one {# dra nevez} other {# dra nevez}}",
"loading_indicator.label": "O kargañ…",
"media_gallery.hide": "Kuzhat",
"navigation_bar.about": "Diwar-benn",
"navigation_bar.account_settings": "Ger-tremen ha surentez",
"navigation_bar.administration": "Merañ",
"navigation_bar.automated_deletion": "Dilemel an embannadenn ent-emgefreek",
"navigation_bar.blocks": "Implijer·ezed·ien berzet",
"navigation_bar.bookmarks": "Sinedoù",
@@ -374,11 +400,12 @@
"navigation_bar.favourites": "Muiañ-karet",
"navigation_bar.filters": "Gerioù kuzhet",
"navigation_bar.follow_requests": "Pedadoù heuliañ",
"navigation_bar.followed_tags": "Hashtagoù o heuliañ",
"navigation_bar.followed_tags": "Gerioù-klik o heuliañ",
"navigation_bar.follows_and_followers": "Heuliadennoù ha heulier·ezed·ien",
"navigation_bar.import_export": "Enporzhiañ hag ezporzhiañ",
"navigation_bar.lists": "Listennoù",
"navigation_bar.logout": "Digennaskañ",
"navigation_bar.moderation": "Habaskadur",
"navigation_bar.more": "Muioc'h",
"navigation_bar.mutes": "Implijer·ion·ezed kuzhet",
"navigation_bar.preferences": "Gwellvezioù",
@@ -391,6 +418,8 @@
"notification.follow.name_and_others": "{name} <a>{count, plural, one {hag # den all} two {ha # zen all} few {ha # den all} many {ha # den all} other {ha # den all}}</a> zo o heuliañ ac'hanoc'h",
"notification.follow_request": "Gant {name} eo bet goulennet ho heuliañ",
"notification.label.reply": "Respont",
"notification.mention": "Meneg",
"notification.mentioned_you": "Gant {name} oc'h bet meneget",
"notification.moderation-warning.learn_more": "Gouzout hiroc'h",
"notification.own_poll": "Echu eo ho sontadeg",
"notification.reblog": "Gant {name} eo bet skignet ho toud",
@@ -447,7 +476,7 @@
"onboarding.profile.display_name": "Anv diskouezet",
"onboarding.profile.display_name_hint": "Hoc'h anv klok pe hoc'h anv fentus…",
"onboarding.profile.note": "Berr-ha-berr",
"onboarding.profile.note_hint": "Gallout a rit @menegiñ tud all pe #hashtagoù…",
"onboarding.profile.note_hint": "Gallout a rit @menegiñ tud all pe #gerioù-klik…",
"onboarding.profile.save_and_continue": "Enrollañ ha kenderc'hel",
"onboarding.profile.upload_avatar": "Enporzhiañ ur skeudenn profil",
"password_confirmation.mismatching": "Disheñvel eo an daou c'her-termen-se",
@@ -480,6 +509,7 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}eil",
"relative_time.today": "hiziv",
"remove_quote_hint.button_label": "Mat eo",
"reply_indicator.cancel": "Nullañ",
"reply_indicator.poll": "Sontadeg",
"report.block": "Stankañ",
@@ -528,7 +558,7 @@
"search.placeholder": "Klask",
"search.quick_action.account_search": "Profiloù a glot gant {x}",
"search.quick_action.go_to_account": "Mont d'ar profil {x}",
"search.quick_action.go_to_hashtag": "Mont d'an hashtag {x}",
"search.quick_action.go_to_hashtag": "Mont d'ar ger-klik {x}",
"search.quick_action.open_url": "Digeriñ an URL e-barzh Mastodon",
"search.quick_action.status_search": "Embannadurioù a glot gant {x}",
"search.search_or_paste": "Klask pe pegañ un URL",
@@ -541,7 +571,7 @@
"search_popout.user": "implijer·ez",
"search_results.accounts": "Profiloù",
"search_results.all": "Pep tra",
"search_results.hashtags": "Hashtagoù",
"search_results.hashtags": "Gerioù-klik",
"search_results.no_results": "Disoc'h ebet.",
"search_results.see_all": "Gwelet pep tra",
"search_results.statuses": "Toudoù",
@@ -607,6 +637,7 @@
"subscribed_languages.save": "Enrollañ ar cheñchamantoù",
"subscribed_languages.target": "Cheñch ar yezhoù koumanantet evit {target}",
"tabs_bar.home": "Degemer",
"tabs_bar.menu": "Lañser",
"tabs_bar.notifications": "Kemennoù",
"tabs_bar.publish": "Embannadenn nevez",
"tabs_bar.search": "Klask",
@@ -638,6 +669,8 @@
"video.hide": "Kuzhat ar video",
"video.pause": "Paouez",
"video.play": "Lenn",
"visibility_modal.privacy_label": "Gwelusted",
"visibility_modal.quote_followers": "Tud koumanantet hepken",
"visibility_modal.quote_public": "Pep den"
"visibility_modal.quote_public": "Pep den",
"visibility_modal.save": "Enrollañ"
}
+5
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} m",
"relative_time.seconds": "{number} s",
"relative_time.today": "dnes",
"remove_quote_hint.button_label": "Chápu",
"remove_quote_hint.message": "Můžete to udělat z {icon} nabídky možností.",
"remove_quote_hint.title": "Chcete odstranit citovaný příspěvek?",
"reply_indicator.attachments": "{count, plural, one {{counter} příloha} few {{counter} přílohy} other {{counter} příloh}}",
"reply_indicator.cancel": "Zrušit",
"reply_indicator.poll": "Anketa",
@@ -863,6 +866,7 @@
"status.block": "Blokovat @{name}",
"status.bookmark": "Přidat do záložek",
"status.cancel_reblog_private": "Zrušit boostnutí",
"status.cannot_quote": "Citování je na tomo příspěvku zakázáno",
"status.cannot_reblog": "Tento příspěvek nemůže být boostnutý",
"status.context.load_new_replies": "K dispozici jsou nové odpovědi",
"status.context.loading": "Hledání dalších odpovědí",
@@ -988,6 +992,7 @@
"visibility_modal.header": "Viditelnost a interakce",
"visibility_modal.helper.direct_quoting": "Soukromé zmínky, které jsou vytvořeny na Mastodonu, nemohou být citovány ostatními.",
"visibility_modal.helper.privacy_editing": "Publikované příspěvky nemohou změnit svou viditelnost.",
"visibility_modal.helper.privacy_private_self_quote": "Citace vlastních soukromých příspěvků nelze zveřejnit.",
"visibility_modal.helper.private_quoting": "Příspěvky pouze pro sledující, které jsou vytvořeny na Mastodonu, nemohou být citovány ostatními.",
"visibility_modal.helper.unlisted_quoting": "Když vás lidé citují, jejich příspěvek bude v časové ose populárních příspěvků také skryt.",
"visibility_modal.instructions": "Nastavte, kdo bude moci interagovat s tímto příspěvkem. Tyto nastavení též můžete změnit pro všechny budoucí příspěvky v <link>Nastavení > Výchozí nastavení příspěvků</link>.",
+1
View File
@@ -768,6 +768,7 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "i dag",
"remove_quote_hint.button_label": "Forstået",
"reply_indicator.attachments": "{count, plural, one {# vedhæftning} other {# vedhæftninger}}",
"reply_indicator.cancel": "Afbryd",
"reply_indicator.poll": "Afstemning",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} Min.",
"relative_time.seconds": "{number} Sek.",
"relative_time.today": "heute",
"remove_quote_hint.button_label": "Verstanden",
"remove_quote_hint.message": "Klicke dafür im Beitrag auf „{icon} Mehr“.",
"remove_quote_hint.title": "Möchtest du aus dem zitierten Beitrag entfernt werden?",
"reply_indicator.attachments": "{count, plural, one {# Anhang} other {# Anhänge}}",
"reply_indicator.cancel": "Abbrechen",
"reply_indicator.poll": "Umfrage",
+5 -2
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "today",
"remove_quote_hint.button_label": "Got it",
"remove_quote_hint.message": "You can do so from the {icon} options menu.",
"remove_quote_hint.title": "Want to remove your quoted post?",
"reply_indicator.attachments": "{count, plural, one {# attachment} other {# attachments}}",
"reply_indicator.cancel": "Cancel",
"reply_indicator.poll": "Poll",
@@ -910,7 +913,7 @@
"status.read_more": "Read more",
"status.reblog": "Boost",
"status.reblog_or_quote": "Boost or quote",
"status.reblog_private": "Boost with original visibility",
"status.reblog_private": "Share again with your followers",
"status.reblogged_by": "{name} boosted",
"status.reblogs": "{count, plural, one {boost} other {boosts}}",
"status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.",
@@ -988,7 +991,7 @@
"visibility_modal.button_title": "Set visibility",
"visibility_modal.header": "Visibility and interaction",
"visibility_modal.helper.direct_quoting": "Private mentions authored on Mastodon can't be quoted by others.",
"visibility_modal.helper.privacy_editing": "Published posts cannot change their visibility.",
"visibility_modal.helper.privacy_editing": "Visibility can't be changed after a post is published.",
"visibility_modal.helper.privacy_private_self_quote": "Self-quotes of private posts cannot be made public.",
"visibility_modal.helper.private_quoting": "Follower-only posts authored on Mastodon can't be quoted by others.",
"visibility_modal.helper.unlisted_quoting": "When people quote you, their post will also be hidden from trending timelines.",
+9
View File
@@ -30,6 +30,8 @@
"account.edit_profile": "Redakti la profilon",
"account.enable_notifications": "Sciigu min kiam @{name} afiŝos",
"account.endorse": "Montri en profilo",
"account.familiar_followers_one": "Sekvita de {name1}",
"account.familiar_followers_two": "Sekvita de {name1} kaj {name2}",
"account.featured": "Montrita",
"account.featured.accounts": "Profiloj",
"account.featured.hashtags": "Kradvortoj",
@@ -305,6 +307,7 @@
"emoji_button.search_results": "Serĉaj rezultoj",
"emoji_button.symbols": "Simboloj",
"emoji_button.travel": "Vojaĝoj kaj lokoj",
"empty_column.account_featured.me": "Vi ankoraŭ nenion prezentis. Ĉu vi sciis, ke vi povas prezenti viajn plej ofte uzatajn kradvortojn, kaj eĉ la kontojn de viaj amikoj sur via profilo?",
"empty_column.account_featured_other.unknown": "Ĉi tiu konto ankoraŭ ne montris ion ajn.",
"empty_column.account_hides_collections": "Ĉi tiu uzanto elektis ne disponebligi ĉi tiu informon",
"empty_column.account_suspended": "Konto suspendita",
@@ -338,6 +341,7 @@
"explore.trending_links": "Novaĵoj",
"explore.trending_statuses": "Afiŝoj",
"explore.trending_tags": "Kradvortoj",
"featured_carousel.header": "{count, plural, one {Alpinglita afiŝo} other {Alpinglitaj afiŝoj}}",
"featured_carousel.next": "Antaŭen",
"featured_carousel.post": "Afiŝi",
"featured_carousel.previous": "Malantaŭen",
@@ -751,6 +755,9 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "hodiaŭ",
"remove_quote_hint.button_label": "Komprenite",
"remove_quote_hint.message": "Vi povas fari tion el la menuo de opcioj {icon}.",
"remove_quote_hint.title": "Ĉu vi volas forigi vian cititan afiŝon?",
"reply_indicator.attachments": "{count, plural, one {# aldonaĵo} other {# aldonaĵoj}}",
"reply_indicator.cancel": "Nuligi",
"reply_indicator.poll": "Balotenketo",
@@ -846,6 +853,7 @@
"status.block": "Bloki @{name}",
"status.bookmark": "Aldoni al la legosignoj",
"status.cancel_reblog_private": "Ne plu diskonigi",
"status.cannot_quote": "Citaĵoj estas malebligitaj en ĉi tiu afiŝo",
"status.cannot_reblog": "Ĉi tiun afiŝon ne eblas diskonigi",
"status.context.load_new_replies": "Disponeblaj novaj respondoj",
"status.context.loading": "Serĉante pliajn respondojn",
@@ -971,6 +979,7 @@
"visibility_modal.helper.privacy_editing": "Publikigitaj afiŝoj ne povas ŝanĝi sian videblon.",
"visibility_modal.helper.private_quoting": "Afiŝoj nur por sekvantoj verkitaj ĉe Mastodon ne povas esti cititaj de aliaj.",
"visibility_modal.helper.unlisted_quoting": "Kiam homoj citas vin, ilia afiŝo ankaŭ estos kaŝita de tendencaj templinioj.",
"visibility_modal.privacy_label": "Videbleco",
"visibility_modal.quote_followers": "Nur sekvantoj",
"visibility_modal.quote_label": "Kiu povas citi",
"visibility_modal.quote_nobody": "Nur mi",
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "hoy",
"remove_quote_hint.button_label": "Entendido",
"remove_quote_hint.message": "Podés hacerlo desde el menú de opciones {icon}.",
"remove_quote_hint.title": "¿Querés eliminar tu mensaje citado?",
"reply_indicator.attachments": "{count, plural,one {# adjunto} other {# adjuntos}}",
"reply_indicator.cancel": "Cancelar",
"reply_indicator.poll": "Encuesta",
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} m",
"relative_time.seconds": "{number} s",
"relative_time.today": "hoy",
"remove_quote_hint.button_label": "Entendido",
"remove_quote_hint.message": "Puedes hacerlo desde el menú de opciones {icon}.",
"remove_quote_hint.title": "¿Quieres eliminar tu publicación citada?",
"reply_indicator.attachments": "{count, plural, one {# adjunto} other {# adjuntos}}",
"reply_indicator.cancel": "Cancelar",
"reply_indicator.poll": "Encuesta",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} m",
"relative_time.seconds": "{number} s",
"relative_time.today": "hoy",
"remove_quote_hint.button_label": "Entendido",
"remove_quote_hint.message": "Puedes hacerlo desde el menú de opciones {icon}.",
"remove_quote_hint.title": "¿Quieres eliminar tu publicación citada?",
"reply_indicator.attachments": "{count, plural, one {# adjunto} other {# adjuntos}}",
"reply_indicator.cancel": "Cancelar",
"reply_indicator.poll": "Encuesta",
+5
View File
@@ -863,6 +863,7 @@
"status.block": "Blokeeri @{name}",
"status.bookmark": "Järjehoidja",
"status.cancel_reblog_private": "Lõpeta jagamine",
"status.cannot_quote": "Selle postituse tsiteerimine pole lubatud",
"status.cannot_reblog": "Seda postitust ei saa jagada",
"status.context.load_new_replies": "Leidub uusi vastuseid",
"status.context.loading": "Kontrollin täiendavate vastuste olemasolu",
@@ -988,9 +989,13 @@
"visibility_modal.header": "Nähtavus ja kasutus",
"visibility_modal.helper.direct_quoting": "Ainult mainituile mõeldud Mastodoni postitusi ei saa teiste poolt tsiteerida.",
"visibility_modal.helper.privacy_editing": "Avaldatud postitused ei saa muuta oma nähtavust.",
"visibility_modal.helper.privacy_private_self_quote": "Privaatsete postituste tsiteerimist oma enda poolt pole võimalik teha avalikuks.",
"visibility_modal.helper.private_quoting": "Ainult jälgijatele mõeldud Mastodoni postitusi ei saa teiste poolt tsiteerida.",
"visibility_modal.helper.unlisted_quoting": "Kui teised kasutajad sind tsiteerivad, siis nende postitused peidetakse ajajoonelt, mis näitavad populaarsust koguvaid postitusi.",
"visibility_modal.instructions": "Halda seda, kes võivad antud postitusega suhestuda. Lisaks võid kõikide tulevaste postituste seadistusi muuta valikust <link>Eelistused > Postituse vaikeseadistused</link>.",
"visibility_modal.privacy_label": "Nähtavus",
"visibility_modal.quote_followers": "Ainult jälgijad",
"visibility_modal.quote_label": "Kes võivad tsiteerida",
"visibility_modal.quote_nobody": "Ainult mina",
"visibility_modal.quote_public": "Kõik",
"visibility_modal.save": "Salvesta"
+1
View File
@@ -852,6 +852,7 @@
"status.block": "انسداد ‎@{name}",
"status.bookmark": "نشانک",
"status.cancel_reblog_private": "ناتقویت",
"status.cannot_quote": "نقل قول برای این پست غیرفعال است",
"status.cannot_reblog": "این فرسته قابل تقویت نیست",
"status.context.load_new_replies": "پاسخ‌های جدیدی موجودند",
"status.context.loading": "بررسی کردن برای پاسخ‌های بیش‌تر",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} min",
"relative_time.seconds": "{number} s",
"relative_time.today": "tänään",
"remove_quote_hint.button_label": "Selvä",
"remove_quote_hint.message": "Voit tehdä sen {icon}-valikosta.",
"remove_quote_hint.title": "Haluatko poistaa lainatun julkaisusi?",
"reply_indicator.attachments": "{count, plural, one {# liite} other {# liitettä}}",
"reply_indicator.cancel": "Peruuta",
"reply_indicator.poll": "Äänestys",
@@ -490,6 +490,7 @@
"keyboard_shortcuts.open_media": "Ouvrir média",
"keyboard_shortcuts.pinned": "Ouvrir la liste de publications épinglés",
"keyboard_shortcuts.profile": "Ouvrir le profil de l’auteur·rice",
"keyboard_shortcuts.quote": "Citer la publication",
"keyboard_shortcuts.reply": "Répondre au message",
"keyboard_shortcuts.requests": "Ouvrir la liste de demandes d’abonnement",
"keyboard_shortcuts.search": "Focuser sur le champ de recherche",
@@ -599,6 +600,7 @@
"notification.label.mention": "Mention",
"notification.label.private_mention": "Mention privée",
"notification.label.private_reply": "Répondre en privé",
"notification.label.quote": "{name} a cité votre publication",
"notification.label.reply": "Réponse",
"notification.mention": "Mention",
"notification.mentioned_you": "{name} vous a mentionné·e",
@@ -613,6 +615,7 @@
"notification.moderation_warning.action_suspend": "Votre compte a été suspendu.",
"notification.own_poll": "Votre sondage est terminé",
"notification.poll": "Un sondage auquel vous avez participé vient de se terminer",
"notification.quoted_update": "{name} a modifié une publication que vous avez cité",
"notification.reblog": "{name} a boosté votre message",
"notification.reblog.name_and_others_with_link": "{name} et <a>{count, plural, one {# autre} other {# autres}}</a> ont boosté votre message",
"notification.relationships_severance_event": "Connexions perdues avec {name}",
@@ -656,6 +659,7 @@
"notifications.column_settings.mention": "Mentions:",
"notifications.column_settings.poll": "Résultats des sondages:",
"notifications.column_settings.push": "Notifications push",
"notifications.column_settings.quote": "Citations:",
"notifications.column_settings.reblog": "Boosts:",
"notifications.column_settings.show": "Afficher dans la colonne",
"notifications.column_settings.sound": "Jouer un son",
@@ -731,12 +735,18 @@
"privacy.private.short": "Abonnés",
"privacy.public.long": "Tout le monde sur et en dehors de Mastodon",
"privacy.public.short": "Public",
"privacy.quote.anyone": "{visibility}, n'importe qui peut citer",
"privacy.quote.disabled": "{visibility}, citations désactivées",
"privacy.quote.limited": "{visibility}, citations limitées",
"privacy.unlisted.additional": "Se comporte exactement comme « public », sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, explorer ou la recherche Mastodon, même si vous les avez activé au niveau de votre compte.",
"privacy.unlisted.long": "Moins de fanfares algorithmiques",
"privacy.unlisted.short": "Public discret",
"privacy_policy.last_updated": "Dernière mise à jour {date}",
"privacy_policy.title": "Politique de confidentialité",
"quote_error.poll": "Les citations ne sont pas autorisées avec les sondages.",
"quote_error.quote": "Une seule citation à la fois est autorisée.",
"quote_error.unauthorized": "Vous n'êtes pas autorisé⋅e à citer cette publication.",
"quote_error.upload": "La citation n'est pas autorisée avec un média joint.",
"recommended": "Recommandé",
"refresh": "Actualiser",
"regeneration_indicator.please_stand_by": "Veuillez patienter.",
@@ -843,14 +853,17 @@
"status.admin_account": "Ouvrir l’interface de modération pour @{name}",
"status.admin_domain": "Ouvrir l’interface de modération pour {domain}",
"status.admin_status": "Ouvrir ce message dans l’interface de modération",
"status.all_disabled": "Partages et citations sont désactivés",
"status.block": "Bloquer @{name}",
"status.bookmark": "Ajouter aux signets",
"status.cancel_reblog_private": "Débooster",
"status.cannot_quote": "Les citations sont désactivées sur cette publication",
"status.cannot_reblog": "Cette publication ne peut pas être boostée",
"status.context.load_new_replies": "Nouvelles réponses disponibles",
"status.continued_thread": "Suite du fil",
"status.copy": "Copier un lien vers cette publication",
"status.delete": "Supprimer",
"status.delete.success": "Publication supprimée",
"status.detailed_status": "Vue détaillée de la conversation",
"status.direct": "Mention privée @{name}",
"status.direct_indicator": "Mention privée",
@@ -875,9 +888,12 @@
"status.pin": "Épingler sur profil",
"status.quote": "Citation",
"status.quote.cancel": "Annuler la citation",
"status.quote_error.filtered": "Caché en raison de l'un de vos filtres",
"status.quote_error.not_available": "Publication non disponible",
"status.quote_error.pending_approval": "Publication en attente",
"status.quote_error.pending_approval_popout.title": "Publication en attente ? Restez calme",
"status.quote_followers_only": "Seul·e·s mes abonné·e·s peuvent citer cette publication",
"status.quote_manual_review": "L'auteur va vérifier manuellement",
"status.quote_policy_change": "Changer qui peut vous citer",
"status.quote_private": "Les publications privées ne peuvent pas être citées",
"status.read_more": "En savoir plus",
@@ -955,6 +971,10 @@
"video.volume_up": "Augmenter le volume",
"visibility_modal.button_title": "Définir la visibilité",
"visibility_modal.header": "Visibilité et interactions",
"visibility_modal.privacy_label": "Visibilité",
"visibility_modal.quote_followers": "Abonné·e·s seulement",
"visibility_modal.quote_label": "Autoriser les citations pour",
"visibility_modal.quote_nobody": "Juste moi",
"visibility_modal.quote_public": "Tout le monde",
"visibility_modal.save": "Sauvegarder"
}
+20
View File
@@ -490,6 +490,7 @@
"keyboard_shortcuts.open_media": "Ouvrir le média",
"keyboard_shortcuts.pinned": "Ouvrir la liste des messages épinglés",
"keyboard_shortcuts.profile": "Ouvrir le profil de l’auteur·rice",
"keyboard_shortcuts.quote": "Citer la publication",
"keyboard_shortcuts.reply": "Répondre au message",
"keyboard_shortcuts.requests": "Ouvrir la liste de demandes d’abonnement",
"keyboard_shortcuts.search": "Se placer dans le champ de recherche",
@@ -599,6 +600,7 @@
"notification.label.mention": "Mention",
"notification.label.private_mention": "Mention privée",
"notification.label.private_reply": "Répondre en privé",
"notification.label.quote": "{name} a cité votre publication",
"notification.label.reply": "Réponse",
"notification.mention": "Mention",
"notification.mentioned_you": "{name} vous a mentionné·e",
@@ -613,6 +615,7 @@
"notification.moderation_warning.action_suspend": "Votre compte a été suspendu.",
"notification.own_poll": "Votre sondage est terminé",
"notification.poll": "Un sondage auquel vous avez participé vient de se terminer",
"notification.quoted_update": "{name} a modifié une publication que vous avez cité",
"notification.reblog": "{name} a partagé votre message",
"notification.reblog.name_and_others_with_link": "{name} et <a>{count, plural, one {# autre} other {# autres}}</a> ont boosté votre message",
"notification.relationships_severance_event": "Connexions perdues avec {name}",
@@ -656,6 +659,7 @@
"notifications.column_settings.mention": "Mentions :",
"notifications.column_settings.poll": "Résultats des sondages :",
"notifications.column_settings.push": "Notifications push",
"notifications.column_settings.quote": "Citations:",
"notifications.column_settings.reblog": "Partages :",
"notifications.column_settings.show": "Afficher dans la colonne",
"notifications.column_settings.sound": "Jouer un son",
@@ -731,12 +735,18 @@
"privacy.private.short": "Abonnés",
"privacy.public.long": "Tout le monde sur et en dehors de Mastodon",
"privacy.public.short": "Public",
"privacy.quote.anyone": "{visibility}, n'importe qui peut citer",
"privacy.quote.disabled": "{visibility}, citations désactivées",
"privacy.quote.limited": "{visibility}, citations limitées",
"privacy.unlisted.additional": "Se comporte exactement comme « public », sauf que le message n'apparaîtra pas dans les flux en direct, les hashtags, explorer ou la recherche Mastodon, même si vous les avez activé au niveau de votre compte.",
"privacy.unlisted.long": "Moins de fanfares algorithmiques",
"privacy.unlisted.short": "Public discret",
"privacy_policy.last_updated": "Dernière mise à jour {date}",
"privacy_policy.title": "Politique de confidentialité",
"quote_error.poll": "Les citations ne sont pas autorisées avec les sondages.",
"quote_error.quote": "Une seule citation à la fois est autorisée.",
"quote_error.unauthorized": "Vous n'êtes pas autorisé⋅e à citer cette publication.",
"quote_error.upload": "La citation n'est pas autorisée avec un média joint.",
"recommended": "Recommandé",
"refresh": "Actualiser",
"regeneration_indicator.please_stand_by": "Veuillez patienter.",
@@ -843,14 +853,17 @@
"status.admin_account": "Ouvrir l’interface de modération pour @{name}",
"status.admin_domain": "Ouvrir l’interface de modération pour {domain}",
"status.admin_status": "Ouvrir ce message dans l’interface de modération",
"status.all_disabled": "Partages et citations sont désactivés",
"status.block": "Bloquer @{name}",
"status.bookmark": "Ajouter aux marque-pages",
"status.cancel_reblog_private": "Annuler le partage",
"status.cannot_quote": "Les citations sont désactivées sur cette publication",
"status.cannot_reblog": "Ce message ne peut pas être partagé",
"status.context.load_new_replies": "Nouvelles réponses disponibles",
"status.continued_thread": "Suite du fil",
"status.copy": "Copier le lien vers le message",
"status.delete": "Supprimer",
"status.delete.success": "Publication supprimée",
"status.detailed_status": "Vue détaillée de la conversation",
"status.direct": "Mention privée @{name}",
"status.direct_indicator": "Mention privée",
@@ -875,9 +888,12 @@
"status.pin": "Épingler sur le profil",
"status.quote": "Citation",
"status.quote.cancel": "Annuler la citation",
"status.quote_error.filtered": "Caché en raison de l'un de vos filtres",
"status.quote_error.not_available": "Publication non disponible",
"status.quote_error.pending_approval": "Publication en attente",
"status.quote_error.pending_approval_popout.title": "Publication en attente ? Restez calme",
"status.quote_followers_only": "Seul·e·s mes abonné·e·s peuvent citer cette publication",
"status.quote_manual_review": "L'auteur va vérifier manuellement",
"status.quote_policy_change": "Changer qui peut vous citer",
"status.quote_private": "Les publications privées ne peuvent pas être citées",
"status.read_more": "En savoir plus",
@@ -955,6 +971,10 @@
"video.volume_up": "Augmenter le volume",
"visibility_modal.button_title": "Définir la visibilité",
"visibility_modal.header": "Visibilité et interactions",
"visibility_modal.privacy_label": "Visibilité",
"visibility_modal.quote_followers": "Abonné·e·s seulement",
"visibility_modal.quote_label": "Autoriser les citations pour",
"visibility_modal.quote_nobody": "Juste moi",
"visibility_modal.quote_public": "Tout le monde",
"visibility_modal.save": "Sauvegarder"
}
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "hoxe",
"remove_quote_hint.button_label": "Entendido",
"remove_quote_hint.message": "Pódelo facer desde o {icon} menú de opcións.",
"remove_quote_hint.title": "Queres eliminar a publicación citada?",
"reply_indicator.attachments": "{count, plural, one {# adxunto} other {# adxuntos}}",
"reply_indicator.cancel": "Desbotar",
"reply_indicator.poll": "Enquisa",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} דקות",
"relative_time.seconds": "{number} שניות",
"relative_time.today": "היום",
"remove_quote_hint.button_label": "הבנתי",
"remove_quote_hint.message": "ניתן לעשות זאת מתפריט האפשרויות {icon}",
"remove_quote_hint.title": "להסיר את ההודעה המצוטטת?",
"reply_indicator.attachments": "{count, plural,one {# קובץ מצורף}other {# קבצים מצורפים}}",
"reply_indicator.cancel": "ביטול",
"reply_indicator.poll": "משאל",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number}mín",
"relative_time.seconds": "{number}sek",
"relative_time.today": "í dag",
"remove_quote_hint.button_label": "Náði því",
"remove_quote_hint.message": "Þú getur gert það úr {icon} valmyndinni.",
"remove_quote_hint.title": "Viltu fjarlægja tilvitnuðu færsluna þína?",
"reply_indicator.attachments": "{count, plural, one {# viðhengi} other {# viðhengi}}",
"reply_indicator.cancel": "Hætta við",
"reply_indicator.poll": "Könnun",
+7 -5
View File
@@ -97,8 +97,8 @@
"admin.impact_report.title": "Ietekmes kopsavilkums",
"alert.rate_limited.message": "Lūdzu, mēģini vēlreiz pēc {retry_time, time, medium}.",
"alert.rate_limited.title": "Biežums ierobežots",
"alert.unexpected.message": "Radās negaidīta kļūda.",
"alert.unexpected.title": "Ups!",
"alert.unexpected.message": "Atgadījās neparedzēta kļūda.",
"alert.unexpected.title": "Ak vai!",
"alt_text_badge.title": "Alt teksts",
"alt_text_modal.add_alt_text": "Pievienot aprakstošo tekstu",
"alt_text_modal.add_text_from_image": "Pievienot tekstu no attēla",
@@ -140,7 +140,7 @@
"bundle_column_error.copy_stacktrace": "Ievietot kļūdu ziņojumu starpliktuvē",
"bundle_column_error.error.body": "Pieprasīto lapu nevarēja atveidot. Tas varētu būt saistīts ar kļūdu mūsu kodā, vai tā ir pārlūkprogrammas saderības problēma.",
"bundle_column_error.error.title": "Ak vai!",
"bundle_column_error.network.body": "Mēģinot ielādēt šo lapu, radās kļūda. Tas varētu būt saistīts ar īslaicīgu interneta savienojuma vai šī servera problēmu.",
"bundle_column_error.network.body": "Kļūda lapas ielādēšanas laikā. Tas varētu būt īzlaicīgs sarežģījums ar interneta savienojumu vai šo serveri.",
"bundle_column_error.network.title": "Tīkla kļūda",
"bundle_column_error.retry": "Mēģināt vēlreiz",
"bundle_column_error.return": "Atgriezties",
@@ -202,7 +202,7 @@
"compose_form.poll.switch_to_multiple": "Mainīt aptaujas veidu, lai atļautu vairākas izvēles",
"compose_form.poll.switch_to_single": "Mainīt aptaujas veidu, lai atļautu vienu izvēli",
"compose_form.poll.type": "Stils",
"compose_form.publish": "Nosūtīt",
"compose_form.publish": "Iesūtīt",
"compose_form.reply": "Atbildēt",
"compose_form.save_changes": "Atjaunināt",
"compose_form.spoiler.marked": "Noņemt satura brīdinājumu",
@@ -509,10 +509,11 @@
"navigation_bar.filters": "Apklusinātie vārdi",
"navigation_bar.follow_requests": "Sekošanas pieprasījumi",
"navigation_bar.followed_tags": "Sekojamie tēmturi",
"navigation_bar.follows_and_followers": "Sekojamie un sekotāji",
"navigation_bar.follows_and_followers": "Seko un sekotāji",
"navigation_bar.lists": "Saraksti",
"navigation_bar.logout": "Iziet",
"navigation_bar.moderation": "Satura pārraudzība",
"navigation_bar.more": "Vairāk",
"navigation_bar.mutes": "Apklusinātie lietotāji",
"navigation_bar.opened_in_classic_interface": "Ieraksti, konti un citas noteiktas lapas pēc noklusējuma tiek atvērtas klasiskajā tīmekļa saskarnē.",
"navigation_bar.preferences": "Iestatījumi",
@@ -734,6 +735,7 @@
"status.bookmark": "Grāmatzīme",
"status.cancel_reblog_private": "Nepastiprināt",
"status.cannot_reblog": "Šo ierakstu nevar pastiprināt",
"status.context.loading": "Pārbauda, vai ir vairāk atbilžu",
"status.continued_thread": "Turpināts pavediens",
"status.copy": "Ievietot ieraksta saiti starpliktuvē",
"status.delete": "Dzēst",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number}m",
"relative_time.seconds": "{number}s",
"relative_time.today": "vandaag",
"remove_quote_hint.button_label": "Begrepen",
"remove_quote_hint.message": "Je kunt dit doen vanuit het {icon} optiesmenu.",
"remove_quote_hint.title": "Wil je jouw geciteerd bericht verwijderen?",
"reply_indicator.attachments": "{count, plural, one {# bijlage} other {# bijlagen}}",
"reply_indicator.cancel": "Annuleren",
"reply_indicator.poll": "Peiling",
+3
View File
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} phút",
"relative_time.seconds": "{number}s",
"relative_time.today": "hôm nay",
"remove_quote_hint.button_label": "Đã hiểu",
"remove_quote_hint.message": "Bạn cũng có thể làm trong menu tùy chọn {icon}",
"remove_quote_hint.title": "Gỡ tút mà bạn đã trích dẫn?",
"reply_indicator.attachments": "{count, plural, other {# tập tin đính kèm}}",
"reply_indicator.cancel": "Hủy bỏ",
"reply_indicator.poll": "Vốt",
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} 分钟前",
"relative_time.seconds": "{number} 秒前",
"relative_time.today": "今天",
"remove_quote_hint.button_label": "明白了",
"remove_quote_hint.message": "你可以通过 {icon} 选项菜单进行此操作。",
"remove_quote_hint.title": "是否需要删除你的引用嘟文?",
"reply_indicator.attachments": "{count, plural, other {# 个附件}}",
"reply_indicator.cancel": "取消",
"reply_indicator.poll": "投票",
@@ -768,6 +768,9 @@
"relative_time.minutes": "{number} 分鐘前",
"relative_time.seconds": "{number} 秒",
"relative_time.today": "今天",
"remove_quote_hint.button_label": "了解",
"remove_quote_hint.message": "您能自 {icon} 選單完成此操作。",
"remove_quote_hint.title": "是否想要移除您的引用嘟文?",
"reply_indicator.attachments": "{count, plural, other {# 個附加檔案}}",
"reply_indicator.cancel": "取消",
"reply_indicator.poll": "投票",
+2 -2
View File
@@ -101,9 +101,9 @@ const RootStateRecord = ImmutableRecord(initialRootState, 'RootState');
export const rootReducer = combineReducers(reducers, RootStateRecord);
export function reducerWithInitialState(
stateOverrides: Record<string, unknown> = {},
...stateOverrides: Record<string, unknown>[]
) {
const initialStateRecord = mergeDeep(initialRootState, stateOverrides);
const initialStateRecord = mergeDeep(initialRootState, ...stateOverrides);
const PatchedRootStateRecord = ImmutableRecord(
initialStateRecord,
'RootState',
@@ -117,6 +117,7 @@ const initialState = ImmutableMap({
'explore/links': false,
'explore/statuses': false,
'explore/tags': false,
'notifications/remove_quote_hint': false,
}),
});
+57 -5
View File
@@ -201,6 +201,41 @@
}
}
&.button--plain {
color: $highlight-text-color;
background: transparent;
padding: 6px;
// The button has no outline, so we use negative margin to
// visually align its label with its surroundings while maintaining
// a generous click target
margin-inline: -6px;
border: 1px solid transparent;
&:active,
&:focus,
&:hover {
border-color: transparent;
color: lighten($highlight-text-color, 4%);
background-color: transparent;
text-decoration: none;
}
&:disabled,
&.disabled {
opacity: 0.7;
border-color: transparent;
color: $ui-button-disabled-color;
&:active,
&:focus,
&:hover {
border-color: transparent;
color: $ui-button-disabled-color;
}
}
}
&.button-tertiary {
background: transparent;
padding: 6px 17px;
@@ -436,8 +471,8 @@
}
}
body > [data-popper-placement] {
z-index: 3;
[data-popper-placement] {
z-index: 9999;
}
.invisible {
@@ -7092,7 +7127,8 @@ a.status-card {
cursor: default;
}
.media-gallery__alt__popover {
.info-tooltip {
color: $white;
background: color.change($black, $alpha: 0.65);
backdrop-filter: $backdrop-blur-filter;
border-radius: 4px;
@@ -7104,20 +7140,36 @@ a.status-card {
max-height: 30em;
overflow-y: auto;
&--solid {
color: var(--nested-card-text);
background:
/* This is a bit of a silly hack for layering two background colours
* since --nested-card-background is too transparent for a tooltip */
linear-gradient(
var(--nested-card-background),
var(--nested-card-background)
),
linear-gradient(var(--background-color), var(--background-color));
border: var(--nested-card-border);
}
h4 {
font-size: 15px;
line-height: 20px;
font-weight: 500;
color: $white;
margin-bottom: 8px;
}
p {
font-size: 15px;
line-height: 20px;
color: color.change($white, $alpha: 0.85);
opacity: 0.85;
white-space: pre-line;
}
.button {
margin-block-start: 8px;
}
}
.attachment-list {