Merge commit '4e276e4476c81482143440f1f405479e0e4be7eb' into glitch-soc/merge-upstream

This commit is contained in:
Claire
2026-03-20 18:03:14 +01:00
118 changed files with 1106 additions and 391 deletions

View File

@@ -99,8 +99,8 @@ GEM
ast (2.4.3)
attr_required (1.0.2)
aws-eventstream (1.4.0)
aws-partitions (1.1225.0)
aws-sdk-core (3.243.0)
aws-partitions (1.1227.0)
aws-sdk-core (3.244.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
@@ -108,11 +108,11 @@ GEM
bigdecimal
jmespath (~> 1, >= 1.6.1)
logger
aws-sdk-kms (1.122.0)
aws-sdk-core (~> 3, >= 3.241.4)
aws-sdk-kms (1.123.0)
aws-sdk-core (~> 3, >= 3.244.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.216.0)
aws-sdk-core (~> 3, >= 3.243.0)
aws-sdk-s3 (1.217.0)
aws-sdk-core (~> 3, >= 3.244.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.12.1)
@@ -304,8 +304,8 @@ GEM
highline (3.1.2)
reline
hiredis (0.6.3)
hiredis-client (0.27.0)
redis-client (= 0.27.0)
hiredis-client (0.28.0)
redis-client (= 0.28.0)
hkdf (0.3.0)
htmlentities (4.4.2)
http (5.3.1)
@@ -707,7 +707,7 @@ GEM
reline
redcarpet (3.6.1)
redis (4.8.1)
redis-client (0.27.0)
redis-client (0.28.0)
connection_pool
regexp_parser (2.11.3)
reline (0.6.3)
@@ -862,7 +862,7 @@ GEM
unicode-display_width (>= 1.1.1, < 4)
terrapin (1.1.1)
climate_control
test-prof (1.5.2)
test-prof (1.6.0)
thor (1.5.0)
tilt (2.7.0)
timeout (0.6.1)

View File

@@ -158,7 +158,7 @@ export const expandPublicTimeline = ({ maxId, onlyMedia, onlyRemote } =
export const expandCommunityTimeline = ({ maxId, onlyMedia } = {}) => expandTimeline(`community${onlyMedia ? ':media' : ''}`, '/api/v1/timelines/public', { local: true, max_id: maxId, only_media: !!onlyMedia });
export const expandAccountTimeline = (accountId, { maxId, withReplies, tagged } = {}) => expandTimeline(`account:${accountId}${withReplies ? ':with_replies' : ''}${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { exclude_replies: !withReplies, exclude_reblogs: withReplies, tagged, max_id: maxId });
export const expandAccountFeaturedTimeline = (accountId, { tagged } = {}) => expandTimeline(`account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, `/api/v1/accounts/${accountId}/statuses`, { pinned: true, tagged });
export const expandAccountMediaTimeline = (accountId, { maxId } = {}) => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40 });
export const expandAccountMediaTimeline = (accountId, { maxId, withReplies } = {}) => expandTimeline(`account:${accountId}:media${withReplies ? ':with_replies' : ''}`, `/api/v1/accounts/${accountId}/statuses`, { max_id: maxId, only_media: true, limit: 40, exclude_replies: !withReplies });
export const expandListTimeline = (id, { maxId } = {}) => expandTimeline(`list:${id}`, `/api/v1/timelines/list/${id}`, { max_id: maxId });
export const expandLinkTimeline = (url, { maxId } = {}) => expandTimeline(`link:${url}`, `/api/v1/timelines/link`, { url, max_id: maxId });
export const expandHashtagTimeline = (hashtag, { maxId, tags, local } = {}) => {

View File

@@ -155,8 +155,12 @@ export async function apiRequest<
export async function apiRequestGet<ApiResponse = unknown, ApiParams = unknown>(
url: ApiUrl,
params?: RequestParamsOrData<ApiParams>,
args: {
signal?: AbortSignal;
timeout?: number;
} = {},
) {
return apiRequest<ApiResponse>('GET', url, { params });
return apiRequest<ApiResponse>('GET', url, { params, ...args });
}
export async function apiRequestPost<ApiResponse = unknown, ApiData = unknown>(

View File

@@ -4,13 +4,22 @@ import type {
ApiSearchResultsJSON,
} from 'mastodon/api_types/search';
export const apiGetSearch = (params: {
export const apiGetSearch = (
params: {
q: string;
resolve?: boolean;
type?: ApiSearchType;
limit?: number;
offset?: number;
}) =>
apiRequestGet<ApiSearchResultsJSON>('v2/search', {
},
options: {
signal?: AbortSignal;
} = {},
) =>
apiRequestGet<ApiSearchResultsJSON>(
'v2/search',
{
...params,
});
},
options,
);

View File

@@ -53,6 +53,9 @@ export interface BaseApiAccountJSON {
id: string;
last_status_at: string;
locked: boolean;
show_media: boolean;
show_media_replies: boolean;
show_featured: boolean;
noindex?: boolean;
note: string;
roles?: ApiAccountJSON[];

View File

@@ -6,7 +6,7 @@ import classNames from 'classnames';
import { Link } from 'react-router-dom';
import { useIdentity } from '@/mastodon/identity_context';
import { isClientFeatureEnabled } from '@/mastodon/utils/environment';
import { isServerFeatureEnabled } from '@/mastodon/utils/environment';
import {
fetchRelationships,
followAccount,
@@ -171,7 +171,7 @@ export const FollowButton: React.FC<{
'button--compact': compact,
});
if (isClientFeatureEnabled('profile_editing')) {
if (isServerFeatureEnabled('profile_redesign')) {
return (
<Link to='/profile/edit' className={buttonClasses}>
{label}

View File

@@ -28,7 +28,10 @@ export interface ComboboxItemState {
isDisabled: boolean;
}
interface ComboboxProps<T extends ComboboxItem> extends TextInputProps {
interface ComboboxProps<T extends ComboboxItem> extends Omit<
TextInputProps,
'icon'
> {
/**
* The value of the combobox's text input
*/
@@ -71,6 +74,18 @@ interface ComboboxProps<T extends ComboboxItem> extends TextInputProps {
* The main selection handler, called when an option is selected or deselected.
*/
onSelectItem: (item: T) => void;
/**
* Icon to be displayed in the text input
*/
icon?: TextInputProps['icon'] | null;
/**
* Set to false to keep the menu open when an item is selected
*/
closeOnSelect?: boolean;
/**
* Prevent the menu from opening, e.g. to prevent the empty state from showing
*/
suppressMenu?: boolean;
}
interface Props<T extends ComboboxItem>
@@ -124,6 +139,8 @@ const ComboboxWithRef = <T extends ComboboxItem>(
onSelectItem,
onChange,
onKeyDown,
closeOnSelect = true,
suppressMenu = false,
icon = SearchIcon,
className,
...otherProps
@@ -148,7 +165,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
const showStatusMessageInMenu =
!!statusMessage && value.length > 0 && items.length === 0;
const hasMenuContent =
!disabled && (items.length > 0 || showStatusMessageInMenu);
!disabled && !suppressMenu && (items.length > 0 || showStatusMessageInMenu);
const isMenuOpen = shouldMenuOpen && hasMenuContent;
const openMenu = useCallback(() => {
@@ -204,11 +221,15 @@ const ComboboxWithRef = <T extends ComboboxItem>(
const isDisabled = getIsItemDisabled?.(item) ?? false;
if (!isDisabled) {
onSelectItem(item);
if (closeOnSelect) {
closeMenu();
}
}
}
inputRef.current?.focus();
},
[getIsItemDisabled, items, onSelectItem],
[closeMenu, closeOnSelect, getIsItemDisabled, items, onSelectItem],
);
const handleSelectItem = useCallback(
@@ -343,7 +364,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
value={value}
onChange={handleInputChange}
onKeyDown={handleInputKeyDown}
icon={icon}
icon={icon ?? undefined}
className={classNames(classes.input, className)}
ref={mergeRefs}
/>

View File

@@ -1,87 +1,71 @@
import type { ChangeEventHandler, FC } from 'react';
import { useCallback, useMemo } from 'react';
import { useCallback, useId, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import type { ApiHashtagJSON } from '@/mastodon/api_types/tags';
import { Combobox } from '@/mastodon/components/form_fields';
import {
addFeaturedTag,
clearSearch,
updateSearchQuery,
} from '@/mastodon/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { useSearchTags } from '@/mastodon/hooks/useSearchTags';
import type { TagSearchResult } from '@/mastodon/hooks/useSearchTags';
import { addFeaturedTag } from '@/mastodon/reducers/slices/profile_edit';
import { useAppDispatch } from '@/mastodon/store';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import classes from '../styles.module.scss';
type SearchResult = Omit<ApiHashtagJSON, 'url' | 'history'> & {
label?: string;
};
const messages = defineMessages({
placeholder: {
id: 'account_edit_tags.search_placeholder',
defaultMessage: 'Enter a hashtag…',
},
addTag: {
id: 'account_edit_tags.add_tag',
defaultMessage: 'Add #{tagName}',
},
});
export const AccountEditTagSearch: FC = () => {
const intl = useIntl();
const [query, setQuery] = useState('');
const {
query,
tags: suggestedTags,
searchTags,
resetSearch,
isLoading,
results: rawResults,
} = useAppSelector((state) => state.profileEdit.search);
const results = useMemo(() => {
if (!rawResults) {
return [];
}
const results: SearchResult[] = [...rawResults]; // Make array mutable
const trimmedQuery = query.trim();
if (
trimmedQuery.length > 0 &&
results.every(
(result) => result.name.toLowerCase() !== trimmedQuery.toLowerCase(),
)
) {
results.push({
id: 'new',
name: trimmedQuery,
label: intl.formatMessage(messages.addTag, { tagName: trimmedQuery }),
} = useSearchTags({
query,
// Remove existing featured tags from suggestions
filterResults: (tag) => !tag.featuring,
});
}
return results;
}, [intl, query, rawResults]);
const dispatch = useAppDispatch();
const handleSearchChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
void dispatch(updateSearchQuery(e.target.value));
setQuery(e.target.value);
searchTags(e.target.value);
},
[dispatch],
[searchTags],
);
const dispatch = useAppDispatch();
const handleSelect = useCallback(
(item: SearchResult) => {
void dispatch(clearSearch());
(item: TagSearchResult) => {
resetSearch();
setQuery('');
void dispatch(addFeaturedTag({ name: item.name }));
},
[dispatch],
[dispatch, resetSearch],
);
const inputId = useId();
const inputLabel = intl.formatMessage(messages.placeholder);
return (
<>
<label htmlFor={inputId} className='sr-only'>
{inputLabel}
</label>
<Combobox
id={inputId}
value={query}
onChange={handleSearchChange}
placeholder={intl.formatMessage(messages.placeholder)}
items={results}
placeholder={inputLabel}
items={suggestedTags as TagSearchResult[]}
isLoading={isLoading}
renderItem={renderItem}
onSelectItem={handleSelect}
@@ -89,7 +73,8 @@ export const AccountEditTagSearch: FC = () => {
icon={SearchIcon}
type='search'
/>
</>
);
};
const renderItem = (item: SearchResult) => item.label ?? `#${item.name}`;
const renderItem = (item: TagSearchResult) => item.label ?? `#${item.name}`;

View File

@@ -2,10 +2,12 @@ import { useEffect } from 'react';
import { FormattedMessage } from 'react-intl';
import { useParams } from 'react-router';
import { useHistory } from 'react-router';
import { List as ImmutableList } from 'immutable';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { isServerFeatureEnabled } from '@/mastodon/utils/environment';
import { fetchEndorsedAccounts } from 'mastodon/actions/accounts';
import { fetchFeaturedTags } from 'mastodon/actions/featured_tags';
import { Account } from 'mastodon/components/account';
@@ -35,21 +37,27 @@ import { EmptyMessage } from './components/empty_message';
import { FeaturedTag } from './components/featured_tag';
import type { TagMap } from './components/featured_tag';
interface Params {
acct?: string;
id?: string;
}
const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
multiColumn,
}) => {
const accountId = useAccountId();
const account = useAccount(accountId);
const { suspended, blockedBy, hidden } = useAccountVisibility(accountId);
const forceEmptyState = suspended || blockedBy || hidden;
const { acct = '' } = useParams<Params>();
const dispatch = useAppDispatch();
const history = useHistory();
useEffect(() => {
if (
account &&
!account.show_featured &&
isServerFeatureEnabled('profile_redesign')
) {
history.push(`/@${account.acct}`);
}
}, [account, history]);
useEffect(() => {
if (accountId) {
void dispatch(fetchFeaturedTags({ accountId }));
@@ -166,7 +174,7 @@ const AccountFeatured: React.FC<{ multiColumn: boolean }> = ({
aria-posinset={index + 1}
aria-setsize={featuredTags.size}
>
<FeaturedTag tag={tag} account={acct} />
<FeaturedTag tag={tag} account={account?.acct ?? ''} />
</Article>
))}
</ItemList>

View File

@@ -2,10 +2,9 @@ import { useEffect, useCallback } from 'react';
import { FormattedMessage } from 'react-intl';
import { createSelector } from '@reduxjs/toolkit';
import type { Map as ImmutableMap } from 'immutable';
import { List as ImmutableList } from 'immutable';
import { List as ImmutableList, isList } from 'immutable';
import { isServerFeatureEnabled } from '@/mastodon/utils/environment';
import { openModal } from 'mastodon/actions/modal';
import { expandAccountMediaTimeline } from 'mastodon/actions/timelines';
import { ColumnBackButton } from 'mastodon/components/column_back_button';
@@ -18,38 +17,69 @@ import Column from 'mastodon/features/ui/components/column';
import { useAccountId } from 'mastodon/hooks/useAccountId';
import { useAccountVisibility } from 'mastodon/hooks/useAccountVisibility';
import type { MediaAttachment } from 'mastodon/models/media_attachment';
import type { RootState } from 'mastodon/store';
import { useAppSelector, useAppDispatch } from 'mastodon/store';
import {
useAppSelector,
useAppDispatch,
createAppSelector,
} from 'mastodon/store';
import { MediaItem } from './components/media_item';
const getAccountGallery = createSelector(
const emptyList = ImmutableList<MediaAttachment>();
const redesignEnabled = isServerFeatureEnabled('profile_redesign');
const selectGalleryTimeline = createAppSelector(
[
(state: RootState, accountId: string) =>
(state.timelines as ImmutableMap<string, unknown>).getIn(
[`account:${accountId}:media`, 'items'],
ImmutableList(),
) as ImmutableList<string>,
(state: RootState) => state.statuses,
(_state, accountId?: string | null) => accountId,
(state) => state.timelines,
(state) => state.accounts,
(state) => state.statuses,
],
(statusIds, statuses) => {
let items = ImmutableList<MediaAttachment>();
(accountId, timelines, accounts, statuses) => {
if (!accountId) {
return null;
}
const account = accounts.get(accountId);
if (!account) {
return null;
}
statusIds.forEach((statusId) => {
const status = statuses.get(statusId) as
| ImmutableMap<string, unknown>
| undefined;
let items = emptyList;
const { show_media, show_media_replies } = account;
// If the account disabled showing media, don't display anything.
if (!show_media && redesignEnabled) {
return {
items,
hasMore: false,
isLoading: false,
showingReplies: false,
};
}
if (status) {
const showingReplies = show_media_replies && redesignEnabled;
const timeline = timelines.get(
`account:${accountId}:media${showingReplies ? ':with_replies' : ''}`,
);
const statusIds = timeline?.get('items');
if (isList(statusIds)) {
for (const statusId of statusIds) {
const status = statuses.get(statusId);
items = items.concat(
(
status.get('media_attachments') as ImmutableList<MediaAttachment>
status?.get('media_attachments') as ImmutableList<MediaAttachment>
).map((media) => media.set('status', status)),
);
}
});
}
return items;
return {
items,
hasMore: !!timeline?.get('hasMore'),
isLoading: !!timeline?.get('isLoading'),
showingReplies,
};
},
);
@@ -58,27 +88,12 @@ export const AccountGallery: React.FC<{
}> = ({ multiColumn }) => {
const dispatch = useAppDispatch();
const accountId = useAccountId();
const attachments = useAppSelector((state) =>
accountId
? getAccountGallery(state, accountId)
: ImmutableList<MediaAttachment>(),
);
const isLoading = useAppSelector((state) =>
(state.timelines as ImmutableMap<string, unknown>).getIn([
`account:${accountId}:media`,
'isLoading',
]),
);
const hasMore = useAppSelector((state) =>
(state.timelines as ImmutableMap<string, unknown>).getIn([
`account:${accountId}:media`,
'hasMore',
]),
);
const account = useAppSelector((state) =>
accountId ? state.accounts.get(accountId) : undefined,
);
const isAccount = !!account;
const {
isLoading = true,
hasMore = false,
items: attachments = emptyList,
showingReplies: withReplies = false,
} = useAppSelector((state) => selectGalleryTimeline(state, accountId)) ?? {};
const { suspended, blockedBy, hidden } = useAccountVisibility(accountId);
@@ -87,16 +102,18 @@ export const AccountGallery: React.FC<{
| undefined;
useEffect(() => {
if (accountId && isAccount) {
void dispatch(expandAccountMediaTimeline(accountId));
if (accountId) {
void dispatch(expandAccountMediaTimeline(accountId, { withReplies }));
}
}, [dispatch, accountId, isAccount]);
}, [dispatch, accountId, withReplies]);
const handleLoadMore = useCallback(() => {
if (maxId) {
void dispatch(expandAccountMediaTimeline(accountId, { maxId }));
void dispatch(
expandAccountMediaTimeline(accountId, { maxId, withReplies }),
);
}
}, [dispatch, accountId, maxId]);
}, [maxId, dispatch, accountId, withReplies]);
const handleOpenMedia = useCallback(
(attachment: MediaAttachment) => {

View File

@@ -5,25 +5,16 @@ import { FormattedMessage } from 'react-intl';
import type { NavLinkProps } from 'react-router-dom';
import { NavLink } from 'react-router-dom';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { useAccountId } from '@/mastodon/hooks/useAccountId';
import { isRedesignEnabled } from '../common';
import classes from './redesign.module.scss';
export const AccountTabs: FC<{ acct: string }> = ({ acct }) => {
if (isRedesignEnabled()) {
return (
<div className={classes.tabs}>
<NavLink isActive={isActive} to={`/@${acct}`}>
<FormattedMessage id='account.activity' defaultMessage='Activity' />
</NavLink>
<NavLink exact to={`/@${acct}/media`}>
<FormattedMessage id='account.media' defaultMessage='Media' />
</NavLink>
<NavLink exact to={`/@${acct}/featured`}>
<FormattedMessage id='account.featured' defaultMessage='Featured' />
</NavLink>
</div>
);
return <RedesignTabs />;
}
return (
<div className='account__section-headline'>
@@ -49,3 +40,32 @@ export const AccountTabs: FC<{ acct: string }> = ({ acct }) => {
const isActive: Required<NavLinkProps>['isActive'] = (match, location) =>
match?.url === location.pathname ||
(!!match?.url && location.pathname.startsWith(`${match.url}/tagged/`));
const RedesignTabs: FC = () => {
const accountId = useAccountId();
const account = useAccount(accountId);
if (!account) {
return null;
}
const { acct, show_featured, show_media } = account;
return (
<div className={classes.tabs}>
<NavLink isActive={isActive} to={`/@${acct}`}>
<FormattedMessage id='account.activity' defaultMessage='Activity' />
</NavLink>
{show_media && (
<NavLink exact to={`/@${acct}/media`}>
<FormattedMessage id='account.media' defaultMessage='Media' />
</NavLink>
)}
{show_featured && (
<NavLink exact to={`/@${acct}/featured`}>
<FormattedMessage id='account.featured' defaultMessage='Featured' />
</NavLink>
)}
</div>
);
};

View File

@@ -25,8 +25,8 @@ import {
ItemList,
Scrollable,
} from 'mastodon/components/scrollable_list/components';
import { useSearchAccounts } from 'mastodon/features/lists/use_search_accounts';
import { useAccount } from 'mastodon/hooks/useAccount';
import { useSearchAccounts } from 'mastodon/hooks/useSearchAccounts';
import { me } from 'mastodon/initial_state';
import {
addCollectionItem,
@@ -374,6 +374,7 @@ export const CollectionAccounts: React.FC<{
onSelectItem={
isEditMode ? instantToggleAccountItem : toggleAccountItem
}
closeOnSelect={false}
/>
{hasMaxAccounts && (
<FormattedMessage

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo } from 'react';
import { Fragment, useCallback, useMemo, useState } from 'react';
import { FormattedMessage, useIntl } from 'react-intl';
@@ -6,9 +6,11 @@ import { useHistory } from 'react-router-dom';
import { isFulfilled } from '@reduxjs/toolkit';
import { languages } from '@/mastodon/initial_state';
import {
hasSpecialCharacters,
inputToHashtag,
trimHashFromStart,
} from '@/mastodon/utils/hashtags';
import type {
ApiCreateCollectionPayload,
@@ -17,12 +19,16 @@ import type {
import { Button } from 'mastodon/components/button';
import {
CheckboxField,
ComboboxField,
Fieldset,
FormStack,
RadioButtonField,
SelectField,
TextAreaField,
} from 'mastodon/components/form_fields';
import { TextInputField } from 'mastodon/components/form_fields/text_input_field';
import { useSearchTags } from 'mastodon/hooks/useSearchTags';
import type { TagSearchResult } from 'mastodon/hooks/useSearchTags';
import {
createCollection,
updateCollection,
@@ -34,7 +40,6 @@ import classes from './styles.module.scss';
import { WizardStepHeader } from './wizard_step_header';
export const CollectionDetails: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const history = useHistory();
const { id, name, description, topic, discoverable, sensitive, accountIds } =
@@ -64,18 +69,6 @@ export const CollectionDetails: React.FC = () => {
[dispatch],
);
const handleTopicChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
dispatch(
updateCollectionEditorField({
field: 'topic',
value: inputToHashtag(event.target.value),
}),
);
},
[dispatch],
);
const handleDiscoverableChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
dispatch(
@@ -156,11 +149,6 @@ export const CollectionDetails: React.FC = () => {
],
);
const topicHasSpecialCharacters = useMemo(
() => hasSpecialCharacters(topic),
[topic],
);
return (
<form onSubmit={handleSubmit} className={classes.form}>
<FormStack className={classes.formFieldStack}>
@@ -213,39 +201,9 @@ export const CollectionDetails: React.FC = () => {
maxLength={100}
/>
<TextInputField
required={false}
label={
<FormattedMessage
id='collections.collection_topic'
defaultMessage='Topic'
/>
}
hint={
<FormattedMessage
id='collections.topic_hint'
defaultMessage='Add a hashtag that helps others understand the main topic of this collection.'
/>
}
value={topic}
onChange={handleTopicChange}
autoCapitalize='off'
autoCorrect='off'
spellCheck='false'
maxLength={40}
status={
topicHasSpecialCharacters
? {
variant: 'warning',
message: intl.formatMessage({
id: 'collections.topic_special_chars_hint',
defaultMessage:
'Special characters will be removed when saving',
}),
}
: undefined
}
/>
<TopicField />
<LanguageField />
<Fieldset
legend={
@@ -335,3 +293,143 @@ export const CollectionDetails: React.FC = () => {
</form>
);
};
const TopicField: React.FC = () => {
const intl = useIntl();
const dispatch = useAppDispatch();
const { id, topic } = useAppSelector((state) => state.collections.editor);
const collection = useAppSelector((state) =>
id ? state.collections.collections[id] : undefined,
);
const [isInitialValue, setIsInitialValue] = useState(
() => trimHashFromStart(topic) === (collection?.tag?.name ?? ''),
);
const { tags, isLoading, searchTags } = useSearchTags({
query: topic,
});
const handleTopicChange = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
setIsInitialValue(false);
dispatch(
updateCollectionEditorField({
field: 'topic',
value: inputToHashtag(event.target.value),
}),
);
searchTags(event.target.value);
},
[dispatch, searchTags],
);
const handleSelectTopicSuggestion = useCallback(
(item: TagSearchResult) => {
dispatch(
updateCollectionEditorField({
field: 'topic',
value: inputToHashtag(item.name),
}),
);
},
[dispatch],
);
const topicHasSpecialCharacters = useMemo(
() => hasSpecialCharacters(topic),
[topic],
);
return (
<ComboboxField
required={false}
icon={null}
label={
<FormattedMessage
id='collections.collection_topic'
defaultMessage='Topic'
/>
}
hint={
<FormattedMessage
id='collections.topic_hint'
defaultMessage='Add a hashtag that helps others understand the main topic of this collection.'
/>
}
value={topic}
items={tags}
isLoading={isLoading}
renderItem={renderTagItem}
onSelectItem={handleSelectTopicSuggestion}
onChange={handleTopicChange}
autoCapitalize='off'
autoCorrect='off'
spellCheck='false'
maxLength={40}
status={
topicHasSpecialCharacters
? {
variant: 'warning',
message: intl.formatMessage({
id: 'collections.topic_special_chars_hint',
defaultMessage:
'Special characters will be removed when saving',
}),
}
: undefined
}
suppressMenu={isInitialValue}
/>
);
};
const renderTagItem = (item: TagSearchResult) => item.label ?? `#${item.name}`;
const LanguageField: React.FC = () => {
const dispatch = useAppDispatch();
const initialLanguage = useAppSelector(
(state) => state.compose.get('default_language') as string,
);
const { language } = useAppSelector((state) => state.collections.editor);
const selectedLanguage = language ?? initialLanguage;
const handleLanguageChange = useCallback(
(event: React.ChangeEvent<HTMLSelectElement>) => {
dispatch(
updateCollectionEditorField({
field: 'language',
value: event.target.value,
}),
);
},
[dispatch],
);
return (
<SelectField
label={
<FormattedMessage
id='collections.collection_language'
defaultMessage='Language'
/>
}
value={selectedLanguage}
onChange={handleLanguageChange}
>
<option value=''>
<FormattedMessage
id='collections.collection_language_none'
defaultMessage='None'
tagName={Fragment}
/>
</option>
{languages?.map(([code, name, localName]) => (
<option key={code} value={code}>
{localName} ({name})
</option>
))}
</SelectField>
);
};

View File

@@ -21,8 +21,7 @@ export const LinkTimeline: React.FC<{
const columnRef = useRef<ColumnRef>(null);
const firstStatusId = useAppSelector((state) =>
decodedUrl
? // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
(state.timelines.getIn([`link:${decodedUrl}`, 'items', 0]) as string)
? (state.timelines.getIn([`link:${decodedUrl}`, 'items', 0]) as string)
: undefined,
);
const story = useAppSelector((state) =>

View File

@@ -28,11 +28,10 @@ import { DisplayName } from 'mastodon/components/display_name';
import ScrollableList from 'mastodon/components/scrollable_list';
import { ShortNumber } from 'mastodon/components/short_number';
import { VerifiedBadge } from 'mastodon/components/verified_badge';
import { useSearchAccounts } from 'mastodon/hooks/useSearchAccounts';
import { me } from 'mastodon/initial_state';
import { useAppDispatch, useAppSelector } from 'mastodon/store';
import { useSearchAccounts } from './use_search_accounts';
export const messages = defineMessages({
manageMembers: {
id: 'column.list_members',

View File

@@ -23,7 +23,7 @@ import { identityContextPropShape, withIdentity } from 'mastodon/identity_contex
import { layoutFromWindow } from 'mastodon/is_mobile';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
import { checkAnnualReport } from '@/mastodon/reducers/slices/annual_report';
import { isClientFeatureEnabled } from '@/mastodon/utils/environment';
import { isServerFeatureEnabled } from '@/mastodon/utils/environment';
import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose';
import { clearHeight } from '../../actions/height_cache';
@@ -182,7 +182,7 @@ class SwitchingColumnsArea extends PureComponent {
}
const profileRedesignRoutes = [];
if (isClientFeatureEnabled('profile_editing')) {
if (isServerFeatureEnabled('profile_redesign')) {
profileRedesignRoutes.push(
<WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />,
<WrappedRoute key="featured_tags" path='/profile/featured_tags' component={AccountEditFeaturedTags} content={children} />

View File

@@ -0,0 +1,121 @@
import { useCallback, useMemo, useRef, useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useDebouncedCallback } from 'use-debounce';
import { apiGetSearch } from 'mastodon/api/search';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
import { trimHashFromStart } from 'mastodon/utils/hashtags';
export type TagSearchResult = Omit<ApiHashtagJSON, 'url' | 'history'> & {
label?: string;
};
const messages = defineMessages({
addTag: {
id: 'account_edit_tags.add_tag',
defaultMessage: 'Add #{tagName}',
},
});
const fetchSearchHashtags = ({
q,
limit,
signal,
}: {
q: string;
limit: number;
signal: AbortSignal;
}) => apiGetSearch({ q, type: 'hashtags', limit }, { signal });
export function useSearchTags({
query,
limit = 11,
filterResults,
}: {
query?: string;
limit?: number;
filterResults?: (account: ApiHashtagJSON) => boolean;
} = {}) {
const intl = useIntl();
const [fetchedTags, setFetchedTags] = useState<ApiHashtagJSON[]>([]);
const [loadingState, setLoadingState] = useState<
'idle' | 'loading' | 'error'
>('idle');
const searchRequestRef = useRef<AbortController | null>(null);
const searchTags = useDebouncedCallback(
(value: string) => {
if (searchRequestRef.current) {
searchRequestRef.current.abort();
}
const trimmedQuery = trimHashFromStart(value.trim());
if (trimmedQuery.length === 0) {
setFetchedTags([]);
return;
}
setLoadingState('loading');
searchRequestRef.current = new AbortController();
void fetchSearchHashtags({
q: trimmedQuery,
limit,
signal: searchRequestRef.current.signal,
})
.then(({ hashtags }) => {
const tags = filterResults
? hashtags.filter(filterResults)
: hashtags;
setFetchedTags(tags);
setLoadingState('idle');
})
.catch(() => {
setLoadingState('error');
});
},
500,
{ leading: true, trailing: true },
);
const resetSearch = useCallback(() => {
setFetchedTags([]);
setLoadingState('idle');
}, []);
// Add dedicated item for adding the current query
const tags = useMemo(() => {
const trimmedQuery = query ? trimHashFromStart(query.trim()) : '';
if (!trimmedQuery || !fetchedTags.length) {
return fetchedTags;
}
const results: TagSearchResult[] = [...fetchedTags]; // Make array mutable
if (
trimmedQuery.length > 0 &&
results.every(
(result) => result.name.toLowerCase() !== trimmedQuery.toLowerCase(),
)
) {
results.push({
id: 'new',
name: trimmedQuery,
label: intl.formatMessage(messages.addTag, { tagName: trimmedQuery }),
});
}
return results;
}, [fetchedTags, query, intl]);
return {
tags,
searchTags,
resetSearch,
isLoading: loadingState === 'loading',
isError: loadingState === 'error',
};
}

View File

@@ -153,7 +153,7 @@ export const languages = initialState?.languages.map((lang) => {
lang[0],
displayNames?.of(lang[0].replace('zh-YUE', 'yue')) ?? lang[1],
lang[2],
];
] as InitialStateLanguage;
});
export function getAccessToken(): string | undefined {

View File

@@ -39,7 +39,7 @@
"account.edit_profile_short": "Рэдагаваць",
"account.enable_notifications": "Апавяшчаць мяне пра допісы @{name}",
"account.endorse": "Паказваць у профілі",
"account.familiar_followers_many": "Мае сярод падпісчыкаў {name1}, {name2}, і {othersCount, plural, one {яшчэ # чалавека, знаёмага Вам} few {яшчэ # чалавекі, знаёмыя Вам} many {яшчэ # чалавек, знаёмых Вам} other {яшчэ # чалавекі, знаёмыя Вам}}",
"account.familiar_followers_many": "Мае сярод падпісчыкаў {name1}, {name2}, і {othersCount, plural, one {яшчэ #-го чалавека, знаёмага Вам} few {яшчэ #-х чалавек, знаёмых Вам} many {яшчэ # людзей, знаёмых Вам} other {яшчэ # чалавек, знаёмых Вам}}",
"account.familiar_followers_one": "Мае сярод падпісчыкаў {name1}",
"account.familiar_followers_two": "Мае сярод падпісчыкаў {name1} і {name2}",
"account.featured": "Рэкамендаванае",
@@ -73,7 +73,6 @@
"account.go_to_profile": "Перайсці да профілю",
"account.hide_reblogs": "Схаваць пашырэнні ад @{name}",
"account.in_memoriam": "У памяць.",
"account.joined_long": "Далучыў(-ла)ся {date}",
"account.joined_short": "Далучыўся",
"account.languages": "Змяніць выбраныя мовы",
"account.link_verified_on": "Права ўласнасці на гэтую спасылку праверана {date}",
@@ -151,13 +150,53 @@
"account_edit.button.edit": "Змяніць {item}",
"account_edit.column_button": "Гатова",
"account_edit.column_title": "Рэдагаваць профіль",
"account_edit.custom_fields.name": "поле",
"account_edit.custom_fields.placeholder": "Дадайце свае займеннікі, знешнія спасылкі ці нешта іншае, чым Вы хацелі б падзяліцца.",
"account_edit.custom_fields.title": "Карыстальніцкія палі",
"account_edit.custom_fields.reorder_button": "Змяніць парадак палёў",
"account_edit.custom_fields.tip_content": "Вы можаце лёгка дадаць даверу да свайго ўліковага запісу Mastodon пацвярджэннем спасылак на любы з Вашых сайтаў.",
"account_edit.custom_fields.tip_title": "Падказка: Дадаванне пацверджаных спасылак",
"account_edit.custom_fields.title": "Адвольныя палі",
"account_edit.custom_fields.verified_hint": "Як мне дадаць пацверджаную спасылку?",
"account_edit.display_name.placeholder": "Вашае бачнае імя — гэта імя, якое іншыя людзі бачаць у Вашым профілі і ў стужках.",
"account_edit.display_name.title": "Бачнае імя",
"account_edit.featured_hashtags.item": "хэштэгі",
"account_edit.featured_hashtags.placeholder": "Дапамажыце іншым зразумець, якія тэмы Вас цікавяць, і атрымаць доступ да іх.",
"account_edit.featured_hashtags.title": "Выбраныя хэштэгі",
"account_edit.field_delete_modal.confirm": "Вы ўпэўненыя, што хочаце выдаліць гэтае адвольнае поле? Гэтае дзеянне будзе незваротным.",
"account_edit.field_delete_modal.delete_button": "Выдаліць",
"account_edit.field_delete_modal.title": "Выдаліць адвольнае поле?",
"account_edit.field_edit_modal.add_title": "Дадаць адвольнае поле",
"account_edit.field_edit_modal.edit_title": "Рэдагаваць адвольнае поле",
"account_edit.field_edit_modal.limit_header": "Перавышаная рэкамендаваная колькасць сімвалаў",
"account_edit.field_edit_modal.limit_message": "Карыстальнікі мабільных прылад могуць не ўбачыць Вашае поле цалкам.",
"account_edit.field_edit_modal.link_emoji_warning": "Мы раім не ўжываць адвольныя эмодзі разам з url-спасылкамі. Адвольныя палі, якія ўтрымліваюць і тое, і другое, будуць адлюстраваныя выключна як тэкст, а не спасылкі, каб не блытаць карыстальнікаў.",
"account_edit.field_edit_modal.name_hint": "Напрыклад, \"Асабісты Сайт\"",
"account_edit.field_edit_modal.name_label": "Назва",
"account_edit.field_edit_modal.url_warning": "Каб дадаць спасылку, калі ласка, дадайце {protocol} у яе пачатку.",
"account_edit.field_edit_modal.value_hint": "Напрыклад, “https://example.me”",
"account_edit.field_edit_modal.value_label": "Значэнне",
"account_edit.field_reorder_modal.drag_cancel": "Перасоўванне адмененае. Поле {item} было павернутае на месца.",
"account_edit.field_reorder_modal.drag_end": "Поле {item} было павернутае на месца.",
"account_edit.field_reorder_modal.drag_instructions": "Каб змяніць парадак адвольных палёў, націсніце прабел або ўвод. Падчас перасоўвання карыстайцеся клавішамі са стрэлкамі, каб пасунуць поле ўверх ці ўніз. Націсніце прабел ці ўвод зноў, каб замацаваць поле на новым месцы, або націсніце Esc, каб скасаваць дзеянне.",
"account_edit.field_reorder_modal.drag_move": "Поле {item} было перасунутае.",
"account_edit.field_reorder_modal.drag_over": "Поле {item} было перасунутае над \"{over}\".",
"account_edit.field_reorder_modal.drag_start": "Абранае поле \"{item}\".",
"account_edit.field_reorder_modal.handle_label": "Перасунуць поле \"{item}\"",
"account_edit.field_reorder_modal.title": "Перасунуць палі",
"account_edit.image_alt_modal.add_title": "Дадаць альт. тэкст",
"account_edit.image_alt_modal.details_content": "ЯК РАБІЦЬ: <ul> <li>Апішыце, як Вы выглядаеце на відарысе</li> <li>Апісвайце ад трэцяй асобы (напрыклад, “Алесь” замест \"я”)</li> <li>Будзьце сціслымі — некалькі слоў звычайна дастаткова</li> </ul> ЯК НЕ РАБІЦЬ: <ul> <li>Пачынаць з \"Фотаздымак...\" — гэта залішняе для чытачоў</li> </ul> ПРЫКЛАД: <ul> <li>“Алесь у вышыванцы і акулярах”</li> </ul>",
"account_edit.image_alt_modal.details_title": "Падказка: Альтэрнатыўны тэкст для фота профілю",
"account_edit.image_alt_modal.edit_title": "Рэдагаваць альт. тэкст",
"account_edit.image_alt_modal.text_hint": "Альтэрнатыўны тэкст дапамагае чытачам Вашага кантэнту лепш яго разумець.",
"account_edit.image_alt_modal.text_label": "Альт. тэкст",
"account_edit.image_delete_modal.confirm": "Вы ўпэўненыя, што хочаце выдаліць гэты відарыс? Гэтае дзеянне будзе незваротным.",
"account_edit.image_delete_modal.delete_button": "Выдаліць",
"account_edit.image_delete_modal.title": "Выдаліць відарыс?",
"account_edit.image_edit.add_button": "Дадаць відарыс",
"account_edit.image_edit.alt_add_button": "Дадаць альт. тэкст",
"account_edit.image_edit.alt_edit_button": "Рэдагаваць альт. тэкст",
"account_edit.image_edit.remove_button": "Прыбраць відарыс",
"account_edit.image_edit.replace_button": "Замяніць відарыс",
"account_edit.name_modal.add_title": "Дадаць бачнае імя",
"account_edit.name_modal.edit_title": "Змяніць бачнае імя",
"account_edit.profile_tab.button_label": "Змяніць",
@@ -172,6 +211,23 @@
"account_edit.profile_tab.subtitle": "Змяняйце на свой густ укладкі свайго профілю і тое, што яны паказваюць.",
"account_edit.profile_tab.title": "Налады ўкладкі профілю",
"account_edit.save": "Захаваць",
"account_edit.upload_modal.back": "Назад",
"account_edit.upload_modal.done": "Гатова",
"account_edit.upload_modal.next": "Далей",
"account_edit.upload_modal.step_crop.zoom": "Маштаб",
"account_edit.upload_modal.step_upload.button": "Агляд файлаў",
"account_edit.upload_modal.step_upload.dragging": "Перацягн. сюды, каб запамп.",
"account_edit.upload_modal.step_upload.header": "Выбраць відарыс",
"account_edit.upload_modal.step_upload.hint": "Фармату WEBP, PNG, GIF або JPG, да {limit} МБ.{br}Відарыс будзе сціснуты да памеру {width}x{height} пікселяў.",
"account_edit.upload_modal.title_add": "Дадаць фота профілю",
"account_edit.upload_modal.title_replace": "Замяніць фота профілю",
"account_edit.verified_modal.details": "Дадайце даверу да Вашага профілю Mastodon, пацвярджэннем спасылак на ўласныя сайты. Вось як гэта працуе:",
"account_edit.verified_modal.invisible_link.details": "Дадайце спасылку ў свой загаловак. Важнай часткай з'яўляецца rel=\"me\", яна прадухіляе выдачу сябе за іншую асобу на сайтах з карыстальніцкім кантэнтам. Вы нават можаце выкарыстоўваць тэг link у загалоўку старонкі замест {tag}, але HTML код павінен быць даступным без выканання JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "Як мне зрабіць спасылку нябачнай?",
"account_edit.verified_modal.step1.header": "Скапіруйце HTML код знізу і ўстаўце яго ў загаловак свайго сайту",
"account_edit.verified_modal.step2.details": "Калі Вы ўжо дадалі свой сайт у якасці адвольнага поля, Вам спатрэбіцца яго выдаліць і зноў дадаць, каб запусціць верыфікацыю.",
"account_edit.verified_modal.step2.header": "Дадаць свой сайт як адвольнае поле",
"account_edit.verified_modal.title": "Як дадаць пацверджаную спасылку",
"account_edit_tags.add_tag": "Дадаць #{tagName}",
"account_edit_tags.column_title": "Змяніць выбраныя хэштэгі",
"account_edit_tags.help_text": "Выбраныя хэштэгі дапамагаюць карыстальнікам знаходзіць Ваш профіль і ўзаемадзейнічаць з ім. Яны дзейнічаюць як фільтры пры праглядзе актыўнасці на Вашай старонцы.",
@@ -306,10 +362,15 @@
"collections.create_collection": "Стварыць калекцыю",
"collections.delete_collection": "Выдаліць калекцыю",
"collections.description_length_hint": "Максімум 100 сімвалаў",
"collections.detail.accept_inclusion": "Добра",
"collections.detail.accounts_heading": "Уліковыя запісы",
"collections.detail.author_added_you": "{author} дадаў(-ла) Вас у гэтую калекцыю",
"collections.detail.curated_by_author": "Курыруе {author}",
"collections.detail.curated_by_you": "Курыруеце Вы",
"collections.detail.loading": "Загружаецца калекцыя…",
"collections.detail.other_accounts_in_collection": "Іншыя ў гэтай калекцыі:",
"collections.detail.revoke_inclusion": "Прыбраць сябе",
"collections.detail.sensitive_note": "У гэтай калекцыі прысутнічаюць уліковыя запісы і кантэнт, змесціва якіх можа падацца адчувальным для некаторых карыстальнікаў.",
"collections.detail.share": "Падзяліцца гэтай калекцыяй",
"collections.edit_details": "Рэдагаваць падрабязнасці",
"collections.error_loading_collections": "Адбылася памылка падчас загрузкі Вашых калекцый.",
@@ -324,10 +385,14 @@
"collections.old_last_post_note": "Апошні допіс быў больш за тыдзень таму",
"collections.remove_account": "Прыбраць гэты ўліковы запіс",
"collections.report_collection": "Паскардзіцца на гэту калекцыю",
"collections.revoke_collection_inclusion": "Прыбраць сябе з гэтай калекцыі",
"collections.revoke_inclusion.confirmation": "Вас прыбралі з \"{collection}\"",
"collections.revoke_inclusion.error": "Адбылася памылка, калі ласка, спрабуйце яшчэ раз пазней.",
"collections.search_accounts_label": "Шукайце ўліковыя запісы, каб дадаць іх сюды…",
"collections.search_accounts_max_reached": "Вы дадалі максімальную колькасць уліковых запісаў",
"collections.sensitive": "Адчувальная",
"collections.topic_hint": "Дадайце хэштэг, які дапаможа іншым зразумець галоўную тэму гэтай калекцыі.",
"collections.topic_special_chars_hint": "Спецыяльныя сімвалы будуць прыбраныя пры захаванні",
"collections.view_collection": "Глядзець калекцыю",
"collections.view_other_collections_by_user": "Паглядзець іншыя калекцыі гэтага карыстальніка",
"collections.visibility_public": "Публічная",
@@ -447,6 +512,9 @@
"confirmations.remove_from_followers.confirm": "Выдаліць падпісчыка",
"confirmations.remove_from_followers.message": "{name} больш не будзе падпісаны(-ая) на Вас. Упэўненыя, што хочаце працягнуць?",
"confirmations.remove_from_followers.title": "Выдаліць падпісчыка?",
"confirmations.revoke_collection_inclusion.confirm": "Прыбраць сябе",
"confirmations.revoke_collection_inclusion.message": "Гэтае дзеянне канчатковае, і куратар не зможа пасля зноў дадаць Вас у гэтую калекцыю.",
"confirmations.revoke_collection_inclusion.title": "Прыбраць Вас з гэтай калекцыі?",
"confirmations.revoke_quote.confirm": "Выдаліць допіс",
"confirmations.revoke_quote.message": "Гэтае дзеянне немагчыма адмяніць.",
"confirmations.revoke_quote.title": "Выдаліць допіс?",
@@ -769,6 +837,7 @@
"navigation_bar.automated_deletion": "Аўтаматычнае выдаленне допісаў",
"navigation_bar.blocks": "Заблакіраваныя карыстальнікі",
"navigation_bar.bookmarks": "Закладкі",
"navigation_bar.collections": "Калекцыі",
"navigation_bar.direct": "Прыватныя згадванні",
"navigation_bar.domain_blocks": "Заблакіраваныя дамены",
"navigation_bar.favourites": "Упадабанае",
@@ -916,12 +985,14 @@
"notifications_permission_banner.title": "Не прапусціце нічога",
"onboarding.follows.back": "Назад",
"onboarding.follows.empty": "На жаль, зараз немагчыма паказаць вынікі. Вы можаце паспрабаваць выкарыстоўваць пошук і праглядзець старонку агляду, каб знайсці людзей, на якіх можна падпісацца, або паўтарыць спробу пазней.",
"onboarding.follows.next": "Далей: Наладзьце свой профіль",
"onboarding.follows.search": "Пошук",
"onboarding.follows.title": "Падпішыцеся на некага, каб пачаць",
"onboarding.profile.discoverable": "Зрабіць мой профіль бачным",
"onboarding.profile.discoverable_hint": "Калі Вы звяртаецеся да адкрытасці на Mastodon, Вашы допісы могуць з'яўляцца ў выніках пошуку і трэндах, а Ваш профіль можа быць прапанаваны людзям з такімі ж інтарэсамі.",
"onboarding.profile.display_name": "Бачнае імя",
"onboarding.profile.display_name_hint": "Ваша поўнае імя або ваш псеўданім…",
"onboarding.profile.finish": "Гатова",
"onboarding.profile.note": "Біяграфія",
"onboarding.profile.note_hint": "Вы можаце @згадваць іншых людзей або выкарыстоўваць #хэштэгі…",
"onboarding.profile.title": "Налады профілю",

View File

@@ -70,7 +70,6 @@
"account.go_to_profile": "Vés al perfil",
"account.hide_reblogs": "Amaga els impulsos de @{name}",
"account.in_memoriam": "En Memòria.",
"account.joined_long": "Membre des de {date}",
"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}",

View File

@@ -71,7 +71,6 @@
"account.go_to_profile": "Přejít na profil",
"account.hide_reblogs": "Skrýt boosty od @{name}",
"account.in_memoriam": "In Memoriam.",
"account.joined_long": "Přidali se {date}",
"account.joined_short": "Připojen/a",
"account.languages": "Změnit odebírané jazyky",
"account.link_verified_on": "Vlastnictví tohoto odkazu bylo zkontrolováno {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Mynd i'r proffil",
"account.hide_reblogs": "Cuddio hybiau gan @{name}",
"account.in_memoriam": "Er Cof.",
"account.joined_long": "Ymunodd ar {date}",
"account.joined_short": "Ymunodd",
"account.languages": "Newid ieithoedd wedi tanysgrifio iddyn nhw",
"account.link_verified_on": "Gwiriwyd perchnogaeth y ddolen yma ar {date}",
@@ -183,6 +182,15 @@
"account_edit.field_reorder_modal.drag_start": "Wedi codi maes \"{item}\".",
"account_edit.field_reorder_modal.handle_label": "Llusgo'r maes \"{item}\"",
"account_edit.field_reorder_modal.title": "Aildrefnu meysydd",
"account_edit.image_alt_modal.add_title": "Ychwanegu testun amgen",
"account_edit.image_alt_modal.details_content": "GWNEUD:<ul><li> Disgrifio'ch hun fel yn eich llun</li><li> Defnyddio iaith trydydd person (e.e. “Siôn” yn lle “fi”)</li><li> Bod yn gryno mae ychydig o eiriaun aml yn ddigon</li></ul> PEIDIO:<ul><li> Dechrau gyda “Llun o” maen ddiangen ar gyfer darllenwyr sgrin</li></ul> ENGHRAIFFT:<ul><li> “Dyma Siôn yn gwisgo crys gwyrdd a sbectol”</li></ul>",
"account_edit.image_alt_modal.details_title": "Awgrymiadau: Testun amgen ar gyfer lluniau proffil",
"account_edit.image_alt_modal.edit_title": "Golygu testun amgen",
"account_edit.image_alt_modal.text_hint": "Mae testun amgen yn helpu defnyddwyr darllenwyr sgrin i ddeall eich cynnwys.",
"account_edit.image_alt_modal.text_label": "Testun amgen",
"account_edit.image_delete_modal.confirm": "Ydych chi'n siŵr eich bod chi eisiau dileu'r ddelwedd hon? Does dim modd dadwneud hynny.",
"account_edit.image_delete_modal.delete_button": "Dileu",
"account_edit.image_delete_modal.title": "Dileu delwedd?",
"account_edit.image_edit.add_button": "Ychwanegu Delwedd",
"account_edit.image_edit.alt_add_button": "Ychwanegu testun amgen",
"account_edit.image_edit.alt_edit_button": "Golygu testun amgen",
@@ -202,6 +210,16 @@
"account_edit.profile_tab.subtitle": "Cyfaddaswch y tabiau ar eich proffil a'r hyn maen nhw'n ei ddangos.",
"account_edit.profile_tab.title": "Gosodiadau tab proffil",
"account_edit.save": "Cadw",
"account_edit.upload_modal.back": "Nôl",
"account_edit.upload_modal.done": "Gorffen",
"account_edit.upload_modal.next": "Nesaf",
"account_edit.upload_modal.step_crop.zoom": "Chwyddo",
"account_edit.upload_modal.step_upload.button": "Pori ffeiliau",
"account_edit.upload_modal.step_upload.dragging": "Gollwng i lwytho i fyny",
"account_edit.upload_modal.step_upload.header": "Dewiswch ddelwedd",
"account_edit.upload_modal.step_upload.hint": "Fformat WEBP, PNG, GIF neu JPG, hyd at {limit}MB.{br}Bydd y ddelwedd yn cael ei haddasu i {width}x{height}px.",
"account_edit.upload_modal.title_add": "Ychwanegu llun proffil",
"account_edit.upload_modal.title_replace": "Amnewid llun proffil",
"account_edit.verified_modal.details": "Ychwanegwch hygrededd at eich proffil Mastodon trwy wirio dolenni i wefannau personol. Dyma sut mae'n gweithio:",
"account_edit.verified_modal.invisible_link.details": "Ychwanegwch y ddolen at eich pennyn. Y rhan bwysig yw rel=\"me\" sy'n atal dynwared ar wefannau gyda chynnwys sy'n cael ei gynhyrchu gan ddefnyddwyr. Gallwch hyd yn oed ddefnyddio tag dolen ym mhennyn y dudalen yn lle {tag}, ond rhaid bod yr HTML yn hygyrch ac heb weithredu JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "Sut ydw i'n gwneud y ddolen yn anweledig?",
@@ -373,6 +391,7 @@
"collections.search_accounts_max_reached": "Rydych chi wedi ychwanegu'r nifer mwyaf o gyfrifon",
"collections.sensitive": "Sensitif",
"collections.topic_hint": "Ychwanegwch hashnod sy'n helpu eraill i ddeall prif bwnc y casgliad hwn.",
"collections.topic_special_chars_hint": "Bydd nodau arbennig yn cael eu tynnu wrth gadw",
"collections.view_collection": "Gweld y casgliad",
"collections.view_other_collections_by_user": "Edrychwch ar gasgliadau eraill gan y defnyddiwr hwn",
"collections.visibility_public": "Cyhoeddus",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Gå til profil",
"account.hide_reblogs": "Skjul fremhævelser fra @{name}",
"account.in_memoriam": "Til minde om.",
"account.joined_long": "Tilmeldt {date}",
"account.joined_short": "Oprettet",
"account.languages": "Skift abonnementssprog",
"account.link_verified_on": "Ejerskab af dette link blev tjekket {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Profil aufrufen",
"account.hide_reblogs": "Geteilte Beiträge von @{name} ausblenden",
"account.in_memoriam": "Zum Andenken.",
"account.joined_long": "Registriert am {date}",
"account.joined_short": "Registriert am",
"account.languages": "Sprachen verwalten",
"account.link_verified_on": "Das Profil mit dieser E-Mail-Adresse wurde bereits am {date} bestätigt",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Μετάβαση στο προφίλ",
"account.hide_reblogs": "Απόκρυψη ενισχύσεων από @{name}",
"account.in_memoriam": "Εις μνήμην.",
"account.joined_long": "Έγινε μέλος {date}",
"account.joined_short": "Έγινε μέλος",
"account.languages": "Αλλαγή εγγεγραμμένων γλωσσών",
"account.link_verified_on": "Η ιδιοκτησία αυτού του συνδέσμου ελέγχθηκε στις {date}",
@@ -214,6 +213,7 @@
"account_edit.save": "Αποθήκευση",
"account_edit.upload_modal.back": "Πίσω",
"account_edit.upload_modal.done": "Έγινε",
"account_edit.upload_modal.next": "Επόμενο",
"account_edit.upload_modal.step_crop.zoom": "Μεγέθυνση",
"account_edit.upload_modal.step_upload.button": "Περιήγηση αρχείων",
"account_edit.upload_modal.step_upload.dragging": "Αποθέστε εδώ για ανέβασμα",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Go to profile",
"account.hide_reblogs": "Hide boosts from @{name}",
"account.in_memoriam": "In Memoriam.",
"account.joined_long": "Joined on {date}",
"account.joined_short": "Joined",
"account.languages": "Change subscribed languages",
"account.link_verified_on": "Ownership of this link was checked on {date}",

View File

@@ -349,6 +349,8 @@
"collections.accounts.empty_description": "Add up to {count} accounts you follow",
"collections.accounts.empty_title": "This collection is empty",
"collections.collection_description": "Description",
"collections.collection_language": "Language",
"collections.collection_language_none": "None",
"collections.collection_name": "Name",
"collections.collection_topic": "Topic",
"collections.confirm_account_removal": "Are you sure you want to remove this account from this collection?",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir al perfil",
"account.hide_reblogs": "Ocultar adhesiones de @{name}",
"account.in_memoriam": "Cuenta conmemorativa.",
"account.joined_long": "En este servidor desde el {date}",
"account.joined_short": "En este servidor desde el",
"account.languages": "Cambiar idiomas suscritos",
"account.link_verified_on": "La propiedad de este enlace fue verificada el {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir al perfil",
"account.hide_reblogs": "Ocultar impulsos de @{name}",
"account.in_memoriam": "En memoria.",
"account.joined_long": "Se unió el {date}",
"account.joined_short": "Se unió",
"account.languages": "Cambiar idiomas suscritos",
"account.link_verified_on": "Se verificó la propiedad de este enlace el {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir al perfil",
"account.hide_reblogs": "Ocultar impulsos de @{name}",
"account.in_memoriam": "Cuenta conmemorativa.",
"account.joined_long": "Se unió el {date}",
"account.joined_short": "Se unió",
"account.languages": "Cambiar idiomas suscritos",
"account.link_verified_on": "La propiedad de este enlace fue verificada el {date}",
@@ -184,6 +183,15 @@
"account_edit.field_reorder_modal.drag_start": "Campo \"{item}\" seleccionado.",
"account_edit.field_reorder_modal.handle_label": "Arrastra el campo \"{item}\"",
"account_edit.field_reorder_modal.title": "Reorganizar campos",
"account_edit.image_alt_modal.add_title": "Añadir texto alternativo",
"account_edit.image_alt_modal.details_content": "QUE HACER: <ul> <li>Descríbete tal y como apareces en la imagen</li> <li>Exprésate en tercera persona (p. ej. “Alex” en lugar de “yo”)</li> <li>Sé breve, unas pocas palabras son a menudo suficientes</li> </ul> QUE NO HACER: <ul> <li>Comenzar con “Foto de” es redundante para lectores de pantalla</li> </ul> EJEMPLO: <ul> <li>“Alex visitiendo una camisa verde y gafas”</li> </ul>",
"account_edit.image_alt_modal.details_title": "Consejo: Texto alternativo para fotos de perfil",
"account_edit.image_alt_modal.edit_title": "Editar texto alternativo",
"account_edit.image_alt_modal.text_hint": "El texto alternativo ayuda a los usuarios de lectores de pantalla a entender tu contenido.",
"account_edit.image_alt_modal.text_label": "Texto alternativo",
"account_edit.image_delete_modal.confirm": "¿Estás seguro de que deseas eliminar esta imagen? Esta acción no se puede deshacer.",
"account_edit.image_delete_modal.delete_button": "Eliminar",
"account_edit.image_delete_modal.title": "¿Eliminar imagen?",
"account_edit.image_edit.add_button": "Añadir imagen",
"account_edit.image_edit.alt_add_button": "Añadir texto alternativo",
"account_edit.image_edit.alt_edit_button": "Editar texto alternativo",
@@ -203,6 +211,16 @@
"account_edit.profile_tab.subtitle": "Personaliza las pestañas de tu perfil y lo que muestran.",
"account_edit.profile_tab.title": "Configuración de la pestaña de perfil",
"account_edit.save": "Guardar",
"account_edit.upload_modal.back": "Atrás",
"account_edit.upload_modal.done": "Hecho",
"account_edit.upload_modal.next": "Siguiente",
"account_edit.upload_modal.step_crop.zoom": "Zoom",
"account_edit.upload_modal.step_upload.button": "Explorar archivos",
"account_edit.upload_modal.step_upload.dragging": "Suelta para subir",
"account_edit.upload_modal.step_upload.header": "Elige una imagen",
"account_edit.upload_modal.step_upload.hint": "Formato WEBP, PNG, GIF o JPG, hasta {limit}MB.{br}La imagen será escalada a {width}x{height}px.",
"account_edit.upload_modal.title_add": "Añadir foto de perfil",
"account_edit.upload_modal.title_replace": "Reemplazar foto de perfil",
"account_edit.verified_modal.details": "Añade credibilidad a tu perfil de Mastodon verificando enlaces a tus webs personales. Así es como funciona:",
"account_edit.verified_modal.invisible_link.details": "Añade el enlace en el encabezado. La parte importante es rel=\"me\", que evita la suplantación de identidad en webs con contenido generado por usuarios. Incluso puedes utilizar un enlace con etiqueta en el encabezado de la página en vez de {tag}, pero el HTML debe ser accesible sin ejecutar JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "¿Cómo puedo hacer el enlace invisible?",
@@ -368,7 +386,7 @@
"collections.remove_account": "Quitar esta cuenta",
"collections.report_collection": "Informar de esta colección",
"collections.revoke_collection_inclusion": "Sácame de esta colección",
"collections.revoke_inclusion.confirmation": "Has salido de la \"{collection}\"",
"collections.revoke_inclusion.confirmation": "Has salido de \"{collection}\"",
"collections.revoke_inclusion.error": "Se ha producido un error, inténtalo de nuevo más tarde.",
"collections.search_accounts_label": "Buscar cuentas para añadir…",
"collections.search_accounts_max_reached": "Has añadido el número máximo de cuentas",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Vaata profiili",
"account.hide_reblogs": "Peida @{name} jagamised",
"account.in_memoriam": "In Memoriam.",
"account.joined_long": "Liitus {date}",
"account.joined_short": "Liitus",
"account.languages": "Muuda tellitud keeli",
"account.link_verified_on": "Selle lingi autorsust kontrolliti {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Siirry profiiliin",
"account.hide_reblogs": "Piilota käyttäjän @{name} tehostukset",
"account.in_memoriam": "Muistoissamme.",
"account.joined_long": "Liittynyt {date}",
"account.joined_short": "Liittynyt",
"account.languages": "Vaihda tilattuja kieliä",
"account.link_verified_on": "Linkin omistus tarkistettiin {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Far til vanga",
"account.hide_reblogs": "Fjal stimbran frá @{name}",
"account.in_memoriam": "In memoriam.",
"account.joined_long": "Meldaði til {date}",
"account.joined_short": "Gjørdist limur",
"account.languages": "Broyt fylgd mál",
"account.link_verified_on": "Ognarskapur av hesum leinki var eftirkannaður {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Voir ce profil",
"account.hide_reblogs": "Masquer les boosts de @{name}",
"account.in_memoriam": "En souvenir de",
"account.joined_long": "Ici depuis le {date}",
"account.joined_short": "Inscrit·e",
"account.languages": "Changer les langues abonnées",
"account.link_verified_on": "La propriété de ce lien a été vérifiée le {date}",
@@ -185,6 +184,14 @@
"account_edit.field_reorder_modal.handle_label": "Faites glisser le champ « {item} »",
"account_edit.field_reorder_modal.title": "Réorganiser les champs",
"account_edit.image_alt_modal.add_title": "Ajouter un texte alternatif",
"account_edit.image_alt_modal.details_content": "À faire : <ul> <li>Se décrire comme vous apparaissez sur la photo</li> <li>Utiliser la troisième personne (par exemple « Alex » au lieu de « moi »)</li> <li>Être succinct·e quelques mot suffisent souvent</li> </ul> À éviter : <ul> <li>Commencer par « Une photo de » c'est redondant pour les lecteurs d'écran</li> </ul> Example : <ul> <li>« Alex portant une chemise vert et des lunettes »</li> </ul>",
"account_edit.image_alt_modal.details_title": "Astuces : texte alternatif pour les photos de profil",
"account_edit.image_alt_modal.edit_title": "Modifier le texte alternatif",
"account_edit.image_alt_modal.text_hint": "Le texte alternatif aide les personnes utilisant un lecteur d'écran à comprendre votre contenu.",
"account_edit.image_alt_modal.text_label": "Texte alternatif",
"account_edit.image_delete_modal.confirm": "Voulez-vous vraiment supprimer cette image ? Cette action est irréversible.",
"account_edit.image_delete_modal.delete_button": "Supprimer",
"account_edit.image_delete_modal.title": "Supprimer l'image ?",
"account_edit.image_edit.add_button": "Ajouter une image",
"account_edit.image_edit.alt_add_button": "Ajouter un texte alternatif",
"account_edit.image_edit.alt_edit_button": "Modifier le texte alternatif",
@@ -206,6 +213,14 @@
"account_edit.save": "Enregistrer",
"account_edit.upload_modal.back": "Retour",
"account_edit.upload_modal.done": "Terminé",
"account_edit.upload_modal.next": "Suivant",
"account_edit.upload_modal.step_crop.zoom": "Agrandir",
"account_edit.upload_modal.step_upload.button": "Parcourir les fichiers",
"account_edit.upload_modal.step_upload.dragging": "Déposer pour téléverser",
"account_edit.upload_modal.step_upload.header": "Choisir une image",
"account_edit.upload_modal.step_upload.hint": "Format WebP, PNG, GIF ou JPEG, jusqu'à {limit} Mo.{br}L'image sera redimensionnée à {width} × {height} px.",
"account_edit.upload_modal.title_add": "Ajouter une photo de profil",
"account_edit.upload_modal.title_replace": "Remplacer la photo de profil",
"account_edit.verified_modal.details": "Ajouter de la crédibilité à votre profil Mastodon en vérifiant les liens vers vos sites Web personnels. Voici comment cela fonctionne :",
"account_edit.verified_modal.invisible_link.details": "Ajouter le lien dans votre en-tête. La partie importante est « rel=\"me\" » qui empêche l'usurpation d'identité sur des sites Web ayant du contenu généré par d'autres utilisateur·rice·s. Vous pouvez aussi utiliser une balise link dans l'en-tête de la page au lieu de {tag}, mais le code HTML doit être accessible sans avoir besoin d'exécuter du JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "Comment rendre le lien invisible ?",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Voir le profil",
"account.hide_reblogs": "Masquer les partages de @{name}",
"account.in_memoriam": "En mémoire.",
"account.joined_long": "Ici depuis le {date}",
"account.joined_short": "Ici depuis",
"account.languages": "Modifier les langues d'abonnements",
"account.link_verified_on": "La propriété de ce lien a été vérifiée le {date}",
@@ -185,6 +184,14 @@
"account_edit.field_reorder_modal.handle_label": "Faites glisser le champ « {item} »",
"account_edit.field_reorder_modal.title": "Réorganiser les champs",
"account_edit.image_alt_modal.add_title": "Ajouter un texte alternatif",
"account_edit.image_alt_modal.details_content": "À faire : <ul> <li>Se décrire comme vous apparaissez sur la photo</li> <li>Utiliser la troisième personne (par exemple « Alex » au lieu de « moi »)</li> <li>Être succinct·e quelques mot suffisent souvent</li> </ul> À éviter : <ul> <li>Commencer par « Une photo de » c'est redondant pour les lecteurs d'écran</li> </ul> Example : <ul> <li>« Alex portant une chemise vert et des lunettes »</li> </ul>",
"account_edit.image_alt_modal.details_title": "Astuces : texte alternatif pour les photos de profil",
"account_edit.image_alt_modal.edit_title": "Modifier le texte alternatif",
"account_edit.image_alt_modal.text_hint": "Le texte alternatif aide les personnes utilisant un lecteur d'écran à comprendre votre contenu.",
"account_edit.image_alt_modal.text_label": "Texte alternatif",
"account_edit.image_delete_modal.confirm": "Voulez-vous vraiment supprimer cette image ? Cette action est irréversible.",
"account_edit.image_delete_modal.delete_button": "Supprimer",
"account_edit.image_delete_modal.title": "Supprimer l'image ?",
"account_edit.image_edit.add_button": "Ajouter une image",
"account_edit.image_edit.alt_add_button": "Ajouter un texte alternatif",
"account_edit.image_edit.alt_edit_button": "Modifier le texte alternatif",
@@ -206,6 +213,14 @@
"account_edit.save": "Enregistrer",
"account_edit.upload_modal.back": "Retour",
"account_edit.upload_modal.done": "Terminé",
"account_edit.upload_modal.next": "Suivant",
"account_edit.upload_modal.step_crop.zoom": "Agrandir",
"account_edit.upload_modal.step_upload.button": "Parcourir les fichiers",
"account_edit.upload_modal.step_upload.dragging": "Déposer pour téléverser",
"account_edit.upload_modal.step_upload.header": "Choisir une image",
"account_edit.upload_modal.step_upload.hint": "Format WebP, PNG, GIF ou JPEG, jusqu'à {limit} Mo.{br}L'image sera redimensionnée à {width} × {height} px.",
"account_edit.upload_modal.title_add": "Ajouter une photo de profil",
"account_edit.upload_modal.title_replace": "Remplacer la photo de profil",
"account_edit.verified_modal.details": "Ajouter de la crédibilité à votre profil Mastodon en vérifiant les liens vers vos sites Web personnels. Voici comment cela fonctionne :",
"account_edit.verified_modal.invisible_link.details": "Ajouter le lien dans votre en-tête. La partie importante est « rel=\"me\" » qui empêche l'usurpation d'identité sur des sites Web ayant du contenu généré par d'autres utilisateur·rice·s. Vous pouvez aussi utiliser une balise link dans l'en-tête de la page au lieu de {tag}, mais le code HTML doit être accessible sans avoir besoin d'exécuter du JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "Comment rendre le lien invisible ?",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Téigh go dtí próifíl",
"account.hide_reblogs": "Folaigh moltaí ó @{name}",
"account.in_memoriam": "Ón tseanaimsir.",
"account.joined_long": "Chuaigh isteach ar {date}",
"account.joined_short": "Cláraithe",
"account.languages": "Athraigh teangacha foscríofa",
"account.link_verified_on": "Seiceáladh úinéireacht an naisc seo ar {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir ao perfil",
"account.hide_reblogs": "Agochar promocións de @{name}",
"account.in_memoriam": "Lembranzas.",
"account.joined_long": "Uníuse o {date}",
"account.joined_short": "Uniuse",
"account.languages": "Modificar os idiomas subscritos",
"account.link_verified_on": "A propiedade desta ligazón foi verificada o {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "מעבר לפרופיל",
"account.hide_reblogs": "להסתיר הידהודים מאת @{name}",
"account.in_memoriam": "פרופיל זכרון.",
"account.joined_long": "הצטרפו ב־{date}",
"account.joined_short": "תאריך הצטרפות",
"account.languages": "שנה רישום לשפות",
"account.link_verified_on": "בעלות על הקישור הזה נבדקה לאחרונה ב{date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ugrás a profilhoz",
"account.hide_reblogs": "@{name} megtolásainak elrejtése",
"account.in_memoriam": "Emlékünkben.",
"account.joined_long": "Csatlakozás ideje: {date}",
"account.joined_short": "Csatlakozott",
"account.languages": "Feliratkozott nyelvek módosítása",
"account.link_verified_on": "A linket eredetiségét ebben az időpontban ellenőriztük: {date}",
@@ -163,7 +162,7 @@
"account_edit.featured_hashtags.item": "hashtagek",
"account_edit.featured_hashtags.placeholder": "Segíts másoknak, hogy azonosíthassák a kedvenc témáid, és gyorsan elérjék azokat.",
"account_edit.featured_hashtags.title": "Kiemelt hashtagek",
"account_edit.field_delete_modal.confirm": "Biztos, hogy töröld ezt az egyéni mezőt? Ez a művelet nem vonható vissza.",
"account_edit.field_delete_modal.confirm": "Biztos, hogy törlöd ezt az egyéni mezőt? Ez a művelet nem vonható vissza.",
"account_edit.field_delete_modal.delete_button": "Törlés",
"account_edit.field_delete_modal.title": "Egyéni mező törlése?",
"account_edit.field_edit_modal.add_title": "Egyéni mező hozzáadása",
@@ -184,6 +183,15 @@
"account_edit.field_reorder_modal.drag_start": "A(z) „{item}” mező áthelyezéshez felvéve.",
"account_edit.field_reorder_modal.handle_label": "A(z) „{item}” mező húzása",
"account_edit.field_reorder_modal.title": "Mezők átrendezése",
"account_edit.image_alt_modal.add_title": "Helyettesítő szöveg hozzáadása",
"account_edit.image_alt_modal.details_content": "TEDD: <ul> <li>Írd le a képedet</li> <li>Használj egyes szám harmadik személyt (például „én” helyett „Alex”)</li> <li>Légy tömör sokszor néhány szó is elég</li> </ul> NE TEDD: <ul> <li>Ne kezdd azzal, hogy „X fényképe” a képernyőolvasók számára felesleges</li> </ul> Példa: <ul> <li>„Alex zöld inget és szemüveget viselve”</li> </ul>",
"account_edit.image_alt_modal.details_title": "Tippek: helyettesítő szöveg a profilképekhez",
"account_edit.image_alt_modal.edit_title": "Helyettesítő szöveg szerkesztése",
"account_edit.image_alt_modal.text_hint": "A helyettesítő szövegek segítenek a képernyőolvasót használóknak abban, hogy megértsék a tartalmat.",
"account_edit.image_alt_modal.text_label": "Helyettesítő szöveg",
"account_edit.image_delete_modal.confirm": "Biztos, hogy törlöd ezt a képet? Ez a művelet nem vonható vissza.",
"account_edit.image_delete_modal.delete_button": "Törlés",
"account_edit.image_delete_modal.title": "Törlöd a képet?",
"account_edit.image_edit.add_button": "Kép hozzáadása",
"account_edit.image_edit.alt_add_button": "Helyettesítő szöveg hozzáadása",
"account_edit.image_edit.alt_edit_button": "Helyettesítő szöveg szerkesztése",
@@ -203,6 +211,15 @@
"account_edit.profile_tab.subtitle": "Szabd testre a profilodon látható lapokat, és a megjelenített tartalmukat.",
"account_edit.profile_tab.title": "Profil lap beállításai",
"account_edit.save": "Mentés",
"account_edit.upload_modal.back": "Vissza",
"account_edit.upload_modal.done": "Kész",
"account_edit.upload_modal.next": "Következő",
"account_edit.upload_modal.step_crop.zoom": "Nagyítás",
"account_edit.upload_modal.step_upload.button": "Fájlok tallózása",
"account_edit.upload_modal.step_upload.dragging": "Ejtsd ide a feltöltéshez",
"account_edit.upload_modal.step_upload.header": "Válassz egy képet",
"account_edit.upload_modal.title_add": "Profilkép hozzáadása",
"account_edit.upload_modal.title_replace": "Profilkép cseréje",
"account_edit.verified_modal.details": "Növeld a Mastodon-profilod hitelességét a személyes webhelyekre mutató hivatkozások ellenőrzésével. Így működik:",
"account_edit.verified_modal.invisible_link.details": "A hivatkozás hozzáadása a fejlécedhez. A fontos rész a rel=\"me\", mely megakadályozza, hogy mások a nevedben lépjenek fel olyan oldalakon, ahol van felhasználók által előállított tartalom. A(z) {tag} helyett a „link” címkét is használhatod az oldal fejlécében, de a HTML-nek elérhetőnek kell lennie JavaScript futtatása nélkül is.",
"account_edit.verified_modal.invisible_link.summary": "Hogyan lehet egy hivatkozás láthatatlanná tenni?",
@@ -374,6 +391,7 @@
"collections.search_accounts_max_reached": "Elérte a hozzáadott fiókok maximális számát",
"collections.sensitive": "Érzékeny",
"collections.topic_hint": "Egy hashtag hozzáadása segít másoknak abban, hogy megértsék a gyűjtemény fő témáját.",
"collections.topic_special_chars_hint": "A különleges karakterek mentéskor el lesznek távolítva",
"collections.view_collection": "Gyűjtemény megtekintése",
"collections.view_other_collections_by_user": "Felhasználó más gyűjteményeinek megtekintése",
"collections.visibility_public": "Nyilvános",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Fara í notandasnið",
"account.hide_reblogs": "Fela endurbirtingar fyrir @{name}",
"account.in_memoriam": "Minning.",
"account.joined_long": "Skáði sig {date}",
"account.joined_short": "Gerðist þátttakandi",
"account.languages": "Breyta tungumálum í áskrift",
"account.link_verified_on": "Eignarhald á þessum tengli var athugað þann {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Vai al profilo",
"account.hide_reblogs": "Nascondi condivisioni da @{name}",
"account.in_memoriam": "In memoria.",
"account.joined_long": "Su questa istanza dal {date}",
"account.joined_short": "Iscritto",
"account.languages": "Modifica le lingue d'iscrizione",
"account.link_verified_on": "La proprietà di questo link è stata controllata il {date}",

View File

@@ -58,7 +58,6 @@
"account.follows_you": "Yeṭṭafaṛ-ik·em-id",
"account.go_to_profile": "Ddu ɣer umaɣnu",
"account.hide_reblogs": "Ffer ayen i ibeṭṭu @{name}",
"account.joined_long": "Yerna-d ass n {date}",
"account.joined_short": "Izeddi da seg ass n",
"account.languages": "Beddel tutlayin yettwajerden",
"account.link_verified_on": "Taɣara n useɣwen-a tettwasenqed ass n {date}",

View File

@@ -72,7 +72,6 @@
"account.go_to_profile": "프로필로 이동",
"account.hide_reblogs": "@{name}의 부스트를 숨기기",
"account.in_memoriam": "고인의 계정입니다.",
"account.joined_long": "{date}에 가입함",
"account.joined_short": "가입",
"account.languages": "구독한 언어 변경",
"account.link_verified_on": "{date}에 이 링크의 소유권이 확인 됨",

View File

@@ -54,7 +54,7 @@
"account.follow": "Sekti",
"account.follow_back": "Sekti atgal",
"account.follow_back_short": "Sekti atgal",
"account.follow_request": "Prašyti sekti",
"account.follow_request": "Prašymas sekti",
"account.follow_request_cancel": "Atšaukti prašymą",
"account.follow_request_cancel_short": "Atšaukti",
"account.follow_request_short": "Prašymas",
@@ -69,7 +69,6 @@
"account.go_to_profile": "Eiti į profilį",
"account.hide_reblogs": "Slėpti pasidalinimus iš @{name}",
"account.in_memoriam": "Atminimui.",
"account.joined_long": "Prisijungė {date}",
"account.joined_short": "Prisijungė",
"account.languages": "Keisti prenumeruojamas kalbas",
"account.link_verified_on": "Šios nuorodos nuosavybė buvo patikrinta {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "行kàu個人資料",
"account.hide_reblogs": "Tshàng tuì @{name} 來ê轉PO",
"account.in_memoriam": "佇tsia追悼。",
"account.joined_long": "佇 {date} 加入",
"account.joined_short": "加入ê時",
"account.languages": "變更訂閱的語言",
"account.link_verified_on": "Tsit ê連結ê所有權佇 {date} 受檢查",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ga naar profiel",
"account.hide_reblogs": "Boosts van @{name} verbergen",
"account.in_memoriam": "In memoriam.",
"account.joined_long": "Geregistreerd op {date}",
"account.joined_short": "Geregistreerd op",
"account.languages": "Getoonde talen wijzigen",
"account.link_verified_on": "Eigendom van deze link is gecontroleerd op {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Gå til profil",
"account.hide_reblogs": "Gøym framhevingar frå @{name}",
"account.in_memoriam": "Til minne om.",
"account.joined_long": "Vart med {date}",
"account.joined_short": "Vart med",
"account.languages": "Endre språktingingar",
"account.link_verified_on": "Eigarskap for denne lenkja vart sist sjekka {date}",
@@ -222,6 +221,13 @@
"account_edit.upload_modal.step_upload.hint": "WEBP, PNG, GIF eller JPG-format, opp til {limit}MB.{br}Biletet blir skalert til {width}*{height} punkt.",
"account_edit.upload_modal.title_add": "Legg til profilbilete",
"account_edit.upload_modal.title_replace": "Byt ut profilbilete",
"account_edit.verified_modal.details": "Auk truverdet til Mastodon-profilen din ved å stadfesta lenker til personlege nettstader. Slik verkar det:",
"account_edit.verified_modal.invisible_link.details": "Den viktige delen er rel=\"me\", som på nettstader med brukargenerert innhald vil hindra at andre kan låst som dei er deg. Du kan til og med bruka link i staden for {tag} i toppteksten til sida, men HTML-koden må vera tilgjengeleg utan å måtte køyra JavaScript.",
"account_edit.verified_modal.invisible_link.summary": "Korleis gjer eg lenka usynleg?",
"account_edit.verified_modal.step1.header": "Kopier HTML-koden under og lim han inn i toppfeltet på nettstaden din",
"account_edit.verified_modal.step2.details": "Viss du allereie har lagt til nettsida di i eit tilpassa felt, må du sletta ho og leggja ho til på nytt for å setja i gang stadfestinga.",
"account_edit.verified_modal.step2.header": "Legg til nettstaden din som eige felt",
"account_edit.verified_modal.title": "Korleis legg eg til ei stadfesta lenke",
"account_edit_tags.add_tag": "Legg til #{tagName}",
"account_edit_tags.column_title": "Rediger utvalde emneknaggar",
"account_edit_tags.help_text": "Utvalde emneknaggar hjelper folk å oppdaga og samhandla med profilen din. Dei blir viste som filter på aktivitetsoversikta på profilsida di.",
@@ -325,8 +331,8 @@
"callout.dismiss": "Avvis",
"carousel.current": "<sr>Side</sr> {current, number} / {max, number}",
"carousel.slide": "Side {current, number} av {max, number}",
"character_counter.recommended": "{currentLength}/{maxLength} anbefalte tegn",
"character_counter.required": "{currentLength}/{maxLength} tegn",
"character_counter.recommended": "{currentLength}/{maxLength} tilrådde teikn",
"character_counter.required": "{currentLength}/{maxLength} teikn",
"closed_registrations.other_server_instructions": "Sidan Mastodon er desentralisert kan du lage ein brukar på ein anna tenar og framleis interagere med denne.",
"closed_registrations_modal.description": "Det er ikkje mogleg å opprette ein konto på {domain} nett no, men hugs at du ikkje treng ein konto på akkurat {domain} for å nytte Mastodon.",
"closed_registrations_modal.find_another_server": "Finn ein annan tenar",
@@ -356,10 +362,15 @@
"collections.create_collection": "Lag ei samling",
"collections.delete_collection": "Slett samlinga",
"collections.description_length_hint": "Maks 100 teikn",
"collections.detail.accept_inclusion": "Ok",
"collections.detail.accounts_heading": "Kontoar",
"collections.detail.author_added_you": "{author} la deg til i denne samlinga",
"collections.detail.curated_by_author": "Kuratert av {author}",
"collections.detail.curated_by_you": "Kuratert av deg",
"collections.detail.loading": "Lastar inn samling…",
"collections.detail.other_accounts_in_collection": "Andre i denne samlinga:",
"collections.detail.revoke_inclusion": "Fjern meg",
"collections.detail.sensitive_note": "Denne samlinga inneheld kontoar og innhald som kan vera ømtolige for nokre menneske.",
"collections.detail.share": "Del denne samlinga",
"collections.edit_details": "Rediger detaljar",
"collections.error_loading_collections": "Noko gjekk gale då me prøvde å henta samlingane dine.",
@@ -374,10 +385,14 @@
"collections.old_last_post_note": "Sist lagt ut for over ei veke sidan",
"collections.remove_account": "Fjern denne kontoen",
"collections.report_collection": "Rapporter denne samlinga",
"collections.revoke_collection_inclusion": "Fjern meg frå denne samlinga",
"collections.revoke_inclusion.confirmation": "Du er fjerna frå «{collection}»",
"collections.revoke_inclusion.error": "Noko gjekk gale, prøv att seinare.",
"collections.search_accounts_label": "Søk etter kontoar å leggja til…",
"collections.search_accounts_max_reached": "Du har nådd grensa for kor mange kontoar du kan leggja til",
"collections.sensitive": "Ømtolig",
"collections.topic_hint": "Legg til ein emneknagg som hjelper andre å forstå hovudemnet for denne samlinga.",
"collections.topic_special_chars_hint": "Spesialteikn vil bli fjerna ved lagring",
"collections.view_collection": "Sjå samlinga",
"collections.view_other_collections_by_user": "Sjå andre samlingar frå denne personen",
"collections.visibility_public": "Offentleg",
@@ -498,7 +513,8 @@
"confirmations.remove_from_followers.message": "{name} vil ikkje fylgja deg meir. Vil du halda fram?",
"confirmations.remove_from_followers.title": "Fjern fylgjar?",
"confirmations.revoke_collection_inclusion.confirm": "Fjern meg",
"confirmations.revoke_collection_inclusion.title": "Fjern deg selv fra denne samlingen?",
"confirmations.revoke_collection_inclusion.message": "Denne handlinga er endeleg, og kuratoren kan ikkje leggja deg til samlinga på nytt seinare.",
"confirmations.revoke_collection_inclusion.title": "Vil du fjerna deg sjølv frå denne samlinga?",
"confirmations.revoke_quote.confirm": "Fjern innlegget",
"confirmations.revoke_quote.message": "Du kan ikkje angra denne handlinga.",
"confirmations.revoke_quote.title": "Fjern innlegget?",
@@ -821,6 +837,7 @@
"navigation_bar.automated_deletion": "Automatisk sletting av innlegg",
"navigation_bar.blocks": "Blokkerte brukarar",
"navigation_bar.bookmarks": "Bokmerke",
"navigation_bar.collections": "Samlingar",
"navigation_bar.direct": "Private omtaler",
"navigation_bar.domain_blocks": "Skjulte domene",
"navigation_bar.favourites": "Favorittar",
@@ -968,12 +985,14 @@
"notifications_permission_banner.title": "Gå aldri glipp av noko",
"onboarding.follows.back": "Tilbake",
"onboarding.follows.empty": "Me kan ikkje visa deg nokon resultat no. Du kan prøva å søkja eller bla gjennom utforsk-sida for å finna folk å fylgja, eller du kan prøva att seinare.",
"onboarding.follows.next": "Neste: Set opp profilen din",
"onboarding.follows.search": "Søk",
"onboarding.follows.title": "Fylg folk for å koma i gang",
"onboarding.profile.discoverable": "Gjer profilen min synleg",
"onboarding.profile.discoverable_hint": "Når du vel å gjera profilen din synleg på Mastodon, vil innlegga dine syna i søkjeresultat og populære innlegg, og profilen din kan bli føreslegen for folk med liknande interesser som deg.",
"onboarding.profile.display_name": "Synleg namn",
"onboarding.profile.display_name_hint": "Det fulle namnet eller kallenamnet ditt…",
"onboarding.profile.finish": "Fullfør",
"onboarding.profile.note": "Om meg",
"onboarding.profile.note_hint": "Du kan @nemna folk eller #emneknaggar…",
"onboarding.profile.title": "Profiloppsett",

View File

@@ -71,7 +71,6 @@
"account.go_to_profile": "Gå til profil",
"account.hide_reblogs": "Skjul fremhevinger fra @{name}",
"account.in_memoriam": "Til minne om.",
"account.joined_long": "Ble med den {date}",
"account.joined_short": "Ble med",
"account.languages": "Endre hvilke språk du abonnerer på",
"account.link_verified_on": "Eierskap av denne lenken ble sjekket {date}",

View File

@@ -61,7 +61,6 @@
"account.follows_you": "ਤੁਹਾਨੂੰ ਫ਼ਾਲੋ ਕਰਦੇ ਹਨ",
"account.go_to_profile": "ਪਰੋਫਾਇਲ ਉੱਤੇ ਜਾਓ",
"account.hide_reblogs": "{name} ਵਲੋਂ ਬੂਸਟ ਨੂੰ ਲੁਕਾਓ",
"account.joined_long": "{date} ਨੂੰ ਜੁਆਇਨ ਕੀਤਾ",
"account.joined_short": "ਜੁਆਇਨ ਕੀਤਾ",
"account.media": "ਮੀਡੀਆ",
"account.mention": "@{name} ਦਾ ਜ਼ਿਕਰ",

View File

@@ -57,7 +57,6 @@
"account.go_to_profile": "Przejdź do profilu",
"account.hide_reblogs": "Ukryj podbicia od @{name}",
"account.in_memoriam": "Ku pamięci.",
"account.joined_long": "Dołączył(a) dnia {date}",
"account.joined_short": "Dołączył(a)",
"account.languages": "Zmień subskrybowane języki",
"account.link_verified_on": "Własność tego odnośnika została potwierdzona {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir ao perfil",
"account.hide_reblogs": "Ocultar impulsos de @{name}",
"account.in_memoriam": "In Memoriam.",
"account.joined_long": "Entrou em {date}",
"account.joined_short": "Entrou",
"account.languages": "Mudar idiomas inscritos",
"account.link_verified_on": "A propriedade deste link foi verificada em {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Ir para o perfil",
"account.hide_reblogs": "Esconder partilhas de @{name}",
"account.in_memoriam": "Em Memória.",
"account.joined_long": "Juntou-se em {date}",
"account.joined_short": "Juntou-se a",
"account.languages": "Alterar idiomas subscritos",
"account.link_verified_on": "O proprietário desta hiperligação foi verificado em {date}",

View File

@@ -55,7 +55,6 @@
"account.go_to_profile": "Pojdi na profil",
"account.hide_reblogs": "Skrij izpostavitve od @{name}",
"account.in_memoriam": "V spomin.",
"account.joined_long": "Pridružen/a {date}",
"account.joined_short": "Pridružil/a",
"account.languages": "Spremeni naročene jezike",
"account.link_verified_on": "Lastništvo te povezave je bilo preverjeno {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Kalo te profili",
"account.hide_reblogs": "Fshih përforcime nga @{name}",
"account.in_memoriam": "In Memoriam.",
"account.joined_long": "U bë pjesë më {date}",
"account.joined_short": "U bë pjesë",
"account.languages": "Ndryshoni gjuhë pajtimesh",
"account.link_verified_on": "Pronësia e kësaj lidhjeje qe kontrolluar më {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Gå till profilen",
"account.hide_reblogs": "Dölj boostar från @{name}",
"account.in_memoriam": "Till minne av.",
"account.joined_long": "Gick med {date}",
"account.joined_short": "Gick med",
"account.languages": "Ändra vilka språk du helst vill se i ditt flöde",
"account.link_verified_on": "Ägarskap för denna länk kontrollerades den {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Profile git",
"account.hide_reblogs": "@{name} kişisinin yeniden paylaşımlarını gizle",
"account.in_memoriam": "Hatırasına.",
"account.joined_long": "{date} tarihinde katıldı",
"account.joined_short": "Katıldı",
"account.languages": "Abone olunan dilleri değiştir",
"account.link_verified_on": "Bu bağlantının sahipliği {date} tarihinde denetlendi",

View File

@@ -68,7 +68,6 @@
"account.go_to_profile": "Перейти до профілю",
"account.hide_reblogs": "Сховати поширення від @{name}",
"account.in_memoriam": "Пам'ятник.",
"account.joined_long": "Долучилися {date}",
"account.joined_short": "Дата приєднання",
"account.languages": "Змінити обрані мови",
"account.link_verified_on": "Права власності на це посилання були перевірені {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "Xem hồ sơ",
"account.hide_reblogs": "Ẩn tút @{name} đăng lại",
"account.in_memoriam": "Tưởng Niệm.",
"account.joined_long": "Tham gia {date}",
"account.joined_short": "Tham gia",
"account.languages": "Đổi ngôn ngữ mong muốn",
"account.link_verified_on": "Liên kết này đã được xác minh vào {date}",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "前往个人资料页",
"account.hide_reblogs": "隐藏来自 @{name} 的转嘟",
"account.in_memoriam": "谨此悼念。",
"account.joined_long": "加入于 {date}",
"account.joined_short": "加入于",
"account.languages": "更改订阅语言",
"account.link_verified_on": "此链接的所有权已在 {date} 检查",

View File

@@ -73,7 +73,6 @@
"account.go_to_profile": "前往個人檔案",
"account.hide_reblogs": "隱藏來自 @{name} 之轉嘟",
"account.in_memoriam": "謹此悼念。",
"account.joined_long": "加入於 {date}",
"account.joined_short": "加入時間",
"account.languages": "變更訂閱的語言",
"account.link_verified_on": "已於 {date} 檢查此連結的擁有者權限",

View File

@@ -82,6 +82,9 @@ export const accountDefaultValues: AccountShape = {
last_status_at: '',
locked: false,
noindex: false,
show_featured: true,
show_media: true,
show_media_replies: true,
note: '',
note_emojified: '',
note_plain: 'string',

View File

@@ -1,8 +1,5 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { debounce } from 'lodash';
import { fetchAccount } from '@/mastodon/actions/accounts';
import {
apiDeleteFeaturedTag,
@@ -14,7 +11,6 @@ import {
apiPatchProfile,
apiPostFeaturedTag,
} from '@/mastodon/api/accounts';
import { apiGetSearch } from '@/mastodon/api/search';
import type { ApiAccountFieldJSON } from '@/mastodon/api_types/accounts';
import type {
ApiProfileJSON,
@@ -24,7 +20,6 @@ import type {
ApiFeaturedTagJSON,
ApiHashtagJSON,
} from '@/mastodon/api_types/tags';
import type { AppDispatch } from '@/mastodon/store';
import {
createAppAsyncThunk,
createAppSelector,
@@ -59,40 +54,16 @@ export interface ProfileEditState {
profile?: ProfileData;
tagSuggestions?: ApiHashtagJSON[];
isPending: boolean;
search: {
query: string;
isLoading: boolean;
results?: ApiHashtagJSON[];
};
}
const initialState: ProfileEditState = {
isPending: false,
search: {
query: '',
isLoading: false,
},
};
const profileEditSlice = createSlice({
name: 'profileEdit',
initialState,
reducers: {
setSearchQuery(state, action: PayloadAction<string>) {
if (state.search.query === action.payload) {
return;
}
state.search.query = action.payload;
state.search.isLoading = true;
state.search.results = undefined;
},
clearSearch(state) {
state.search.query = '';
state.search.isLoading = false;
state.search.results = undefined;
},
},
reducers: {},
extraReducers(builder) {
builder.addCase(fetchProfile.fulfilled, (state, action) => {
state.profile = action.payload;
@@ -172,37 +143,10 @@ const profileEditSlice = createSlice({
);
state.isPending = false;
});
builder.addCase(fetchSearchResults.pending, (state) => {
state.search.isLoading = true;
});
builder.addCase(fetchSearchResults.rejected, (state) => {
state.search.isLoading = false;
state.search.results = undefined;
});
builder.addCase(fetchSearchResults.fulfilled, (state, action) => {
state.search.isLoading = false;
const searchResults: ApiHashtagJSON[] = [];
const currentTags = new Set(
(state.profile?.featuredTags ?? []).map((tag) => tag.name),
);
for (const tag of action.payload) {
if (currentTags.has(tag.name)) {
continue;
}
searchResults.push(tag);
if (searchResults.length >= 10) {
break;
}
}
state.search.results = searchResults;
});
},
});
export const profileEdit = profileEditSlice.reducer;
export const { clearSearch } = profileEditSlice.actions;
const transformTag = (result: ApiFeaturedTagJSON): TagData => ({
id: result.id,
@@ -426,27 +370,3 @@ export const deleteFeaturedTag = createDataLoadingThunk(
`${profileEditSlice.name}/deleteFeaturedTag`,
({ tagId }: { tagId: string }) => apiDeleteFeaturedTag(tagId),
);
const debouncedFetchSearchResults = debounce(
async (dispatch: AppDispatch, query: string) => {
await dispatch(fetchSearchResults({ q: query }));
},
300,
);
export const updateSearchQuery = createAppAsyncThunk(
`${profileEditSlice.name}/updateSearchQuery`,
(query: string, { dispatch }) => {
dispatch(profileEditSlice.actions.setSearchQuery(query));
if (query.trim().length > 0) {
void debouncedFetchSearchResults(dispatch, query);
}
},
);
export const fetchSearchResults = createDataLoadingThunk(
`${profileEditSlice.name}/fetchSearchResults`,
({ q }: { q: string }) => apiGetSearch({ q, type: 'hashtags', limit: 11 }),
(result) => result.hashtags,
);

View File

@@ -28,6 +28,7 @@ import {
} from '../actions/timelines_typed';
import { compareId } from '../compare_id';
/** @type {ImmutableMap<string, typeof initialTimeline>} */
const initialState = ImmutableMap();
const initialTimeline = ImmutableMap({
@@ -36,7 +37,9 @@ const initialTimeline = ImmutableMap({
top: true,
isLoading: false,
hasMore: true,
/** @type {ImmutableList<string>} */
pendingItems: ImmutableList(),
/** @type {ImmutableList<string>} */
items: ImmutableList(),
});
@@ -197,6 +200,7 @@ const reconnectTimeline = (state, usePendingItems) => {
});
};
/** @type {import('@reduxjs/toolkit').Reducer<typeof initialState>} */
export default function timelines(state = initialState, action) {
switch(action.type) {
case TIMELINE_LOAD_PENDING:

View File

@@ -18,7 +18,7 @@ export function isServerFeatureEnabled(feature: ServerFeatures) {
return initialState?.features.includes(feature) ?? false;
}
type ClientFeatures = 'collections' | 'profile_editing';
type ClientFeatures = 'collections';
export function isClientFeatureEnabled(feature: ClientFeatures) {
try {

View File

@@ -28,6 +28,12 @@ export const HASHTAG_PATTERN_REGEX = buildHashtagPatternRegex();
export const HASHTAG_REGEX = buildHashtagRegex();
export const trimHashFromStart = (input: string) => {
return input.startsWith('#') || input.startsWith('')
? input.slice(1)
: input;
};
/**
* Formats an input string as a hashtag:
* - Prepends `#` unless present
@@ -41,11 +47,7 @@ export const inputToHashtag = (input: string): string => {
const trailingSpace = /\s+$/.exec(input)?.[0] ?? '';
const trimmedInput = input.trimEnd();
const withoutHash =
trimmedInput.startsWith('#') || trimmedInput.startsWith('')
? trimmedInput.slice(1)
: trimmedInput;
const withoutHash = trimHashFromStart(trimmedInput);
// Split by space, filter empty strings, and capitalise the start of each word but the first
const words = withoutHash

View File

@@ -45,6 +45,9 @@ export const accountFactory: FactoryFunction<ApiAccountJSON> = ({
indexable: true,
last_status_at: '2023-01-01',
locked: false,
show_featured: true,
show_media: true,
show_media_replies: true,
mute_expires_at: null,
note: 'This is a test user account.',
statuses_count: 0,

View File

@@ -2,12 +2,11 @@
class ActivityPub::Activity::Delete < ActivityPub::Activity
def perform
if @account.uri == object_uri
delete_person
else
return delete_person if @account.uri == object_uri
return delete_feature_authorization! unless !Mastodon::Feature.collections_federation_enabled? || feature_authorization_from_object.nil?
delete_object
end
end
private
@@ -66,7 +65,18 @@ class ActivityPub::Activity::Delete < ActivityPub::Activity
DistributionWorker.perform_async(@quote.status_id, { 'update' => true }) if @quote.status.present?
end
def delete_feature_authorization!
collection_item = feature_authorization_from_object
DeleteCollectionItemService.new.call(collection_item, revoke: true)
end
def forwarder
@forwarder ||= ActivityPub::Forwarder.new(@account, @json, @status)
end
def feature_authorization_from_object
return @collection_item if instance_variable_defined?(:@collection_item)
@collection_item = CollectionItem.local.find_by(approval_uri: value_or_id(@object), account_id: @account.id)
end
end

View File

@@ -29,6 +29,7 @@ class Web::PushSubscription < ApplicationRecord
validates_with WebPushKeyValidator
delegate :locale, to: :user
delegate :token, to: :access_token, prefix: :associated_access
generates_token_for :unsubscribe, expires_in: Web::PushNotificationWorker::TTL
@@ -36,10 +37,6 @@ class Web::PushSubscription < ApplicationRecord
policy_allows_notification?(notification) && alert_enabled_for_notification_type?(notification)
end
def associated_access_token
access_token.token
end
class << self
def unsubscribe_for(application_id, resource_owner)
access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id).not_revoked.pluck(:id)

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
class ActivityPub::FetchFeaturedCollectionsCollectionService < BaseService
include JsonLdHelper
MAX_PAGES = 10
MAX_ITEMS = 50
def call(account, request_id: nil)
return if account.collections_url.blank? || account.suspended? || account.local?
@request_id = request_id
@account = account
@items, = collection_items(@account.collections_url, max_pages: MAX_PAGES, reference_uri: @account.uri)
process_items(@items)
end
private
def process_items(items)
return if items.nil?
items.take(MAX_ITEMS).each do |collection_json|
if collection_json.is_a?(String)
ActivityPub::FetchRemoteFeaturedCollectionService.new.call(collection_json, request_id: @request_id)
else
ActivityPub::ProcessFeaturedCollectionService.new.call(@account, collection_json, request_id: @request_id)
end
end
end
end

View File

@@ -3,7 +3,7 @@
class ActivityPub::FetchRemoteFeaturedCollectionService < BaseService
include JsonLdHelper
def call(uri, on_behalf_of = nil)
def call(uri, request_id: nil, on_behalf_of: nil)
json = fetch_resource(uri, true, on_behalf_of)
return unless supported_context?(json)
@@ -17,6 +17,6 @@ class ActivityPub::FetchRemoteFeaturedCollectionService < BaseService
existing_collection = account.collections.find_by(uri:)
return existing_collection if existing_collection.present?
ActivityPub::ProcessFeaturedCollectionService.new.call(account, json)
ActivityPub::ProcessFeaturedCollectionService.new.call(account, json, request_id:)
end
end

View File

@@ -60,6 +60,7 @@ class ActivityPub::ProcessAccountService < BaseService
unless @options[:only_key] || @account.suspended?
check_featured_collection! if @json['featured'].present?
check_featured_tags_collection! if @json['featuredTags'].present?
check_featured_collections_collection! if @json['featuredCollections'].present? && Mastodon::Feature.collections_federation_enabled?
check_links! if @account.fields.any?(&:requires_verification?)
end
@@ -201,6 +202,10 @@ class ActivityPub::ProcessAccountService < BaseService
ActivityPub::SynchronizeFeaturedTagsCollectionWorker.perform_async(@account.id, @json['featuredTags'])
end
def check_featured_collections_collection!
ActivityPub::SynchronizeFeaturedCollectionsCollectionWorker.perform_async(@account.id, @options[:request_id])
end
def check_links!
VerifyAccountLinksWorker.perform_in(rand(10.minutes.to_i), @account.id)
end

View File

@@ -7,9 +7,10 @@ class ActivityPub::ProcessFeaturedCollectionService
ITEMS_LIMIT = 150
def call(account, json)
def call(account, json, request_id: nil)
@account = account
@json = json
@request_id = request_id
return if non_matching_uri_hosts?(@account.uri, @json['id'])
with_redis_lock("collection:#{@json['id']}") do
@@ -46,7 +47,7 @@ class ActivityPub::ProcessFeaturedCollectionService
def process_items!
@json['orderedItems'].take(ITEMS_LIMIT).each do |item_json|
ActivityPub::ProcessFeaturedItemWorker.perform_async(@collection.id, item_json)
ActivityPub::ProcessFeaturedItemWorker.perform_async(@collection.id, item_json, @request_id)
end
end
end

View File

@@ -5,7 +5,8 @@ class ActivityPub::ProcessFeaturedItemService
include Lockable
include Redisable
def call(collection, uri_or_object)
def call(collection, uri_or_object, request_id: nil)
@request_id = request_id
item_json = uri_or_object.is_a?(String) ? fetch_resource(uri_or_object, true) : uri_or_object
return if non_matching_uri_hosts?(collection.uri, item_json['id'])
@@ -35,8 +36,8 @@ class ActivityPub::ProcessFeaturedItemService
private
def verify_authorization!
ActivityPub::VerifyFeaturedItemService.new.call(@collection_item, @approval_uri)
ActivityPub::VerifyFeaturedItemService.new.call(@collection_item, @approval_uri, request_id: @request_id)
rescue Mastodon::RecursionLimitExceededError, Mastodon::UnexpectedResponseError, *Mastodon::HTTP_CONNECTION_ERRORS
ActivityPub::VerifyFeaturedItemWorker.perform_in(rand(30..600).seconds, @collection_item.id, @approval_uri)
ActivityPub::VerifyFeaturedItemWorker.perform_in(rand(30..600).seconds, @collection_item.id, @approval_uri, @request_id)
end
end

View File

@@ -3,7 +3,7 @@
class ActivityPub::VerifyFeaturedItemService
include JsonLdHelper
def call(collection_item, approval_uri)
def call(collection_item, approval_uri, request_id: nil)
@collection_item = collection_item
@authorization = fetch_resource(approval_uri, true, raise_on_error: :temporary)
@@ -16,7 +16,7 @@ class ActivityPub::VerifyFeaturedItemService
return unless matching_type? && matching_collection_uri?
account = Account.where(uri: @collection_item.object_uri).first
account ||= ActivityPub::FetchRemoteAccountService.new.call(@collection_item.object_uri)
account ||= ActivityPub::FetchRemoteAccountService.new.call(@collection_item.object_uri, request_id:)
return if account.blank?
@collection_item.update!(account:, approval_uri:, state: :accepted)

View File

@@ -1,10 +1,11 @@
# frozen_string_literal: true
class DeleteCollectionItemService
def call(collection_item)
def call(collection_item, revoke: false)
@collection_item = collection_item
@collection = collection_item.collection
@collection_item.destroy!
revoke ? @collection_item.revoke! : @collection_item.destroy!
distribute_remove_activity if Mastodon::Feature.collections_federation_enabled?
end

View File

@@ -88,11 +88,18 @@ class ReportService < BaseService
has_followers = @target_account.followers.with_domain(domain).exists?
visibility = has_followers ? %i(public unlisted private) : %i(public unlisted)
scope = @target_account.statuses.with_discarded
scope.merge!(scope.where(visibility: visibility).or(scope.where('EXISTS (SELECT 1 FROM mentions m JOIN accounts a ON m.account_id = a.id WHERE lower(a.domain) = ?)', domain)))
scope.merge!(scope.where(visibility: visibility).or(scope.where(domain_mentions(domain))))
# Allow missing posts to not drop reports that include e.g. a deleted post
scope.where(id: Array(@status_ids)).pluck(:id)
end
def domain_mentions(domain)
Mention
.joins(:account)
.where(Account.arel_table[:domain].lower.eq domain)
.select(1).arel.exists
end
def reported_collection_ids
@target_account.collections.find(Array(@collection_ids)).pluck(:id)
end

View File

@@ -6,10 +6,10 @@ class ActivityPub::ProcessFeaturedItemWorker
sidekiq_options queue: 'pull', retry: 3
def perform(collection_id, id_or_json)
def perform(collection_id, id_or_json, request_id = nil)
collection = Collection.find(collection_id)
ActivityPub::ProcessFeaturedItemService.new.call(collection, id_or_json)
ActivityPub::ProcessFeaturedItemService.new.call(collection, id_or_json, request_id:)
rescue ActiveRecord::RecordNotFound
true
end

View File

@@ -0,0 +1,15 @@
# frozen_string_literal: true
class ActivityPub::SynchronizeFeaturedCollectionsCollectionWorker
include Sidekiq::Worker
sidekiq_options queue: 'pull', lock: :until_executed, lock_ttl: 1.day.to_i
def perform(account_id, request_id = nil)
account = Account.find(account_id)
ActivityPub::FetchFeaturedCollectionsCollectionService.new.call(account, request_id:)
rescue ActiveRecord::RecordNotFound
true
end
end

View File

@@ -7,10 +7,10 @@ class ActivityPub::VerifyFeaturedItemWorker
sidekiq_options queue: 'pull', retry: 5
def perform(collection_item_id, approval_uri)
def perform(collection_item_id, approval_uri, request_id = nil)
collection_item = CollectionItem.find(collection_item_id)
ActivityPub::VerifyFeaturedItemService.new.call(collection_item, approval_uri)
ActivityPub::VerifyFeaturedItemService.new.call(collection_item, approval_uri, request_id:)
rescue ActiveRecord::RecordNotFound
# Do nothing
nil

View File

@@ -810,6 +810,8 @@ be:
administrator_description: Карыстальнікі з гэтым дазволам будуць абыходзіць усе абмежаванні
delete_user_data: Выдаленне даных карыстальнікаў
delete_user_data_description: Дазваляе карыстальнікам без затрымкі выдаляць даныя іншых карыстальнікаў
invite_bypass_approval: Запрашаць карыстальнікаў без разгляду
invite_bypass_approval_description: Дазваляе людзям, якіх запрасілі на сервер гэтыя карыстальнікі, абыходзіць ухвалу мадэратараў
invite_users: Запрашэнне карыстальнікаў
invite_users_description: Дазваляе запрашаць новых людзей на сервер
manage_announcements: Кіраванне аб’явамі
@@ -1337,6 +1339,7 @@ be:
invited_by: 'Вы можаце далучыцца да %{domain} дзякуючы запрашэнню, якое вы атрымалі ад:'
preamble: Правілы вызначаныя мадэратарамі дамена %{domain}.
preamble_invited: Перш чым працягнуць, азнаёмцеся з асноўнымі правіламі, усталяванымі мадэратарамі %{domain}.
read_more: Падрабязней
title: Некалькі базавых правілаў.
title_invited: Вас запрасілі.
security: Бяспека

View File

@@ -1363,6 +1363,7 @@ cy:
progress:
confirm: Cadarnhau'r e-bost
details: Eich manylion
list: Y drefn cofrestru
review: Ein hadolygiad
rules: Derbyn rheolau
providers:
@@ -1378,6 +1379,7 @@ cy:
invited_by: 'Gallwch ymuno â %{domain} diolch i''r gwahoddiad a gawsoch gan:'
preamble: Mae'r rhain yn cael eu gosod a'u gorfodi gan y %{domain} cymedrolwyr.
preamble_invited: Cyn i chi barhau, ystyriwch y rheolau sylfaenol a osodwyd gan gymedrolwyr %{domain}.
read_more: Darllen rhagor
title: Rhai rheolau sylfaenol.
title_invited: Rydych wedi derbyn gwahoddiad.
security: Diogelwch

View File

@@ -778,6 +778,8 @@ da:
administrator_description: Brugere med denne rolle kan omgå alle tilladelser
delete_user_data: Slet brugerdata
delete_user_data_description: Tillader brugere at slette andre brugeres data straks
invite_bypass_approval: Invitere brugere uden gennemgang
invite_bypass_approval_description: Gør det muligt for personer, der er inviteret til serveren af disse brugere, at undgå moderatorgodkendelse
invite_users: Invitér brugere
invite_users_description: Tillader brugere at invitere nye personer til serveren
manage_announcements: Administrer annonceringer

View File

@@ -778,6 +778,8 @@ de:
administrator_description: Beschränkung aller Berechtigungen umgehen
delete_user_data: Kontodaten löschen
delete_user_data_description: Daten anderer Profile ohne Verzögerung löschen
invite_bypass_approval: Einladungen ohne Überprüfungen
invite_bypass_approval_description: Neue Benutzer*innen zur Registrierung auf diesem Server einladen, ohne manuell genehmigt werden zu müssen
invite_users: Einladungen
invite_users_description: Neue Benutzer*innen zur Registrierung auf diesem Server einladen
manage_announcements: Ankündigungen

View File

@@ -778,6 +778,8 @@ el:
administrator_description: Οι χρήστες με αυτό το δικαίωμα θα παρακάμπτουν κάθε δικαίωμα
delete_user_data: Διαγραφή Δεδομένων Χρήστη
delete_user_data_description: Επιτρέπει στους χρήστες να διαγράφουν τα δεδομένα άλλων χρηστών χωρίς καθυστέρηση
invite_bypass_approval: Πρόσκληση Χρηστών χωρίς έλεγχο
invite_bypass_approval_description: Επιτρέπει σε άτομα που προσκαλούνται στον διακομιστή από αυτούς τους χρήστες, να παρακάμψουν την έγκριση από συντονιστές
invite_users: Πρόσκληση Χρηστών
invite_users_description: Επιτρέπει στους χρήστες να προσκαλούν νέα άτομα στον διακομιστή
manage_announcements: Διαχείριση Ανακοινώσεων

View File

@@ -778,6 +778,8 @@ es-AR:
administrator_description: Los usuarios con este permiso saltarán todos los permisos
delete_user_data: Eliminar datos del usuario
delete_user_data_description: Permite a los usuarios eliminar los datos de otros usuarios sin demora
invite_bypass_approval: Invitar a usuarios sin revisión
invite_bypass_approval_description: Permite —a las personas invitadas al servidor por estos usuarios— eludir la aprobación de moderación
invite_users: Invitar usuarios
invite_users_description: Permite a los usuarios invitar a nuevas personas al servidor
manage_announcements: Administrar anuncios

View File

@@ -778,6 +778,8 @@ es-MX:
administrator_description: Los usuarios con este permiso saltarán todos los permisos
delete_user_data: Borrar Datos de Usuario
delete_user_data_description: Permite a los usuarios eliminar los datos de otros usuarios sin demora
invite_bypass_approval: Invitar a usuarios sin revisión
invite_bypass_approval_description: Permite que las personas invitadas al servidor por estos usuarios no tengan que pasar por el proceso de aprobación de la moderación
invite_users: Invitar usuarios
invite_users_description: Permite a los usuarios invitar a nuevas personas al servidor
manage_announcements: Administrar Anuncios
@@ -1295,6 +1297,7 @@ es-MX:
invited_by: 'Puedes unirte a %{domain} gracias a la invitación que has recibido de:'
preamble: Estas son establecidas y aplicadas por los moderadores de %{domain}.
preamble_invited: Antes de continuar, por favor, revisa las reglas básicas establecidas por los moderadores de %{domain}.
read_more: Leer más
title: Algunas reglas básicas.
title_invited: Has sido invitado.
security: Cambiar contraseña

View File

@@ -778,6 +778,8 @@ es:
administrator_description: Los usuarios con este permiso saltarán todos los permisos
delete_user_data: Borrar Datos de Usuario
delete_user_data_description: Permite a los usuarios eliminar los datos de otros usuarios sin demora
invite_bypass_approval: Invitar usuarios sin revisión
invite_bypass_approval_description: Permite registrarse a las personas invitadas al servidor por estos usuarios sin la aprobación de la moderación
invite_users: Invitar usuarios
invite_users_description: Permite a los usuarios invitar a nuevas personas al servidor
manage_announcements: Administrar Anuncios
@@ -1279,6 +1281,7 @@ es:
progress:
confirm: Confirmar dirección de correo
details: Tus detalles
list: Progreso de registro
review: Nuestra revisión
rules: Aceptar reglas
providers:
@@ -1294,6 +1297,7 @@ es:
invited_by: 'Puedes unirte a %{domain} gracias a la invitación que has recibido de:'
preamble: Estas son establecidas y aplicadas por los moderadores de %{domain}.
preamble_invited: Antes de continuar, por favor, revisa las reglas básicas establecidas por los moderadores de %{domain}.
read_more: Leer más
title: Algunas reglas básicas.
title_invited: Has sido invitado.
security: Cambiar contraseña

View File

@@ -1295,6 +1295,7 @@ fi:
invited_by: 'Voit liittyä palvelimelle %{domain} kutsulla, jonka sait seuraavalta käyttäjältä:'
preamble: Palvelimen %{domain} moderaattorit määrittävät ja valvovat sääntöjä.
preamble_invited: Ennen kuin jatkat ota huomioon palvelimen %{domain} moderaattorien asettamat perussäännöt.
read_more: Lue lisää
title: Joitakin perussääntöjä.
title_invited: Sinut on kutsuttu.
security: Turvallisuus

View File

@@ -1298,6 +1298,7 @@ fr-CA:
invited_by: 'Vous pouvez rejoindre %{domain} grâve à l''invitation reçue de:'
preamble: Celles-ci sont définies et appliqués par les modérateurs de %{domain}.
preamble_invited: Avant de continuer, veuillez lire les règles de base définies par les modérateurs de %{domain}.
read_more: Lire plus
title: Quelques règles de base.
title_invited: Vous avez été invité·e.
security: Sécurité

View File

@@ -1298,6 +1298,7 @@ fr:
invited_by: 'Vous pouvez rejoindre %{domain} grâce à l''invitation de :'
preamble: Celles-ci sont définies et appliqués par les modérateurs de %{domain}.
preamble_invited: Avant de continuer, veuillez lire les règles de base définies par les modérateurs de %{domain}.
read_more: Lire plus
title: Quelques règles de base.
title_invited: Vous avez été invité·e.
security: Sécurité

View File

@@ -826,6 +826,8 @@ ga:
administrator_description: Seachnóidh úsáideoirí a bhfuil an cead seo acu gach cead
delete_user_data: Scrios Sonraí Úsáideora
delete_user_data_description: Ligeann sé d'úsáideoirí sonraí úsáideoirí eile a scriosadh gan mhoill
invite_bypass_approval: Tabhair cuireadh d'úsáideoirí gan athbhreithniú
invite_bypass_approval_description: Ceadaíonn sé do dhaoine a bhfuil cuireadh tugtha dóibh chuig an bhfreastalaí ag na húsáideoirí seo ceadú modhnóireachta a sheachaint
invite_users: Tabhair cuireadh d'Úsáideoirí
invite_users_description: Ligeann sé d'úsáideoirí cuireadh a thabhairt do dhaoine nua chuig an bhfreastalaí
manage_announcements: Bainistigh Fógraí
@@ -1360,6 +1362,7 @@ ga:
invited_by: 'Is féidir leat páirt a ghlacadh i %{domain} a bhuíochas leis an gcuireadh a fuair tú ó:'
preamble: Socraíonn agus cuireann na modhnóirí %{domain} iad seo i bhfeidhm.
preamble_invited: Sula dtéann tú ar aghaidh, smaoinigh le do thoil ar na bunrialacha atá socraithe ag modhnóirí %{domain}.
read_more: Léigh tuilleadh
title: Roinnt bunrialacha.
title_invited: Tá cuireadh faighte agat.
security: Slándáil

View File

@@ -778,6 +778,8 @@ gl:
administrator_description: As usuarias con este permiso poderán superar calquera restrición
delete_user_data: Eliminar datos de usuarias
delete_user_data_description: Permite eliminar datos doutras usuarias sen demoras
invite_bypass_approval: Invitar sen precisar revisión
invite_bypass_approval_description: Permitir que as persoas invitadas ao servidor por estas usuarias non precisen aprobación
invite_users: Convidar usuarias
invite_users_description: Permite que outras usuarias conviden a xente ao servidor
manage_announcements: Xestionar anuncios

View File

@@ -810,6 +810,8 @@ he:
administrator_description: משתמשים עם הרשאה זו יוכלו לעקוף כל הרשאה
delete_user_data: מחיקת כל נתוני המשתמש
delete_user_data_description: מאפשר למשתמשים למחוק נתוני משתמשים אחרים ללא דיחוי
invite_bypass_approval: הזמנה להרשם ללא הליך בדיקה
invite_bypass_approval_description: להרשות למשתמשים אלו להזמין א.נשים להרשם לשרת תוך עקיפת מנגנון הפיקוח על ההרשמה
invite_users: הזמנת משתמשים
invite_users_description: מאפשר למשתמשים להזמין אנשים חדשים לשרת
manage_announcements: ניהול הכרזות
@@ -1337,6 +1339,7 @@ he:
invited_by: 'ניתן להצטרף אל %{domain} הודות להזמנה מאת:'
preamble: אלו נקבעים ונאכפים ע"י המנחים של %{domain}.
preamble_invited: לפני ההמשך יש להתחשב בחוקי המקום כפי שקבעו מנהלי הדיון על %{domain}.
read_more: לקריאה נוספת
title: כמה חוקים בסיסיים.
title_invited: קיבלת הזמנה.
security: אבטחה

View File

@@ -1279,6 +1279,7 @@ hu:
progress:
confirm: E-mail megerősítése
details: Saját adatok
list: Regisztrációs folyamat
review: A felülvizsgálatunk
rules: Szabályok elfogadása
providers:
@@ -1294,6 +1295,7 @@ hu:
invited_by: 'Csatlakozhatsz a %{domain} kiszolgálóhoz, köszönhetően a meghívónak, melyet tőle kaptál:'
preamble: Ezeket a(z) %{domain} moderátorai adjak meg és tartatják be.
preamble_invited: Mielőtt csatlakozol, kérlek vedd fontolóra a %{domain} moderátorai által állított szabályokat.
read_more: Bővebben
title: Néhány alapszabály.
title_invited: Meghívtak.
security: Biztonság

View File

@@ -778,6 +778,8 @@ is:
administrator_description: Notendur með þessa heimild fara framhjá öllum öðrum heimildum
delete_user_data: Eyða gögnum notanda
delete_user_data_description: Leyfir notendum að eyða gögnum annarra notenda án tafar
invite_bypass_approval: Bjóða notendum án samþykktar
invite_bypass_approval_description: Leyfir fólki sem boðið er á netþjóninn af þessum notendum að sleppa við samþykki umsjónaraðila
invite_users: Bjóða notendum
invite_users_description: Leyfir notendum að bjóða nýju fólki inn á netþjóninn
manage_announcements: Sýsla með tilkynningar

View File

@@ -778,6 +778,8 @@ it:
administrator_description: Gli utenti con questo permesso saranno esentati da ogni permesso
delete_user_data: Cancella dati utente
delete_user_data_description: Consente agli utenti di eliminare subito i dati degli altri utenti
invite_bypass_approval: Invita utenti senza revisione
invite_bypass_approval_description: Permette alle persone invitate al server da questi utenti, di aggirare l'approvazione della moderazione
invite_users: Invita Utenti
invite_users_description: Consente agli utenti di invitare nuove persone su questo server
manage_announcements: Gestisci Annunci

View File

@@ -587,6 +587,7 @@ lt:
manage_taxonomies_description: Leidžia naudotojams peržiūrėti tendencingą turinį ir atnaujinti grotažymių nustatymus
settings:
branding:
preamble: Jūsų serverio pavadinimas išskiria jį iš kitų tinklo serverių. Ši informacija gali būti rodoma įvairiose aplinkose, pavyzdžiui, „Mastodon“ žiniatinklio sąsajoje, programėlėse, nuorodų peržiūrose kitose svetainėse, žinučių programėlėse ir pan. Dėl to geriausia, kad ši informacija būtų aiški, trumpa ir glausta.
title: Firminio ženklo kūrimas
captcha_enabled:
desc_html: Tai priklauso nuo hCaptcha išorinių skriptų, kurie gali kelti susirūpinimą dėl saugumo ir privatumo. Be to, <strong>dėl to registracijos procesas kai kuriems žmonėms (ypač neįgaliesiems) gali būti gerokai sunkiau prieinami</strong>. Dėl šių priežasčių apsvarstyk alternatyvias priemones, pavyzdžiui, patvirtinimu arba kvietimu grindžiamą registraciją.

View File

@@ -1279,6 +1279,7 @@ nn:
progress:
confirm: Stadfest e-post
details: Opplysingane dine
list: Innmeldingsprosess
review: Vår gjennomgang
rules: Godta reglane
providers:
@@ -1294,6 +1295,7 @@ nn:
invited_by: 'Du kan bli med i %{domain} takka vere invitasjonen du har fått frå:'
preamble: Disse angis og håndheves av %{domain}-moderatorene.
preamble_invited: Før du held fram, ver snill og sjå gjennom reglane bestemt av moderatorane av %{domain}.
read_more: Les meir
title: Nokre grunnreglar.
title_invited: Du har blitt invitert.
security: Tryggleik

View File

@@ -40,14 +40,14 @@ be:
text: Вы можаце абскардзіць рашэнне толькі адзін раз
defaults:
autofollow: Людзі, якія зарэгістраваліся праз запрашэнне, аўтаматычна падпішуцца на вас
avatar: WEBP, PNG, GIF ці JPG. Не больш за %{size}. Будзе сціснуты да памеру %{dimensions}} пікселяў
avatar: WEBP, PNG, GIF ці JPG. Не больш за %{size}. Будзе сціснуты да памеру %{dimensions} пікселяў
bot: Паведаміць іншым, што гэты ўліковы запіс у асноўным выконвае аўтаматычныя дзеянні і можа не кантралявацца
context: Адзін ці некалькі кантэкстаў, да якіх трэба прымяніць фільтр
current_password: У мэтах бяспекі, увядзіце пароль бягучага ўліковага запісу
current_username: Каб пацвердзіць, увядзіце, калі ласка імя карыстальніка бягучага ўліковага запісу
digest: Будзе даслана толькі пасля доўгага перыяду неактыўнасці і толькі, калі Вы атрымалі асабістыя паведамленні падчас Вашай адсутнасці
email: Пацвярджэнне будзе выслана па электроннай пошце
header: WEBP, PNG, GIF ці JPG. Не больш за %{size}. Будзе сціснуты да памеру %{dimensions}} пікселяў
header: WEBP, PNG, GIF ці JPG. Не больш за %{size}. Будзе сціснуты да памеру %{dimensions} пікселяў
inbox_url: Капіраваць URL са старонкі рэтранслятара, якім вы хочаце карыстацца
irreversible: Адфільтраваныя пасты прападуць незваротна, нават калі фільтр потым будзе выдалены
locale: Мова карыстальніцкага інтэрфейсу, электронных паведамленняў і апавяшчэнняў

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