Merge remote-tracking branch 'parent/main' into kbtopic-remove-quote

This commit is contained in:
KMY 2025-05-27 10:51:58 +09:00
commit 7c65b6f9df
464 changed files with 8217 additions and 8135 deletions

View file

@ -0,0 +1,22 @@
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
import { apiGetFamiliarFollowers } from '../api/accounts';
import { importFetchedAccounts } from './importer';
export const fetchAccountsFamiliarFollowers = createDataLoadingThunk(
'accounts_familiar_followers/fetch',
({ id }: { id: string }) => apiGetFamiliarFollowers(id),
([data], { dispatch }) => {
if (!data) {
return null;
}
dispatch(importFetchedAccounts(data.accounts));
return {
id: data.id,
accountIds: data.accounts.map((account) => account.id),
};
},
);

View file

@ -69,6 +69,10 @@ export function importFetchedStatuses(statuses) {
processStatus(status.reblog);
}
if (status.quote?.quoted_status) {
processStatus(status.quote.quoted_status);
}
if (status.poll?.id) {
pushUnique(polls, createPollFromServerJSON(status.poll, getState().polls[status.poll.id]));
}

View file

@ -23,12 +23,20 @@ export function normalizeFilterResult(result) {
export function normalizeStatus(status, normalOldStatus) {
const normalStatus = { ...status };
normalStatus.account = status.account.id;
if (status.reblog && status.reblog.id) {
normalStatus.reblog = status.reblog.id;
}
if (status.quote?.quoted_status ?? status.quote?.quoted_status_id) {
normalStatus.quote = {
...status.quote,
quoted_status: status.quote.quoted_status?.id ?? status.quote?.quoted_status_id,
};
}
if (status.poll && status.poll.id) {
normalStatus.poll = status.poll.id;
}

View file

@ -83,6 +83,7 @@ export default function api(withAuthorization = true) {
return instance;
}
type ApiUrl = `v${1 | 2}/${string}`;
type RequestParamsOrData = Record<string, unknown>;
export async function apiRequest<ApiResponse = unknown>(
@ -105,28 +106,28 @@ export async function apiRequest<ApiResponse = unknown>(
}
export async function apiRequestGet<ApiResponse = unknown>(
url: string,
url: ApiUrl,
params?: RequestParamsOrData,
) {
return apiRequest<ApiResponse>('GET', url, { params });
}
export async function apiRequestPost<ApiResponse = unknown>(
url: string,
url: ApiUrl,
data?: RequestParamsOrData,
) {
return apiRequest<ApiResponse>('POST', url, { data });
}
export async function apiRequestPut<ApiResponse = unknown>(
url: string,
url: ApiUrl,
data?: RequestParamsOrData,
) {
return apiRequest<ApiResponse>('PUT', url, { data });
}
export async function apiRequestDelete<ApiResponse = unknown>(
url: string,
url: ApiUrl,
params?: RequestParamsOrData,
) {
return apiRequest<ApiResponse>('DELETE', url, { params });

View file

@ -1,5 +1,8 @@
import { apiRequestPost, apiRequestGet } from 'mastodon/api';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type {
ApiAccountJSON,
ApiFamiliarFollowersJSON,
} from 'mastodon/api_types/accounts';
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
@ -31,3 +34,8 @@ export const apiGetFeaturedTags = (id: string) =>
export const apiGetEndorsedAccounts = (id: string) =>
apiRequestGet<ApiAccountJSON>(`v1/accounts/${id}/endorsements`);
export const apiGetFamiliarFollowers = (id: string) =>
apiRequestGet<ApiFamiliarFollowersJSON>('v1/accounts/familiar_followers', {
id,
});

View file

@ -2,9 +2,9 @@ import { apiRequestGet, apiRequestPost } from 'mastodon/api';
import type { ApiPollJSON } from 'mastodon/api_types/polls';
export const apiGetPoll = (pollId: string) =>
apiRequestGet<ApiPollJSON>(`/v1/polls/${pollId}`);
apiRequestGet<ApiPollJSON>(`v1/polls/${pollId}`);
export const apiPollVote = (pollId: string, choices: string[]) =>
apiRequestPost<ApiPollJSON>(`/v1/polls/${pollId}/votes`, {
apiRequestPost<ApiPollJSON>(`v1/polls/${pollId}/votes`, {
choices,
});

View file

@ -81,3 +81,9 @@ export interface ApiMutedAccountJSON extends BaseApiAccountJSON {
// For now, we have the same type representing both `Account` and `MutedAccount`
// objects, but we should refactor this in the future.
export type ApiAccountJSON = ApiMutedAccountJSON;
// See app/serializers/rest/familiar_followers_serializer.rb
export type ApiFamiliarFollowersJSON = {
id: string;
accounts: ApiAccountJSON[];
}[];

View file

@ -1,8 +1,6 @@
import Rails from '@rails/ujs';
export function start() {
require.context('../images/', true, /\.(jpg|png|svg)$/);
try {
Rails.start();
} catch {

View file

@ -1,11 +1,13 @@
import { fromJS } from 'immutable';
import renderer from 'react-test-renderer';
import { accountDefaultValues, createAccountFromServerJSON } from '@/mastodon/models/account';
import { Avatar } from '../avatar';
describe('<Avatar />', () => {
const account = fromJS({
const account = createAccountFromServerJSON({
...accountDefaultValues,
username: 'alice',
acct: 'alice',
display_name: 'Alice',

View file

@ -13,9 +13,12 @@ import {
unblockAccount,
muteAccount,
unmuteAccount,
followAccountSuccess,
} from 'mastodon/actions/accounts';
import { showAlertForError } from 'mastodon/actions/alerts';
import { openModal } from 'mastodon/actions/modal';
import { initMuteModal } from 'mastodon/actions/mutes';
import { apiFollowAccount } from 'mastodon/api/accounts';
import { Avatar } from 'mastodon/components/avatar';
import { Button } from 'mastodon/components/button';
import { FollowersCounter } from 'mastodon/components/counters';
@ -26,6 +29,8 @@ import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import { ShortNumber } from 'mastodon/components/short_number';
import { Skeleton } from 'mastodon/components/skeleton';
import { VerifiedBadge } from 'mastodon/components/verified_badge';
import { useIdentity } from 'mastodon/identity_context';
import { me } from 'mastodon/initial_state';
import type { MenuItem } from 'mastodon/models/dropdown_menu';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
@ -79,10 +84,12 @@ export const Account: React.FC<{
children,
}) => {
const intl = useIntl();
const { signedIn } = useIdentity();
const account = useAppSelector((state) => state.accounts.get(id));
const relationship = useAppSelector((state) => state.relationships.get(id));
const dispatch = useAppDispatch();
const accountUrl = account?.url;
const isRemote = account?.acct !== account?.username;
const handleBlock = useCallback(() => {
if (relationship?.blocking) {
@ -125,37 +132,74 @@ export const Account: React.FC<{
},
];
} else if (defaultAction !== 'block') {
const handleAddToLists = () => {
dispatch(
openModal({
modalType: 'LIST_ADDER',
modalProps: {
accountId: id,
},
}),
);
};
arr = [];
arr = [
{
if (isRemote && accountUrl) {
arr.push({
text: intl.formatMessage(messages.openOriginalPage),
href: accountUrl,
});
}
if (signedIn) {
const handleAddToLists = () => {
const openAddToListModal = () => {
dispatch(
openModal({
modalType: 'LIST_ADDER',
modalProps: {
accountId: id,
},
}),
);
};
if (relationship?.following || relationship?.requested || id === me) {
openAddToListModal();
} else {
dispatch(
openModal({
modalType: 'CONFIRM_FOLLOW_TO_LIST',
modalProps: {
accountId: id,
onConfirm: () => {
apiFollowAccount(id)
.then((relationship) => {
dispatch(
followAccountSuccess({
relationship,
alreadyFollowing: false,
}),
);
openAddToListModal();
})
.catch((err: unknown) => {
dispatch(showAlertForError(err));
});
},
},
}),
);
}
};
arr.push({
text: intl.formatMessage(messages.addToLists),
action: handleAddToLists,
},
];
if (accountUrl) {
arr.unshift(
{
text: intl.formatMessage(messages.openOriginalPage),
href: accountUrl,
},
null,
);
});
}
}
return arr;
}, [dispatch, intl, id, accountUrl, relationship, defaultAction]);
}, [
dispatch,
intl,
id,
accountUrl,
relationship,
defaultAction,
isRemote,
signedIn,
]);
if (hidden) {
return (

View file

@ -1,17 +1,21 @@
import { useState, useCallback } from 'react';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import { useHovering } from 'mastodon/hooks/useHovering';
import { autoPlayGif } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';
interface Props {
account: Account | undefined; // FIXME: remove `undefined` once we know for sure its always there
size: number;
account:
| Pick<Account, 'id' | 'acct' | 'avatar' | 'avatar_static'>
| undefined; // FIXME: remove `undefined` once we know for sure its always there
size?: number;
style?: React.CSSProperties;
inline?: boolean;
animate?: boolean;
withLink?: boolean;
counter?: number | string;
counterBorderColor?: string;
}
@ -21,6 +25,7 @@ export const Avatar: React.FC<Props> = ({
animate = autoPlayGif,
size = 20,
inline = false,
withLink = false,
style: styleFromParent,
counter,
counterBorderColor,
@ -35,10 +40,7 @@ export const Avatar: React.FC<Props> = ({
height: `${size}px`,
};
const src =
hovering || animate
? account?.get('avatar')
: account?.get('avatar_static');
const src = hovering || animate ? account?.avatar : account?.avatar_static;
const handleLoad = useCallback(() => {
setLoading(false);
@ -48,7 +50,7 @@ export const Avatar: React.FC<Props> = ({
setError(true);
}, [setError]);
return (
const avatar = (
<div
className={classNames('account__avatar', {
'account__avatar--inline': inline,
@ -72,4 +74,18 @@ export const Avatar: React.FC<Props> = ({
)}
</div>
);
if (withLink) {
return (
<Link
to={`/@${account?.acct}`}
title={`@${account?.acct}`}
data-hover-card-account={account?.id}
>
{avatar}
</Link>
);
}
return avatar;
};

View file

@ -0,0 +1,23 @@
import classNames from 'classnames';
/**
* Wrapper for displaying a number of Avatar components horizontally,
* either spaced out (default) or overlapping (using the `compact` prop).
*/
export const AvatarGroup: React.FC<{
compact?: boolean;
avatarHeight?: number;
children: React.ReactNode;
}> = ({ children, compact = false, avatarHeight }) => (
<div
className={classNames('avatar-group', { 'avatar-group--compact': compact })}
style={
avatarHeight
? ({ '--avatar-height': `${avatarHeight}px` } as React.CSSProperties)
: undefined
}
>
{children}
</div>
);

View file

@ -43,3 +43,17 @@ export const FollowersCounter = (
}}
/>
);
export const FollowersYouKnowCounter = (
displayNumber: React.ReactNode,
pluralReady: number,
) => (
<FormattedMessage
id='account.followers_you_know_counter'
defaultMessage='{counter} you know'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);

View file

@ -0,0 +1,211 @@
import type { ComponentPropsWithRef } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import type { Map as ImmutableMap } from 'immutable';
import { List as ImmutableList } from 'immutable';
import type { AnimatedProps } from '@react-spring/web';
import { animated, useSpring } from '@react-spring/web';
import { useDrag } from '@use-gesture/react';
import { expandAccountFeaturedTimeline } from '@/mastodon/actions/timelines';
import { IconButton } from '@/mastodon/components/icon_button';
import StatusContainer from '@/mastodon/containers/status_container';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import ChevronLeftIcon from '@/material-icons/400-24px/chevron_left.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
const messages = defineMessages({
previous: { id: 'featured_carousel.previous', defaultMessage: 'Previous' },
next: { id: 'featured_carousel.next', defaultMessage: 'Next' },
slide: {
id: 'featured_carousel.slide',
defaultMessage: '{index} of {total}',
},
});
export const FeaturedCarousel: React.FC<{
accountId: string;
tagged?: string;
}> = ({ accountId, tagged }) => {
const intl = useIntl();
// Load pinned statuses
const dispatch = useAppDispatch();
useEffect(() => {
if (accountId) {
void dispatch(expandAccountFeaturedTimeline(accountId, { tagged }));
}
}, [accountId, dispatch, tagged]);
const pinnedStatuses = useAppSelector(
(state) =>
(state.timelines as ImmutableMap<string, unknown>).getIn(
[`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'],
ImmutableList(),
) as ImmutableList<string>,
);
// Handle slide change
const [slideIndex, setSlideIndex] = useState(0);
const wrapperRef = useRef<HTMLDivElement>(null);
const handleSlideChange = useCallback(
(direction: number) => {
setSlideIndex((prev) => {
const max = pinnedStatuses.size - 1;
let newIndex = prev + direction;
if (newIndex < 0) {
newIndex = max;
} else if (newIndex > max) {
newIndex = 0;
}
const slide = wrapperRef.current?.children[newIndex];
if (slide) {
setCurrentSlideHeight(slide.scrollHeight);
}
return newIndex;
});
},
[pinnedStatuses.size],
);
// Handle slide heights
const [currentSlideHeight, setCurrentSlideHeight] = useState(
wrapperRef.current?.scrollHeight ?? 0,
);
const observerRef = useRef<ResizeObserver>(
new ResizeObserver(() => {
handleSlideChange(0);
}),
);
const wrapperStyles = useSpring({
x: `-${slideIndex * 100}%`,
height: currentSlideHeight,
});
useEffect(() => {
// Update slide height when the component mounts
if (currentSlideHeight === 0) {
handleSlideChange(0);
}
}, [currentSlideHeight, handleSlideChange]);
// Handle swiping animations
const bind = useDrag(({ swipe: [swipeX] }) => {
handleSlideChange(swipeX * -1); // Invert swipe as swiping left loads the next slide.
});
const handlePrev = useCallback(() => {
handleSlideChange(-1);
}, [handleSlideChange]);
const handleNext = useCallback(() => {
handleSlideChange(1);
}, [handleSlideChange]);
if (!accountId || pinnedStatuses.isEmpty()) {
return null;
}
return (
<div
className='featured-carousel'
{...bind()}
aria-roledescription='carousel'
aria-labelledby='featured-carousel-title'
role='region'
>
<div className='featured-carousel__header'>
<h4 className='featured-carousel__title' id='featured-carousel-title'>
<FormattedMessage
id='featured_carousel.header'
defaultMessage='{count, plural, one {Pinned Post} other {Pinned Posts}}'
values={{ count: pinnedStatuses.size }}
/>
</h4>
{pinnedStatuses.size > 1 && (
<>
<IconButton
title={intl.formatMessage(messages.previous)}
icon='chevron-left'
iconComponent={ChevronLeftIcon}
onClick={handlePrev}
/>
<span aria-live='polite'>
<FormattedMessage
id='featured_carousel.post'
defaultMessage='Post'
>
{(text) => <span className='sr-only'>{text}</span>}
</FormattedMessage>
{slideIndex + 1} / {pinnedStatuses.size}
</span>
<IconButton
title={intl.formatMessage(messages.next)}
icon='chevron-right'
iconComponent={ChevronRightIcon}
onClick={handleNext}
/>
</>
)}
</div>
<animated.div
className='featured-carousel__slides'
ref={wrapperRef}
style={wrapperStyles}
aria-atomic='false'
aria-live='polite'
>
{pinnedStatuses.map((statusId, index) => (
<FeaturedCarouselItem
key={`f-${statusId}`}
data-index={index}
aria-label={intl.formatMessage(messages.slide, {
index: index + 1,
total: pinnedStatuses.size,
})}
statusId={statusId}
observer={observerRef.current}
active={index === slideIndex}
/>
))}
</animated.div>
</div>
);
};
interface FeaturedCarouselItemProps {
statusId: string;
active: boolean;
observer: ResizeObserver;
}
const FeaturedCarouselItem: React.FC<
FeaturedCarouselItemProps & AnimatedProps<ComponentPropsWithRef<'div'>>
> = ({ statusId, active, observer, ...props }) => {
const handleRef = useCallback(
(instance: HTMLDivElement | null) => {
if (instance) {
observer.observe(instance);
}
},
[observer],
);
return (
<animated.div
className='featured-carousel__slide'
// @ts-expect-error inert in not in this version of React
inert={!active ? 'true' : undefined}
aria-roledescription='slide'
role='group'
ref={handleRef}
{...props}
>
<StatusContainer
// @ts-expect-error inferred props are wrong
id={statusId}
contextType='account'
withCounters
/>
</animated.div>
);
};

View file

@ -9,11 +9,16 @@ import { fetchAccount } from 'mastodon/actions/accounts';
import { AccountBio } from 'mastodon/components/account_bio';
import { AccountFields } from 'mastodon/components/account_fields';
import { Avatar } from 'mastodon/components/avatar';
import { FollowersCounter } from 'mastodon/components/counters';
import { AvatarGroup } from 'mastodon/components/avatar_group';
import {
FollowersCounter,
FollowersYouKnowCounter,
} from 'mastodon/components/counters';
import { DisplayName } from 'mastodon/components/display_name';
import { FollowButton } from 'mastodon/components/follow_button';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { ShortNumber } from 'mastodon/components/short_number';
import { useFetchFamiliarFollowers } from 'mastodon/features/account_timeline/hooks/familiar_followers';
import { domain } from 'mastodon/initial_state';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
@ -38,6 +43,8 @@ export const HoverCardAccount = forwardRef<
}
}, [dispatch, accountId, account]);
const { familiarFollowers } = useFetchFamiliarFollowers({ accountId });
return (
<div
ref={ref}
@ -73,12 +80,28 @@ export const HoverCardAccount = forwardRef<
)}
</div>
<div className='hover-card__number'>
<div className='hover-card__numbers'>
<ShortNumber
value={account.followers_count}
renderer={FollowersCounter}
isHide={account.other_settings.hide_followers_count}
/>
{familiarFollowers.length > 0 && (
<>
&middot;
<div className='hover-card__familiar-followers'>
<ShortNumber
value={familiarFollowers.length}
renderer={FollowersYouKnowCounter}
/>
<AvatarGroup compact>
{familiarFollowers.slice(0, 3).map((account) => (
<Avatar key={account.id} account={account} size={22} />
))}
</AvatarGroup>
</div>
</>
)}
</div>
<FollowButton accountId={accountId} />

View file

@ -1,17 +0,0 @@
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { IconLogo } from 'mastodon/components/logo';
import { AuthorLink } from 'mastodon/features/explore/components/author_link';
export const MoreFromAuthor = ({ accountId }) => (
<div className='more-from-author'>
<IconLogo />
<FormattedMessage id='link_preview.more_from_author' defaultMessage='More from {name}' values={{ name: <AuthorLink accountId={accountId} /> }} />
</div>
);
MoreFromAuthor.propTypes = {
accountId: PropTypes.string.isRequired,
};

View file

@ -0,0 +1,21 @@
import { FormattedMessage } from 'react-intl';
import { IconLogo } from 'mastodon/components/logo';
import { AuthorLink } from 'mastodon/features/explore/components/author_link';
export const MoreFromAuthor: React.FC<{ accountId: string }> = ({
accountId,
}) => (
<FormattedMessage
id='link_preview.more_from_author'
defaultMessage='More from {name}'
values={{ name: <AuthorLink accountId={accountId} /> }}
>
{(chunks) => (
<div className='more-from-author'>
<IconLogo />
{chunks}
</div>
)}
</FormattedMessage>
);

View file

@ -5,7 +5,6 @@ import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
@ -13,7 +12,6 @@ import { HotKeys } from 'react-hotkeys';
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import ReferenceIcon from '@/material-icons/400-24px/link.svg?react';
import PushPinIcon from '@/material-icons/400-24px/push_pin.svg?react';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
import LimitedIcon from '@/material-icons/400-24px/shield.svg?react';
import TimerIcon from '@/material-icons/400-24px/timer.svg?react';
@ -91,6 +89,7 @@ class Status extends ImmutablePureComponent {
status: ImmutablePropTypes.map,
account: ImmutablePropTypes.record,
contextType: PropTypes.string,
children: PropTypes.node,
previousId: PropTypes.string,
rootId: PropTypes.string,
onClick: PropTypes.func,
@ -120,6 +119,7 @@ class Status extends ImmutablePureComponent {
onMoveUp: PropTypes.func,
onMoveDown: PropTypes.func,
showThread: PropTypes.bool,
isQuotedPost: PropTypes.bool,
getScrollPosition: PropTypes.func,
updateScrollBottom: PropTypes.func,
cacheMediaWidth: PropTypes.func,
@ -181,9 +181,8 @@ class Status extends ImmutablePureComponent {
}
};
handleMouseUp = e => {
handleHeaderClick = e => {
// Only handle clicks on the empty space above the content
if (e.target !== e.currentTarget && e.detail >= 1) {
return;
}
@ -379,7 +378,7 @@ class Status extends ImmutablePureComponent {
};
render () {
const { intl, hidden, featured, unfocusable, unread, showThread, scrollKey, pictureInPicture, previousId, rootId, skipPrepend, avatarSize = 46 } = this.props;
const { intl, hidden, featured, unfocusable, unread, showThread, isQuotedPost = false, scrollKey, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46, children } = this.props;
let { status, account, ...other } = this.props;
@ -543,7 +542,7 @@ class Status extends ImmutablePureComponent {
</Bundle>
);
}
} else if (status.get('card') && !this.props.muted) {
} else if (status.get('card') && !status.get('quote') && !this.props.muted) {
media = (
<Card
onOpenMedia={this.handleOpenMedia}
@ -577,17 +576,29 @@ class Status extends ImmutablePureComponent {
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility_ex')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted || unfocusable ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
{!skipPrepend && prepend}
<div className={classNames('status', `status-${status.get('visibility_ex')}`, { 'status-reply': !!status.get('in_reply_to_id'), 'status--in-thread': !!rootId, 'status--first-in-thread': previousId && (!connectUp || connectToRoot), muted: this.props.muted })} data-id={status.get('id')}>
<div
className={
classNames('status', `status-${status.get('visibility_ex')}`,
{
'status-reply': !!status.get('in_reply_to_id'),
'status--in-thread': !!rootId,
'status--first-in-thread': previousId && (!connectUp || connectToRoot), muted: this.props.muted,
'status--is-quote': isQuotedPost,
'status--has-quote': !!status.get('quote'),
})
}
data-id={status.get('id')}
>
{(connectReply || connectUp || connectToRoot) && <div className={classNames('status__line', { 'status__line--full': connectReply, 'status__line--first': !status.get('in_reply_to_id') && !connectToRoot })} />}
{(!matchedFilters || expanded || isShowItem('avatar_on_filter')) && (
<div onMouseUp={this.handleMouseUp} className='status__info'>
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time'>
{withReference}
{withExpiration}
{withLimited}
<span className='status__visibility-icon'><VisibilityIcon visibility={visibilityName} /></span>
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
</Link>
<div onClick={this.handleHeaderClick} onAuxClick={this.handleHeaderClick} className='status__info'>
<Link to={`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`} className='status__relative-time'>
{withReference}
{withExpiration}
{withLimited}
<span className='status__visibility-icon'><VisibilityIcon visibility={status.get('visibility_ex')} /></span>
<RelativeTimestamp timestamp={status.get('created_at')} />{status.get('edited_at') && <abbr title={intl.formatMessage(messages.edited, { date: intl.formatDate(status.get('edited_at'), { year: 'numeric', month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) })}> *</abbr>}
</Link>
<Link to={`/@${status.getIn(['account', 'acct'])}`} title={status.getIn(['account', 'acct'])} data-hover-card-account={status.getIn(['account', 'id'])} className='status__display-name'>
<div className='status__avatar'>
@ -614,13 +625,17 @@ class Status extends ImmutablePureComponent {
{...statusContentProps}
/>
{children}
{media}
{hashtagBar}
{emojiReactionsBar}
</>
)}
{(!matchedFilters || this.state.showDespiteFilter) && <StatusActionBar scrollKey={scrollKey} status={status} account={account} {...other} />}
{!isQuotedPost && (!matchedFilters || this.state.showDespiteFilter) &&
<StatusActionBar scrollKey={scrollKey} status={status} account={account} {...other} />
}
</div>
</div>
</HotKeys>

View file

@ -9,7 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg';
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';

View file

@ -9,7 +9,7 @@ import { TIMELINE_GAP, TIMELINE_SUGGESTIONS } from 'mastodon/actions/timelines';
import { RegenerationIndicator } from 'mastodon/components/regeneration_indicator';
import { InlineFollowSuggestions } from 'mastodon/features/home_timeline/components/inline_follow_suggestions';
import StatusContainer from '../containers/status_container';
import { StatusQuoteManager } from '../components/status_quoted';
import { LoadGap } from './load_gap';
import ScrollableList from './scrollable_list';
@ -113,7 +113,7 @@ export default class StatusList extends ImmutablePureComponent {
);
default:
return (
<StatusContainer
<StatusQuoteManager
key={statusId}
id={statusId}
onMoveUp={this.handleMoveUp}
@ -130,7 +130,7 @@ export default class StatusList extends ImmutablePureComponent {
if (scrollableContent && featuredStatusIds) {
scrollableContent = featuredStatusIds.map(statusId => (
<StatusContainer
<StatusQuoteManager
key={`f-${statusId}`}
id={statusId}
featured

View file

@ -0,0 +1,208 @@
import { useMemo } from 'react';
import { FormattedMessage } from 'react-intl';
import classNames from 'classnames';
import { Link } from 'react-router-dom';
import type { Map as ImmutableMap } from 'immutable';
import ArticleIcon from '@/material-icons/400-24px/article.svg?react';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'mastodon/components/icon';
import StatusContainer from 'mastodon/containers/status_container';
import type { Status } from 'mastodon/models/status';
import type { RootState } from 'mastodon/store';
import { useAppSelector } from 'mastodon/store';
import QuoteIcon from '../../images/quote.svg?react';
import { makeGetStatus } from '../selectors';
const MAX_QUOTE_POSTS_NESTING_LEVEL = 1;
const QuoteWrapper: React.FC<{
isError?: boolean;
children: React.ReactElement;
}> = ({ isError, children }) => {
return (
<div
className={classNames('status__quote', {
'status__quote--error': isError,
})}
>
<Icon id='quote' icon={QuoteIcon} className='status__quote-icon' />
{children}
</div>
);
};
const QuoteLink: React.FC<{
status: Status;
}> = ({ status }) => {
const accountId = status.get('account') as string;
const account = useAppSelector((state) =>
accountId ? state.accounts.get(accountId) : undefined,
);
const quoteAuthorName = account?.display_name_html;
if (!quoteAuthorName) {
return null;
}
const quoteAuthorElement = (
<span dangerouslySetInnerHTML={{ __html: quoteAuthorName }} />
);
const quoteUrl = `/@${account.get('acct')}/${status.get('id') as string}`;
return (
<Link to={quoteUrl} className='status__quote-author-button'>
<FormattedMessage
id='status.quote_post_author'
defaultMessage='Post by {name}'
values={{ name: quoteAuthorElement }}
/>
<Icon id='chevron_right' icon={ChevronRightIcon} />
<Icon id='article' icon={ArticleIcon} />
</Link>
);
};
type QuoteMap = ImmutableMap<'state' | 'quoted_status', string | null>;
type GetStatusSelector = (
state: RootState,
props: { id?: string | null; contextType?: string },
) => Status | null;
export const QuotedStatus: React.FC<{
quote: QuoteMap;
contextType?: string;
variant?: 'full' | 'link';
nestingLevel?: number;
}> = ({ quote, contextType, nestingLevel = 1, variant = 'full' }) => {
const quotedStatusId = quote.get('quoted_status');
const quoteState = quote.get('state');
const status = useAppSelector((state) =>
quotedStatusId ? state.statuses.get(quotedStatusId) : undefined,
);
let quoteError: React.ReactNode = null;
// In order to find out whether the quoted post should be completely hidden
// due to a matching filter, we run it through the selector used by `status_container`.
// If this returns null even though `status` exists, it's because it's filtered.
const getStatus = useMemo(() => makeGetStatus(), []) as GetStatusSelector;
const statusWithExtraData = useAppSelector((state) =>
getStatus(state, { id: quotedStatusId, contextType }),
);
const isFilteredAndHidden = status && statusWithExtraData === null;
if (isFilteredAndHidden) {
quoteError = (
<FormattedMessage
id='status.quote_error.filtered'
defaultMessage='Hidden due to one of your filters'
/>
);
} else if (quoteState === 'deleted') {
quoteError = (
<FormattedMessage
id='status.quote_error.removed'
defaultMessage='This post was removed by its author.'
/>
);
} else if (quoteState === 'unauthorized') {
quoteError = (
<FormattedMessage
id='status.quote_error.unauthorized'
defaultMessage='This post cannot be displayed as you are not authorized to view it.'
/>
);
} else if (quoteState === 'pending') {
quoteError = (
<FormattedMessage
id='status.quote_error.pending_approval'
defaultMessage='This post is pending approval from the original author.'
/>
);
} else if (quoteState === 'rejected' || quoteState === 'revoked') {
quoteError = (
<FormattedMessage
id='status.quote_error.rejected'
defaultMessage='This post cannot be displayed as the original author does not allow it to be quoted.'
/>
);
} else if (!status || !quotedStatusId) {
quoteError = (
<FormattedMessage
id='status.quote_error.not_found'
defaultMessage='This post cannot be displayed.'
/>
);
}
if (quoteError) {
return <QuoteWrapper isError>{quoteError}</QuoteWrapper>;
}
if (variant === 'link' && status) {
return <QuoteLink status={status} />;
}
const childQuote = status?.get('quote') as QuoteMap | undefined;
const canRenderChildQuote =
childQuote && nestingLevel <= MAX_QUOTE_POSTS_NESTING_LEVEL;
return (
<QuoteWrapper>
{/* @ts-expect-error Status is not yet typed */}
<StatusContainer
isQuotedPost
id={quotedStatusId}
contextType={contextType}
avatarSize={40}
>
{canRenderChildQuote && (
<QuotedStatus
quote={childQuote}
contextType={contextType}
variant={
nestingLevel === MAX_QUOTE_POSTS_NESTING_LEVEL ? 'link' : 'full'
}
nestingLevel={nestingLevel + 1}
/>
)}
</StatusContainer>
</QuoteWrapper>
);
};
interface StatusQuoteManagerProps {
id: string;
contextType?: string;
[key: string]: unknown;
}
/**
* This wrapper component takes a status ID and, if the associated status
* is a quote post, it renders the quote into `StatusContainer` as a child.
* It passes all other props through to `StatusContainer`.
*/
export const StatusQuoteManager = (props: StatusQuoteManagerProps) => {
const status = useAppSelector((state) => {
const status = state.statuses.get(props.id);
const reblogId = status?.get('reblog') as string | undefined;
return reblogId ? state.statuses.get(reblogId) : status;
});
const quote = status?.get('quote') as QuoteMap | undefined;
if (quote) {
return (
<StatusContainer {...props}>
<QuotedStatus quote={quote} contextType={props.contextType} />
</StatusContainer>
);
}
return <StatusContainer {...props} />;
};

View file

@ -61,6 +61,7 @@ const severityMessages = {
const mapStateToProps = state => ({
server: state.getIn(['server', 'server']),
locale: state.getIn(['meta', 'locale']),
extendedDescription: state.getIn(['server', 'extendedDescription']),
domainBlocks: state.getIn(['server', 'domainBlocks']),
});
@ -130,6 +131,7 @@ class About extends PureComponent {
static propTypes = {
server: ImmutablePropTypes.map,
locale: ImmutablePropTypes.string,
extendedDescription: ImmutablePropTypes.map,
domainBlocks: ImmutablePropTypes.contains({
isLoading: PropTypes.bool,
@ -153,7 +155,7 @@ class About extends PureComponent {
};
render () {
const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props;
const { multiColumn, intl, server, extendedDescription, domainBlocks, locale } = this.props;
const isLoading = server.get('isLoading');
const fedibirdCapabilities = server.get('fedibird_capabilities') || []; // thinking about isLoading is true
@ -218,12 +220,15 @@ class About extends PureComponent {
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
) : (
<ol className='rules-list'>
{server.get('rules').map(rule => (
<li key={rule.get('id')}>
<div className='rules-list__text'>{rule.get('text')}</div>
{rule.get('hint').length > 0 && (<div className='rules-list__hint'>{rule.get('hint')}</div>)}
</li>
))}
{server.get('rules').map(rule => {
const text = rule.getIn(['translations', locale, 'text']) || rule.getIn(['translations', locale.split('-')[0], 'text']) || rule.get('text');
const hint = rule.getIn(['translations', locale, 'hint']) || rule.getIn(['translations', locale.split('-')[0], 'hint']) || rule.get('hint');
return (
<li key={rule.get('id')}>
<div className='rules-list__text'>{text}</div>
{hint.length > 0 && (<div className='rules-list__hint'>{hint}</div>)}
</li>
)})}
</ol>
))}
</Section>

View file

@ -29,7 +29,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
message = (
<FormattedMessage
id='empty_column.account_featured.me'
defaultMessage='You have not featured anything yet. Did you know that you can feature your posts, hashtags you use the most, and even your friends accounts on your profile?'
defaultMessage='You have not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friends accounts on your profile?'
/>
);
} else if (suspended) {
@ -52,7 +52,7 @@ export const EmptyMessage: React.FC<EmptyMessageProps> = ({
message = (
<FormattedMessage
id='empty_column.account_featured.other'
defaultMessage='{acct} has not featured anything yet. Did you know that you can feature your posts, hashtags you use the most, and even your friends accounts on your profile?'
defaultMessage='{acct} has not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friends accounts on your profile?'
values={{ acct }}
/>
);

View file

@ -4,17 +4,14 @@ import { FormattedMessage } from 'react-intl';
import { useParams } from 'react-router';
import type { Map as ImmutableMap } from 'immutable';
import { List as ImmutableList } from 'immutable';
import { fetchEndorsedAccounts } from 'mastodon/actions/accounts';
import { fetchFeaturedTags } from 'mastodon/actions/featured_tags';
import { expandAccountFeaturedTimeline } from 'mastodon/actions/timelines';
import { Account } from 'mastodon/components/account';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { RemoteHint } from 'mastodon/components/remote_hint';
import StatusContainer from 'mastodon/containers/status_container';
import { AccountHeader } from 'mastodon/features/account_timeline/components/account_header';
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
import Column from 'mastodon/features/ui/components/column';
@ -43,7 +40,6 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
useEffect(() => {
if (accountId) {
void dispatch(expandAccountFeaturedTimeline(accountId));
void dispatch(fetchFeaturedTags({ accountId }));
void dispatch(fetchEndorsedAccounts({ accountId }));
}
@ -52,10 +48,6 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
const isLoading = useAppSelector(
(state) =>
!accountId ||
!!(state.timelines as ImmutableMap<string, unknown>).getIn([
`account:${accountId}:pinned`,
'isLoading',
]) ||
!!state.user_lists.getIn(['featured_tags', accountId, 'isLoading']),
);
const featuredTags = useAppSelector(
@ -65,13 +57,6 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
ImmutableList(),
) as ImmutableList<TagMap>,
);
const featuredStatusIds = useAppSelector(
(state) =>
(state.timelines as ImmutableMap<string, unknown>).getIn(
[`account:${accountId}:pinned`, 'items'],
ImmutableList(),
) as ImmutableList<string>,
);
const featuredAccountIds = useAppSelector(
(state) =>
state.user_lists.getIn(
@ -94,11 +79,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
);
}
if (
featuredStatusIds.isEmpty() &&
featuredTags.isEmpty() &&
featuredAccountIds.isEmpty()
) {
if (featuredTags.isEmpty() && featuredAccountIds.isEmpty()) {
return (
<AccountFeaturedWrapper accountId={accountId}>
<EmptyMessage
@ -133,24 +114,6 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
))}
</>
)}
{!featuredStatusIds.isEmpty() && (
<>
<h4 className='column-subheading'>
<FormattedMessage
id='account.featured.posts'
defaultMessage='Posts'
/>
</h4>
{featuredStatusIds.map((statusId) => (
<StatusContainer
key={`f-${statusId}`}
// @ts-expect-error inferred props are wrong
id={statusId}
contextType='account'
/>
))}
</>
)}
{!featuredAccountIds.isEmpty() && (
<>
<h4 className='column-subheading'>

View file

@ -67,6 +67,7 @@ import {
import { getAccountHidden } from 'mastodon/selectors/accounts';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { FamiliarFollowers } from './familiar_followers';
import { MemorialNote } from './memorial_note';
import { MovedNote } from './moved_note';
@ -1007,6 +1008,10 @@ export const AccountHeader: React.FC<{
<div className='account__header__badges'>{badges}</div>
)}
{account.id !== me && signedIn && (
<FamiliarFollowers accountId={accountId} />
)}
{!(suspended || hidden) && (
<div className='account__header__extra'>
<div

View file

@ -0,0 +1,82 @@
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { Avatar } from '@/mastodon/components/avatar';
import { AvatarGroup } from '@/mastodon/components/avatar_group';
import type { Account } from '@/mastodon/models/account';
import { useFetchFamiliarFollowers } from '../hooks/familiar_followers';
const AccountLink: React.FC<{ account?: Account }> = ({ account }) => {
if (!account) {
return null;
}
return (
<Link
to={`/@${account.acct}`}
data-hover-card-account={account.id}
dangerouslySetInnerHTML={{ __html: account.display_name_html }}
/>
);
};
const FamiliarFollowersReadout: React.FC<{ familiarFollowers: Account[] }> = ({
familiarFollowers,
}) => {
const messageData = {
name1: <AccountLink account={familiarFollowers.at(0)} />,
name2: <AccountLink account={familiarFollowers.at(1)} />,
othersCount: familiarFollowers.length - 2,
};
if (familiarFollowers.length === 1) {
return (
<FormattedMessage
id='account.familiar_followers_one'
defaultMessage='Followed by {name1}'
values={messageData}
/>
);
} else if (familiarFollowers.length === 2) {
return (
<FormattedMessage
id='account.familiar_followers_two'
defaultMessage='Followed by {name1} and {name2}'
values={messageData}
/>
);
} else {
return (
<FormattedMessage
id='account.familiar_followers_many'
defaultMessage='Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}'
values={messageData}
/>
);
}
};
export const FamiliarFollowers: React.FC<{ accountId: string }> = ({
accountId,
}) => {
const { familiarFollowers, isLoading } = useFetchFamiliarFollowers({
accountId,
});
if (isLoading || familiarFollowers.length === 0) {
return null;
}
return (
<div className='account__header__familiar-followers'>
<AvatarGroup compact>
{familiarFollowers.slice(0, 3).map((account) => (
<Avatar withLink key={account.id} account={account} size={28} />
))}
</AvatarGroup>
<FamiliarFollowersReadout familiarFollowers={familiarFollowers} />
</div>
);
};

View file

@ -0,0 +1,30 @@
import { useEffect } from 'react';
import { fetchAccountsFamiliarFollowers } from '@/mastodon/actions/accounts_familiar_followers';
import { getAccountFamiliarFollowers } from '@/mastodon/selectors/accounts';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { me } from 'mastodon/initial_state';
export const useFetchFamiliarFollowers = ({
accountId,
}: {
accountId?: string;
}) => {
const dispatch = useAppDispatch();
const familiarFollowers = useAppSelector((state) =>
accountId ? getAccountFamiliarFollowers(state, accountId) : null,
);
const hasNoData = familiarFollowers === null;
useEffect(() => {
if (hasNoData && accountId && accountId !== me) {
void dispatch(fetchAccountsFamiliarFollowers({ id: accountId }));
}
}, [dispatch, accountId, hasNoData]);
return {
familiarFollowers: hasNoData ? [] : familiarFollowers,
isLoading: hasNoData,
};
};

View file

@ -23,6 +23,7 @@ import { RemoteHint } from 'mastodon/components/remote_hint';
import { AccountHeader } from './components/account_header';
import { LimitedAccountHint } from './components/limited_account_hint';
import { fetchFeaturedTags } from 'mastodon/actions/featured_tags';
import { FeaturedCarousel } from '@/mastodon/components/featured_carousel';
const emptyList = ImmutableList();
@ -171,7 +172,12 @@ class AccountTimeline extends ImmutablePureComponent {
<ColumnBackButton />
<StatusList
prepend={<AccountHeader accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />}
prepend={
<>
<AccountHeader accountId={this.props.accountId} hideTabs={forceEmptyState} tagged={this.props.params.tagged} />
<FeaturedCarousel accountId={this.props.accountId} />
</>
}
alwaysPrepend
append={<RemoteHint accountId={accountId} />}
scrollKey='account_timeline'

View file

@ -15,10 +15,6 @@ import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
import { useSpring, animated } from '@react-spring/web';
import Textarea from 'react-textarea-autosize';
import { length } from 'stringz';
// eslint-disable-next-line import/extensions
import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
// eslint-disable-next-line import/no-extraneous-dependencies
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
import { showAlertForError } from 'mastodon/actions/alerts';
import { uploadThumbnail } from 'mastodon/actions/compose';
@ -350,9 +346,15 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
fetchTesseract()
.then(async ({ createWorker }) => {
const [tesseractWorkerPath, tesseractCorePath] = await Promise.all([
// eslint-disable-next-line import/extensions
import('tesseract.js/dist/worker.min.js?url'),
// eslint-disable-next-line import/no-extraneous-dependencies
import('tesseract.js-core/tesseract-core.wasm.js?url'),
]);
const worker = await createWorker('eng', 1, {
workerPath: tesseractWorkerPath as string,
corePath: tesseractCorePath as string,
workerPath: tesseractWorkerPath.default,
corePath: tesseractCorePath.default,
langPath: `${assetHost}/ocr/lang-data`,
cacheMethod: 'write',
});
@ -501,5 +503,4 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
);
},
);
AltTextModal.displayName = 'AltTextModal';

View file

@ -12,14 +12,10 @@ import Overlay from 'react-overlays/Overlay';
import MoodIcon from '@/material-icons/400-20px/mood.svg?react';
import { IconButton } from 'mastodon/components/icon_button';
import emojiCompressed from 'mastodon/features/emoji/emoji_compressed';
import { assetHost } from 'mastodon/utils/config';
import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji';
import { EmojiPicker as EmojiPickerAsync } from '../../ui/util/async-components';
const nimblePickerData = emojiCompressed[5];
const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
emoji_search: { id: 'emoji_button.search', defaultMessage: 'Search...' },
@ -40,19 +36,11 @@ let EmojiPicker, Emoji; // load asynchronously
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
const backgroundImageFn = () => `${assetHost}/emoji/sheet_15_1.png`;
const notFoundFn = () => (
<div className='emoji-mart-no-results'>
<Emoji
data={nimblePickerData}
emoji='sleuth_or_spy'
set='twitter'
size={32}
sheetSize={32}
sheetColumns={62}
sheetRows={62}
backgroundImageFn={backgroundImageFn}
/>
<div className='emoji-mart-no-results-label'>
@ -110,12 +98,12 @@ class ModifierPickerMenu extends PureComponent {
return (
<div className='emoji-picker-dropdown__modifiers__menu' style={{ display: active ? 'block' : 'none' }} ref={this.setRef}>
<button type='button' onClick={this.handleClick} data-index={1}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={1} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={2}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={2} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={3}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={3} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={4}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={4} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={5}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={5} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={6}><Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={6} backgroundImageFn={backgroundImageFn} /></button>
<button type='button' onClick={this.handleClick} data-index={1}><Emoji emoji='fist' size={22} skin={1} /></button>
<button type='button' onClick={this.handleClick} data-index={2}><Emoji emoji='fist' size={22} skin={2} /></button>
<button type='button' onClick={this.handleClick} data-index={3}><Emoji emoji='fist' size={22} skin={3} /></button>
<button type='button' onClick={this.handleClick} data-index={4}><Emoji emoji='fist' size={22} skin={4} /></button>
<button type='button' onClick={this.handleClick} data-index={5}><Emoji emoji='fist' size={22} skin={5} /></button>
<button type='button' onClick={this.handleClick} data-index={6}><Emoji emoji='fist' size={22} skin={6} /></button>
</div>
);
}
@ -150,7 +138,7 @@ class ModifierPicker extends PureComponent {
return (
<div className='emoji-picker-dropdown__modifiers'>
<Emoji data={nimblePickerData} sheetColumns={62} sheetRows={62} emoji='fist' set='twitter' size={22} sheetSize={32} skin={modifier} onClick={this.handleClick} backgroundImageFn={backgroundImageFn} />
<Emoji emoji='fist' size={22} skin={modifier} onClick={this.handleClick} />
<ModifierPickerMenu active={active} onSelect={this.handleSelect} onClose={this.props.onClose} />
</div>
);
@ -286,16 +274,11 @@ class EmojiPickerMenuImpl extends PureComponent {
return (
<div className={classNames('emoji-picker-dropdown__menu', { selecting: modifierOpen })} style={style} ref={this.setRef}>
<EmojiPicker
data={nimblePickerData}
sheetColumns={62}
sheetRows={62}
perLine={8}
emojiSize={22}
sheetSize={32}
custom={buildCustomEmojis(custom_emojis)}
color=''
emoji=''
set='twitter'
title={title}
i18n={this.getI18n()}
onClick={this.handleClick}
@ -304,7 +287,6 @@ class EmojiPickerMenuImpl extends PureComponent {
skin={skinTone}
showPreview={false}
showSkinTones={false}
backgroundImageFn={backgroundImageFn}
notFound={notFoundFn}
autoFocus={this.state.readyToFocus}
emojiTooltip

View file

@ -45,7 +45,6 @@ type EmojiCompressed = [
Category[],
Data['aliases'],
EmojisWithoutShortCodes,
Data,
];
/*

View file

@ -9,28 +9,27 @@
// to ensure that the prevaled file is regenerated by Babel
// version: 4
const { NimbleEmojiIndex } = require('emoji-mart');
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
import { NimbleEmojiIndex } from 'emoji-mart';
import { uncompress as emojiMartUncompress } from 'emoji-mart/dist/utils/data';
let data = require('./emoji_data.json');
const emojiMap = require('./emoji_map.json');
const { unicodeToFilename } = require('./unicode_to_filename_s');
const { unicodeToUnifiedName } = require('./unicode_to_unified_name_s');
import data from './emoji_data.json';
import emojiMap from './emoji_map.json';
import { unicodeToFilename } from './unicode_to_filename_s';
import { unicodeToUnifiedName } from './unicode_to_unified_name_s';
emojiMartUncompress(data);
const emojiMartData = data;
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
const excluded = ['®', '©', '™'];
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
const shortcodeMap = {};
const excluded = ['®', '©', '™'];
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
const shortcodeMap = {};
const shortCodesToEmojiData = {};
const emojisWithoutShortCodes = [];
Object.keys(emojiIndex.emojis).forEach(key => {
Object.keys(emojiIndex.emojis).forEach((key) => {
let emoji = emojiIndex.emojis[key];
// Emojis with skin tone modifiers are stored like this
@ -41,22 +40,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
shortcodeMap[emoji.native] = emoji.id;
});
const stripModifiers = unicode => {
skinTones.forEach(tone => {
const stripModifiers = (unicode) => {
skinTones.forEach((tone) => {
unicode = unicode.replace(tone, '');
});
return unicode;
};
Object.keys(emojiMap).forEach(key => {
Object.keys(emojiMap).forEach((key) => {
if (excluded.includes(key)) {
delete emojiMap[key];
return;
}
const normalizedKey = stripModifiers(key);
let shortcode = shortcodeMap[normalizedKey];
let shortcode = shortcodeMap[normalizedKey];
if (!shortcode) {
shortcode = shortcodeMap[normalizedKey + '\uFE0F'];
@ -82,7 +81,7 @@ Object.keys(emojiMap).forEach(key => {
}
});
Object.keys(emojiIndex.emojis).forEach(key => {
Object.keys(emojiIndex.emojis).forEach((key) => {
let emoji = emojiIndex.emojis[key];
// Emojis with skin tone modifiers are stored like this
@ -94,9 +93,11 @@ Object.keys(emojiIndex.emojis).forEach(key => {
let { short_names, search, unified } = emojiMartData.emojis[key];
if (short_names[0] !== key) {
throw new Error('The compressor expects the first short_code to be the ' +
'key. It may need to be rewritten if the emoji change such that this ' +
'is no longer the case.');
throw new Error(
'The compressor expects the first short_code to be the ' +
'key. It may need to be rewritten if the emoji change such that this ' +
'is no longer the case.',
);
}
short_names = short_names.slice(1); // first short name can be inferred from the key
@ -117,21 +118,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
// JSON.parse/stringify is to emulate what @preval is doing and avoid any
// inconsistent behavior in dev mode
module.exports = JSON.parse(JSON.stringify([
shortCodesToEmojiData,
/*
* The property `skins` is not found in the current context.
* This could potentially lead to issues when interacting with modules or data structures
* that expect the presence of `skins` property.
* Currently, no definitions or references to `skins` property can be found in:
* - {@link node_modules/emoji-mart/dist/utils/data.js}
* - {@link node_modules/emoji-mart/data/all.json}
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
*/
emojiMartData.skins,
emojiMartData.categories,
emojiMartData.aliases,
emojisWithoutShortCodes,
emojiMartData
]));
export default JSON.parse(
JSON.stringify([
shortCodesToEmojiData,
/*
* The property `skins` is not found in the current context.
* This could potentially lead to issues when interacting with modules or data structures
* that expect the presence of `skins` property.
* Currently, no definitions or references to `skins` property can be found in:
* - {@link node_modules/emoji-mart/dist/utils/data.js}
* - {@link node_modules/emoji-mart/data/all.json}
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
*/
emojiMartData.skins,
emojiMartData.categories,
emojiMartData.aliases,
emojisWithoutShortCodes,
]),
);

View file

@ -3,9 +3,13 @@
// emojiIndex.search functionality.
import type { BaseEmoji } from 'emoji-mart';
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
// eslint-disable-next-line import/no-unresolved
import emojiCompressed from 'virtual:mastodon-emoji-compressed';
import type {
Search,
ShortCodesToEmojiData,
} from 'virtual:mastodon-emoji-compressed';
import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
import emojiCompressed from './emoji_compressed';
import { unicodeToUnifiedName } from './unicode_to_unified_name';
type Emojis = Record<

View file

@ -1,7 +0,0 @@
import Emoji from 'emoji-mart/dist-es/components/emoji/nimble-emoji';
import Picker from 'emoji-mart/dist-es/components/picker/nimble-picker';
export {
Picker,
Emoji,
};

View file

@ -0,0 +1,53 @@
import type { EmojiProps, PickerProps } from 'emoji-mart';
import EmojiRaw from 'emoji-mart/dist-es/components/emoji/nimble-emoji';
import PickerRaw from 'emoji-mart/dist-es/components/picker/nimble-picker';
import { assetHost } from 'mastodon/utils/config';
import EmojiData from './emoji_data.json';
const backgroundImageFnDefault = () => `${assetHost}/emoji/sheet_15_1.png`;
const Emoji = ({
set = 'twitter',
sheetSize = 32,
sheetColumns = 62,
sheetRows = 62,
backgroundImageFn = backgroundImageFnDefault,
...props
}: EmojiProps) => {
return (
<EmojiRaw
data={EmojiData}
set={set}
sheetSize={sheetSize}
sheetColumns={sheetColumns}
sheetRows={sheetRows}
backgroundImageFn={backgroundImageFn}
{...props}
/>
);
};
const Picker = ({
set = 'twitter',
sheetSize = 32,
sheetColumns = 62,
sheetRows = 62,
backgroundImageFn = backgroundImageFnDefault,
...props
}: PickerProps) => {
return (
<PickerRaw
data={EmojiData}
set={set}
sheetSize={sheetSize}
sheetColumns={sheetColumns}
sheetRows={sheetRows}
backgroundImageFn={backgroundImageFn}
{...props}
/>
);
};
export { Picker, Emoji };

View file

@ -2,11 +2,13 @@
// (i.e. the svg filename) and a shortCode intended to be shown
// as a "title" attribute in an HTML element (aka tooltip).
// eslint-disable-next-line import/no-unresolved
import emojiCompressed from 'virtual:mastodon-emoji-compressed';
import type {
FilenameData,
ShortCodesToEmojiDataKey,
} from './emoji_compressed';
import emojiCompressed from './emoji_compressed';
} from 'virtual:mastodon-emoji-compressed';
import { unicodeToFilename } from './unicode_to_filename';
type UnicodeMapping = Record<

View file

@ -1,7 +1,6 @@
// taken from:
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
// eslint-disable-next-line import/no-commonjs, no-undef
exports.unicodeToFilename = (str) => {
export const unicodeToFilename = (str) => {
let result = '';
let charCode = 0;
let p = 0;

View file

@ -6,8 +6,7 @@ function padLeft(str, num) {
return str;
}
// eslint-disable-next-line import/no-commonjs, no-undef
exports.unicodeToUnifiedName = (str) => {
export const unicodeToUnifiedName = (str) => {
let output = '';
for (let i = 0; i < str.length; i += 2) {

View file

@ -35,8 +35,11 @@ import { VerifiedBadge } from 'mastodon/components/verified_badge';
import { me } from 'mastodon/initial_state';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
const messages = defineMessages({
heading: { id: 'column.list_members', defaultMessage: 'Manage list members' },
export const messages = defineMessages({
manageMembers: {
id: 'column.list_members',
defaultMessage: 'Manage list members',
},
placeholder: {
id: 'lists.search',
defaultMessage: 'Search',
@ -256,10 +259,10 @@ const ListMembers: React.FC<{
return (
<Column
bindToDocument={!multiColumn}
label={intl.formatMessage(messages.heading)}
label={intl.formatMessage(messages.manageMembers)}
>
<ColumnHeader
title={intl.formatMessage(messages.heading)}
title={intl.formatMessage(messages.manageMembers)}
icon='list-ul'
iconComponent={ListAltIcon}
multiColumn={multiColumn}
@ -332,7 +335,7 @@ const ListMembers: React.FC<{
</ScrollableList>
<Helmet>
<title>{intl.formatMessage(messages.heading)}</title>
<title>{intl.formatMessage(messages.manageMembers)}</title>
<meta name='robots' content='noindex' />
</Helmet>
</Column>

View file

@ -9,16 +9,23 @@ import { isFulfilled } from '@reduxjs/toolkit';
import Toggle from 'react-toggle';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import { fetchList } from 'mastodon/actions/lists';
import { createList, updateList } from 'mastodon/actions/lists_typed';
import { apiGetAccounts } from 'mastodon/api/lists';
import type { ApiAccountJSON } from 'mastodon/api_types/accounts';
import type { RepliesPolicyType } from 'mastodon/api_types/lists';
import { Avatar } from 'mastodon/components/avatar';
import { AvatarGroup } from 'mastodon/components/avatar_group';
import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { messages as membersMessages } from './members';
const messages = defineMessages({
edit: { id: 'column.edit_list', defaultMessage: 'Edit list' },
create: { id: 'column.create_list', defaultMessage: 'Create list' },
@ -27,42 +34,40 @@ const messages = defineMessages({
const MembersLink: React.FC<{
id: string;
}> = ({ id }) => {
const [count, setCount] = useState(0);
const [avatars, setAvatars] = useState<string[]>([]);
const intl = useIntl();
const [avatarCount, setAvatarCount] = useState(0);
const [avatarAccounts, setAvatarAccounts] = useState<ApiAccountJSON[]>([]);
useEffect(() => {
void apiGetAccounts(id)
.then((data) => {
setCount(data.length);
setAvatars(data.slice(0, 3).map((a) => a.avatar));
return '';
setAvatarCount(data.length);
setAvatarAccounts(data.slice(0, 3));
})
.catch(() => {
// Nothing
});
}, [id, setCount, setAvatars]);
}, [id]);
return (
<Link to={`/lists/${id}/members`} className='app-form__link'>
<div className='app-form__link__text'>
<strong>
<FormattedMessage
id='lists.list_members'
defaultMessage='List members'
/>
{intl.formatMessage(membersMessages.manageMembers)}
<Icon id='chevron_right' icon={ChevronRightIcon} />
</strong>
<FormattedMessage
id='lists.list_members_count'
defaultMessage='{count, plural, one {# member} other {# members}}'
values={{ count }}
values={{ count: avatarCount }}
/>
</div>
<div className='avatar-pile'>
{avatars.map((url) => (
<img key={url} src={url} alt='' />
<AvatarGroup compact>
{avatarAccounts.map((a) => (
<Avatar key={a.id} account={a} size={30} />
))}
</div>
</AvatarGroup>
</Link>
);
};

View file

@ -23,7 +23,7 @@ import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
import { Account } from 'mastodon/components/account';
import EmojiView from 'mastodon/components/emoji_view';
import { Icon } from 'mastodon/components/icon';
import StatusContainer from 'mastodon/containers/status_container';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { me } from 'mastodon/initial_state';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
@ -181,7 +181,7 @@ class Notification extends ImmutablePureComponent {
renderMention (notification) {
return (
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
withDismiss
hidden={this.props.hidden}
@ -211,7 +211,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
account={notification.get('account')}
muted
@ -276,7 +276,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
account={notification.get('account')}
muted
@ -345,7 +345,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
contextType='notifications'
muted
@ -415,7 +415,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
account={notification.get('account')}
contextType='notifications'
@ -457,7 +457,7 @@ class Notification extends ImmutablePureComponent {
</span>
</div>
<StatusContainer
<StatusQuoteManager
id={notification.get('status')}
account={account}
contextType='notifications'

View file

@ -1,31 +0,0 @@
import { Link } from 'react-router-dom';
import { Avatar } from 'mastodon/components/avatar';
import { NOTIFICATIONS_GROUP_MAX_AVATARS } from 'mastodon/models/notification_group';
import { useAppSelector } from 'mastodon/store';
const AvatarWrapper: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((state) => state.accounts.get(accountId));
if (!account) return null;
return (
<Link
to={`/@${account.acct}`}
title={`@${account.acct}`}
data-hover-card-account={account.id}
>
<Avatar account={account} size={28} />
</Link>
);
};
export const AvatarGroup: React.FC<{ accountIds: string[] }> = ({
accountIds,
}) => (
<div className='notification-group__avatar-group'>
{accountIds.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS).map((accountId) => (
<AvatarWrapper key={accountId} accountId={accountId} />
))}
</div>
);

View file

@ -7,17 +7,29 @@ import { HotKeys } from 'react-hotkeys';
import { replyComposeById } from 'mastodon/actions/compose';
import { navigateToStatus } from 'mastodon/actions/statuses';
import { Avatar } from 'mastodon/components/avatar';
import { AvatarGroup } from 'mastodon/components/avatar_group';
import EmojiView from 'mastodon/components/emoji_view';
import type { EmojiReactionGroup } from 'mastodon/models/notification_group';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
import type { EmojiReactionGroup } from 'mastodon/models/notification_group';
import { NOTIFICATIONS_GROUP_MAX_AVATARS } from 'mastodon/models/notification_group';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { AvatarGroup } from './avatar_group';
import { DisplayedName } from './displayed_name';
import { EmbeddedStatus } from './embedded_status';
const AVATAR_SIZE = 28;
export const AvatarById: React.FC<{ accountId: string }> = ({ accountId }) => {
const account = useAppSelector((state) => state.accounts.get(accountId));
if (!account) return null;
return <Avatar withLink account={account} size={AVATAR_SIZE} />;
};
export type LabelRenderer = (
displayedName: JSX.Element,
total: number,
@ -109,7 +121,13 @@ export const NotificationGroupWithStatus: React.FC<{
url={group.emoji.url}
staticUrl={group.emoji.static_url}
/>
<AvatarGroup accountIds={group.sampleAccountIds} />
<AvatarGroup avatarHeight={AVATAR_SIZE}>
{group.sampleAccountIds
.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS)
.map((id) => (
<AvatarById key={id} accountId={id} />
))}
</AvatarGroup>
{actions && (
<div className='notification-group__actions'>{actions}</div>
@ -120,7 +138,13 @@ export const NotificationGroupWithStatus: React.FC<{
{!emojiReactionGroups && (
<div className='notification-group__main__header__wrapper'>
<AvatarGroup accountIds={accountIds} />
<AvatarGroup avatarHeight={AVATAR_SIZE}>
{accountIds
.slice(0, NOTIFICATIONS_GROUP_MAX_AVATARS)
.map((id) => (
<AvatarById key={id} accountId={id} />
))}
</AvatarGroup>
{actions && (
<div className='notification-group__actions'>{actions}</div>
@ -130,7 +154,14 @@ export const NotificationGroupWithStatus: React.FC<{
<div className='notification-group__main__header__label'>
{label}
{timestamp && <RelativeTimestamp timestamp={timestamp} />}
{timestamp && (
<>
<span className='notification-group__main__header__label-separator'>
&middot;
</span>
<RelativeTimestamp timestamp={timestamp} />
</>
)}
</div>
</div>

View file

@ -12,7 +12,7 @@ import {
} from 'mastodon/actions/statuses';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import Status from 'mastodon/containers/status_container';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { getStatusHidden } from 'mastodon/selectors/filters';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
@ -104,8 +104,7 @@ export const NotificationWithStatus: React.FC<{
{label}
</div>
<Status
// @ts-expect-error -- <Status> is not yet typed
<StatusQuoteManager
id={statusId}
contextType='notifications'
withDismiss

View file

@ -0,0 +1,192 @@
/* eslint-disable @typescript-eslint/no-unsafe-return,
@typescript-eslint/no-explicit-any,
@typescript-eslint/no-unsafe-call,
@typescript-eslint/no-unsafe-member-access,
@typescript-eslint/no-unsafe-assignment */
import type { ReactNode } from 'react';
import { useCallback } from 'react';
import { FormattedMessage, defineMessages, useIntl } from 'react-intl';
import { Helmet } from 'react-helmet';
import MenuIcon from '@/material-icons/400-24px/menu.svg?react';
import EmojiReactionIcon from '@/material-icons/400-24px/mood.svg?react';
import { updateReactionDeck } from 'mastodon/actions/reaction_deck';
import { Button } from 'mastodon/components/button';
import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header';
import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_picker_dropdown_container';
import { autoPlayGif } from 'mastodon/initial_state';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import emojify from '../emoji/emoji';
const messages = defineMessages({
reaction_deck_add: { id: 'reaction_deck.add', defaultMessage: 'Add' },
heading: { id: 'column.reaction_deck', defaultMessage: 'Reaction deck' },
});
const ReactionEmoji: React.FC<{
index: number;
emoji: string;
emojiMap: any;
onChange: (index: number, emoji: any) => void;
onRemove: (index: number) => void;
}> = ({ index, emoji, emojiMap, onChange, onRemove }) => {
const handleChange = useCallback((emoji: any) => {
onChange(index, emoji);
}, [index, onChange]);
const handleRemove = useCallback(() => {
onRemove(index);
}, [index, onRemove]);
let content: ReactNode;
const mapEmoji = emojiMap.find((e: any) => e.get('shortcode') === emoji);
if (mapEmoji) {
const filename = autoPlayGif
? mapEmoji.get('url')
: mapEmoji.get('static_url');
const shortCode = `:${emoji}:`;
content = (
<img
draggable='false'
className='emojione custom-emoji'
alt={shortCode}
title={shortCode}
src={filename}
/>
);
} else {
const html = { __html: emojify(emoji) };
content = <span dangerouslySetInnerHTML={html} />;
}
return (
<div className='reaction_deck__emoji'>
<div className='reaction_deck__emoji__wrapper'>
<div className='reaction_deck__emoji__wrapper__content'>
<EmojiPickerDropdown onPickEmoji={handleChange} />
<div>
{content}
</div>
</div>
<div className='reaction_deck__emoji__wrapper__options'>
<Button secondary text={'Remove'} onClick={handleRemove} />
</div>
</div>
</div>
);
};
export const ReactionDeck: React.FC<{
multiColumn?: boolean;
}> = ({ multiColumn }) => {
const dispatch = useAppDispatch();
const intl = useIntl();
const emojiMap = useAppSelector((state) => state.custom_emojis);
const deck = useAppSelector((state) => state.reaction_deck);
const onChange = useCallback(
(emojis: any) => {
dispatch(updateReactionDeck(emojis));
},
[dispatch],
);
const deckToArray = (deckData: any) =>
deckData.map((item: any) => item.get('name')).toArray();
/*
const handleReorder = useCallback((result: any) => {
const newDeck = deckToArray(deck);
const deleted = newDeck.splice(result.source.index, 1);
newDeck.splice(result.destination.index, 0, deleted[0]);
onChange(newDeck);
}, [onChange, deck]);
*/
const handleChange = useCallback(
(index: number, emoji: any) => {
const newDeck = deckToArray(deck);
newDeck[index] = emoji.native || emoji.id.replace(':', '');
onChange(newDeck);
},
[onChange, deck]
);
const handleRemove = useCallback(
(index: number) => {
const newDeck = deckToArray(deck);
newDeck.splice(index, 1);
onChange(newDeck);
},
[onChange, deck],
);
const handleAdd = useCallback(
(emoji: any) => {
const newDeck = deckToArray(deck);
newDeck.push('👍');
onChange(newDeck);
},
[onChange, deck],
);
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!deck) {
return (
<Column>
<LoadingIndicator />
</Column>
);
}
return (
<Column bindToDocument={!multiColumn}>
<ColumnHeader
icon='smile-o'
iconComponent={EmojiReactionIcon}
title={intl.formatMessage(messages.heading)}
multiColumn={multiColumn}
showBackButton
/>
{deck.map((emoji: any, index) => (
<ReactionEmoji
emojiMap={emojiMap}
key={index}
emoji={emoji.get('name')}
index={index}
onChange={handleChange}
onRemove={handleRemove}
/>
))}
<div>
<EmojiPickerDropdown
onPickEmoji={handleAdd}
button={
<Button secondary>
<FormattedMessage id='reaction_deck.add' defaultMessage='Add' />
</Button>
}
/>
</div>
<Helmet>
<meta name='robots' content='noindex' />
</Helmet>
</Column>
);
};
// eslint-disable-next-line import/no-default-export
export default ReactionDeck;

View file

@ -12,6 +12,7 @@ import Option from './components/option';
const mapStateToProps = state => ({
rules: state.getIn(['server', 'server', 'rules']),
locale: state.getIn(['meta', 'locale']),
});
class Rules extends PureComponent {
@ -19,6 +20,7 @@ class Rules extends PureComponent {
static propTypes = {
onNextStep: PropTypes.func.isRequired,
rules: ImmutablePropTypes.list,
locale: PropTypes.string,
selectedRuleIds: ImmutablePropTypes.set.isRequired,
onToggle: PropTypes.func.isRequired,
};
@ -34,7 +36,7 @@ class Rules extends PureComponent {
};
render () {
const { rules, selectedRuleIds } = this.props;
const { rules, locale, selectedRuleIds } = this.props;
return (
<>
@ -49,7 +51,7 @@ class Rules extends PureComponent {
value={item.get('id')}
checked={selectedRuleIds.includes(item.get('id'))}
onToggle={this.handleRulesToggle}
label={item.get('text')}
label={item.getIn(['translations', locale, 'text']) || item.getIn(['translations', locale.split('-')[0], 'text']) || item.get('text')}
multiple
/>
))}

View file

@ -17,7 +17,7 @@ import { ColumnHeader } from 'mastodon/components/column_header';
import { CompatibilityHashtag as Hashtag } from 'mastodon/components/hashtag';
import { Icon } from 'mastodon/components/icon';
import ScrollableList from 'mastodon/components/scrollable_list';
import Status from 'mastodon/containers/status_container';
import { StatusQuoteManager } from 'mastodon/components/status_quoted';
import { Search } from 'mastodon/features/compose/components/search';
import { useSearchParam } from 'mastodon/hooks/useSearchParam';
import type { Hashtag as HashtagType } from 'mastodon/models/tags';
@ -53,8 +53,7 @@ const renderHashtags = (hashtags: HashtagType[]) =>
const renderStatuses = (statusIds: string[]) =>
hidePeek<string>(statusIds).map((id) => (
// @ts-expect-error inferred props are wrong
<Status key={id} id={id} contextType='explore' />
<StatusQuoteManager key={id} id={id} contextType='explore' />
));
type SearchType = 'all' | ApiSearchType;
@ -190,8 +189,7 @@ export const SearchResults: React.FC<{ multiColumn: boolean }> = ({
onClickMore={handleSelectStatuses}
>
{results.statuses.slice(0, INITIAL_DISPLAY).map((id) => (
// @ts-expect-error inferred props are wrong
<Status key={id} id={id} contextType='explore' />
<StatusQuoteManager key={id} id={id} contextType='explore' />
))}
</SearchSection>
)}

View file

@ -28,6 +28,7 @@ import { PictureInPicturePlaceholder } from 'mastodon/components/picture_in_pict
import { SearchabilityIcon } from 'mastodon/components/searchability_icon';
import StatusContent from 'mastodon/components/status_content';
import StatusEmojiReactionsBar from 'mastodon/components/status_emoji_reactions_bar';
import { QuotedStatus } from 'mastodon/components/status_quoted';
import { VisibilityIcon } from 'mastodon/components/visibility_icon';
import { Audio } from 'mastodon/features/audio';
import scheduleIdleTask from 'mastodon/features/ui/util/schedule_idle_task';
@ -235,7 +236,7 @@ export const DetailedStatus: React.FC<{
/>
);
}
} else if (status.get('card')) {
} else if (status.get('card') && !status.get('quote')) {
media = (
<Card
sensitive={status.get('sensitive') && !status.get('spoiler_text')}
@ -381,7 +382,12 @@ export const DetailedStatus: React.FC<{
return (
<div style={outerStyle}>
<div ref={handleRef} className={classNames('detailed-status')}>
<div
ref={handleRef}
className={classNames('detailed-status', {
'status--has-quote': !!status.get('quote'),
})}
>
{status.get('visibility_ex') === 'direct' && (
<div className='status__prepend'>
<div className='status__prepend-icon-wrapper'>
@ -446,6 +452,10 @@ export const DetailedStatus: React.FC<{
{...(statusContentProps as any)}
/>
{status.get('quote') && (
<QuotedStatus quote={status.get('quote')} />
)}
{media}
{hashtagBar}
{emojiReactionsBar}

View file

@ -6,8 +6,6 @@ import classNames from 'classnames';
import { Helmet } from 'react-helmet';
import { withRouter } from 'react-router-dom';
import { createSelector } from '@reduxjs/toolkit';
import { List as ImmutableList } from 'immutable';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { connect } from 'react-redux';
@ -65,7 +63,7 @@ import {
} from '../../actions/statuses';
import ColumnHeader from '../../components/column_header';
import { textForScreenReader, defaultMediaVisibility } from '../../components/status';
import StatusContainer from '../../containers/status_container';
import { StatusQuoteManager } from '../../components/status_quoted';
import { bookmarkCategoryNeeded, deleteModal } from '../../initial_state';
import { makeGetStatus, makeGetPictureInPicture } from '../../selectors';
import { getAncestorsIds, getDescendantsIds, getReferencesIds } from 'mastodon/selectors/contexts';
@ -539,7 +537,7 @@ class Status extends ImmutablePureComponent {
const { params: { statusId } } = this.props;
return list.map((id, i) => (
<StatusContainer
<StatusQuoteManager
key={id}
id={id}
onMoveUp={this.handleMoveUp}

View file

@ -1,315 +1,315 @@
export function EmojiPicker () {
return import(/* webpackChunkName: "emoji_picker" */'../../emoji/emoji_picker');
return import('../../emoji/emoji_picker');
}
export function Compose () {
return import(/* webpackChunkName: "features/compose" */'../../compose');
return import('../../compose');
}
export function Notifications () {
return import(/* webpackChunkName: "features/notifications" */'../../notifications_v2');
return import('../../notifications_v2');
}
export function HomeTimeline () {
return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline');
return import('../../home_timeline');
}
export function PublicTimeline () {
return import(/* webpackChunkName: "features/public_timeline" */'../../public_timeline');
return import('../../public_timeline');
}
export function CommunityTimeline () {
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
return import('../../community_timeline');
}
export function Firehose () {
return import(/* webpackChunkName: "features/firehose" */'../../firehose');
return import('../../firehose');
}
export function HashtagTimeline () {
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
return import('../../hashtag_timeline');
}
export function DirectTimeline() {
return import(/* webpackChunkName: "features/direct_timeline" */'../../direct_timeline');
return import('../../direct_timeline');
}
export function AntennaTimeline () {
return import(/* webpackChunkName: "features/antenna_timeline" */'../../antenna_timeline');
return import('../../antenna_timeline');
}
export function ListTimeline () {
return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline');
return import('../../list_timeline');
}
export function Lists () {
return import(/* webpackChunkName: "features/lists" */'../../lists');
return import('../../lists');
}
export function Antennas () {
return import(/* webpackChunkName: "features/antennas" */'../../antennas');
return import('../../antennas');
}
export function Circles () {
return import(/* webpackChunkName: "features/circles" */'../../circles');
return import('../../circles');
}
export function CircleStatuses () {
return import(/* webpackChunkName: "features/circle_statuses" */'../../circle_statuses');
return import('../../circle_statuses');
}
export function Status () {
return import(/* webpackChunkName: "features/status" */'../../status');
return import('../../status');
}
export function GettingStarted () {
return import(/* webpackChunkName: "features/getting_started" */'../../getting_started');
return import('../../getting_started');
}
export function KeyboardShortcuts () {
return import(/* webpackChunkName: "features/keyboard_shortcuts" */'../../keyboard_shortcuts');
return import('../../keyboard_shortcuts');
}
export function PinnedStatuses () {
return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses');
return import('../../pinned_statuses');
}
export function AccountTimeline () {
return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline');
return import('../../account_timeline');
}
export function AccountGallery () {
return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery');
return import('../../account_gallery');
}
export function AccountFeatured() {
return import(/* webpackChunkName: "features/account_featured" */'../../account_featured');
return import('../../account_featured');
}
export function Followers () {
return import(/* webpackChunkName: "features/followers" */'../../followers');
return import('../../followers');
}
export function Following () {
return import(/* webpackChunkName: "features/following" */'../../following');
return import('../../following');
}
export function Reblogs () {
return import(/* webpackChunkName: "features/reblogs" */'../../reblogs');
return import('../../reblogs');
}
export function Favourites () {
return import(/* webpackChunkName: "features/favourites" */'../../favourites');
return import('../../favourites');
}
export function EmojiReactions () {
return import(/* webpackChunkName: "features/emoji_reactions" */'../../emoji_reactions');
return import('../../emoji_reactions');
}
export function StatusReferences () {
return import(/* webpackChunkName: "features/status_references" */'../../status_references');
return import('../../status_references');
}
export function MentionedUsers () {
return import(/* webpackChunkName: "features/mentioned_users" */'../../mentioned_users');
return import('../../mentioned_users');
}
export function FollowRequests () {
return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests');
return import('../../follow_requests');
}
export function FavouritedStatuses () {
return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses');
return import('../../favourited_statuses');
}
export function EmojiReactedStatuses () {
return import(/* webpackChunkName: "features/emoji_reacted_statuses" */'../../emoji_reacted_statuses');
return import('../../emoji_reacted_statuses');
}
export function FollowedTags () {
return import(/* webpackChunkName: "features/followed_tags" */'../../followed_tags');
return import('../../followed_tags');
}
export function BookmarkedStatuses () {
return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses');
return import('../../bookmarked_statuses');
}
export function BookmarkCategories () {
return import(/* webpackChunkName: "features/bookmark_categories" */'../../bookmark_categories');
return import('../../bookmark_categories');
}
export function BookmarkCategoryStatuses () {
return import(/* webpackChunkName: "features/bookmark_category_statuses" */'../../bookmark_category_statuses');
return import('../../bookmark_category_statuses');
}
export function BookmarkCategoryAdder () {
return import(/* webpackChunkName: "features/bookmark_category_adder" */'../../bookmark_category_adder');
return import('../../bookmark_category_adder');
}
export function Blocks () {
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
return import('../../blocks');
}
export function DomainBlocks () {
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
return import('../../domain_blocks');
}
export function Mutes () {
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
return import('../../mutes');
}
export function MuteModal () {
return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
return import('../components/mute_modal');
}
export function BlockModal () {
return import(/* webpackChunkName: "modals/block_modal" */'../components/block_modal');
return import('../components/block_modal');
}
export function DomainBlockModal () {
return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/domain_block_modal');
return import('../components/domain_block_modal');
}
export function ReportModal () {
return import(/* webpackChunkName: "modals/report_modal" */'../components/report_modal');
return import('../components/report_modal');
}
export function IgnoreNotificationsModal () {
return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/ignore_notifications_modal');
return import('../components/ignore_notifications_modal');
}
export function MediaGallery () {
return import(/* webpackChunkName: "status/media_gallery" */'../../../components/media_gallery');
return import('../../../components/media_gallery');
}
export function Video () {
return import(/* webpackChunkName: "features/video" */'../../video');
return import('../../video');
}
export function EmbedModal () {
return import(/* webpackChunkName: "modals/embed_modal" */'../components/embed_modal');
return import('../components/embed_modal');
}
export function ListAdder () {
return import(/*webpackChunkName: "features/list_adder" */'../../list_adder');
return import('../../list_adder');
}
export function AntennaAdder () {
return import(/*webpackChunkName: "features/antenna_adder" */'../../antenna_adder');
return import('../../antenna_adder');
}
export function CircleAdder () {
return import(/*webpackChunkName: "features/circle_adder" */'../../circle_adder');
return import('../../circle_adder');
}
export function Tesseract () {
return import(/*webpackChunkName: "tesseract" */'tesseract.js');
return import('tesseract.js');
}
export function Audio () {
return import(/* webpackChunkName: "features/audio" */'../../audio');
return import('../../audio');
}
export function Directory () {
return import(/* webpackChunkName: "features/directory" */'../../directory');
return import('../../directory');
}
export function OnboardingProfile () {
return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/profile');
return import('../../onboarding/profile');
}
export function OnboardingFollows () {
return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/follows');
return import('../../onboarding/follows');
}
export function ReactionDeck () {
return import(/* webpackChunkName: "features/reaction_deck" */'../../reaction_deck');
return import('../../reaction_deck');
}
export function CompareHistoryModal () {
return import(/*webpackChunkName: "modals/compare_history_modal" */'../components/compare_history_modal');
return import('../components/compare_history_modal');
}
export function Explore () {
return import(/* webpackChunkName: "features/explore" */'../../explore');
return import('../../explore');
}
export function Search () {
return import(/* webpackChunkName: "features/explore" */'../../search');
return import('../../search');
}
export function FilterModal () {
return import(/*webpackChunkName: "modals/filter_modal" */'../components/filter_modal');
return import('../components/filter_modal');
}
export function InteractionModal () {
return import(/*webpackChunkName: "modals/interaction_modal" */'../../interaction_modal');
return import('../../interaction_modal');
}
export function SubscribedLanguagesModal () {
return import(/*webpackChunkName: "modals/subscribed_languages_modal" */'../../subscribed_languages_modal');
return import('../../subscribed_languages_modal');
}
export function ClosedRegistrationsModal () {
return import(/*webpackChunkName: "modals/closed_registrations_modal" */'../../closed_registrations_modal');
return import('../../closed_registrations_modal');
}
export function About () {
return import(/*webpackChunkName: "features/about" */'../../about');
return import('../../about');
}
export function PrivacyPolicy () {
return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy');
return import('../../privacy_policy');
}
export function TermsOfService () {
return import(/*webpackChunkName: "features/terms_of_service" */'../../terms_of_service');
return import('../../terms_of_service');
}
export function NotificationRequests () {
return import(/*webpackChunkName: "features/notifications/requests" */'../../notifications/requests');
return import('../../notifications/requests');
}
export function NotificationRequest () {
return import(/*webpackChunkName: "features/notifications/request" */'../../notifications/request');
return import('../../notifications/request');
}
export function LinkTimeline () {
return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
return import('../../link_timeline');
}
export function AnnualReportModal () {
return import(/*webpackChunkName: "modals/annual_report_modal" */'../components/annual_report_modal');
return import('../components/annual_report_modal');
}
export function ListEdit () {
return import(/*webpackChunkName: "features/lists" */'../../lists/new');
return import('../../lists/new');
}
export function ListMembers () {
return import(/* webpackChunkName: "features/lists" */'../../lists/members');
return import('../../lists/members');
}
export function AntennaEdit () {
return import(/*webpackChunkName: "features/antennas" */'../../antennas/new');
return import('../../antennas/new');
}
export function AntennaMembers () {
return import(/* webpackChunkName: "features/antennas" */'../../antennas/members');
return import('../../antennas/members');
}
export function AntennaSetting () {
return import(/*webpackChunkName: "features/antennas/filtering" */'../../antennas/filtering');
return import('../../antennas/filtering');
}
export function CircleEdit () {
return import(/*webpackChunkName: "features/circles" */'../../circles/new');
return import('../../circles/new');
}
export function CircleMembers () {
return import(/* webpackChunkName: "features/circles" */'../../circles/members');
return import('../../circles/members');
}
export function BookmarkCategoryEdit () {
return import(/*webpackChunkName: "features/bookmark_categories" */'../../bookmark_categories/new');
return import('../../bookmark_categories/new');
}

View file

@ -346,8 +346,10 @@ export const Video: React.FC<{
const updateProgress = () => {
nextFrame = requestAnimationFrame(() => {
if (videoRef.current) {
const progress =
videoRef.current.currentTime / videoRef.current.duration;
void api.start({
progress: `${(videoRef.current.currentTime / videoRef.current.duration) * 100}%`,
progress: isNaN(progress) ? '0%' : `${progress * 100}%`,
immediate: reduceMotion,
config: config.stiff,
});

View file

@ -3,7 +3,7 @@
// can at least log in using KaiOS devices).
function importArrowKeyNavigation() {
return import(/* webpackChunkName: "arrow-key-navigation" */ 'arrow-key-navigation');
return import('arrow-key-navigation');
}
export default function loadKeyboardExtensions() {

View file

@ -23,9 +23,11 @@
"account.copy": "Profil linkini kopyala",
"account.direct": "@{name} istifadəçisini fərdi olaraq etiketlə",
"account.disable_notifications": "@{name} paylaşım edəndə mənə bildiriş göndərməyi dayandır",
"account.domain_blocking": "Domenin bloklanması",
"account.edit_profile": "Profili redaktə et",
"account.enable_notifications": "@{name} paylaşım edəndə mənə bildiriş göndər",
"account.endorse": "Profildə seçilmişlərə əlavə et",
"account.featured.hashtags": "Etiketler",
"account.featured_tags.last_status_at": "Son paylaşım {date} tarixində olub",
"account.featured_tags.last_status_never": "Paylaşım yoxdur",
"account.follow": "İzlə",

View file

@ -28,6 +28,8 @@
"account.edit_profile": "Редактиране на профила",
"account.enable_notifications": "Известяване при публикуване от @{name}",
"account.endorse": "Представи в профила",
"account.familiar_followers_one": "Последвано от {name1}",
"account.familiar_followers_two": "Последвано от {name1} и {name2}",
"account.featured": "Препоръчано",
"account.featured.accounts": "Профили",
"account.featured.hashtags": "Хаштагове",
@ -304,6 +306,7 @@
"emoji_button.search_results": "Резултати от търсене",
"emoji_button.symbols": "Символи",
"emoji_button.travel": "Пътуване и места",
"empty_column.account_featured_other.unknown": "Този акаунт още не е отличил нищо.",
"empty_column.account_hides_collections": "Този потребител е избрал да не дава тази информация",
"empty_column.account_suspended": "Спрян акаунт",
"empty_column.account_timeline": "Тук няма публикации!",
@ -508,7 +511,6 @@
"lists.exclusive": "Скриване на членуващи в Начало",
"lists.exclusive_hint": "Ако някой е в този списък, то скрийте го в инфоканала си на Начало, за да избегнете виждането на публикациите му два пъти.",
"lists.find_users_to_add": "Намерете потребители за добавяне",
"lists.list_members": "Списък членуващи",
"lists.list_members_count": "{count, plural, one {# членуващ} other {# членуващи}}",
"lists.list_name": "Име на списък",
"lists.new_list_name": "Ново име на списък",

View file

@ -25,6 +25,8 @@
"account.edit_profile": "Kemmañ ar profil",
"account.enable_notifications": "Ma c'hemenn pa vez embannet traoù gant @{name}",
"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_tags.last_status_at": "Toud diwezhañ : {date}",
"account.featured_tags.last_status_never": "Embannadur ebet",
"account.follow": "Heuliañ",
@ -32,6 +34,7 @@
"account.followers": "Tud koumanantet",
"account.followers.empty": "Den na heul an implijer·ez-mañ c'hoazh.",
"account.followers_counter": "{count, plural, one {{counter} heulier} two {{counter} heulier} few {{counter} heulier} many {{counter} heulier} other {{counter} heulier}}",
"account.followers_you_know_counter": "{counter} a anavezit",
"account.following": "Koumanantoù",
"account.follows.empty": "An implijer·ez-mañ na heul den ebet.",
"account.go_to_profile": "Gwelet ar profil",
@ -575,6 +578,7 @@
"status.mute": "Kuzhat @{name}",
"status.mute_conversation": "Kuzhat ar gaozeadenn",
"status.open": "Digeriñ ar c'hannad-mañ",
"status.quote_post_author": "Embannadenn gant {name}",
"status.read_more": "Lenn muioc'h",
"status.reblog": "Skignañ",
"status.reblog_private": "Skignañ gant ar weledenn gentañ",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Edita el perfil",
"account.enable_notifications": "Notifica'm els tuts de @{name}",
"account.endorse": "Recomana en el perfil",
"account.familiar_followers_many": "Seguit per {name1}, {name2} i {othersCount, plural, one {# altre compte} other {# altres comptes}} que coneixeu",
"account.familiar_followers_one": "Seguit per {name1}",
"account.familiar_followers_two": "Seguit per {name1} i {name2}",
"account.featured": "Destacat",
"account.featured.accounts": "Perfils",
"account.featured.hashtags": "Etiquetes",
@ -39,6 +42,7 @@
"account.followers": "Seguidors",
"account.followers.empty": "A aquest usuari encara no el segueix ningú.",
"account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidors}}",
"account.followers_you_know_counter": "{counter} que coneixeu",
"account.following": "Seguint",
"account.following_counter": "{count, plural, other {Seguint-ne {counter}}}",
"account.follows.empty": "Aquest usuari encara no segueix ningú.",
@ -49,7 +53,7 @@
"account.joined_short": "S'hi va unir",
"account.languages": "Canvia les llengües subscrites",
"account.link_verified_on": "La propietat d'aquest enllaç es va verificar el dia {date}",
"account.locked_info": "L'estat de privadesa del compte està definit com a blocat. El propietari revisa manualment qui pot seguir-lo.",
"account.locked_info": "L'estat de privacitat del compte està definit com a blocat. El propietari revisa manualment qui pot seguir-lo.",
"account.media": "Contingut",
"account.mention": "Menciona @{name}",
"account.moved_to": "{name} ha indicat que el seu nou compte és:",
@ -514,7 +518,6 @@
"lists.exclusive": "Amaga membres a Inici",
"lists.exclusive_hint": "Si algú és a la llista, amagueu-los de la pantalla d'inici, per a no veure'n les publicacions duplicades.",
"lists.find_users_to_add": "Troba usuaris per a afegir",
"lists.list_members": "Membres de la llista",
"lists.list_members_count": "{count, plural, one {# membre} other {# membres}}",
"lists.list_name": "Nom de la llista",
"lists.new_list_name": "Nom de la nova llista",
@ -725,7 +728,7 @@
"privacy.unlisted.long": "Menys fanfàrries algorísmiques",
"privacy.unlisted.short": "Públic silenciós",
"privacy_policy.last_updated": "Darrera actualització {date}",
"privacy_policy.title": "Política de privadesa",
"privacy_policy.title": "Política de Privacitat",
"recommended": "Recomanat",
"refresh": "Actualitza",
"regeneration_indicator.please_stand_by": "Espereu.",
@ -860,6 +863,13 @@
"status.mute_conversation": "Silencia la conversa",
"status.open": "Amplia el tut",
"status.pin": "Destaca al perfil",
"status.quote_error.filtered": "No es mostra a causa d'un dels vostres filtres",
"status.quote_error.not_found": "No es pot mostrar aquesta publicació.",
"status.quote_error.pending_approval": "Aquesta publicació està pendent d'aprovació per l'autor original.",
"status.quote_error.rejected": "No es pot mostrar aquesta publicació perquè l'autor original no en permet la citació.",
"status.quote_error.removed": "Aquesta publicació ha estat eliminada per l'autor.",
"status.quote_error.unauthorized": "No es pot mostrar aquesta publicació perquè no teniu autorització per a veure-la.",
"status.quote_post_author": "Publicació de {name}",
"status.read_more": "Més informació",
"status.reblog": "Impulsa",
"status.reblog_private": "Impulsa amb la visibilitat original",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Upravit profil",
"account.enable_notifications": "Oznamovat mi příspěvky @{name}",
"account.endorse": "Zvýraznit na profilu",
"account.familiar_followers_many": "Sleduje je {name1}, {name2} a {othersCount, plural, one {jeden další, které znáte} few {# další, které znáte} many {# dalších, které znáte} other {# dalších, které znáte}}",
"account.familiar_followers_one": "Sleduje je {name1}",
"account.familiar_followers_two": "Sleduje je {name1} a {name2}",
"account.featured": "Zvýrazněné",
"account.featured.accounts": "Profily",
"account.featured.hashtags": "Hashtagy",
@ -39,6 +42,7 @@
"account.followers": "Sledující",
"account.followers.empty": "Tohoto uživatele zatím nikdo nesleduje.",
"account.followers_counter": "{count, plural, one {{counter} sledující} few {{counter} sledující} many {{counter} sledujících} other {{counter} sledujících}}",
"account.followers_you_know_counter": "{count, one {{counter}, kterého znáte}, few {{counter}, které znáte}, many {{counter}, kterých znáte} other {{counter}, kterých znáte}}",
"account.following": "Sledujete",
"account.following_counter": "{count, plural, one {{counter} sledovaný} few {{counter} sledovaní} many {{counter} sledovaných} other {{counter} sledovaných}}",
"account.follows.empty": "Tento uživatel zatím nikoho nesleduje.",
@ -515,7 +519,6 @@
"lists.exclusive": "Skrýt členy na domovském kanálu",
"lists.exclusive_hint": "Pokud je někdo na tomto seznamu, skryjte jej ve vašem domovském kanálu, abyste se vyhnuli dvojímu vidění jejich příspěvků.",
"lists.find_users_to_add": "Najít uživatele, které chcete přidat",
"lists.list_members": "Členové seznamu",
"lists.list_members_count": "{count, plural, one {# člen} few {# členové} many {# členů} other {# členů}}",
"lists.list_name": "Název seznamu",
"lists.new_list_name": "Název nového seznamu",
@ -681,7 +684,7 @@
"notifications.policy.filter_not_followers_title": "Lidé, kteří vás nesledují",
"notifications.policy.filter_not_following_hint": "Dokud je ručně neschválíte",
"notifications.policy.filter_not_following_title": "Lidé, které nesledujete",
"notifications.policy.filter_private_mentions_hint": "Vyfiltrováno, pokud to není odpověď na vaši zmínku nebo pokud sledujete odesílatele",
"notifications.policy.filter_private_mentions_hint": "Filtrováno, pokud to není v odpovědi na vaši vlastní zmínku nebo pokud nesledujete odesílatele",
"notifications.policy.filter_private_mentions_title": "Nevyžádané soukromé zmínky",
"notifications.policy.title": "Spravovat oznámení od…",
"notifications_permission_banner.enable": "Povolit oznámení na ploše",
@ -742,7 +745,7 @@
"relative_time.minutes": "{number} m",
"relative_time.seconds": "{number} s",
"relative_time.today": "dnes",
"reply_indicator.attachments": "{count, plural, one {{counter} příloha} few {{counter} přílohy} other {{counter} přilohů}}",
"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",
"report.block": "Blokovat",
@ -861,6 +864,13 @@
"status.mute_conversation": "Skrýt konverzaci",
"status.open": "Rozbalit tento příspěvek",
"status.pin": "Zvýraznit na profilu",
"status.quote_error.filtered": "Skryté kvůli jednomu z vašich filtrů",
"status.quote_error.not_found": "Tento příspěvek nelze zobrazit.",
"status.quote_error.pending_approval": "Tento příspěvek čeká na schválení od původního autora.",
"status.quote_error.rejected": "Tento příspěvek nemůže být zobrazen, protože původní autor neumožňuje, aby byl citován.",
"status.quote_error.removed": "Tento příspěvek byl odstraněn jeho autorem.",
"status.quote_error.unauthorized": "Tento příspěvek nelze zobrazit, protože nemáte oprávnění k jeho zobrazení.",
"status.quote_post_author": "Příspěvek od {name}",
"status.read_more": "Číst více",
"status.reblog": "Boostnout",
"status.reblog_private": "Boostnout s původní viditelností",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Golygu'r proffil",
"account.enable_notifications": "Rhowch wybod i fi pan fydd @{name} yn postio",
"account.endorse": "Dangos ar fy mhroffil",
"account.familiar_followers_many": "Yn cael ei ddilyn gan {name1},{name2}, a {othersCount, plural, one {one other you know} other{# others you know}}",
"account.familiar_followers_one": "Wedi'i ddilyn gan {name1}",
"account.familiar_followers_two": "Wedi'i ddilyn gan {name1} a {name2}",
"account.featured": "Nodwedd",
"account.featured.accounts": "Proffilau",
"account.featured.hashtags": "Hashnodau",
@ -39,6 +42,7 @@
"account.followers": "Dilynwyr",
"account.followers.empty": "Does neb yn dilyn y defnyddiwr hwn eto.",
"account.followers_counter": "{count, plural, one {{counter} dilynwr} two {{counter} ddilynwr} other {{counter} dilynwyr}}",
"account.followers_you_know_counter": "{counter} rydych chi'n adnabod",
"account.following": "Yn dilyn",
"account.following_counter": "{count, plural, one {Yn dilyn {counter}} other {Yn dilyn {counter} arall}}",
"account.follows.empty": "Dyw'r defnyddiwr hwn ddim yn dilyn unrhyw un eto.",
@ -515,7 +519,6 @@
"lists.exclusive": "Cuddio aelodau yn y Cartref",
"lists.exclusive_hint": "Os oes rhywun ar y rhestr hon, cuddiwch nhw yn eich llif Cartref i osgoi gweld eu postiadau ddwywaith.",
"lists.find_users_to_add": "Canfod defnyddwyr i'w hychwanegu",
"lists.list_members": "Aelodau rhestr",
"lists.list_members_count": "{count, plural, one {# aelod} other {# aelod}}",
"lists.list_name": "Enw rhestr",
"lists.new_list_name": "Enw rhestr newydd",
@ -861,6 +864,12 @@
"status.mute_conversation": "Anwybyddu sgwrs",
"status.open": "Ehangu'r post hwn",
"status.pin": "Dangos ar y proffil",
"status.quote_error.not_found": "Does dim modd dangos y postiad hwn.",
"status.quote_error.pending_approval": "Mae'r postiad hwn yn aros am gymeradwyaeth yr awdur gwreiddiol.",
"status.quote_error.rejected": "Does dim modd dangos y postiad hwn gan nad yw'r awdur gwreiddiol yn caniatáu iddo gael ei ddyfynnu.",
"status.quote_error.removed": "Cafodd y postiad hwn ei ddileu gan ei awdur.",
"status.quote_error.unauthorized": "Does dim modd dangos y postiad hwn gan nad oes gennych awdurdod i'w weld.",
"status.quote_post_author": "Postiad gan {name}",
"status.read_more": "Darllen rhagor",
"status.reblog": "Hybu",
"status.reblog_private": "Hybu i'r gynulleidfa wreiddiol",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Redigér profil",
"account.enable_notifications": "Advisér mig, når @{name} poster",
"account.endorse": "Fremhæv på profil",
"account.familiar_followers_many": "Følges af {name1}, {name2} og {othersCount, plural, one {# mere, man kender} other {# mere, man kender}}",
"account.familiar_followers_one": "Følges af {name1}",
"account.familiar_followers_two": "Følges af {name1} og {name2}",
"account.featured": "Fremhævet",
"account.featured.accounts": "Profiler",
"account.featured.hashtags": "Hashtags",
@ -39,6 +42,7 @@
"account.followers": "Følgere",
"account.followers.empty": "Ingen følger denne bruger endnu.",
"account.followers_counter": "{count, plural, one {{counter} følger} other {{counter} følgere}}",
"account.followers_you_know_counter": "{counter} man kender",
"account.following": "Følger",
"account.following_counter": "{count, plural, one {{counter} følger} other {{counter} følger}}",
"account.follows.empty": "Denne bruger følger ikke nogen endnu.",
@ -515,7 +519,6 @@
"lists.exclusive": "Skjul medlemmer i Hjem",
"lists.exclusive_hint": "Er nogen er på denne liste, skjul personen i hjemme-feeds for at undgå at se vedkommendes indlæg to gange.",
"lists.find_users_to_add": "Find brugere at tilføje",
"lists.list_members": "Liste over medlemmer",
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemmer}}",
"lists.list_name": "Listetitel",
"lists.new_list_name": "Ny listetitel",
@ -861,6 +864,13 @@
"status.mute_conversation": "Skjul samtale",
"status.open": "Udvid dette indlæg",
"status.pin": "Fremhæv på profil",
"status.quote_error.filtered": "Skjult grundet et af filterne",
"status.quote_error.not_found": "Dette indlæg kan ikke vises.",
"status.quote_error.pending_approval": "Dette indlæg afventer godkendelse fra den oprindelige forfatter.",
"status.quote_error.rejected": "Dette indlæg kan ikke vises, da den oprindelige forfatter ikke tillader citering heraf.",
"status.quote_error.removed": "Dette indlæg er fjernet af forfatteren.",
"status.quote_error.unauthorized": "Dette indlæg kan ikke vises, da man ikke har tilladelse til at se det.",
"status.quote_post_author": "Indlæg fra {name}",
"status.read_more": "Læs mere",
"status.reblog": "Fremhæv",
"status.reblog_private": "Fremhæv med oprindelig synlighed",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Profil bearbeiten",
"account.enable_notifications": "Benachrichtige mich wenn @{name} etwas postet",
"account.endorse": "Im Profil vorstellen",
"account.familiar_followers_many": "Gefolgt von {name1}, {name2} und {othersCount, plural, one {einem weiteren Profil, das dir bekannt ist} other {# weiteren Profilen, die dir bekannt sind}}",
"account.familiar_followers_one": "Gefolgt von {name1}",
"account.familiar_followers_two": "Gefolgt von {name1} und {name2}",
"account.featured": "Vorgestellt",
"account.featured.accounts": "Profile",
"account.featured.hashtags": "Hashtags",
@ -39,6 +42,7 @@
"account.followers": "Follower",
"account.followers.empty": "Diesem Profil folgt noch niemand.",
"account.followers_counter": "{count, plural, one {{counter} Follower} other {{counter} Follower}}",
"account.followers_you_know_counter": "{counter} bekannt",
"account.following": "Folge ich",
"account.following_counter": "{count, plural, one {{counter} Folge ich} other {{counter} Folge ich}}",
"account.follows.empty": "Dieses Profil folgt noch niemandem.",
@ -357,7 +361,7 @@
"filter_modal.select_filter.title": "Diesen Beitrag filtern",
"filter_modal.title.status": "Beitrag per Filter ausblenden",
"filter_warning.matches_filter": "Übereinstimmend mit dem Filter „<span>{title}</span>“",
"filtered_notifications_banner.pending_requests": "Von {count, plural, =0 {keinem, den} one {einer Person, die} other {# Personen, die}} du möglicherweise kennst",
"filtered_notifications_banner.pending_requests": "Von {count, plural, =0 {keinem Profil, das dir möglicherweise bekannt ist} one {einem Profil, das dir möglicherweise bekannt ist} other {# Profilen, die dir möglicherweise bekannt sind}}",
"filtered_notifications_banner.title": "Gefilterte Benachrichtigungen",
"firehose.all": "Alle Server",
"firehose.local": "Dieser Server",
@ -515,7 +519,6 @@
"lists.exclusive": "Mitglieder auf der Startseite ausblenden",
"lists.exclusive_hint": "Profile, die sich auf dieser Liste befinden, werden nicht auf deiner Startseite angezeigt, damit deren Beiträge nicht doppelt erscheinen.",
"lists.find_users_to_add": "Suche nach Profilen, um sie hinzuzufügen",
"lists.list_members": "Listenmitglieder",
"lists.list_members_count": "{count, plural, one {# Mitglied} other {# Mitglieder}}",
"lists.list_name": "Titel der Liste",
"lists.new_list_name": "Neuer Listentitel",
@ -861,6 +864,13 @@
"status.mute_conversation": "Unterhaltung stummschalten",
"status.open": "Beitrag öffnen",
"status.pin": "Im Profil vorstellen",
"status.quote_error.filtered": "Ausgeblendet wegen eines deiner Filter",
"status.quote_error.not_found": "Dieser Beitrag kann nicht angezeigt werden.",
"status.quote_error.pending_approval": "Dieser Beitrag muss noch durch das ursprüngliche Profil genehmigt werden.",
"status.quote_error.rejected": "Dieser Beitrag kann nicht angezeigt werden, weil das ursprüngliche Profil das Zitieren nicht erlaubt.",
"status.quote_error.removed": "Dieser Beitrag wurde durch das Profil entfernt.",
"status.quote_error.unauthorized": "Dieser Beitrag kann nicht angezeigt werden, weil du zum Ansehen nicht berechtigt bist.",
"status.quote_post_author": "Beitrag von {name}",
"status.read_more": "Gesamten Beitrag anschauen",
"status.reblog": "Teilen",
"status.reblog_private": "Mit der ursprünglichen Zielgruppe teilen",

View file

@ -497,7 +497,6 @@
"lists.exclusive": "Απόκρυψη μελών από την Αρχική",
"lists.exclusive_hint": "Αν κάποιος είναι σε αυτή τη λίστα, απόκρυψέ τον στην Αρχική σου για να αποφύγεις να βλέπεις τις αναρτήσεις του δύο φορές.",
"lists.find_users_to_add": "Εύρεση χρηστών για προσθήκη",
"lists.list_members": "Λίστα μελών",
"lists.list_members_count": "{count, plural, one {# μέλος} other {# μέλη}}",
"lists.list_name": "Όνομα λίστας",
"lists.new_list_name": "Νέο όνομα λίστας",

View file

@ -490,7 +490,6 @@
"lists.exclusive": "Hide members in Home",
"lists.exclusive_hint": "If someone is on this list, hide them in your Home feed to avoid seeing their posts twice.",
"lists.find_users_to_add": "Find users to add",
"lists.list_members": "List members",
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
"lists.list_name": "List name",
"lists.new_list_name": "New list name",

View file

@ -39,10 +39,12 @@
"account.edit_profile": "Edit profile",
"account.enable_notifications": "Notify me when @{name} posts",
"account.endorse": "Feature on profile",
"account.familiar_followers_many": "Followed by {name1}, {name2}, and {othersCount, plural, one {one other you know} other {# others you know}}",
"account.familiar_followers_one": "Followed by {name1}",
"account.familiar_followers_two": "Followed by {name1} and {name2}",
"account.featured": "Featured",
"account.featured.accounts": "Profiles",
"account.featured.hashtags": "Hashtags",
"account.featured.posts": "Posts",
"account.featured_tags.last_status_at": "Last post on {date}",
"account.featured_tags.last_status_never": "No posts",
"account.follow": "Follow",
@ -51,6 +53,7 @@
"account.followers.empty": "No one follows this user yet.",
"account.followers.hidden_from_me": "This information is hidden by your setting.",
"account.followers_counter": "{count, plural, one {{counter} follower} other {{counter} followers}}",
"account.followers_you_know_counter": "{counter} you know",
"account.following": "Following",
"account.following_counter": "{count, plural, one {{counter} following} other {{counter} following}}",
"account.follows.empty": "This user doesn't follow anyone yet.",
@ -293,7 +296,7 @@
"column.local": "Local",
"column.mutes": "Muted users",
"column.notifications": "Notifications",
"column.pins": "Featured posts",
"column.pins": "Pinned posts",
"column.public": "Federated timeline",
"column.reaction_deck": "Reaction deck",
"column_back_button.label": "Back",
@ -444,8 +447,8 @@
"emoji_button.search_results": "Search results",
"emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places",
"empty_column.account_featured.me": "You have not featured anything yet. Did you know that you can feature your posts, hashtags you use the most, and even your friends accounts on your profile?",
"empty_column.account_featured.other": "{acct} has not featured anything yet. Did you know that you can feature your posts, hashtags you use the most, and even your friends accounts on your profile?",
"empty_column.account_featured.me": "You have not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friends accounts on your profile?",
"empty_column.account_featured.other": "{acct} has not featured anything yet. Did you know that you can feature your hashtags you use the most, and even your friends accounts on your profile?",
"empty_column.account_featured_other.unknown": "This account has not featured anything yet.",
"empty_column.account_hides_collections": "This user has chosen to not make this information available",
"empty_column.account_suspended": "Account suspended",
@ -485,6 +488,11 @@
"explore.trending_links": "News",
"explore.trending_statuses": "Posts",
"explore.trending_tags": "Hashtags",
"featured_carousel.header": "{count, plural, one {Pinned Post} other {Pinned Posts}}",
"featured_carousel.next": "Next",
"featured_carousel.post": "Post",
"featured_carousel.previous": "Previous",
"featured_carousel.slide": "{index} of {total}",
"filter_modal.added.context_mismatch_explanation": "This filter category does not apply to the context in which you have accessed this post. If you want the post to be filtered in this context too, you will have to edit the filter.",
"filter_modal.added.context_mismatch_title": "Context mismatch!",
"filter_modal.added.expired_explanation": "This filter category has expired, you will need to change the expiration date for it to apply.",
@ -626,7 +634,7 @@
"keyboard_shortcuts.my_profile": "Open your profile",
"keyboard_shortcuts.notifications": "Open notifications column",
"keyboard_shortcuts.open_media": "Open media",
"keyboard_shortcuts.pinned": "Open featured posts list",
"keyboard_shortcuts.pinned": "Open pinned posts list",
"keyboard_shortcuts.profile": "Open author's profile",
"keyboard_shortcuts.reply": "Reply to post",
"keyboard_shortcuts.requests": "Open follow requests list",
@ -664,7 +672,6 @@
"lists.favourite": "Favorite",
"lists.favourite_hint": "When opening the Web Client on a PC, this list appears in the navigation.",
"lists.find_users_to_add": "Find users to add",
"lists.list_members": "List members",
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
"lists.list_name": "List name",
"lists.memo_related_antenna": "Antenna: \"{title}\"",
@ -721,7 +728,7 @@
"navigation_bar.mutes": "Muted users",
"navigation_bar.opened_in_classic_interface": "Posts, accounts, and other specific pages are opened by default in the classic web interface.",
"navigation_bar.personal": "Personal",
"navigation_bar.pins": "Featured posts",
"navigation_bar.pins": "Pinned posts",
"navigation_bar.preferences": "Preferences",
"navigation_bar.public_timeline": "Federated timeline",
"navigation_bar.reaction_deck": "Reaction deck",
@ -1072,7 +1079,14 @@
"status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation",
"status.open": "Expand this post",
"status.pin": "Feature on profile",
"status.pin": "Pin on profile",
"status.quote_error.filtered": "Hidden due to one of your filters",
"status.quote_error.not_found": "This post cannot be displayed.",
"status.quote_error.pending_approval": "This post is pending approval from the original author.",
"status.quote_error.rejected": "This post cannot be displayed as the original author does not allow it to be quoted.",
"status.quote_error.removed": "This post was removed by its author.",
"status.quote_error.unauthorized": "This post cannot be displayed as you are not authorized to view it.",
"status.quote_post_author": "Post by {name}",
"status.read_more": "Read more",
"status.reblog": "Boost",
"status.reblog_private": "Boost with original visibility",
@ -1100,7 +1114,7 @@
"status.translated_from_with": "Translated from {lang} using {provider}",
"status.uncached_media_warning": "Preview not available",
"status.unmute_conversation": "Unmute conversation",
"status.unpin": "Don't feature on profile",
"status.unpin": "Unpin from profile",
"subscribed_languages.lead": "Only posts in selected languages will appear on your home and list timelines after the change. Select none to receive posts in all languages.",
"subscribed_languages.save": "Save changes",
"subscribed_languages.target": "Change subscribed languages for {target}",

View file

@ -515,7 +515,6 @@
"lists.exclusive": "Kaŝi membrojn en Hejmpaĝo",
"lists.exclusive_hint": "Se iu estas en ĉi tiuj listo, kaŝu ilin en via hejmpaĝo por eviti vidi iliajn afiŝojn dufoje.",
"lists.find_users_to_add": "Trovi uzantojn por aldoni",
"lists.list_members": "Listoj de membroj",
"lists.list_members_count": "{count, plural,one {# membro} other {# membroj}}",
"lists.list_name": "Nomo de la listo",
"lists.new_list_name": "Nomo de nova listo",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Editar perfil",
"account.enable_notifications": "Notificarme cuando @{name} envíe mensajes",
"account.endorse": "Destacar en el perfil",
"account.familiar_followers_many": "Seguido por {name1}, {name2} y {othersCount, plural, one {# cuenta más que conocés} other {# cuentas más que conocés}}",
"account.familiar_followers_one": "Seguido por {name1}",
"account.familiar_followers_two": "Seguido por {name1} y {name2}",
"account.featured": "Destacados",
"account.featured.accounts": "Perfiles",
"account.featured.hashtags": "Etiquetas",
@ -39,6 +42,7 @@
"account.followers": "Seguidores",
"account.followers.empty": "Todavía nadie sigue a este usuario.",
"account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}",
"account.followers_you_know_counter": "{counter} seguidores que conocés",
"account.following": "Siguiendo",
"account.following_counter": "{count, plural, one {siguiendo a {counter}} other {siguiendo a {counter}}}",
"account.follows.empty": "Todavía este usuario no sigue a nadie.",
@ -515,7 +519,6 @@
"lists.exclusive": "Ocultar miembros en la línea temporal principal",
"lists.exclusive_hint": "Si alguien está en esta lista, ocultalo en tu línea temporal principal para evitar que aparezcan sus mensajes dos veces.",
"lists.find_users_to_add": "Buscar usuarios para agregar",
"lists.list_members": "Miembros de lista",
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
"lists.list_name": "Nombre de la lista",
"lists.new_list_name": "Nombre de la nueva lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir este mensaje",
"status.pin": "Destacar en el perfil",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_found": "No se puede mostrar este mensaje.",
"status.quote_error.pending_approval": "Este mensaje está pendiente de aprobación del autor original.",
"status.quote_error.rejected": "No se puede mostrar este mensaje, ya que el autor original no permite que se cite.",
"status.quote_error.removed": "Este mensaje fue eliminado por su autor.",
"status.quote_error.unauthorized": "No se puede mostrar este mensaje, ya que no tenés autorización para verlo.",
"status.quote_post_author": "Mensaje de @{name}",
"status.read_more": "Leé más",
"status.reblog": "Adherir",
"status.reblog_private": "Adherir a la audiencia original",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Editar perfil",
"account.enable_notifications": "Notificarme cuando @{name} publique algo",
"account.endorse": "Destacar en mi perfil",
"account.familiar_followers_many": "Seguido por {name1}, {name2} y {othersCount, plural,one {# más que conoces}other {# más que conoces}}",
"account.familiar_followers_one": "Seguido por {name1}",
"account.familiar_followers_two": "Seguid por {name1} y {name2}",
"account.featured": "Destacado",
"account.featured.accounts": "Perfiles",
"account.featured.hashtags": "Etiquetas",
@ -39,6 +42,7 @@
"account.followers": "Seguidores",
"account.followers.empty": "Nadie sigue a este usuario todavía.",
"account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}",
"account.followers_you_know_counter": "{counter} que conoces",
"account.following": "Siguiendo",
"account.following_counter": "{count, plural, one {{counter} siguiendo} other {{counter} siguiendo}}",
"account.follows.empty": "Este usuario no sigue a nadie todavía.",
@ -515,7 +519,6 @@
"lists.exclusive": "Ocultar miembros en Inicio",
"lists.exclusive_hint": "Si alguien aparece en esta lista, ocúltalo en tu página de inicio para evitar ver sus publicaciones dos veces.",
"lists.find_users_to_add": "Buscar usuarios para agregar",
"lists.list_members": "Miembros de la lista",
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
"lists.list_name": "Nombre de la lista",
"lists.new_list_name": "Nombre de la nueva lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir estado",
"status.pin": "Destacar en el perfil",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_found": "No se puede mostrar esta publicación.",
"status.quote_error.pending_approval": "Esta publicación está pendiente de aprobación del autor original.",
"status.quote_error.rejected": "No se puede mostrar esta publicación, puesto que el autor original no permite que sea citado.",
"status.quote_error.removed": "Esta publicación fue eliminada por su autor.",
"status.quote_error.unauthorized": "No se puede mostrar esta publicación, puesto que no estás autorizado a verla.",
"status.quote_post_author": "Publicado por {name}",
"status.read_more": "Leer más",
"status.reblog": "Impulsar",
"status.reblog_private": "Implusar a la audiencia original",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Editar perfil",
"account.enable_notifications": "Notificarme cuando @{name} publique algo",
"account.endorse": "Destacar en el perfil",
"account.familiar_followers_many": "Seguido por {name1}, {name2} y {othersCount, plural,one {# más que conoces}other {# más que conoces}}",
"account.familiar_followers_one": "Seguido por {name1}",
"account.familiar_followers_two": "Seguido por {name1} y {name2}",
"account.featured": "Destacado",
"account.featured.accounts": "Perfiles",
"account.featured.hashtags": "Etiquetas",
@ -39,6 +42,7 @@
"account.followers": "Seguidores",
"account.followers.empty": "Todavía nadie sigue a este usuario.",
"account.followers_counter": "{count, plural, one {{counter} seguidor} other {{counter} seguidores}}",
"account.followers_you_know_counter": "{counter} que conoces",
"account.following": "Siguiendo",
"account.following_counter": "{count, plural, one {{counter} siguiendo} other {{counter} siguiendo}}",
"account.follows.empty": "Este usuario todavía no sigue a nadie.",
@ -515,7 +519,6 @@
"lists.exclusive": "Ocultar miembros en Inicio",
"lists.exclusive_hint": "Si alguien está en esta lista, escóndelo en tu página de inicio para evitar ver sus publicaciones dos veces.",
"lists.find_users_to_add": "Buscar usuarios para añadir",
"lists.list_members": "Miembros de la lista",
"lists.list_members_count": "{count, plural,one {# miembro} other {# miembros}}",
"lists.list_name": "Nombre de la lista",
"lists.new_list_name": "Nombre de la nueva lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Silenciar conversación",
"status.open": "Expandir publicación",
"status.pin": "Destacar en el perfil",
"status.quote_error.filtered": "Oculto debido a uno de tus filtros",
"status.quote_error.not_found": "No se puede mostrar esta publicación.",
"status.quote_error.pending_approval": "Esta publicación está pendiente de aprobación del autor original.",
"status.quote_error.rejected": "Esta publicación no puede mostrarse porque el autor original no permite que se cite.",
"status.quote_error.removed": "Esta publicación fue eliminada por su autor.",
"status.quote_error.unauthorized": "Esta publicación no puede mostrarse, ya que no estás autorizado a verla.",
"status.quote_post_author": "Publicación de {name}",
"status.read_more": "Leer más",
"status.reblog": "Impulsar",
"status.reblog_private": "Impulsar a la audiencia original",

View file

@ -490,7 +490,6 @@
"lists.exclusive": "Peida avalehelt liikmed",
"lists.exclusive_hint": "Kui keegi on selles loetelus, peida ta avalehe lõimest, vältimaks tema postituste kaks korda nägemist.",
"lists.find_users_to_add": "Leia kasutajaid, keda lisada",
"lists.list_members": "Loetelu liikmed",
"lists.list_members_count": "{count, plural, one {# liige} other {# liiget}}",
"lists.list_name": "Loetelu nimi",
"lists.new_list_name": "Loetelu uus nimi",

View file

@ -28,7 +28,11 @@
"account.edit_profile": "ویرایش نمایه",
"account.enable_notifications": "هنگام فرسته‌های @{name} مرا آگاه کن",
"account.endorse": "معرّفی در نمایه",
"account.familiar_followers_many": "پی‌گرفته از سوی {name1}، {name2} و {othersCount, plural,one {یکی دیگر از پی‌گرفته‌هایتان} other {# نفر دیگر از پی‌گرفته‌هایتان}}",
"account.familiar_followers_one": "پی‌گرفته از سوی {name1}",
"account.familiar_followers_two": "پی‌گرفته از سوی {name1} و {name2}",
"account.featured": " پیشنهادی",
"account.featured.accounts": "نمایه‌ها",
"account.featured.hashtags": "برچسب‌ها",
"account.featured.posts": "فرسته‌ها",
"account.featured_tags.last_status_at": "آخرین فرسته در {date}",
@ -168,6 +172,7 @@
"column.lists": "سیاهه‌ها",
"column.mutes": "کاربران خموش",
"column.notifications": "آگاهی‌ها",
"column.pins": "فرسته‌های معرّفی شده",
"column.public": "خط زمانی همگانی",
"column_back_button.label": "بازگشت",
"column_header.hide_settings": "نهفتن تنظیمات",
@ -404,8 +409,10 @@
"hashtag.counter_by_accounts": "{count, plural, one {{counter} مشارکت کننده} other {{counter} مشارکت کننده}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} فرسته} other {{counter} فرسته}} امروز",
"hashtag.feature": "معرّفی در نمایه",
"hashtag.follow": "پی‌گرفتن برچسب",
"hashtag.mute": "خموشی #{hashtag}",
"hashtag.unfeature": "معرّفی نکردن در نمایه",
"hashtag.unfollow": "پی‌نگرفتن برچسب",
"hashtags.and_other": "…و {count, plural, other {# بیش‌تر}}",
"hints.profiles.followers_may_be_missing": "شاید پی‌گیرندگان این نمایه نباشند.",
@ -476,6 +483,7 @@
"keyboard_shortcuts.my_profile": "گشودن نمایه‌تان",
"keyboard_shortcuts.notifications": "گشودن ستون آگاهی‌ها",
"keyboard_shortcuts.open_media": "گشودن رسانه",
"keyboard_shortcuts.pinned": "گشودن سیاههٔ فرسته‌های معرّفی شده",
"keyboard_shortcuts.profile": "گشودن نمایهٔ نویسنده",
"keyboard_shortcuts.reply": "پاسخ به فرسته",
"keyboard_shortcuts.requests": "گشودن سیاههٔ درخواست‌های پی‌گیری",
@ -510,7 +518,6 @@
"lists.exclusive": "نهفتن اعضا در خانه",
"lists.exclusive_hint": "اگر کسی در این سیاهه باشد، در خوراک خانگیتان نهفته تا از نمایش دویارهٔ فرسته‌هایش خودداری شود.",
"lists.find_users_to_add": "یافتن کاربرانی برای افزودن",
"lists.list_members": "اعضای سیاهه",
"lists.list_members_count": "{count, plural,one {# عضو}other {# عضو}}",
"lists.list_name": "نام سیاهه",
"lists.new_list_name": "نام سیاههٔ جدید",
@ -559,6 +566,7 @@
"navigation_bar.mutes": "کاربران خموشانده",
"navigation_bar.opened_in_classic_interface": "فرسته‌ها، حساب‌ها و دیگر صفحه‌های خاص به طور پیش‌گزیده در میانای وب کلاسیک گشوده می‌شوند.",
"navigation_bar.personal": "شخصی",
"navigation_bar.pins": "فرسته‌های معرّفی شده",
"navigation_bar.preferences": "ترجیحات",
"navigation_bar.public_timeline": "خط زمانی همگانی",
"navigation_bar.search": "جست‌وجو",
@ -854,6 +862,7 @@
"status.mute": "خموشاندن @{name}",
"status.mute_conversation": "خموشاندن گفت‌وگو",
"status.open": "گسترش این فرسته",
"status.pin": "معرّفی در نمایه",
"status.read_more": "بیشتر بخوانید",
"status.reblog": "تقویت",
"status.reblog_private": "تقویت برای مخاطبان نخستین",
@ -878,6 +887,7 @@
"status.translated_from_with": "ترجمه از {lang} با {provider}",
"status.uncached_media_warning": "پیش‌نمایش موجود نیست",
"status.unmute_conversation": "رفع خموشی گفت‌وگو",
"status.unpin": "معرّفی نکردن در نمایه",
"subscribed_languages.lead": "پس از تغییر، تنها فرسته‌های به زبان‌های گزیده روی خانه و خط‌زمانی‌های سیاهه ظاهر خواهند شد. برای دریافت فرسته‌ها به تمامی زبان‌ها، هیچ‌کدام را برنگزینید.",
"subscribed_languages.save": "ذخیرهٔ تغییرات",
"subscribed_languages.target": "تغییر زبان‌های مشترک شده برای {target}",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Muokkaa profiilia",
"account.enable_notifications": "Ilmoita minulle, kun @{name} julkaisee",
"account.endorse": "Suosittele profiilissa",
"account.familiar_followers_many": "Seuraajina {name1}, {name2} ja {othersCount, plural, one {1 muu, jonka tunnet} other {# muuta, jotka tunnet}}",
"account.familiar_followers_one": "Seuraajana {name1}",
"account.familiar_followers_two": "Seuraajina {name1} ja {name2}",
"account.featured": "Suositellut",
"account.featured.accounts": "Profiilit",
"account.featured.hashtags": "Aihetunnisteet",
@ -39,6 +42,7 @@
"account.followers": "Seuraajat",
"account.followers.empty": "Kukaan ei seuraa tätä käyttäjää vielä.",
"account.followers_counter": "{count, plural, one {{counter} seuraaja} other {{counter} seuraajaa}}",
"account.followers_you_know_counter": "{count, plural, one {{counter} tuntemasi} other {{counter} tuntemaasi}}",
"account.following": "Seurattavat",
"account.following_counter": "{count, plural, one {{counter} seurattava} other {{counter} seurattavaa}}",
"account.follows.empty": "Tämä käyttäjä ei vielä seuraa ketään.",
@ -515,7 +519,6 @@
"lists.exclusive": "Piilota jäsenet kotisyötteestä",
"lists.exclusive_hint": "Jos joku on tässä listassa, piilota hänet kotisyötteestäsi, jotta et näe hänen julkaisujaan kahteen kertaan.",
"lists.find_users_to_add": "Etsi lisättäviä käyttäjiä",
"lists.list_members": "Listan jäsenet",
"lists.list_members_count": "{count, plural, one {# jäsen} other {# jäsentä}}",
"lists.list_name": "Listan nimi",
"lists.new_list_name": "Uuden listan nimi",
@ -861,6 +864,13 @@
"status.mute_conversation": "Mykistä keskustelu",
"status.open": "Laajenna julkaisu",
"status.pin": "Suosittele profiilissa",
"status.quote_error.filtered": "Piilotettu jonkin asettamasi suodattimen takia",
"status.quote_error.not_found": "Tätä julkaisua ei voi näyttää.",
"status.quote_error.pending_approval": "Tämä julkaisu odottaa alkuperäisen tekijänsä hyväksyntää.",
"status.quote_error.rejected": "Tätä julkaisua ei voi näyttää, sillä sen alkuperäinen tekijä ei salli lainattavan julkaisua.",
"status.quote_error.removed": "Tekijä on poistanut julkaisun.",
"status.quote_error.unauthorized": "Tätä julkaisua ei voi näyttää, koska sinulla ei ole oikeutta tarkastella sitä.",
"status.quote_post_author": "Julkaisu käyttäjältä {name}",
"status.read_more": "Näytä enemmän",
"status.reblog": "Tehosta",
"status.reblog_private": "Tehosta alkuperäiselle yleisölle",

View file

@ -26,6 +26,7 @@
"account.edit_profile": "Baguhin ang profile",
"account.enable_notifications": "Ipaalam sa akin kapag nag-post si @{name}",
"account.endorse": "I-tampok sa profile",
"account.featured": "Itinatampok",
"account.featured_tags.last_status_at": "Huling post noong {date}",
"account.featured_tags.last_status_never": "Walang mga post",
"account.follow": "Sundan",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Broyt vanga",
"account.enable_notifications": "Boða mær frá, tá @{name} skrivar",
"account.endorse": "Víst á vangamyndini",
"account.familiar_followers_many": "{name1}, {name2} og {othersCount, plural, one {ein annar/onnur tú kennir} other {# onnur tú kennir}} fylgja",
"account.familiar_followers_one": "{name1} fylgir",
"account.familiar_followers_two": "{name1} og {name2} fylgja",
"account.featured": "Tikin fram",
"account.featured.accounts": "Vangar",
"account.featured.hashtags": "Frámerki",
@ -39,6 +42,7 @@
"account.followers": "Fylgjarar",
"account.followers.empty": "Ongar fylgjarar enn.",
"account.followers_counter": "{count, plural, one {{counter} fylgjari} other {{counter} fylgjarar}}",
"account.followers_you_know_counter": "{counter} tú kennir",
"account.following": "Fylgir",
"account.following_counter": "{count, plural, one {{counter} fylgir} other {{counter} fylgja}}",
"account.follows.empty": "Hesin brúkari fylgir ongum enn.",
@ -515,7 +519,6 @@
"lists.exclusive": "Fjal limir á heimarás",
"lists.exclusive_hint": "Um onkur er á hesum listanum, so skulu tey fjalast á heimarásini, so tú sleppir undan at síggja postar teirra tvær ferðir.",
"lists.find_users_to_add": "Finn brúkarar at leggja afturat",
"lists.list_members": "Lista limir",
"lists.list_members_count": "{count, plural, one {# limur} other {# limir}}",
"lists.list_name": "Listanavn",
"lists.new_list_name": "Nýtt listanavn",
@ -861,6 +864,13 @@
"status.mute_conversation": "Doyv samrøðu",
"status.open": "Víðka henda postin",
"status.pin": "Vís á vanga",
"status.quote_error.filtered": "Eitt av tínum filtrum fjalir hetta",
"status.quote_error.not_found": "Tað ber ikki til at vísa hendan postin.",
"status.quote_error.pending_approval": "Hesin posturin bíðar eftir góðkenning frá upprunahøvundinum.",
"status.quote_error.rejected": "Hesin posturin kann ikki vísast, tí upprunahøvundurin loyvir ikki at posturin verður siteraður.",
"status.quote_error.removed": "Hesin posturin var strikaður av høvundinum.",
"status.quote_error.unauthorized": "Hesin posturin kann ikki vísast, tí tú hevur ikki rættindi at síggja hann.",
"status.quote_post_author": "Postur hjá @{name}",
"status.read_more": "Les meira",
"status.reblog": "Stimbra",
"status.reblog_private": "Stimbra við upprunasýni",

View file

@ -494,7 +494,6 @@
"lists.exclusive": "Cacher les membres de la page d'accueil",
"lists.exclusive_hint": "Si quelqu'un est dans cette liste, les cacher dans votre fil pour éviter de voir leurs messages deux fois.",
"lists.find_users_to_add": "Trouver des utilisateurs à ajouter",
"lists.list_members": "Lister les membres",
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
"lists.list_name": "Nom de la liste",
"lists.new_list_name": "Nom de la nouvelle liste",

View file

@ -494,7 +494,6 @@
"lists.exclusive": "Cacher les membres de la page d'accueil",
"lists.exclusive_hint": "Si quelqu'un est dans cette liste, les cacher dans votre fil pour éviter de voir leurs messages deux fois.",
"lists.find_users_to_add": "Trouver des utilisateurs à ajouter",
"lists.list_members": "Lister les membres",
"lists.list_members_count": "{count, plural, one {# member} other {# members}}",
"lists.list_name": "Nom de la liste",
"lists.new_list_name": "Nom de la nouvelle liste",

View file

@ -510,7 +510,6 @@
"lists.exclusive": "Leden op jo Startside ferstopje",
"lists.exclusive_hint": "As ien op dizze list stiet, ferstopje dizze persoan dan op jo starttiidline om foar te kommen dat harren berjochten twa kear toand wurde.",
"lists.find_users_to_add": "Fyn brûkers om ta te foegjen",
"lists.list_members": "Listleden",
"lists.list_members_count": "{count, plural, one{# lid} other{# leden}}",
"lists.list_name": "Listnamme",
"lists.new_list_name": "Nije listnamme",

View file

@ -28,7 +28,11 @@
"account.edit_profile": "Cuir an phróifíl in eagar",
"account.enable_notifications": "Cuir mé in eol nuair bpostálann @{name}",
"account.endorse": "Cuir ar an phróifíl mar ghné",
"account.familiar_followers_many": "Ina dhiaidh sin ag {name1}, {name2}, agus {othersCount, plural, \n one {duine eile atá aithnid duit} \n two {# duine eile atá aithnid duit} \n few {# dhuine eile atá aithnid duit} \n many {# nduine eile atá aithnid duit} \n other {# duine eile atá aithnid duit}}",
"account.familiar_followers_one": "Ina dhiaidh sin {name1}",
"account.familiar_followers_two": "Ina dhiaidh sin tá {name1} agus {name2}",
"account.featured": "Faoi thrácht",
"account.featured.accounts": "Próifílí",
"account.featured.hashtags": "Haischlibeanna",
"account.featured.posts": "Poist",
"account.featured_tags.last_status_at": "Postáil is déanaí ar {date}",
@ -38,6 +42,7 @@
"account.followers": "Leantóirí",
"account.followers.empty": "Ní leanann éinne an t-úsáideoir seo fós.",
"account.followers_counter": "{count, plural, one {{counter} leantóir} other {{counter} leantóirí}}",
"account.followers_you_know_counter": "{counter} tá a fhios agat",
"account.following": "Ag leanúint",
"account.following_counter": "{count, plural, one {{counter} ag leanúint} other {{counter} ag leanúint}}",
"account.follows.empty": "Ní leanann an t-úsáideoir seo aon duine go fóill.",
@ -405,8 +410,10 @@
"hashtag.counter_by_accounts": "{count, plural, one {{counter} rannpháirtí} two {{counter} rannpháirtí} few {{counter} rannpháirtí} many {{counter} rannpháirtí} other {{counter} rannpháirtí}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} post} two {{counter} post} few {{counter} post} many {{counter} post} other {{counter} poist}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} post inniu} other {{counter} poist inniu}} inniu",
"hashtag.feature": "Gné ar phróifíl",
"hashtag.follow": "Lean haischlib",
"hashtag.mute": "Balbhaigh #{hashtag}",
"hashtag.unfeature": "Ná cuir le feiceáil ar phróifíl",
"hashtag.unfollow": "Ná lean haischlib",
"hashtags.and_other": "agus {count, plural, one {} two {# níos} few {# níos} many {# níos} other {# níos}}",
"hints.profiles.followers_may_be_missing": "Seans go bhfuil leantóirí don phróifíl seo in easnamh.",
@ -512,7 +519,6 @@
"lists.exclusive": "Folaigh baill sa Bhaile",
"lists.exclusive_hint": "Má tá duine ar an liosta seo, cuir i bhfolach iad i do fhotha Baile ionas nach bhfeicfidh tú a bpoist faoi dhó.",
"lists.find_users_to_add": "Aimsigh úsáideoirí le cur leis",
"lists.list_members": "Liostaigh baill",
"lists.list_members_count": "{count, plural, one {# ball} two {# bhall} few {# baill} many {# baill} other {# baill}}",
"lists.list_name": "Ainm an liosta",
"lists.new_list_name": "Ainm liosta nua",
@ -858,6 +864,13 @@
"status.mute_conversation": "Balbhaigh comhrá",
"status.open": "Leathnaigh an post seo",
"status.pin": "Gné ar phróifíl",
"status.quote_error.filtered": "I bhfolach mar gheall ar cheann de do scagairí",
"status.quote_error.not_found": "Ní féidir an post seo a thaispeáint.",
"status.quote_error.pending_approval": "Tá an post seo ag feitheamh ar cheadú ón údar bunaidh.",
"status.quote_error.rejected": "Ní féidir an post seo a thaispeáint mar ní cheadaíonn an t-údar bunaidh é a lua.",
"status.quote_error.removed": "Baineadh an post seo ag a údar.",
"status.quote_error.unauthorized": "Ní féidir an post seo a thaispeáint mar níl údarú agat é a fheiceáil.",
"status.quote_post_author": "Postáil le {name}",
"status.read_more": "Léan a thuilleadh",
"status.reblog": "Treisiú",
"status.reblog_private": "Mol le léargas bunúsach",

View file

@ -515,7 +515,6 @@
"lists.exclusive": "Falaich na buill san dachaigh",
"lists.exclusive_hint": "Falaich an fheadhainn a tha air an liosta seo air loidhne-ama na dachaigh ach nach fhaic thu na postaichean aca dà thuras.",
"lists.find_users_to_add": "Lorg cleachdaichean ri chur ris",
"lists.list_members": "Buill na liosta",
"lists.list_members_count": "{count, plural, one {# bhall} two {# bhall} few {# buill} other {# ball}}",
"lists.list_name": "Ainm na liosta",
"lists.new_list_name": "Ainm na liosta ùire",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Editar perfil",
"account.enable_notifications": "Noficarme cando @{name} publique",
"account.endorse": "Amosar no perfil",
"account.familiar_followers_many": "Seguida por {name1}, {name2}, e {othersCount, plural, one {outra conta que coñeces} other {outras # contas que coñeces}}",
"account.familiar_followers_one": "Seguida por {name1}",
"account.familiar_followers_two": "Seguida por {name1} e {name2}",
"account.featured": "Destacado",
"account.featured.accounts": "Perfís",
"account.featured.hashtags": "Cancelos",
@ -39,6 +42,7 @@
"account.followers": "Seguidoras",
"account.followers.empty": "Aínda ninguén segue esta usuaria.",
"account.followers_counter": "{count, plural, one {{counter} seguidora} other {{counter} seguidoras}}",
"account.followers_you_know_counter": "{counter} que coñeces",
"account.following": "Seguindo",
"account.following_counter": "{count, plural, one {{counter} seguimento} other {{counter} seguimentos}}",
"account.follows.empty": "Esta usuaria aínda non segue a ninguén.",
@ -388,7 +392,7 @@
"footer.privacy_policy": "Política de privacidade",
"footer.source_code": "Ver código fonte",
"footer.status": "Estado",
"footer.terms_of_service": "Termos do servizo",
"footer.terms_of_service": "Condicións do servizo",
"generic.saved": "Gardado",
"getting_started.heading": "Primeiros pasos",
"hashtag.admin_moderation": "Abrir interface de moderación para ##{name}",
@ -515,7 +519,6 @@
"lists.exclusive": "Ocultar membros no Inicio",
"lists.exclusive_hint": "Se alguén está nesta lista non aparerá na cronoloxía de Inicio para evitar duplicidades das publicacións.",
"lists.find_users_to_add": "Buscar persoas que engadir",
"lists.list_members": "Membros da lista",
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
"lists.list_name": "Nome da lista",
"lists.new_list_name": "Novo nome da lista",
@ -861,6 +864,12 @@
"status.mute_conversation": "Silenciar conversa",
"status.open": "Estender esta publicación",
"status.pin": "Destacar no perfil",
"status.quote_error.not_found": "Non se pode mostrar a publicación.",
"status.quote_error.pending_approval": "A publicación está pendente da aprobación pola autora orixinal.",
"status.quote_error.rejected": "Non se pode mostrar esta publicación xa que a autora orixinal non permite que se cite.",
"status.quote_error.removed": "Publicación eliminada pola autora.",
"status.quote_error.unauthorized": "Non se pode mostrar esta publicación porque non tes permiso para vela.",
"status.quote_post_author": "Publicación de {name}",
"status.read_more": "Ler máis",
"status.reblog": "Promover",
"status.reblog_private": "Compartir coa audiencia orixinal",
@ -892,7 +901,7 @@
"tabs_bar.home": "Inicio",
"tabs_bar.notifications": "Notificacións",
"terms_of_service.effective_as_of": "Con efecto desde o {date}",
"terms_of_service.title": "Termos do Servizo",
"terms_of_service.title": "Condicións do Servizo",
"terms_of_service.upcoming_changes_on": "Cambios por vir o {date}",
"time_remaining.days": "Remata en {number, plural, one {# día} other {# días}}",
"time_remaining.hours": "Remata en {number, plural, one {# hora} other {# horas}}",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "עריכת פרופיל",
"account.enable_notifications": "שלח לי התראות כש@{name} מפרסם",
"account.endorse": "קדם את החשבון בפרופיל",
"account.familiar_followers_many": "החשבון נעקב על ידי {name1}, {name2} ועוד {othersCount, plural,one {אחד נוסף שמוכר לך}other {# נוספים שמוכרים לך}}",
"account.familiar_followers_one": "החשבון נעקב על ידי {name1}",
"account.familiar_followers_two": "החשבון נעקב על ידי {name1} ו־{name2}",
"account.featured": "מומלץ",
"account.featured.accounts": "פרופילים",
"account.featured.hashtags": "תגיות",
@ -39,6 +42,7 @@
"account.followers": "עוקבים",
"account.followers.empty": "אף אחד לא עוקב אחר המשתמש הזה עדיין.",
"account.followers_counter": "{count, plural,one {עוקב אחד} other {{counter} עוקבים}}",
"account.followers_you_know_counter": "{counter} שמוכרים לך",
"account.following": "נעקבים",
"account.following_counter": "{count, plural,one {עוקב אחרי {count}}other {עוקב אחרי {counter}}}",
"account.follows.empty": "משתמש זה עדיין לא עוקב אחרי אף אחד.",
@ -515,7 +519,6 @@
"lists.exclusive": "הסתרת החברים בפיד הבית",
"lists.exclusive_hint": "אם שם כלשהו ברשימה זו, נסתיר אותי בפיד הבית כדי למנוע כפילות.",
"lists.find_users_to_add": "חיפוש משתמשים להוספה",
"lists.list_members": "פירוט חברי הרשימה",
"lists.list_members_count": "{count, plural, one {חבר רשימה אחד} other {# חברי רשימה}}",
"lists.list_name": "שם הרשימה",
"lists.new_list_name": "שם רשימה חדשה",
@ -861,6 +864,13 @@
"status.mute_conversation": "השתקת שיחה",
"status.open": "הרחבת הודעה זו",
"status.pin": "מובלט בפרופיל",
"status.quote_error.filtered": "מוסתר בהתאם לסננים שלך",
"status.quote_error.not_found": "לא ניתן להציג הודעה זו.",
"status.quote_error.pending_approval": "הודעה זו מחכה לאישור מידי היוצר המקורי.",
"status.quote_error.rejected": "לא ניתן להציג הודעה זו שכן המחבר.ת המקוריים לא הרשו לצטט אותה.",
"status.quote_error.removed": "הודעה זו הוסרה על ידי השולחים המקוריים.",
"status.quote_error.unauthorized": "הודעה זו לא מוצגת כיוון שאין לך רשות לראותה.",
"status.quote_post_author": "פרסום מאת {name}",
"status.read_more": "לקרוא עוד",
"status.reblog": "הדהוד",
"status.reblog_private": "להדהד ברמת הנראות המקורית",

View file

@ -28,7 +28,11 @@
"account.edit_profile": "Profil szerkesztése",
"account.enable_notifications": "Figyelmeztessen, ha @{name} bejegyzést tesz közzé",
"account.endorse": "Kiemelés a profilodon",
"account.familiar_followers_many": "{name1}, {name2} és még {othersCount, plural, one {egy valaki} other {# valaki}}, akit ismersz",
"account.familiar_followers_one": "{name1} követi",
"account.familiar_followers_two": "{name1} és {name2} követi",
"account.featured": "Kiemelt",
"account.featured.accounts": "Profilok",
"account.featured.hashtags": "Hashtagek",
"account.featured.posts": "Bejegyzések",
"account.featured_tags.last_status_at": "Legutolsó bejegyzés ideje: {date}",
@ -38,6 +42,7 @@
"account.followers": "Követő",
"account.followers.empty": "Ezt a felhasználót még senki sem követi.",
"account.followers_counter": "{count, plural, one {{counter} követő} other {{counter} követő}}",
"account.followers_you_know_counter": "{counter} ismerős",
"account.following": "Követve",
"account.following_counter": "{count, plural, one {{counter} követett} other {{counter} követett}}",
"account.follows.empty": "Ez a felhasználó még senkit sem követ.",
@ -405,8 +410,10 @@
"hashtag.counter_by_accounts": "{count, plural, one {{counter} résztvevő} other {{counter} résztvevő}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} bejegyzés} other {{counter} bejegyzés}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} bejegyzés} other {{counter} bejegyzés}} ma",
"hashtag.feature": "Kiemelés a profilodon",
"hashtag.follow": "Hashtag követése",
"hashtag.mute": "#{hashtag} némítása",
"hashtag.unfeature": "Ne legyen kiemelve a profilodon",
"hashtag.unfollow": "Hashtag követésének megszüntetése",
"hashtags.and_other": "…és {count, plural, other {# további}}",
"hints.profiles.followers_may_be_missing": "A profil követői lehet, hogy hiányoznak.",
@ -512,7 +519,6 @@
"lists.exclusive": "Tagok elrejtése a kezdőlapon",
"lists.exclusive_hint": "Ha valaki szerepel ezen a listán, el lesz rejtve a kezdőlapod hírfolyamán, hogy ne lásd kétszer a bejegyzéseit.",
"lists.find_users_to_add": "Hozzáadandó felhasználók keresése",
"lists.list_members": "Tagok listázása",
"lists.list_members_count": "{count, plural, one {# tag} other {# tag}}",
"lists.list_name": "Lista neve",
"lists.new_list_name": "Új lista neve",
@ -561,6 +567,7 @@
"navigation_bar.mutes": "Némított felhasználók",
"navigation_bar.opened_in_classic_interface": "A bejegyzések, fiókok és más speciális oldalak alapértelmezés szerint a klasszikus webes felületen nyílnak meg.",
"navigation_bar.personal": "Személyes",
"navigation_bar.pins": "Kiemelt bejegyzések",
"navigation_bar.preferences": "Beállítások",
"navigation_bar.public_timeline": "Föderációs idővonal",
"navigation_bar.search": "Keresés",
@ -856,6 +863,13 @@
"status.mute": "@{name} némítása",
"status.mute_conversation": "Beszélgetés némítása",
"status.open": "Bejegyzés kibontása",
"status.pin": "Kiemelés a profilodon",
"status.quote_error.not_found": "Ez a bejegyzés nem jeleníthető meg.",
"status.quote_error.pending_approval": "Ez a bejegyzés az eredeti szerző jóváhagyására vár.",
"status.quote_error.rejected": "Ez a bejegyzés nem jeleníthető meg, mert az eredeti szerzője nem engedélyezi az idézését.",
"status.quote_error.removed": "Ezt a bejegyzés eltávolította a szerzője.",
"status.quote_error.unauthorized": "Ez a bejegyzés nem jeleníthető meg, mert nem jogosult a megtekintésére.",
"status.quote_post_author": "Szerző: {name}",
"status.read_more": "Bővebben",
"status.reblog": "Megtolás",
"status.reblog_private": "Megtolás az eredeti közönségnek",
@ -880,6 +894,7 @@
"status.translated_from_with": "{lang} nyelvről fordítva {provider} szolgáltatással",
"status.uncached_media_warning": "Előnézet nem érhető el",
"status.unmute_conversation": "Beszélgetés némításának feloldása",
"status.unpin": "Ne legyen kiemelve a profilodon",
"subscribed_languages.lead": "A változtatás után csak a kiválasztott nyelvű bejegyzések fognak megjelenni a kezdőlapon és az idővonalakon. Ha egy sincs kiválasztva, akkor minden nyelven megjelennek a bejegyzések.",
"subscribed_languages.save": "Változások mentése",
"subscribed_languages.target": "Feliratkozott nyelvek módosítása {target} esetében",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Modificar profilo",
"account.enable_notifications": "Notificar me quando @{name} publica",
"account.endorse": "Evidentiar sur le profilo",
"account.familiar_followers_many": "Sequite per {name1}, {name2}, e {othersCount, plural, one {un altere que tu cognosce} other {# alteres que tu cognosce}}",
"account.familiar_followers_one": "Sequite per {name1}",
"account.familiar_followers_two": "Sequite per {name1} e {name2}",
"account.featured": "In evidentia",
"account.featured.accounts": "Profilos",
"account.featured.hashtags": "Hashtags",
@ -404,7 +407,10 @@
"hashtag.counter_by_accounts": "{count, plural, one {{counter} participante} other {{counter} participantes}}",
"hashtag.counter_by_uses": "{count, plural, one {{counter} message} other {{counter} messages}}",
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} message} other {{counter} messages}} hodie",
"hashtag.feature": "Evidentiar sur le profilo",
"hashtag.follow": "Sequer hashtag",
"hashtag.mute": "Silentiar #{hashtag}",
"hashtag.unfeature": "Non evidentiar sur le profilo",
"hashtag.unfollow": "Non sequer plus le hashtag",
"hashtags.and_other": "…e {count, plural, one {un altere} other {# alteres}}",
"hints.profiles.followers_may_be_missing": "Le sequitores de iste profilo pote mancar.",
@ -475,6 +481,7 @@
"keyboard_shortcuts.my_profile": "Aperir tu profilo",
"keyboard_shortcuts.notifications": "Aperir columna de notificationes",
"keyboard_shortcuts.open_media": "Aperir multimedia",
"keyboard_shortcuts.pinned": "Aperir lista de messages in evidentia",
"keyboard_shortcuts.profile": "Aperir le profilo del autor",
"keyboard_shortcuts.reply": "Responder al message",
"keyboard_shortcuts.requests": "Aperir le lista de requestas de sequimento",
@ -509,7 +516,6 @@
"lists.exclusive": "Celar memberos in Initio",
"lists.exclusive_hint": "Si alcuno es sur iste lista, celar iste persona in tu fluxo de initio pro evitar de vider su messages duo vices.",
"lists.find_users_to_add": "Trovar usatores a adder",
"lists.list_members": "Membros del lista",
"lists.list_members_count": "{count, plural, one {# membro} other {# membros}}",
"lists.list_name": "Nomine del lista",
"lists.new_list_name": "Nove nomine de lista",
@ -558,6 +564,7 @@
"navigation_bar.mutes": "Usatores silentiate",
"navigation_bar.opened_in_classic_interface": "Messages, contos e altere paginas specific es aperite per predefinition in le interfacie web classic.",
"navigation_bar.personal": "Personal",
"navigation_bar.pins": "Messages in evidentia",
"navigation_bar.preferences": "Preferentias",
"navigation_bar.public_timeline": "Chronologia federate",
"navigation_bar.search": "Cercar",
@ -853,6 +860,7 @@
"status.mute": "Silentiar @{name}",
"status.mute_conversation": "Silentiar conversation",
"status.open": "Expander iste message",
"status.pin": "Evidentiar sur le profilo",
"status.read_more": "Leger plus",
"status.reblog": "Impulsar",
"status.reblog_private": "Impulsar con visibilitate original",
@ -877,11 +885,13 @@
"status.translated_from_with": "Traducite de {lang} usante {provider}",
"status.uncached_media_warning": "Previsualisation non disponibile",
"status.unmute_conversation": "Non plus silentiar conversation",
"status.unpin": "Non evidentiar sur le profilo",
"subscribed_languages.lead": "Solmente le messages in le linguas seligite apparera in tu chronologias de initio e de listas post le cambiamento. Selige necun pro reciper messages in tote le linguas.",
"subscribed_languages.save": "Salvar le cambiamentos",
"subscribed_languages.target": "Cambiar le linguas subscribite pro {target}",
"tabs_bar.home": "Initio",
"tabs_bar.notifications": "Notificationes",
"terms_of_service.effective_as_of": "In vigor a partir de {date}",
"terms_of_service.title": "Conditiones de servicio",
"time_remaining.days": "{number, plural, one {# die} other {# dies}} restante",
"time_remaining.hours": "{number, plural, one {# hora} other {# horas}} restante",
@ -913,6 +923,11 @@
"video.expand": "Expander video",
"video.fullscreen": "Schermo plen",
"video.hide": "Celar video",
"video.mute": "Silentiar",
"video.pause": "Pausa",
"video.play": "Reproducer"
"video.play": "Reproducer",
"video.skip_backward": "Saltar a retro",
"video.unmute": "Non plus silentiar",
"video.volume_down": "Abassar le volumine",
"video.volume_up": "Augmentar le volumine"
}

View file

@ -28,7 +28,6 @@
"account.edit_profile": "Ubah profil",
"account.enable_notifications": "Beritahu saya saat @{name} memposting",
"account.endorse": "Tampilkan di profil",
"account.featured": "",
"account.featured_tags.last_status_at": "Kiriman terakhir pada {date}",
"account.featured_tags.last_status_never": "Tidak ada kiriman",
"account.follow": "Ikuti",

View file

@ -490,7 +490,6 @@
"lists.exclusive": "Celar membri sur Hemo",
"lists.exclusive_hint": "Se ulu es en ca listo, celez lu sur vua hemfluo por evitar vidar lua afishi denove.",
"lists.find_users_to_add": "Serchi uzanti por adjuntar",
"lists.list_members": "Listigar membri",
"lists.list_members_count": "{count, plural,one {# membro} other {#membri}}",
"lists.list_name": "Listonomo",
"lists.new_list_name": "Nova listonomo",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Breyta notandasniði",
"account.enable_notifications": "Láta mig vita þegar @{name} sendir inn",
"account.endorse": "Birta á notandasniði",
"account.familiar_followers_many": "Fylgt af {name1}, {name2} og {othersCount, plural, one {einum öðrum sem þú þekkir} other {# öðrum sem þú þekkir}}",
"account.familiar_followers_one": "Fylgt af {name1}",
"account.familiar_followers_two": "Fylgt af {name1} og {name2}",
"account.featured": "Með aukið vægi",
"account.featured.accounts": "Notendasnið",
"account.featured.hashtags": "Myllumerki",
@ -39,6 +42,7 @@
"account.followers": "Fylgjendur",
"account.followers.empty": "Ennþá fylgist enginn með þessum notanda.",
"account.followers_counter": "{count, plural, one {Fylgjandi: {counter}} other {Fylgjendur: {counter}}}",
"account.followers_you_know_counter": "{counter} sem þú þekkir",
"account.following": "Fylgist með",
"account.following_counter": "{count, plural, one {Fylgist með: {counter}} other {Fylgist með: {counter}}}",
"account.follows.empty": "Þessi notandi fylgist ennþá ekki með neinum.",
@ -515,7 +519,6 @@
"lists.exclusive": "Fela meðlimi í heimastreyminu",
"lists.exclusive_hint": "Ef einhver er á þessum lista, geturðu falið viðkomandi í heimastreyminu þínu til að komast hjá því að sjá færslurnar þeirra í tvígang.",
"lists.find_users_to_add": "Finndu notendur til að bæta við",
"lists.list_members": "Meðlimir lista",
"lists.list_members_count": "{count, plural, one {# meðlimur} other {# meðlimir}}",
"lists.list_name": "Heiti lista",
"lists.new_list_name": "Heiti á nýjum lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Þagga niður í samtali",
"status.open": "Opna þessa færslu",
"status.pin": "Birta á notandasniði",
"status.quote_error.filtered": "Falið vegna einnar síu sem er virk",
"status.quote_error.not_found": "Þessa færslu er ekki hægt að birta.",
"status.quote_error.pending_approval": "Þessi færsla bíður eftir samþykki frá upprunalegum höfundi hennar.",
"status.quote_error.rejected": "Þessa færslu er ekki hægt að birta þar sem upphaflegur höfundur hennar leyfir ekki að vitnað sé til hennar.",
"status.quote_error.removed": "Þessi færsla var fjarlægð af höfundi hennar.",
"status.quote_error.unauthorized": "Þessa færslu er ekki hægt að birta þar sem þú hefur ekki heimild til að skoða hana.",
"status.quote_post_author": "Færsla frá {name}",
"status.read_more": "Lesa meira",
"status.reblog": "Endurbirting",
"status.reblog_private": "Endurbirta til upphaflegra lesenda",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Modifica profilo",
"account.enable_notifications": "Avvisami quando @{name} pubblica un post",
"account.endorse": "In evidenza sul profilo",
"account.familiar_followers_many": "Seguito da {name1}, {name2}, e {othersCount, plural, one {un altro che conosci} other {# altri che conosci}}",
"account.familiar_followers_one": "Seguito da {name1}",
"account.familiar_followers_two": "Seguito da {name1} e {name2}",
"account.featured": "In primo piano",
"account.featured.accounts": "Profili",
"account.featured.hashtags": "Hashtag",
@ -39,6 +42,7 @@
"account.followers": "Follower",
"account.followers.empty": "Ancora nessuno segue questo utente.",
"account.followers_counter": "{count, plural, one {{counter} seguace} other {{counter} seguaci}}",
"account.followers_you_know_counter": "{counter} che conosci",
"account.following": "Seguiti",
"account.following_counter": "{count, plural, one {{counter} segui} other {{counter} seguiti}}",
"account.follows.empty": "Questo utente non segue ancora nessuno.",
@ -515,7 +519,6 @@
"lists.exclusive": "Nascondi i membri in Home",
"lists.exclusive_hint": "Se qualcuno è presente in questa lista, nascondilo nel tuo feed Home per evitare di vedere i suoi post due volte.",
"lists.find_users_to_add": "Trova utenti da aggiungere",
"lists.list_members": "Membri della lista",
"lists.list_members_count": "{count, plural, one {# membro} other {# membri}}",
"lists.list_name": "Nome della lista",
"lists.new_list_name": "Nuovo nome della lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Silenzia conversazione",
"status.open": "Espandi questo post",
"status.pin": "In evidenza sul profilo",
"status.quote_error.filtered": "Nascosto a causa di uno dei tuoi filtri",
"status.quote_error.not_found": "Questo post non può essere visualizzato.",
"status.quote_error.pending_approval": "Questo post è in attesa di approvazione dell'autore originale.",
"status.quote_error.rejected": "Questo post non può essere visualizzato perché l'autore originale non consente che venga citato.",
"status.quote_error.removed": "Questo post è stato rimosso dal suo autore.",
"status.quote_error.unauthorized": "Questo post non può essere visualizzato in quanto non sei autorizzato a visualizzarlo.",
"status.quote_post_author": "Post di @{name}",
"status.read_more": "Leggi di più",
"status.reblog": "Reblog",
"status.reblog_private": "Reblog con visibilità originale",

View file

@ -640,7 +640,6 @@
"lists.favourite": "お気に入りに登録",
"lists.favourite_hint": "お気に入りに登録したリストは、PCのWebクライアントでナビゲーションに表示されます",
"lists.find_users_to_add": "追加するユーザーを探しましょう",
"lists.list_members": "リストのメンバー",
"lists.list_members_count": "{count, plural, other{#人のメンバー}}",
"lists.list_name": "リスト名",
"lists.memo_related_antenna": "アンテナ: {title}",

View file

@ -19,39 +19,75 @@
"account.block_short": "Бұғаттау",
"account.blocked": "Бұғатталған",
"account.cancel_follow_request": "Withdraw follow request",
"account.direct": "@{name} жеке айту",
"account.disable_notifications": "@{name} постары туралы ескертпеу",
"account.domain_blocking": "Доменді бұғаттау",
"account.edit_profile": "Профильді өңдеу",
"account.enable_notifications": "@{name} постары туралы ескерту",
"account.endorse": "Профильде ұсыну",
"account.familiar_followers_many": "{name1}, {name2} және {othersCount, plural, one {сіз білетін тағы бір адам} other {сіз білетін тағы # адам}} жазылған",
"account.familiar_followers_one": "{name1} жазылған",
"account.familiar_followers_two": "{name1} мен {name2} жазылған",
"account.featured": "Ерекшеленген",
"account.featured.accounts": "Профильдер",
"account.featured.hashtags": "Хэштегтер",
"account.featured.posts": "Жазбалар",
"account.featured_tags.last_status_at": "Соңғы жазба {date} күні",
"account.featured_tags.last_status_never": "Пост жоқ",
"account.follow": "Жазылу",
"account.follow_back": "Кері жазылу",
"account.followers": "Жазылушы",
"account.followers.empty": "Бұл қолданушыға әлі ешкім жазылмаған.",
"account.followers_counter": "{count, plural, one {{counter} жазылушы} other {{counter} жазылушы}}",
"account.following": "Жазылым",
"account.following_counter": "{count, plural, one {{counter} жазылған} other {{counter} жазылған}}",
"account.follows.empty": "Бұл қолданушы әлі ешкімге жазылмаған.",
"account.follows_you": "Сізге жазылған",
"account.go_to_profile": "Профиліне өту",
"account.hide_reblogs": "@{name} бустарын жасыру",
"account.in_memoriam": "Естелік ретінде.",
"account.joined_short": "Қосылған",
"account.languages": "Жазылған тілдерді өзгерту",
"account.link_verified_on": "Сілтеме меншігі расталған күн {date}",
"account.locked_info": "Бұл қолданушы өзі туралы мәліметтерді жасырған. Тек жазылғандар ғана көре алады.",
"account.media": "Медиа",
"account.mention": "@{name} дегенді атау",
"account.moved_to": "{name} өзінің жаңа аккаунты енді мынау екенін көрсетті:",
"account.mute": "@{name} дегенді елемеу",
"account.mute_notifications_short": "Хабарландыруларды өшіру",
"account.mute_short": "Өшіру",
"account.muted": "Еленбейді",
"account.muting": "Өшіру",
"account.mutual": "Сіздер бір-біріңізге жазылғансыздар",
"account.no_bio": "Сипаттама берілмеген.",
"account.open_original_page": "Бастапқы бетті ашу",
"account.posts": "Пост",
"account.posts_with_replies": "Постар мен жауаптар",
"account.remove_from_followers": "{name} жазылушылардан жою",
"account.report": "Шағымдану @{name}",
"account.requested": "Растауын күтіңіз. Жазылудан бас тарту үшін басыңыз",
"account.requested_follow": "{name} сізге жазылуға сұраныс жіберді",
"account.requests_to_follow_you": "Сізге жазылу сұраныстары",
"account.share": "@{name} профилін бөлісу\"",
"account.show_reblogs": "@{name} бөліскендерін көрсету",
"account.statuses_counter": "{count, plural, one {{counter} жазба} other {{counter} жазба}}",
"account.unblock": "Бұғаттан шығару @{name}",
"account.unblock_domain": "Бұғаттан шығару {domain}",
"account.unblock_domain_short": "Бұғаттауды алу",
"account.unblock_short": "Бұғаттауды алу",
"account.unendorse": "Профильде рекомендемеу",
"account.unfollow": "Оқымау",
"account.unmute": "@{name} ескертпелерін қосу",
"account.unmute_notifications_short": "Хабарландыруларды қосу",
"account.unmute_short": "Қосу",
"account_note.placeholder": "Жазба қалдыру үшін бас",
"admin.dashboard.daily_retention": "Тіркелгеннен кейінгі күн бойынша пайдаланушыларды сақтау көрсеткіші",
"admin.dashboard.monthly_retention": "Тіркелгеннен кейінгі ай бойынша пайдаланушыларды сақтау көрсеткіші",
"admin.dashboard.retention.average": "Орташа",
"admin.dashboard.retention.cohort": "Тіркелу айы",
"admin.dashboard.retention.cohort_size": "Жаңа пайдаланушылар",
"admin.impact_report.instance_accounts": "Бұл жоятын аккаунт профильдері",
"admin.impact_report.instance_followers": "Біздің пайдаланушылар жоғалтатын жазылушылар",
"alert.rate_limited.message": "Қайтадан көріңіз {retry_time, time, medium} кейін.",
"alert.rate_limited.title": "Бағалау шектеулі",
"alert.unexpected.message": "Бір нәрсе дұрыс болмады.",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "프로필 편집",
"account.enable_notifications": "@{name} 의 게시물 알림 켜기",
"account.endorse": "프로필에 추천하기",
"account.familiar_followers_many": "{name1}, {name2} 님 외 내가 아는 {othersCount, plural, other {#}} 명이 팔로우함",
"account.familiar_followers_one": "{name1} 님이 팔로우함",
"account.familiar_followers_two": "{name1}, {name2} 님이 팔로우함",
"account.featured": "추천",
"account.featured.accounts": "프로필",
"account.featured.hashtags": "해시태그",
@ -406,8 +409,10 @@
"hashtag.counter_by_accounts": "{count, plural, other {참여자 {counter}명}}",
"hashtag.counter_by_uses": "{count, plural, other {게시물 {counter}개}}",
"hashtag.counter_by_uses_today": "오늘 {count, plural, other {{counter} 개의 게시물}}",
"hashtag.feature": "프로필에 추천하기",
"hashtag.follow": "해시태그 팔로우",
"hashtag.mute": "#{hashtag} 뮤트",
"hashtag.unfeature": "프로필에 추천하지 않기",
"hashtag.unfollow": "해시태그 팔로우 해제",
"hashtags.and_other": "…및 {count, plural,other {#개}}",
"hints.profiles.followers_may_be_missing": "이 프로필의 팔로워 목록은 일부 누락되었을 수 있습니다.",
@ -513,7 +518,6 @@
"lists.exclusive": "구성원을 홈에서 숨기기",
"lists.exclusive_hint": "누군가가 이 리스트에 있으면 홈 피드에서는 숨겨 게시물을 두 번 보는 것을 방지합니다.",
"lists.find_users_to_add": "추가할 사용자 검색",
"lists.list_members": "리스트 구성원",
"lists.list_members_count": "{count, plural, other {# 명}}",
"lists.list_name": "리스트 이름",
"lists.new_list_name": "새 리스트 이름",
@ -859,6 +863,11 @@
"status.mute_conversation": "대화 뮤트",
"status.open": "상세 정보 표시",
"status.pin": "고정",
"status.quote_error.not_found": "이 게시물은 표시할 수 없습니다.",
"status.quote_error.pending_approval": "이 게시물은 원작자의 승인을 기다리고 있습니다.",
"status.quote_error.rejected": "이 게시물은 원작자가 인용을 허용하지 않았기 때문에 표시할 수 없습니다.",
"status.quote_error.removed": "이 게시물은 작성자에 의해 삭제되었습니다.",
"status.quote_error.unauthorized": "이 게시물은 권한이 없기 때문에 볼 수 없습니다.",
"status.read_more": "더 보기",
"status.reblog": "부스트",
"status.reblog_private": "원래의 수신자들에게 부스트",

View file

@ -19,9 +19,28 @@
"account.block_domain": "Imperire dominium {domain}",
"account.block_short": "Imperire",
"account.blocked": "Impeditum est",
"account.blocking": "Clausus",
"account.cancel_follow_request": "Petitio sequī retrāhere",
"account.copy": "Transcribo connexi ut catagraphum",
"account.direct": "Callim loqui @{name}",
"account.disable_notifications": "Desine me certiorem facere cum @{name} scribit",
"account.domain_blocking": "Domenium obstructum",
"account.edit_profile": "Recolere notionem",
"account.enable_notifications": "Desine me certiorem facere cum @{name} scribit",
"account.endorse": "Notatio in profilo",
"account.familiar_followers_many": "Secuti sunt {name1}, {name2}, et {othersCount, plural, one {alius quem nosti} other {# alii quos nosti}}",
"account.familiar_followers_one": "Sequitur {name1}",
"account.familiar_followers_two": "Sequitur {name1} et {name2}",
"account.featured": "Praeclara",
"account.featured.accounts": "Profilia",
"account.featured.hashtags": "Hashtags",
"account.featured.posts": "Pilae",
"account.featured_tags.last_status_at": "Ultimum nuntium die {date}",
"account.featured_tags.last_status_never": "Nulla contributa",
"account.follow": "Sequere",
"account.follow_back": "Sequere retro",
"account.followers": "Sectatores",
"account.followers.empty": "Nemo hunc usorem adhuc sequitur.",
"account.followers_counter": "{count, plural, one {{counter} sectator} other {{counter} sectatores}}",
"account.following_counter": "{count, plural, one {{counter} sectans} other {{counter} sectans}}",
"account.moved_to": "{name} significavit eum suam rationem novam nunc esse:",

View file

@ -5,6 +5,10 @@ import { isLocaleLoaded, setLocale } from './global_locale';
const localeLoadingSemaphore = new Semaphore(1);
const localeFiles = import.meta.glob<{ default: LocaleData['messages'] }>([
'./*.json',
]);
export async function loadLocale() {
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
const locale = document.querySelector<HTMLElement>('html')?.lang || 'en';
@ -17,13 +21,14 @@ export async function loadLocale() {
// if the locale is already set, then do nothing
if (isLocaleLoaded()) return;
const localeData = (await import(
/* webpackMode: "lazy" */
/* webpackChunkName: "locale/[request]" */
/* webpackInclude: /\.json$/ */
/* webpackPreload: true */
`mastodon/locales/${locale}.json`
)) as LocaleData['messages'];
// If there is no locale file, then fallback to english
const localeFile = Object.hasOwn(localeFiles, `./${locale}.json`)
? localeFiles[`./${locale}.json`]
: localeFiles['./en.json'];
if (!localeFile) throw new Error('Could not load the locale JSON file');
const { default: localeData } = await localeFile();
setLocale({ messages: localeData, locale });
});

View file

@ -504,7 +504,6 @@
"lists.exclusive": "Slėpti narius pagrindiniame",
"lists.exclusive_hint": "Jei kas nors yra šiame sąraše, paslėpkite juos pagrindinio srauto laiko skalėje, kad nematytumėte jų įrašus dukart.",
"lists.find_users_to_add": "Raskite naudotojų, kurių pridėti",
"lists.list_members": "Sąrašo nariai",
"lists.list_members_count": "{count, plural, one {# narys} few {# nariai} many {# nario} other {# narių}}",
"lists.list_name": "Sąrašo pavadinimas",
"lists.new_list_name": "Naujas sąrašo pavadinimas",

View file

@ -19,13 +19,19 @@
"account.block_domain": "Bloķēt domēnu {domain}",
"account.block_short": "Bloķēt",
"account.blocked": "Bloķēts",
"account.blocking": "Bloķēts",
"account.cancel_follow_request": "Atsaukt sekošanas pieprasījumu",
"account.copy": "Ievietot saiti uz profilu starpliktuvē",
"account.direct": "Pieminēt @{name} privāti",
"account.disable_notifications": "Pārtraukt man paziņot, kad @{name} izveido ierakstu",
"account.domain_blocking": "Bloķēts domēns",
"account.edit_profile": "Labot profilu",
"account.enable_notifications": "Paziņot man, kad @{name} izveido ierakstu",
"account.endorse": "Izcelts profilā",
"account.familiar_followers_many": "Kam seko {name1}, {name2}, un {othersCount, plural, zero {pārējie # jums pazīstami} one {vēl viens jums pazīstams} other {pārējie # jums pazīstami}}",
"account.familiar_followers_one": "Kam seko {name1}",
"account.familiar_followers_two": "Kam seko {name1} un {name2}",
"account.featured": "Izcelts",
"account.featured.accounts": "Profili",
"account.featured.hashtags": "Tēmturi",
"account.featured.posts": "Ieraksti",
@ -36,10 +42,11 @@
"account.followers": "Sekotāji",
"account.followers.empty": "Šim lietotājam vēl nav sekotāju.",
"account.followers_counter": "{count, plural, zero {{count} sekotāju} one {{count} sekotājs} other {{count} sekotāji}}",
"account.followers_you_know_counter": "{counter} jūs pazīstiet",
"account.following": "Seko",
"account.following_counter": "{count, plural, one {seko {counter}} other {seko {counter}}}",
"account.follows.empty": "Šis lietotājs pagaidām nevienam neseko.",
"account.follows_you": "Seko tev",
"account.follows_you": "Seko Tev",
"account.go_to_profile": "Doties uz profilu",
"account.hide_reblogs": "Paslēpt @{name} pastiprinātos ierakstus",
"account.in_memoriam": "Piemiņai.",
@ -54,6 +61,7 @@
"account.mute_notifications_short": "Apklusināt paziņojumus",
"account.mute_short": "Apklusināt",
"account.muted": "Apklusināts",
"account.muting": "Apklusināts",
"account.mutual": "Jūs sekojat viens otram",
"account.no_bio": "Apraksts nav sniegts.",
"account.open_original_page": "Atvērt pirmavota lapu",
@ -69,6 +77,7 @@
"account.statuses_counter": "{count, plural, zero {{counter} ierakstu} one {{counter} ieraksts} other {{counter} ieraksti}}",
"account.unblock": "Atbloķēt @{name}",
"account.unblock_domain": "Atbloķēt domēnu {domain}",
"account.unblock_domain_short": "Atbloķēt",
"account.unblock_short": "Atbloķēt",
"account.unendorse": "Neizcelt profilā",
"account.unfollow": "Pārstāt sekot",
@ -90,6 +99,7 @@
"alert.unexpected.message": "Radās negaidīta kļūda.",
"alert.unexpected.title": "Ups!",
"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",
"alt_text_modal.cancel": "Atcelt",
"alt_text_modal.change_thumbnail": "Nomainīt sīktēlu",
@ -159,7 +169,7 @@
"column.lists": "Saraksti",
"column.mutes": "Apklusinātie lietotāji",
"column.notifications": "Paziņojumi",
"column.pins": "Piedāvātās ziņas",
"column.pins": "Attēlotie ieraksti",
"column.public": "Apvienotā laika līnija",
"column_back_button.label": "Atpakaļ",
"column_header.hide_settings": "Paslēpt iestatījumus",
@ -217,8 +227,10 @@
"confirmations.logout.confirm": "Atteikties",
"confirmations.logout.message": "Vai tiešām atteikties?",
"confirmations.logout.title": "Atteikties?",
"confirmations.missing_alt_text.confirm": "Pievienot aprakstošo tekstu",
"confirmations.missing_alt_text.message": "Tavs ieraksts satur informācijas nesējus bez paskaidrojošā teksta. Aprakstu pievienošana palīdz padarīt saturu pieejamāku vairāk cilvēku.",
"confirmations.missing_alt_text.secondary": "Vienalga iesūtīt",
"confirmations.missing_alt_text.title": "Pievienot aprakstošo tekstu?",
"confirmations.mute.confirm": "Apklusināt",
"confirmations.redraft.confirm": "Dzēst un pārrakstīt",
"confirmations.redraft.message": "Vai tiešām vēlies izdzēst šo ierakstu un veidot jaunu tā uzmetumu? Pievienošana izlasēs un pastiprinājumi tiks zaudēti, un sākotnējā ieraksta atbildes paliks bez saiknes ar to.",
@ -241,7 +253,7 @@
"conversation.with": "Ar {names}",
"copy_icon_button.copied": "Ievietots starpliktuvē",
"copypaste.copied": "Nokopēts",
"copypaste.copy_to_clipboard": "Kopēt uz starpliktuvi",
"copypaste.copy_to_clipboard": "Ievietot starpliktuvē",
"directory.federated": "No zināma fediversa",
"directory.local": "Tikai no {domain}",
"directory.new_arrivals": "Jaunpienācēji",
@ -283,6 +295,9 @@
"emoji_button.search_results": "Meklēšanas rezultāti",
"emoji_button.symbols": "Simboli",
"emoji_button.travel": "Ceļošana un vietas",
"empty_column.account_featured.me": "Jūs vēl neko neesiet likuši attēlot savā profilā. Vai zinājāt, ka variet attēlot savus ierakstus, bieži izmantotās mirkļbirkas un pat draugu profilus savā profilā?",
"empty_column.account_featured.other": "{acct} vēl neko nav licis attēlot savā profilā. Vai zinājāt, ka variet attēlot savus ierakstus, bieži izmantotās mirkļbirkas un pat draugu profilus savā profilā?",
"empty_column.account_featured_other.unknown": "Šis lietotājs vēl neko nav licis attēlot savā profilā.",
"empty_column.account_hides_collections": "Šis lietotājs ir izvēlējies nedarīt šo informāciju pieejamu",
"empty_column.account_suspended": "Konta darbība ir apturēta",
"empty_column.account_timeline": "Šeit nav ierakstu.",
@ -334,7 +349,7 @@
"firehose.all": "Visi",
"firehose.local": "Šis serveris",
"firehose.remote": "Citi serveri",
"follow_request.authorize": "Autorizēt",
"follow_request.authorize": "Pilnvarot",
"follow_request.reject": "Noraidīt",
"follow_requests.unlocked_explanation": "Lai gan Tavs konts nav slēgts, {domain} darbinieki iedomājās, ka Tu varētu vēlēties pašrocīgi pārskatīt sekošanas pieprasījumus no šiem kontiem.",
"follow_suggestions.curated_suggestion": "Darbinieku izvēle",
@ -358,6 +373,8 @@
"generic.saved": "Saglabāts",
"getting_started.heading": "Darba sākšana",
"hashtag.admin_moderation": "Atvērt #{name} satura pārraudzības saskarni",
"hashtag.browse": "Pārlūkot #{hashtag} ierakstus",
"hashtag.browse_from_account": "Pārlūkot @{name} #{hashtag} ierakstus",
"hashtag.column_header.tag_mode.all": "un {additional}",
"hashtag.column_header.tag_mode.any": "vai {additional}",
"hashtag.column_header.tag_mode.none": "bez {additional}",
@ -372,6 +389,7 @@
"hashtag.counter_by_uses_today": "{count, plural, zero {{counter} ierakstu} one {{counter} ieraksts} other {{counter} ieraksti}} šodien",
"hashtag.feature": "Attēlot profilā",
"hashtag.follow": "Sekot tēmturim",
"hashtag.mute": "Apklusināt #{hashtag}",
"hashtag.unfeature": "Neattēlot profilā",
"hashtag.unfollow": "Pārstāt sekot tēmturim",
"hashtags.and_other": "… un {count, plural, other {vēl #}}",
@ -389,6 +407,7 @@
"home.show_announcements": "Rādīt paziņojumus",
"ignore_notifications_modal.ignore": "Neņemt vērā paziņojumus",
"ignore_notifications_modal.not_following_title": "Neņemt vērā paziņojumus no cilvēkiem, kuriem neseko?",
"info_button.label": "Palīdzība",
"interaction_modal.action.favourite": "Lai turpinātu, nepieciešams pievienot sava konta izlasei.",
"interaction_modal.action.follow": "Lai turpinātu, nepieciešams sekot no sava konta.",
"interaction_modal.action.reblog": "Lai turpinātu, nepieciešams pastiprināt no sava konta.",
@ -428,7 +447,7 @@
"keyboard_shortcuts.my_profile": "Atvērt savu profilu",
"keyboard_shortcuts.notifications": "Atvērt paziņojumu kolonnu",
"keyboard_shortcuts.open_media": "Atvērt multividi",
"keyboard_shortcuts.pinned": "Atvērt piedāvāto ziņu sarakstu",
"keyboard_shortcuts.pinned": "Atvērt attēloto ierakstu sarakstu",
"keyboard_shortcuts.profile": "Atvērt autora profilu",
"keyboard_shortcuts.reply": "Atbildēt",
"keyboard_shortcuts.requests": "Atvērt sekošanas pieprasījumu sarakstu",
@ -438,27 +457,33 @@
"keyboard_shortcuts.toggle_hidden": "Rādīt/slēpt tekstu aiz satura brīdinājuma",
"keyboard_shortcuts.toggle_sensitivity": "Rādīt/slēpt multividi",
"keyboard_shortcuts.toot": "Uzsākt jaunu ierakstu",
"keyboard_shortcuts.translate": "tulkot ierakstu",
"keyboard_shortcuts.unfocus": "Atfokusēt veidojamā teksta/meklēšanas lauku",
"keyboard_shortcuts.up": "Pārvietoties augšup sarakstā",
"lightbox.close": "Aizvērt",
"lightbox.next": "Tālāk",
"lightbox.previous": "Iepriekšējais",
"lightbox.zoom_in": "Tālummainīt līdz patiesajam izmēram",
"lightbox.zoom_out": "Tālummainīt, lai ietilpinātu",
"limited_account_hint.action": "Tik un tā rādīt profilu",
"limited_account_hint.title": "{domain} moderatori ir paslēpuši šo profilu.",
"link_preview.author": "No {name}",
"link_preview.more_from_author": "Vairāk no {name}",
"lists.add_member": "Pievienot",
"lists.add_to_list": "Pievienot sarakstam",
"lists.add_to_lists": "Pievienot {name} sarakstiem",
"lists.create": "Izveidot",
"lists.create_list": "Izveidot sarakstu",
"lists.delete": "Izdzēst sarakstu",
"lists.done": "Gatavs",
"lists.edit": "Labot sarakstu",
"lists.list_name": "Saraksta nosaukums",
"lists.remove_member": "Noņemt",
"lists.replies_policy.followed": "Jebkuram sekotajam lietotājam",
"lists.replies_policy.list": "Saraksta dalībniekiem",
"lists.replies_policy.none": "Nevienam",
"lists.save": "Saglabāt",
"lists.search": "Meklēt",
"load_pending": "{count, plural, zero{# jaunu vienumu} one {# jauns vienums} other {# jauni vienumi}}",
"loading_indicator.label": "Ielādē…",
"media_gallery.hide": "Paslēpt",
@ -489,7 +514,7 @@
"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.personal": "Personīgie",
"navigation_bar.pins": "Piedāvātās ziņas",
"navigation_bar.pins": "Attēlotie ieraksti",
"navigation_bar.preferences": "Iestatījumi",
"navigation_bar.public_timeline": "Apvienotā laika līnija",
"navigation_bar.search": "Meklēt",
@ -502,6 +527,7 @@
"notification.favourite": "{name} pievienoja izlasei Tavu ierakstu",
"notification.follow": "{name} uzsāka Tev sekot",
"notification.follow_request": "{name} nosūtīja Tev sekošanas pieprasījumu",
"notification.mentioned_you": "{name} pieminēja jūs",
"notification.moderation-warning.learn_more": "Uzzināt vairāk",
"notification.moderation_warning": "Ir saņemts satura pārraudzības brīdinājums",
"notification.moderation_warning.action_delete_statuses": "Daži no Taviem ierakstiem tika noņemti.",
@ -523,6 +549,7 @@
"notification_requests.exit_selection": "Gatavs",
"notification_requests.notifications_from": "Paziņojumi no {name}",
"notification_requests.title": "Atlasītie paziņojumi",
"notification_requests.view": "Skatīt paziņojumus",
"notifications.clear": "Notīrīt paziņojumus",
"notifications.clear_confirmation": "Vai tiešām vēlies neatgriezeniski notīrīt visus savus paziņojumus?",
"notifications.column_settings.admin.report": "Jauni ziņojumi:",
@ -568,6 +595,7 @@
"notifications_permission_banner.title": "Nekad nepalaid neko garām",
"onboarding.follows.back": "Atpakaļ",
"onboarding.follows.empty": "Diemžēl pašlaik nevar parādīt rezultātus. Vari mēģināt izmantot meklēšanu vai pārlūkot izpētes lapu, lai atrastu cilvēkus, kuriem sekot, vai vēlāk mēģināt vēlreiz.",
"onboarding.follows.search": "Meklēt",
"onboarding.profile.discoverable": "Padarīt manu profilu atklājamu",
"onboarding.profile.display_name": "Attēlojamais vārds",
"onboarding.profile.display_name_hint": "Tavs pilnais vārds vai Tavs joku vārds…",
@ -650,7 +678,7 @@
"report.statuses.title": "Vai ir kādi ieraksti, kas apstiprina šo ziņojumu?",
"report.submit": "Iesniegt",
"report.target": "Ziņošana par: {target}",
"report.thanks.take_action": "Šeit ir iespējas, lai pārvaldītu Mastodon redzamo saturu:",
"report.thanks.take_action": "Šeit ir iespējas Mastodon redzamā satura pārvaldīšanai:",
"report.thanks.take_action_actionable": "Kamēr mēs to izskatām, tu vari veikt darbības pret @{name}:",
"report.thanks.title": "Nevēlies to redzēt?",
"report.thanks.title_actionable": "Paldies, ka ziņoji, mēs to izskatīsim.",
@ -725,7 +753,13 @@
"status.mute": "Apklusināt @{name}",
"status.mute_conversation": "Apklusināt sarunu",
"status.open": "Izvērst šo ierakstu",
"status.pin": "Piedāvāt profilā",
"status.pin": "Attēlot profilā",
"status.quote_error.not_found": "Šo ierakstu nevar parādīt.",
"status.quote_error.pending_approval": "Šis ieraksts gaida apstiprinājumu no tā autora.",
"status.quote_error.rejected": "Šo ierakstu nevar parādīt, jo tā autors neļauj to citēt.",
"status.quote_error.removed": "Šo ierakstu noņēma tā autors.",
"status.quote_error.unauthorized": "Šo ierakstu nevar parādīt, jo jums nav atļaujas to skatīt.",
"status.quote_post_author": "Publicēja {name}",
"status.read_more": "Lasīt vairāk",
"status.reblog": "Pastiprināt",
"status.reblog_private": "Pastiprināt ar sākotnējo redzamību",
@ -748,12 +782,13 @@
"status.translated_from_with": "Tulkots no {lang} izmantojot {provider}",
"status.uncached_media_warning": "Priekšskatījums nav pieejams",
"status.unmute_conversation": "Noņemt sarunas apklusinājumu",
"status.unpin": "Nepiedāvāt profilā",
"status.unpin": "Neattēlot profilā",
"subscribed_languages.lead": "Pēc izmaiņu veikšanas Tavā mājas un sarakstu laika līnijā tiks rādīti tikai ieraksti atlasītajās valodās. Neatlasīt nevienu, lai saņemtu ierakstus visās valodās.",
"subscribed_languages.save": "Saglabāt izmaiņas",
"subscribed_languages.target": "Mainīt abonētās valodas priekš {target}",
"tabs_bar.home": "Sākums",
"tabs_bar.notifications": "Paziņojumi",
"terms_of_service.title": "Pakalpojuma izmantošanas noteikumi",
"time_remaining.days": "{number, plural, one {Atlikusi # diena} other {Atlikušas # dienas}}",
"time_remaining.hours": "{number, plural, one {Atlikusi # stunda} other {Atlikušas # stundas}}",
"time_remaining.minutes": "{number, plural, one {Atlikusi # minūte} other {Atlikušas # minūtes}}",
@ -779,6 +814,12 @@
"video.expand": "Paplašināt video",
"video.fullscreen": "Pilnekrāns",
"video.hide": "Slēpt video",
"video.mute": "Izslēgt skaņu",
"video.pause": "Pauze",
"video.play": "Atskaņot"
"video.play": "Atskaņot",
"video.skip_backward": "Tīt atpakaļ",
"video.skip_forward": "Tīt uz priekšu",
"video.unmute": "Ieslēgt skaņu",
"video.volume_down": "Pagriezt klusāk",
"video.volume_up": "Pagriezt skaļāk"
}

View file

@ -19,13 +19,16 @@
"account.block_domain": "Sekat domain {domain}",
"account.block_short": "Sekat",
"account.blocked": "Disekat",
"account.blocking": "Blocking",
"account.cancel_follow_request": "Batalkan permintaan ikut",
"account.copy": "Salin pautan ke profil",
"account.direct": "Sebut secara persendirian @{name}",
"account.disable_notifications": "Berhenti maklumkan saya apabila @{name} mengirim hantaran",
"account.domain_blocking": "Blocking domain",
"account.edit_profile": "Sunting profil",
"account.enable_notifications": "Maklumi saya apabila @{name} mengirim hantaran",
"account.endorse": "Tampilkan di profil",
"account.familiar_followers_one": "melayuikutikut{name1}",
"account.featured_tags.last_status_at": "Hantaran terakhir pada {date}",
"account.featured_tags.last_status_never": "Tiada hantaran",
"account.follow": "Ikuti",

View file

@ -21,13 +21,16 @@
"account.blocked": "Hőng封鎖",
"account.blocking": "Teh封鎖",
"account.cancel_follow_request": "取消跟tuè",
"account.copy": "Khóo-pih kàu個人資料ê連結",
"account.copy": "Khóo-pih個人資料ê連結",
"account.direct": "私人提起 @{name}",
"account.disable_notifications": "停止佇 {name} PO文ê時通知我",
"account.domain_blocking": "Teh封鎖ê網域",
"account.edit_profile": "編輯個人資料",
"account.enable_notifications": "佇 {name} PO文ê時通知我",
"account.endorse": "用個人資料推薦對方",
"account.familiar_followers_many": "Hōo {name1}、{name2}kap {othersCount, plural, other {其他 lí熟似ê # ê lâng}} 跟tuè",
"account.familiar_followers_one": "Hōo {name1} 跟tuè",
"account.familiar_followers_two": "Hōo {name1} kap {name2} 跟tuè",
"account.featured": "精選ê",
"account.featured.accounts": "個人資料",
"account.featured.hashtags": "Hashtag",
@ -39,6 +42,7 @@
"account.followers": "跟tuè lí ê",
"account.followers.empty": "Tsit ê用者iáu bô lâng跟tuè。",
"account.followers_counter": "Hōo {count, plural, other {{count} ê lâng}}跟tuè",
"account.followers_you_know_counter": "Lí所知影ê {counter} ê lâng",
"account.following": "Lí跟tuè ê",
"account.following_counter": "Teh跟tuè {count,plural,other {{count} ê lâng}}",
"account.follows.empty": "Tsit ê用者iáu buē跟tuè別lâng。",
@ -354,7 +358,7 @@
"filter_modal.select_filter.prompt_new": "新ê類別:{name}",
"filter_modal.select_filter.search": "Tshiau-tshuē á是加添",
"filter_modal.select_filter.subtitle": "用有ê類別á是建立新ê",
"filter_modal.select_filter.title": "過濾tsit ê PO文",
"filter_modal.select_filter.title": "過濾tsitPO文",
"filter_modal.title.status": "過濾PO文",
"filter_warning.matches_filter": "合過濾器「<span>{title}</span>」",
"filtered_notifications_banner.pending_requests": "Tuì lí可能熟sāi ê {count, plural, =0 {0 ê人} other {# ê人}}",
@ -515,7 +519,6 @@
"lists.exclusive": "佇tshù ê時間線kā成員tshàng起來。",
"lists.exclusive_hint": "Nā bóo-mi̍h口座佇tsit ê列單,ē tuì lí tshù ê時間線kā tsit ê口座tshàng起來避免koh看見in ê PO文。",
"lists.find_users_to_add": "Tshuē beh加添ê用者",
"lists.list_members": "列單ê成員",
"lists.list_members_count": "{count, plural, other {# 位成員}}",
"lists.list_name": "列單ê名",
"lists.new_list_name": "新ê列單ê名",
@ -685,16 +688,26 @@
"notifications.policy.filter_private_mentions_title": "家kī直接送來ê私人提起",
"notifications.policy.title": "管理通知tuì……",
"notifications_permission_banner.enable": "啟用桌面ê通知",
"notifications_permission_banner.how_to_control": "Nā beh佇Mastodon關起來ê時陣收通知請啟用桌面通知。若準啟用Lí ē當通過面頂ê {icon} 鈕á準準控制siánn物互動ê類型ē生桌面通知。",
"notifications_permission_banner.title": "逐ê著看",
"onboarding.follows.back": "轉去",
"onboarding.follows.done": "做好ah",
"onboarding.follows.empty": "可惜tsit-má無半條結果通顯示。Lí ē當試用tshiau-tshuē á是瀏覽探索ê頁來tshuē beh跟tuè ê lâng或者是sió等leh koh試。",
"onboarding.follows.search": "Tshiau-tshuē",
"onboarding.follows.title": "請跟tuè lâng來開始。",
"onboarding.profile.discoverable": "Hōo我ê個人資料通tshuē著",
"onboarding.profile.discoverable_hint": "Nā lí揀beh佇Mastodon開hōo lâng發現ê功能lí ê PO文通顯示佇tshiau-tshuē結果kap趨勢而且你ê個人資料可能ē推薦hōo kap lí有相siâng興趣ê別lâng。",
"onboarding.profile.display_name": "顯示ê名",
"onboarding.profile.display_name_hint": "Lí ê全名á是別號……",
"onboarding.profile.note": "個人紹介",
"onboarding.profile.note_hint": "Lí ē當 @mention 別lâng á是用 #hashtag……",
"onboarding.profile.save_and_continue": "儲存了後繼續",
"onboarding.profile.title": "個人資料ê設定",
"onboarding.profile.upload_avatar": "Kā個人資料ê相片傳起去。",
"onboarding.profile.upload_header": "Kā個人資料ê橫條á ê圖傳起去",
"password_confirmation.exceeds_maxlength": "密碼確認超過上大ê密碼長度",
"password_confirmation.mismatching": "密碼確認kap密碼無合",
"picture_in_picture.restore": "復原",
"poll.closed": "關ah",
"poll.refresh": "Koh更新",
"poll.reveal": "看結果",
@ -712,6 +725,8 @@
"privacy.private.short": "跟tuè lí ê",
"privacy.public.long": "逐ê lâng無論佇Mastodon以內á是以外",
"privacy.public.short": "公開ê",
"privacy.unlisted.additional": "Tse ê行為kap公開相siângm̄-koh 就算lí佇口座設定phah開有關ê公開功能PO文mā bē顯示佇即時ê動態、hashtag、探索kap Mastodon ê搜尋結果。",
"privacy.unlisted.long": "減少演算法ê宣傳",
"privacy.unlisted.short": "恬靜ê公開",
"privacy_policy.last_updated": "上尾更新tī{date}",
"privacy_policy.title": "隱私權政策",
@ -734,6 +749,7 @@
"reply_indicator.cancel": "取消",
"reply_indicator.poll": "投票",
"report.block": "封鎖",
"report.block_explanation": "Lí bē koh看著in ê PO文。In bē當看tio̍h lí ê PO文kap跟tuè lí。In ē發現家kī受著封鎖。",
"report.categories.legal": "法律ê問題",
"report.categories.other": "其他",
"report.categories.spam": "Pùn-sò訊息",
@ -765,9 +781,143 @@
"report.statuses.subtitle": "請揀所有符合ê選項",
"report.statuses.title": "Kám有任何PO文證明tsit ê檢舉?",
"report.submit": "送出",
"report.target": "檢舉 {target}",
"report.thanks.take_action": "下kha是你控制所beh 佇Mastodon看ê內容ê選項",
"report.thanks.take_action_actionable": "佇guán leh審核ê時陣lí ē當tuì @{name} 做下kha ê行動:",
"report.thanks.title": "無想beh看著tse",
"report.thanks.title_actionable": "多謝lí ê檢舉guán ē處理。",
"report.unfollow": "取消跟tuè @{name}",
"report.unfollow_explanation": "Lí teh跟tuè tsit ê口座。Nā無beh佇頭頁ê時間線koh看見in ê PO文請取消跟tuè。",
"report_notification.attached_statuses": "附 {count, plural, one {{count} 篇PO文} other {{count} 篇PO文}}ah",
"report_notification.categories.legal": "法規",
"report_notification.categories.legal_sentence": "違法ê內容",
"report_notification.categories.other": "其他",
"report_notification.categories.other_sentence": "其他",
"report_notification.categories.spam": "Pùn-sò訊息",
"report_notification.categories.spam_sentence": "pùn-sò訊息",
"report_notification.categories.violation": "違反規則",
"report_notification.categories.violation_sentence": "違反規則",
"report_notification.open": "Phah開檢舉",
"search.no_recent_searches": "無最近ê tshiau-tshuē",
"search.placeholder": "Tshiau-tshuē",
"search.quick_action.account_search": "合 {x} ê個人檔案",
"search.quick_action.go_to_account": "行去個人資料 {x}",
"search.quick_action.go_to_hashtag": "行去hashtag {x}",
"search.quick_action.open_url": "佇Mastodon來phah開URL",
"search.quick_action.status_search": "合 {x} ê PO文",
"search.search_or_paste": "Tshiau-tshuē á是貼URL",
"search_popout.full_text_search_disabled_message": "{domain} 頂bē當用。",
"search_popout.full_text_search_logged_out_message": "Kan-ta佇登入ê時通用。",
"search_popout.language_code": "ISO語言代碼",
"search_popout.options": "Tshiau-tshuē ê選項",
"search_popout.quick_actions": "快速ê行動",
"search_popout.recent": "最近ê tshiau-tshuē",
"search_popout.specific_date": "特定ê日",
"search_popout.user": "用者",
"search_results.accounts": "個人資料",
"search_results.all": "全部",
"search_results.hashtags": "Hashtag",
"search_results.no_results": "無結果。",
"search_results.no_search_yet": "請試tshiau-tshuē PO文、個人資料á是hashtag。",
"search_results.see_all": "看全部",
"search_results.statuses": "PO文",
"search_results.title": "Tshiau-tshuē「{q}」",
"status.translated_from_with": "用 {provider} 翻譯 {lang}"
"server_banner.about_active_users": "最近30kang用本站êlâng月ê活動ê用者",
"server_banner.active_users": "活動ê用者",
"server_banner.administered_by": "管理員:",
"server_banner.is_one_of_many": "{domain} 屬佇tsē-tsē獨立ê Mastodonê服侍器lí ē當用tse參與聯邦宇宙。",
"server_banner.server_stats": "服侍器ê統計:",
"sign_in_banner.create_account": "開口座",
"sign_in_banner.follow_anyone": "跟tuè聯邦宇宙ê任何tsi̍t ê,用時間ê順序看所有ê內容。無演算法、廣告、點滑鼠ê餌(clickbait)。",
"sign_in_banner.mastodon_is": "Mastodon是跟tuè siánn物當teh發生ê上贊ê方法。",
"sign_in_banner.sign_in": "登入",
"sign_in_banner.sso_redirect": "登入á是註冊",
"status.admin_account": "Phah開 @{name} ê管理界面",
"status.admin_domain": "Phah開 {domain} ê管理界面",
"status.admin_status": "Tī管理界面內底看tsit篇PO文",
"status.block": "封鎖 @{name}",
"status.bookmark": "冊籤",
"status.cancel_reblog_private": "取消轉送",
"status.cannot_reblog": "Tsit篇PO文bē當轉送",
"status.continued_thread": "接續ê討論線",
"status.copy": "Khóo-pih PO文ê連結",
"status.delete": "Thâi掉",
"status.detailed_status": "對話ê詳細",
"status.direct": "私人提起 @{name}",
"status.direct_indicator": "私人ê提起",
"status.edit": "編輯",
"status.edited": "上尾編輯tī{date}",
"status.edited_x_times": "有編輯 {count, plural, one {{count} kái} other {{count} kái}}",
"status.embed": "The̍h相tàu ê (embed)程式碼",
"status.favourite": "收藏",
"status.favourites": "{count, plural, other {# 篇收藏}}",
"status.filter": "過濾tsit 篇 PO文",
"status.history.created": "{name} 佇 {date} 建立",
"status.history.edited": "{name} 佇 {date} 編輯",
"status.load_more": "載入其他ê內容",
"status.media.open": "點來開",
"status.media.show": "點來顯示",
"status.media_hidden": "Khàm起來ê媒體",
"status.mention": "提起 @{name}",
"status.more": "詳細",
"status.mute": "消音 @{name}",
"status.mute_conversation": "Kā對話消音",
"status.open": "Kā PO文展開",
"status.pin": "Tī個人資料推薦",
"status.quote_error.filtered": "Lí所設定ê過濾器kā tse khàm起來",
"status.quote_error.not_found": "Tsit篇PO文bē當顯示。",
"status.quote_error.pending_approval": "Tsit篇PO文teh等原作者審查。",
"status.quote_error.rejected": "因為原作者無允准引用tsit篇PO文bē當顯示。",
"status.quote_error.removed": "Tsit篇hōo作者thâi掉ah。",
"status.quote_error.unauthorized": "因為lí無得著讀tse ê權限tsit篇PO文bē當顯示。",
"status.quote_post_author": "{name} 所PO ê",
"status.read_more": "讀詳細",
"status.reblog": "轉送",
"status.reblog_private": "照原PO ê通看見ê範圍轉送",
"status.reblogged_by": "{name} kā轉送ah",
"status.reblogs": "{count, plural, other {# ê 轉送}}",
"status.reblogs.empty": "Iáu無lâng轉送tsit篇PO文。Nā是有lâng轉送ē佇tsia顯示。",
"status.redraft": "Thâi掉了後重寫",
"status.remove_bookmark": "Thâi掉冊籤",
"status.remove_favourite": "Tuì收藏內suá掉",
"status.replied_in_thread": "佇討論線內應",
"status.replied_to": "回應 {name}",
"status.reply": "回應",
"status.replyAll": "應討論線",
"status.report": "檢舉 @{name}",
"status.sensitive_warning": "敏感ê內容",
"status.share": "分享",
"status.show_less_all": "Lóng收起來",
"status.show_more_all": "Lóng展開",
"status.show_original": "顯示原文",
"status.title.with_attachments": "{user} 有PO {attachmentCount, plural, other {{attachmentCount} ê附件}}",
"status.translate": "翻譯",
"status.translated_from_with": "用 {provider} 翻譯 {lang}",
"status.uncached_media_warning": "Bē當先看māi",
"status.unmute_conversation": "Kā對話取消消音",
"status.unpin": "Mài tī個人資料推薦",
"tabs_bar.home": "頭頁",
"tabs_bar.notifications": "通知",
"terms_of_service.effective_as_of": "{date} 起實施",
"terms_of_service.title": "服務規定",
"terms_of_service.upcoming_changes_on": "Ē tī {date} 改變",
"time_remaining.days": "Tshun {number, plural, other {# kang}}",
"upload_form.edit": "編輯",
"upload_progress.label": "Teh傳起去……",
"upload_progress.processing": "Teh處理……",
"username.taken": "Tsit ê口座hōo lâng註冊ah試別ê",
"video.close": "關影片",
"video.download": "Kā檔案載落去",
"video.exit_fullscreen": "離開全螢幕",
"video.expand": "展開影片",
"video.fullscreen": "全螢幕",
"video.hide": "Tshàng影片",
"video.mute": "消音",
"video.pause": "暫停",
"video.play": "播出",
"video.skip_backward": "跳kah後壁",
"video.skip_forward": "跳kah頭前",
"video.unmute": "取消消音",
"video.volume_down": "變khah細聲",
"video.volume_up": "變khah大聲"
}

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Profiel bewerken",
"account.enable_notifications": "Geef een melding wanneer @{name} een bericht plaatst",
"account.endorse": "Op profiel weergeven",
"account.familiar_followers_many": "Gevolgd door {name1}, {name2} en {othersCount, plural, one {één ander bekend account} other {# andere bekende accounts}}",
"account.familiar_followers_one": "Gevolgd door {name1}",
"account.familiar_followers_two": "Gevolgd door {name1} en {name2}",
"account.featured": "Uitgelicht",
"account.featured.accounts": "Profielen",
"account.featured.hashtags": "Hashtags",
@ -39,6 +42,7 @@
"account.followers": "Volgers",
"account.followers.empty": "Deze gebruiker heeft nog geen volgers of heeft deze verborgen.",
"account.followers_counter": "{count, plural, one {{counter} volger} other {{counter} volgers}}",
"account.followers_you_know_counter": "{counter} die je kent",
"account.following": "Volgend",
"account.following_counter": "{count, plural, one {{counter} volgend} other {{counter} volgend}}",
"account.follows.empty": "Deze gebruiker volgt nog niemand of heeft deze verborgen.",
@ -515,7 +519,6 @@
"lists.exclusive": "Leden op je Startpagina verbergen",
"lists.exclusive_hint": "Als iemand op deze lijst staat, verberg deze persoon dan op je starttijdlijn om te voorkomen dat zijn berichten twee keer worden getoond.",
"lists.find_users_to_add": "Vind gebruikers om toe te voegen",
"lists.list_members": "Lijstleden",
"lists.list_members_count": "{count, plural, one{# lid} other{# leden}}",
"lists.list_name": "Lijstnaam",
"lists.new_list_name": "Nieuwe lijstnaam",
@ -861,6 +864,13 @@
"status.mute_conversation": "Gesprek negeren",
"status.open": "Volledig bericht tonen",
"status.pin": "Op profiel uitlichten",
"status.quote_error.filtered": "Verborgen door een van je filters",
"status.quote_error.not_found": "Dit bericht kan niet worden weergegeven.",
"status.quote_error.pending_approval": "Dit bericht is in afwachting van goedkeuring door de oorspronkelijke auteur.",
"status.quote_error.rejected": "Dit bericht kan niet worden weergegeven omdat de oorspronkelijke auteur niet toestaat dat het wordt geciteerd.",
"status.quote_error.removed": "Dit bericht is verwijderd door de auteur.",
"status.quote_error.unauthorized": "Dit bericht kan niet worden weergegeven omdat je niet bevoegd bent om het te bekijken.",
"status.quote_post_author": "Bericht van {name}",
"status.read_more": "Meer lezen",
"status.reblog": "Boosten",
"status.reblog_private": "Boost naar oorspronkelijke ontvangers",

View file

@ -28,6 +28,9 @@
"account.edit_profile": "Rediger profil",
"account.enable_notifications": "Varsle meg når @{name} skriv innlegg",
"account.endorse": "Vis på profilen",
"account.familiar_followers_many": "Fylgt av {name1}, {name2}, og {othersCount, plural, one {ein annan du kjenner} other {# andre du kjenner}}",
"account.familiar_followers_one": "Fylgt av {name1}",
"account.familiar_followers_two": "Fylgt av {name1} og {name2}",
"account.featured": "Utvald",
"account.featured.accounts": "Profilar",
"account.featured.hashtags": "Emneknaggar",
@ -39,6 +42,7 @@
"account.followers": "Fylgjarar",
"account.followers.empty": "Ingen fylgjer denne brukaren enno.",
"account.followers_counter": "{count, plural, one {{counter} fylgjar} other {{counter} fylgjarar}}",
"account.followers_you_know_counter": "{counter} du kjenner",
"account.following": "Fylgjer",
"account.following_counter": "{count, plural, one {{counter} fylgjar} other {{counter} fylgjarar}}",
"account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.",
@ -515,7 +519,6 @@
"lists.exclusive": "Gøym medlemer frå startskjermen",
"lists.exclusive_hint": "Viss nokon er på denne lista, blir dei gøymde frå startskjermen slik at du slepp sjå innlegga deira to gonger.",
"lists.find_users_to_add": "Finn brukarar å leggja til",
"lists.list_members": "Syn medlemer",
"lists.list_members_count": "{count, plural, one {# medlem} other {# medlemer}}",
"lists.list_name": "Namn på lista",
"lists.new_list_name": "Namn på den nye lista",
@ -861,6 +864,13 @@
"status.mute_conversation": "Demp samtale",
"status.open": "Utvid denne statusen",
"status.pin": "Vis på profilen",
"status.quote_error.filtered": "Gøymt på grunn av eitt av filtra dine",
"status.quote_error.not_found": "Du kan ikkje visa dette innlegget.",
"status.quote_error.pending_approval": "Dette innlegget ventar på at skribenten skal godkjenna det.",
"status.quote_error.rejected": "Du kan ikkje visa dette innlegget fordi skribenten ikkje vil at det skal siterast.",
"status.quote_error.removed": "Skribenten sletta dette innlegget.",
"status.quote_error.unauthorized": "Du kan ikkje visa dette innlegget fordi du ikkje har løyve til det.",
"status.quote_post_author": "Innlegg av {name}",
"status.read_more": "Les meir",
"status.reblog": "Framhev",
"status.reblog_private": "Framhev til dei originale mottakarane",

View file

@ -19,13 +19,22 @@
"account.block_domain": "Blokker domenet {domain}",
"account.block_short": "Blokker",
"account.blocked": "Blokkert",
"account.blocking": "Blokkerer",
"account.cancel_follow_request": "Avbryt følgeforespørselen",
"account.copy": "Kopier lenke til profil",
"account.direct": "Nevn @{name} privat",
"account.disable_notifications": "Slutt å varsle meg når @{name} legger ut innlegg",
"account.domain_blocking": "Blokkerer domene",
"account.edit_profile": "Rediger profil",
"account.enable_notifications": "Varsle meg når @{name} legger ut innlegg",
"account.endorse": "Vis frem på profilen",
"account.familiar_followers_many": "Fulgt av {name1}, {name2}, og {othersCount, plural, one {en annen du kjenner} other {# andre du kjenner}}",
"account.familiar_followers_one": "Fulgt av {name1}",
"account.familiar_followers_two": "Fulgt av {name1} og {name2}",
"account.featured": "Utvalgt",
"account.featured.accounts": "Profiler",
"account.featured.hashtags": "Emneknagger",
"account.featured.posts": "Innlegg",
"account.featured_tags.last_status_at": "Siste innlegg {date}",
"account.featured_tags.last_status_never": "Ingen Innlegg",
"account.follow": "Følg",
@ -33,9 +42,11 @@
"account.followers": "Følgere",
"account.followers.empty": "Ingen følger denne brukeren ennå.",
"account.followers_counter": "{count, plural, one {{counter} følger} other {{counter} følgere}}",
"account.followers_you_know_counter": "{counter} du kjenner",
"account.following": "Følger",
"account.following_counter": "{count, plural, one {{counter} som følges} other {{counter} som følges}}",
"account.follows.empty": "Denne brukeren følger ikke noen enda.",
"account.follows_you": "Følger deg",
"account.go_to_profile": "Gå til profil",
"account.hide_reblogs": "Skjul fremhevinger fra @{name}",
"account.in_memoriam": "Til minne om.",
@ -50,18 +61,23 @@
"account.mute_notifications_short": "Demp varsler",
"account.mute_short": "Demp",
"account.muted": "Dempet",
"account.muting": "Demper",
"account.mutual": "Dere følger hverandre",
"account.no_bio": "Ingen beskrivelse oppgitt.",
"account.open_original_page": "Gå til originalsiden",
"account.posts": "Innlegg",
"account.posts_with_replies": "Innlegg med svar",
"account.remove_from_followers": "Fjern {name} fra følgere",
"account.report": "Rapporter @{name}",
"account.requested": "Venter på godkjennelse. Klikk for å avbryte forespørselen",
"account.requested_follow": "{name} har bedt om å få følge deg",
"account.requests_to_follow_you": "Forespørsler om å følge deg",
"account.share": "Del @{name} sin profil",
"account.show_reblogs": "Vis fremhevinger fra @{name}",
"account.statuses_counter": "{count, plural, one {{counter} innlegg} other {{counter} innlegg}}",
"account.unblock": "Opphev blokkering av @{name}",
"account.unblock_domain": "Opphev blokkering av {domain}",
"account.unblock_domain_short": "Opphev blokkering",
"account.unblock_short": "Opphev blokkering",
"account.unendorse": "Ikke vis frem på profilen",
"account.unfollow": "Slutt å følge",
@ -107,6 +123,9 @@
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest brukte evne knagg",
"annual_report.summary.most_used_hashtag.none": "Ingen",
"annual_report.summary.new_posts.new_posts": "nye innlegg",
"annual_report.summary.percentile.text": "<topLabel>Det gjør at du er i topp</topLabel><percentage></percentage><bottomLabel>av brukere på {domain}.</bottomLabel>",
"annual_report.summary.percentile.we_wont_tell_bernie": "Vi skal ikke si noe til Bernie.",
"annual_report.summary.thanks": "Takk for at du er med på Mastodon!",
"attachments_list.unprocessed": "(ubehandlet)",
"audio.hide": "Skjul lyd",
"block_modal.remote_users_caveat": "Vi vil be serveren {domain} om å respektere din beslutning. Det er imidlertid ingen garanti at det blir overholdt, siden noen servere kan håndtere blokkeringer på forskjellig vis. Offentlige innlegg kan fortsatt være synlige for ikke-innloggede brukere.",
@ -130,6 +149,7 @@
"bundle_column_error.routing.body": "Den forespurte siden ble ikke funnet. Er du sikker på at URL-en i adresselinjen er riktig?",
"bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "Lukk",
"bundle_modal_error.message": "Noe gikk galt mens denne komponenten ble lastet inn.",
"bundle_modal_error.retry": "Prøv igjen",
"closed_registrations.other_server_instructions": "Siden Mastodon er desentralizert, kan du opprette en konto på en annen server og fortsatt kommunisere med denne.",
"closed_registrations_modal.description": "Opprettelse av en konto på {domain} er for tiden ikke mulig, men vær oppmerksom på at du ikke trenger en konto spesifikt på {domain} for å kunne bruke Mastodon.",
@ -140,6 +160,7 @@
"column.blocks": "Blokkerte brukere",
"column.bookmarks": "Bokmerker",
"column.community": "Lokal tidslinje",
"column.create_list": "Opprett liste",
"column.direct": "Private omtaler",
"column.directory": "Bla gjennom profiler",
"column.domain_blocks": "Skjulte domener",
@ -148,9 +169,11 @@
"column.firehose": "Tidslinjer",
"column.follow_requests": "Følgeforespørsler",
"column.home": "Hjem",
"column.list_members": "Administrer listemedlemmer",
"column.lists": "Lister",
"column.mutes": "Dempede brukere",
"column.notifications": "Varsler",
"column.pins": "Utvalgte innlegg",
"column.public": "Felles tidslinje",
"column_back_button.label": "Tilbake",
"column_header.hide_settings": "Skjul innstillinger",

View file

@ -319,7 +319,6 @@
"lists.done": "ਮੁਕੰਮਲ",
"lists.edit": "ਸੂਚੀ ਨੂੰ ਸੋਧੋ",
"lists.find_users_to_add": "ਜੋੜਨ ਲਈ ਵਰਤੋਂਕਾਰ ਲੱਭੋ",
"lists.list_members": "ਮੈਂਬਰਾਂ ਦੀ ਸੂਚੀ",
"lists.list_members_count": "{count, plural, one {# ਮੈਂਬਰ} other {# ਮੈਂਬਰ}}",
"lists.list_name": "ਸੂਚੀ ਦਾ ਨਾਂ",
"lists.new_list_name": "ਨਵੀਂ ਸੂਚੀਂ ਦਾ ਨਾਂ",

View file

@ -490,7 +490,6 @@
"lists.exclusive": "Nie pokazuj w mojej osi czasu",
"lists.exclusive_hint": "Wpisy osób znajdujących się na tej liście nie będą wyświetlane w twojej osi czasu, aby uniknąć duplikowania tych samych wpisów.",
"lists.find_users_to_add": "Znajdź kogoś, aby dodać",
"lists.list_members": "Lista osób",
"lists.list_members_count": "{count, plural, one {# osoba} few {# osoby} many {# osób} other {# osób}}",
"lists.list_name": "Nazwa listy",
"lists.new_list_name": "Nazwa nowej listy",

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