Merge pull request #3414 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to ef6405ab28
This commit is contained in:
Claire
2026-02-23 20:55:20 +01:00
committed by GitHub
116 changed files with 2793 additions and 525 deletions

View File

@@ -1,17 +0,0 @@
{
"problemMatcher": [
{
"owner": "haml-lint",
"severity": "warning",
"pattern": [
{
"regexp": "^(.*):(\\d+)\\s\\[W]\\s(.*):\\s(.*)$",
"file": 1,
"line": 2,
"code": 3,
"message": 4
}
]
}
]
}

View File

@@ -42,5 +42,4 @@ jobs:
- name: Run haml-lint - name: Run haml-lint
run: | run: |
echo "::add-matcher::.github/workflows/haml-lint-problem-matcher.json"
bin/haml-lint --reporter github bin/haml-lint --reporter github

View File

@@ -749,7 +749,7 @@ GEM
rspec-expectations (~> 3.13) rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13) rspec-mocks (~> 3.13)
rspec-support (~> 3.13) rspec-support (~> 3.13)
rspec-sidekiq (5.2.0) rspec-sidekiq (5.3.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
rspec-expectations (~> 3.0) rspec-expectations (~> 3.0)
rspec-mocks (~> 3.0) rspec-mocks (~> 3.0)

View File

@@ -1,10 +1,17 @@
import { apiRequestPost, apiRequestGet } from 'flavours/glitch/api'; import {
apiRequestPost,
apiRequestGet,
apiRequestDelete,
} from 'flavours/glitch/api';
import type { import type {
ApiAccountJSON, ApiAccountJSON,
ApiFamiliarFollowersJSON, ApiFamiliarFollowersJSON,
} from 'flavours/glitch/api_types/accounts'; } from 'flavours/glitch/api_types/accounts';
import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships'; import type { ApiRelationshipJSON } from 'flavours/glitch/api_types/relationships';
import type { ApiHashtagJSON } from 'flavours/glitch/api_types/tags'; import type {
ApiFeaturedTagJSON,
ApiHashtagJSON,
} from 'flavours/glitch/api_types/tags';
export const apiSubmitAccountNote = (id: string, value: string) => export const apiSubmitAccountNote = (id: string, value: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, { apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, {
@@ -30,7 +37,19 @@ export const apiRemoveAccountFromFollowers = (id: string) =>
); );
export const apiGetFeaturedTags = (id: string) => export const apiGetFeaturedTags = (id: string) =>
apiRequestGet<ApiHashtagJSON>(`v1/accounts/${id}/featured_tags`); apiRequestGet<ApiHashtagJSON[]>(`v1/accounts/${id}/featured_tags`);
export const apiGetCurrentFeaturedTags = () =>
apiRequestGet<ApiFeaturedTagJSON[]>(`v1/featured_tags`);
export const apiPostFeaturedTag = (name: string) =>
apiRequestPost<ApiFeaturedTagJSON>('v1/featured_tags', { name });
export const apiDeleteFeaturedTag = (id: string) =>
apiRequestDelete(`v1/featured_tags/${id}`);
export const apiGetTagSuggestions = () =>
apiRequestGet<ApiHashtagJSON[]>('v1/featured_tags/suggestions');
export const apiGetEndorsedAccounts = (id: string) => export const apiGetEndorsedAccounts = (id: string) =>
apiRequestGet<ApiAccountJSON>(`v1/accounts/${id}/endorsements`); apiRequestGet<ApiAccountJSON>(`v1/accounts/${id}/endorsements`);

View File

@@ -4,11 +4,29 @@ interface ApiHistoryJSON {
uses: string; uses: string;
} }
export interface ApiHashtagJSON { interface ApiHashtagBase {
id: string; id: string;
name: string; name: string;
url: string; url: string;
}
export interface ApiHashtagJSON extends ApiHashtagBase {
history: [ApiHistoryJSON, ...ApiHistoryJSON[]]; history: [ApiHistoryJSON, ...ApiHistoryJSON[]];
following?: boolean; following?: boolean;
featuring?: boolean; featuring?: boolean;
} }
export interface ApiFeaturedTagJSON extends ApiHashtagBase {
statuses_count: number;
last_status_at: string | null;
}
export function hashtagToFeaturedTag(tag: ApiHashtagJSON): ApiFeaturedTagJSON {
return {
id: tag.id,
name: tag.name,
url: tag.url,
statuses_count: 0,
last_status_at: null,
};
}

View File

@@ -3,7 +3,7 @@
} }
.input { .input {
padding-right: 45px; padding-inline-end: 45px;
} }
.menuButton { .menuButton {

View File

@@ -82,11 +82,23 @@ const ComboboxDemo: React.FC = () => {
const meta = { const meta = {
title: 'Components/Form Fields/ComboboxField', title: 'Components/Form Fields/ComboboxField',
component: ComboboxDemo, component: ComboboxField,
} satisfies Meta<typeof ComboboxDemo>; render: () => <ComboboxDemo />,
} satisfies Meta<typeof ComboboxField>;
export default meta; export default meta;
type Story = StoryObj<typeof meta>; type Story = StoryObj<typeof meta>;
export const Example: Story = {}; export const Example: Story = {
args: {
// Adding these types to keep TS happy, they're not passed on to `ComboboxDemo`
label: '',
value: '',
onChange: () => undefined,
items: [],
getItemId: () => '',
renderItem: () => <>Nothing</>,
onSelectItem: () => undefined,
},
};

View File

@@ -1,4 +1,3 @@
import type { ComponentPropsWithoutRef } from 'react';
import { forwardRef, useCallback, useId, useRef, useState } from 'react'; import { forwardRef, useCallback, useId, useRef, useState } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@@ -9,6 +8,7 @@ import Overlay from 'react-overlays/Overlay';
import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react'; import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react';
import KeyboardArrowUpIcon from '@/material-icons/400-24px/keyboard_arrow_up.svg?react'; import KeyboardArrowUpIcon from '@/material-icons/400-24px/keyboard_arrow_up.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import { matchWidth } from 'flavours/glitch/components/dropdown/utils'; import { matchWidth } from 'flavours/glitch/components/dropdown/utils';
import { IconButton } from 'flavours/glitch/components/icon_button'; import { IconButton } from 'flavours/glitch/components/icon_button';
import { useOnClickOutside } from 'flavours/glitch/hooks/useOnClickOutside'; import { useOnClickOutside } from 'flavours/glitch/hooks/useOnClickOutside';
@@ -17,6 +17,7 @@ import classes from './combobox.module.scss';
import { FormFieldWrapper } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper';
import type { CommonFieldWrapperProps } from './form_field_wrapper'; import type { CommonFieldWrapperProps } from './form_field_wrapper';
import { TextInput } from './text_input_field'; import { TextInput } from './text_input_field';
import type { TextInputProps } from './text_input_field';
interface ComboboxItem { interface ComboboxItem {
id: string; id: string;
@@ -27,17 +28,45 @@ export interface ComboboxItemState {
isDisabled: boolean; isDisabled: boolean;
} }
interface ComboboxProps< interface ComboboxProps<T extends ComboboxItem> extends TextInputProps {
T extends ComboboxItem, /**
> extends ComponentPropsWithoutRef<'input'> { * The value of the combobox's text input
*/
value: string; value: string;
/**
* Change handler for the text input field
*/
onChange: React.ChangeEventHandler<HTMLInputElement>; onChange: React.ChangeEventHandler<HTMLInputElement>;
/**
* Set this to true when the list of options is dynamic and currently loading.
* Causes a loading indicator to be displayed inside of the dropdown menu.
*/
isLoading?: boolean; isLoading?: boolean;
/**
* The set of options/suggestions that should be rendered in the dropdown menu.
*/
items: T[]; items: T[];
getItemId: (item: T) => string; /**
* A function that must return a unique id for each option passed via `items`
*/
getItemId?: (item: T) => string;
/**
* Providing this function turns the combobox into a multi-select box that assumes
* multiple options to be selectable. Single-selection is handled automatically.
*/
getIsItemSelected?: (item: T) => boolean; getIsItemSelected?: (item: T) => boolean;
/**
* Use this function to mark items as disabled, if needed
*/
getIsItemDisabled?: (item: T) => boolean; getIsItemDisabled?: (item: T) => boolean;
/**
* Customise the rendering of each option.
* The rendered content must not contain other interactive content!
*/
renderItem: (item: T, state: ComboboxItemState) => React.ReactElement; renderItem: (item: T, state: ComboboxItemState) => React.ReactElement;
/**
* The main selection handler, called when an option is selected or deselected.
*/
onSelectItem: (item: T) => void; onSelectItem: (item: T) => void;
} }
@@ -45,8 +74,12 @@ interface Props<T extends ComboboxItem>
extends ComboboxProps<T>, CommonFieldWrapperProps {} extends ComboboxProps<T>, CommonFieldWrapperProps {}
/** /**
* The combobox field allows users to select one or multiple items * The combobox field allows users to select one or more items
* from a large list of options by searching or filtering. * by searching or filtering a large or dynamic list of options.
*
* It is an implementation of the [APG Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/),
* with inspiration taken from Sarah Higley's extensive combobox
* [research & implementations](https://sarahmhigley.com/writing/select-your-poison/).
*/ */
export const ComboboxFieldWithRef = <T extends ComboboxItem>( export const ComboboxFieldWithRef = <T extends ComboboxItem>(
@@ -80,7 +113,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
value, value,
isLoading = false, isLoading = false,
items, items,
getItemId, getItemId = (item) => item.id,
getIsItemDisabled, getIsItemDisabled,
getIsItemSelected, getIsItemSelected,
disabled, disabled,
@@ -88,6 +121,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
onSelectItem, onSelectItem,
onChange, onChange,
onKeyDown, onKeyDown,
icon = SearchIcon,
className, className,
...otherProps ...otherProps
}: ComboboxProps<T>, }: ComboboxProps<T>,
@@ -306,6 +340,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
value={value} value={value}
onChange={handleInputChange} onChange={handleInputChange}
onKeyDown={handleInputKeyDown} onKeyDown={handleInputKeyDown}
icon={icon}
className={classNames(classes.input, className)} className={classNames(classes.input, className)}
ref={mergeRefs} ref={mergeRefs}
/> />

View File

@@ -20,6 +20,15 @@
font-size: 16px; font-size: 16px;
} }
.iconWrapper & {
// Make space for icon displayed at start of input
padding-inline-start: 36px;
}
&::placeholder {
color: var(--color-text-secondary);
}
&:focus { &:focus {
outline-color: var(--color-text-brand); outline-color: var(--color-text-brand);
} }
@@ -40,3 +49,17 @@
cursor: not-allowed; cursor: not-allowed;
} }
} }
.iconWrapper {
position: relative;
}
.icon {
pointer-events: none;
position: absolute;
width: 22px;
height: 22px;
inset-inline-start: 10px;
inset-block-start: 10px;
color: var(--color-text-secondary);
}

View File

@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react-vite'; import type { Meta, StoryObj } from '@storybook/react-vite';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import { TextInputField, TextInput } from './text_input_field'; import { TextInputField, TextInput } from './text_input_field';
const meta = { const meta = {
@@ -42,6 +44,14 @@ export const WithError: Story = {
}, },
}; };
export const WithIcon: Story = {
args: {
label: 'Search',
hint: undefined,
icon: SearchIcon,
},
};
export const Plain: Story = { export const Plain: Story = {
render(args) { render(args) {
return <TextInput {...args} />; return <TextInput {...args} />;

View File

@@ -3,12 +3,18 @@ import { forwardRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import type { IconProp } from 'flavours/glitch/components/icon';
import { Icon } from 'flavours/glitch/components/icon';
import { FormFieldWrapper } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper';
import type { CommonFieldWrapperProps } from './form_field_wrapper'; import type { CommonFieldWrapperProps } from './form_field_wrapper';
import classes from './text_input.module.scss'; import classes from './text_input.module.scss';
interface Props export interface TextInputProps extends ComponentPropsWithoutRef<'input'> {
extends ComponentPropsWithoutRef<'input'>, CommonFieldWrapperProps {} icon?: IconProp;
}
interface Props extends TextInputProps, CommonFieldWrapperProps {}
/** /**
* A simple form field for single-line text. * A simple form field for single-line text.
@@ -33,16 +39,33 @@ export const TextInputField = forwardRef<HTMLInputElement, Props>(
TextInputField.displayName = 'TextInputField'; TextInputField.displayName = 'TextInputField';
export const TextInput = forwardRef< export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
HTMLInputElement, ({ type = 'text', icon, className, ...otherProps }, ref) => (
ComponentPropsWithoutRef<'input'> <WrapFieldWithIcon icon={icon}>
>(({ type = 'text', className, ...otherProps }, ref) => ( <input
<input type={type}
type={type} {...otherProps}
{...otherProps} className={classNames(className, classes.input)}
className={classNames(className, classes.input)} ref={ref}
ref={ref} />
/> </WrapFieldWithIcon>
)); ),
);
TextInput.displayName = 'TextInput'; TextInput.displayName = 'TextInput';
const WrapFieldWithIcon: React.FC<{
icon?: IconProp;
children: React.ReactElement;
}> = ({ icon, children }) => {
if (icon) {
return (
<div className={classes.iconWrapper}>
<Icon icon={icon} id='input-icon' className={classes.icon} />
{children}
</div>
);
}
return children;
};

View File

@@ -0,0 +1,57 @@
import type { FC } from 'react';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { Column } from '@/flavours/glitch/components/column';
import { ColumnHeader } from '@/flavours/glitch/components/column_header';
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
import BundleColumnError from '@/flavours/glitch/features/ui/components/bundle_column_error';
import { useColumnsContext } from '../../ui/util/columns_context';
import classes from '../styles.module.scss';
export const AccountEditEmptyColumn: FC<{
notFound?: boolean;
}> = ({ notFound }) => {
const { multiColumn } = useColumnsContext();
if (notFound) {
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
}
return (
<Column bindToDocument={!multiColumn} className={classes.column}>
<LoadingIndicator />
</Column>
);
};
export const AccountEditColumn: FC<{
title: string;
to: string;
children: React.ReactNode;
}> = ({ to, title, children }) => {
const { multiColumn } = useColumnsContext();
return (
<Column bindToDocument={!multiColumn} className={classes.column}>
<ColumnHeader
title={title}
className={classes.columnHeader}
showBackButton
extraButton={
<Link to={to} className='button'>
<FormattedMessage
id='account_edit.column_button'
defaultMessage='Done'
/>
</Link>
}
/>
{children}
</Column>
);
};

View File

@@ -0,0 +1,100 @@
import type { FC, MouseEventHandler } from 'react';
import type { MessageDescriptor } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import classNames from 'classnames';
import { Button } from '@/flavours/glitch/components/button';
import { IconButton } from '@/flavours/glitch/components/icon_button';
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import classes from '../styles.module.scss';
const messages = defineMessages({
add: {
id: 'account_edit.button.add',
defaultMessage: 'Add {item}',
},
edit: {
id: 'account_edit.button.edit',
defaultMessage: 'Edit {item}',
},
delete: {
id: 'account_edit.button.delete',
defaultMessage: 'Delete {item}',
},
});
export interface EditButtonProps {
onClick: MouseEventHandler;
item: string | MessageDescriptor;
edit?: boolean;
icon?: boolean;
disabled?: boolean;
}
export const EditButton: FC<EditButtonProps> = ({
onClick,
item,
edit = false,
icon = edit,
disabled,
}) => {
const intl = useIntl();
const itemText = typeof item === 'string' ? item : intl.formatMessage(item);
const label = intl.formatMessage(messages[edit ? 'edit' : 'add'], {
item: itemText,
});
if (icon) {
return (
<EditIconButton title={label} onClick={onClick} disabled={disabled} />
);
}
return (
<Button
className={classes.editButton}
onClick={onClick}
disabled={disabled}
>
{label}
</Button>
);
};
export const EditIconButton: FC<{
onClick: MouseEventHandler;
title: string;
disabled?: boolean;
}> = ({ title, onClick, disabled }) => (
<IconButton
icon='pencil'
iconComponent={EditIcon}
onClick={onClick}
className={classes.editButton}
title={title}
disabled={disabled}
/>
);
export const DeleteIconButton: FC<{
onClick: MouseEventHandler;
item: string;
disabled?: boolean;
}> = ({ onClick, item, disabled }) => {
const intl = useIntl();
return (
<IconButton
icon='delete'
iconComponent={DeleteIcon}
onClick={onClick}
className={classNames(classes.editButton, classes.deleteButton)}
title={intl.formatMessage(messages.delete, { item })}
disabled={disabled}
/>
);
};

View File

@@ -0,0 +1,89 @@
import { useCallback } from 'react';
import classes from '../styles.module.scss';
import { DeleteIconButton, EditButton } from './edit_button';
interface AnyItem {
id: string;
name: string;
}
interface AccountEditItemListProps<Item extends AnyItem = AnyItem> {
renderItem?: (item: Item) => React.ReactNode;
items: Item[];
onEdit?: (item: Item) => void;
onDelete?: (item: Item) => void;
disabled?: boolean;
}
export const AccountEditItemList = <Item extends AnyItem>({
renderItem,
items,
onEdit,
onDelete,
disabled,
}: AccountEditItemListProps<Item>) => {
if (items.length === 0) {
return null;
}
return (
<ul className={classes.itemList}>
{items.map((item) => (
<li key={item.id}>
<span>{renderItem?.(item) ?? item.name}</span>
<AccountEditItemButtons
item={item}
onEdit={onEdit}
onDelete={onDelete}
disabled={disabled}
/>
</li>
))}
</ul>
);
};
type AccountEditItemButtonsProps<Item extends AnyItem = AnyItem> = Pick<
AccountEditItemListProps<Item>,
'onEdit' | 'onDelete' | 'disabled'
> & { item: Item };
const AccountEditItemButtons = <Item extends AnyItem>({
item,
onDelete,
onEdit,
disabled,
}: AccountEditItemButtonsProps<Item>) => {
const handleEdit = useCallback(() => {
onEdit?.(item);
}, [item, onEdit]);
const handleDelete = useCallback(() => {
onDelete?.(item);
}, [item, onDelete]);
if (!onEdit && !onDelete) {
return null;
}
return (
<div className={classes.itemListButtons}>
{onEdit && (
<EditButton
edit
item={item.name}
disabled={disabled}
onClick={handleEdit}
/>
)}
{onDelete && (
<DeleteIconButton
item={item.name}
disabled={disabled}
onClick={handleDelete}
/>
)}
</div>
);
};

View File

@@ -1,55 +1,36 @@
import type { FC, ReactNode } from 'react'; import type { FC, ReactNode } from 'react';
import type { MessageDescriptor } from 'react-intl'; import type { MessageDescriptor } from 'react-intl';
import { defineMessage, FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { IconButton } from '@/flavours/glitch/components/icon_button';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import classes from '../styles.module.scss'; import classes from '../styles.module.scss';
const buttonMessage = defineMessage({
id: 'account_edit.section_edit_button',
defaultMessage: 'Edit',
});
interface AccountEditSectionProps { interface AccountEditSectionProps {
title: MessageDescriptor; title: MessageDescriptor;
description?: MessageDescriptor; description?: MessageDescriptor;
showDescription?: boolean; showDescription?: boolean;
onEdit?: () => void;
children?: ReactNode; children?: ReactNode;
className?: string; className?: string;
extraButtons?: ReactNode; buttons?: ReactNode;
} }
export const AccountEditSection: FC<AccountEditSectionProps> = ({ export const AccountEditSection: FC<AccountEditSectionProps> = ({
title, title,
description, description,
showDescription, showDescription,
onEdit,
children, children,
className, className,
extraButtons, buttons,
}) => { }) => {
const intl = useIntl();
return ( return (
<section className={classNames(className, classes.section)}> <section className={classNames(className, classes.section)}>
<header className={classes.sectionHeader}> <header className={classes.sectionHeader}>
<h3 className={classes.sectionTitle}> <h3 className={classes.sectionTitle}>
<FormattedMessage {...title} /> <FormattedMessage {...title} />
</h3> </h3>
{onEdit && ( {buttons}
<IconButton
icon='pencil'
iconComponent={EditIcon}
onClick={onEdit}
title={`${intl.formatMessage(buttonMessage)} ${intl.formatMessage(title)}`}
/>
)}
{extraButtons}
</header> </header>
{showDescription && ( {showDescription && (
<p className={classes.sectionSubtitle}> <p className={classes.sectionSubtitle}>

View File

@@ -0,0 +1,60 @@
import type { ChangeEventHandler, FC } from 'react';
import { useCallback } from 'react';
import { useIntl } from 'react-intl';
import type { ApiFeaturedTagJSON } from '@/flavours/glitch/api_types/tags';
import { Combobox } from '@/flavours/glitch/components/form_fields';
import {
addFeaturedTag,
clearSearch,
updateSearchQuery,
} from '@/flavours/glitch/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import classes from '../styles.module.scss';
export const AccountEditTagSearch: FC = () => {
const { query, isLoading, results } = useAppSelector(
(state) => state.profileEdit.search,
);
const dispatch = useAppDispatch();
const handleSearchChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
void dispatch(updateSearchQuery(e.target.value));
},
[dispatch],
);
const intl = useIntl();
const handleSelect = useCallback(
(item: ApiFeaturedTagJSON) => {
void dispatch(clearSearch());
void dispatch(addFeaturedTag({ name: item.name }));
},
[dispatch],
);
return (
<Combobox
value={query}
onChange={handleSearchChange}
placeholder={intl.formatMessage({
id: 'account_edit_tags.search_placeholder',
defaultMessage: 'Enter a hashtag…',
})}
items={results ?? []}
isLoading={isLoading}
renderItem={renderItem}
onSelectItem={handleSelect}
className={classes.autoComplete}
icon={SearchIcon}
type='search'
/>
);
};
const renderItem = (item: ApiFeaturedTagJSON) => <p>#{item.name}</p>;

View File

@@ -0,0 +1,117 @@
import { useCallback, useEffect } from 'react';
import type { FC } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import type { ApiFeaturedTagJSON } from '@/flavours/glitch/api_types/tags';
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
import { Tag } from '@/flavours/glitch/components/tags/tag';
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
import {
addFeaturedTag,
deleteFeaturedTag,
fetchFeaturedTags,
fetchSuggestedTags,
} from '@/flavours/glitch/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import { AccountEditColumn, AccountEditEmptyColumn } from './components/column';
import { AccountEditItemList } from './components/item_list';
import { AccountEditTagSearch } from './components/tag_search';
import classes from './styles.module.scss';
const messages = defineMessages({
columnTitle: {
id: 'account_edit_tags.column_title',
defaultMessage: 'Edit featured hashtags',
},
});
export const AccountEditFeaturedTags: FC = () => {
const accountId = useCurrentAccountId();
const account = useAccount(accountId);
const intl = useIntl();
const { tags, tagSuggestions, isLoading, isPending } = useAppSelector(
(state) => state.profileEdit,
);
const dispatch = useAppDispatch();
useEffect(() => {
void dispatch(fetchFeaturedTags());
void dispatch(fetchSuggestedTags());
}, [dispatch]);
const handleDeleteTag = useCallback(
({ id }: { id: string }) => {
void dispatch(deleteFeaturedTag({ tagId: id }));
},
[dispatch],
);
if (!accountId || !account) {
return <AccountEditEmptyColumn notFound={!accountId} />;
}
return (
<AccountEditColumn
title={intl.formatMessage(messages.columnTitle)}
to='/profile/edit'
>
<div className={classes.wrapper}>
<FormattedMessage
id='account_edit_tags.help_text'
defaultMessage='Featured hashtags help users discover and interact with your profile. They appear as filters on your Profile pages Activity view.'
tagName='p'
/>
<AccountEditTagSearch />
{tagSuggestions.length > 0 && (
<div className={classes.tagSuggestions}>
<FormattedMessage
id='account_edit_tags.suggestions'
defaultMessage='Suggestions:'
/>
{tagSuggestions.map((tag) => (
<SuggestedTag name={tag.name} key={tag.id} disabled={isPending} />
))}
</div>
)}
{isLoading && <LoadingIndicator />}
<AccountEditItemList
items={tags}
disabled={isPending}
renderItem={renderTag}
onDelete={handleDeleteTag}
/>
</div>
</AccountEditColumn>
);
};
function renderTag(tag: ApiFeaturedTagJSON) {
return (
<div className={classes.tagItem}>
<h4>#{tag.name}</h4>
{tag.statuses_count > 0 && (
<FormattedMessage
id='account_edit_tags.tag_status_count'
defaultMessage='{count} posts'
values={{ count: tag.statuses_count }}
tagName='p'
/>
)}
</div>
);
}
const SuggestedTag: FC<{ name: string; disabled?: boolean }> = ({
name,
disabled,
}) => {
const dispatch = useAppDispatch();
const handleAddTag = useCallback(() => {
void dispatch(addFeaturedTag({ name }));
}, [dispatch, name]);
return <Tag name={name} onClick={handleAddTag} disabled={disabled} />;
};

View File

@@ -1,28 +1,31 @@
import { useCallback } from 'react'; import { useCallback, useEffect } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { Link } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import type { ModalType } from '@/flavours/glitch/actions/modal'; import type { ModalType } from '@/flavours/glitch/actions/modal';
import { openModal } from '@/flavours/glitch/actions/modal'; import { openModal } from '@/flavours/glitch/actions/modal';
import { AccountBio } from '@/flavours/glitch/components/account_bio'; import { AccountBio } from '@/flavours/glitch/components/account_bio';
import { Avatar } from '@/flavours/glitch/components/avatar'; import { Avatar } from '@/flavours/glitch/components/avatar';
import { Column } from '@/flavours/glitch/components/column';
import { ColumnHeader } from '@/flavours/glitch/components/column_header';
import { DisplayNameSimple } from '@/flavours/glitch/components/display_name/simple'; import { DisplayNameSimple } from '@/flavours/glitch/components/display_name/simple';
import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator';
import BundleColumnError from '@/flavours/glitch/features/ui/components/bundle_column_error';
import { useAccount } from '@/flavours/glitch/hooks/useAccount'; import { useAccount } from '@/flavours/glitch/hooks/useAccount';
import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId'; import { useCurrentAccountId } from '@/flavours/glitch/hooks/useAccountId';
import { autoPlayGif } from '@/flavours/glitch/initial_state'; import { autoPlayGif } from '@/flavours/glitch/initial_state';
import { useAppDispatch } from '@/flavours/glitch/store'; import { fetchFeaturedTags } from '@/flavours/glitch/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import { AccountEditColumn, AccountEditEmptyColumn } from './components/column';
import { EditButton } from './components/edit_button';
import { AccountEditSection } from './components/section'; import { AccountEditSection } from './components/section';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
const messages = defineMessages({ const messages = defineMessages({
columnTitle: {
id: 'account_edit.column_title',
defaultMessage: 'Edit Profile',
},
displayNameTitle: { displayNameTitle: {
id: 'account_edit.display_name.title', id: 'account_edit.display_name.title',
defaultMessage: 'Display name', defaultMessage: 'Display name',
@@ -58,6 +61,10 @@ const messages = defineMessages({
defaultMessage: defaultMessage:
'Help others identify, and have quick access to, your favorite topics.', 'Help others identify, and have quick access to, your favorite topics.',
}, },
featuredHashtagsItem: {
id: 'account_edit.featured_hashtags.item',
defaultMessage: 'hashtags',
},
profileTabTitle: { profileTabTitle: {
id: 'account_edit.profile_tab.title', id: 'account_edit.profile_tab.title',
defaultMessage: 'Profile tab settings', defaultMessage: 'Profile tab settings',
@@ -68,12 +75,20 @@ const messages = defineMessages({
}, },
}); });
export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => { export const AccountEdit: FC = () => {
const accountId = useCurrentAccountId(); const accountId = useCurrentAccountId();
const account = useAccount(accountId); const account = useAccount(accountId);
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tags: featuredTags, isLoading: isTagsLoading } = useAppSelector(
(state) => state.profileEdit,
);
useEffect(() => {
void dispatch(fetchFeaturedTags());
}, [dispatch]);
const handleOpenModal = useCallback( const handleOpenModal = useCallback(
(type: ModalType, props?: Record<string, unknown>) => { (type: ModalType, props?: Record<string, unknown>) => {
dispatch(openModal({ modalType: type, modalProps: props ?? {} })); dispatch(openModal({ modalType: type, modalProps: props ?? {} }));
@@ -87,38 +102,25 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
handleOpenModal('ACCOUNT_EDIT_BIO'); handleOpenModal('ACCOUNT_EDIT_BIO');
}, [handleOpenModal]); }, [handleOpenModal]);
if (!accountId) { const history = useHistory();
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />; const handleFeaturedTagsEdit = useCallback(() => {
} history.push('/profile/featured_tags');
}, [history]);
if (!account) { if (!accountId || !account) {
return ( return <AccountEditEmptyColumn notFound={!accountId} />;
<Column bindToDocument={!multiColumn} className={classes.column}>
<LoadingIndicator />
</Column>
);
} }
const headerSrc = autoPlayGif ? account.header : account.header_static; const headerSrc = autoPlayGif ? account.header : account.header_static;
const hasName = !!account.display_name;
const hasBio = !!account.note_plain;
const hasTags = !isTagsLoading && featuredTags.length > 0;
return ( return (
<Column bindToDocument={!multiColumn} className={classes.column}> <AccountEditColumn
<ColumnHeader title={intl.formatMessage(messages.columnTitle)}
title={intl.formatMessage({ to={`/@${account.acct}`}
id: 'account_edit.column_title', >
defaultMessage: 'Edit Profile',
})}
className={classes.columnHeader}
showBackButton
extraButton={
<Link to={`/@${account.acct}`} className='button'>
<FormattedMessage
id='account_edit.column_button'
defaultMessage='Done'
/>
</Link>
}
/>
<header> <header>
<div className={classes.profileImage}> <div className={classes.profileImage}>
{headerSrc && <img src={headerSrc} alt='' />} {headerSrc && <img src={headerSrc} alt='' />}
@@ -129,8 +131,14 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.displayNameTitle} title={messages.displayNameTitle}
description={messages.displayNamePlaceholder} description={messages.displayNamePlaceholder}
showDescription={account.display_name.length === 0} showDescription={!hasName}
onEdit={handleNameEdit} buttons={
<EditButton
onClick={handleNameEdit}
item={messages.displayNameTitle}
edit={hasName}
/>
}
> >
<DisplayNameSimple account={account} /> <DisplayNameSimple account={account} />
</AccountEditSection> </AccountEditSection>
@@ -138,8 +146,14 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.bioTitle} title={messages.bioTitle}
description={messages.bioPlaceholder} description={messages.bioPlaceholder}
showDescription={!account.note_plain} showDescription={!hasBio}
onEdit={handleBioEdit} buttons={
<EditButton
onClick={handleBioEdit}
item={messages.bioTitle}
edit={hasBio}
/>
}
> >
<AccountBio accountId={accountId} /> <AccountBio accountId={accountId} />
</AccountEditSection> </AccountEditSection>
@@ -153,14 +167,23 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.featuredHashtagsTitle} title={messages.featuredHashtagsTitle}
description={messages.featuredHashtagsPlaceholder} description={messages.featuredHashtagsPlaceholder}
showDescription showDescription={!hasTags}
/> buttons={
<EditButton
onClick={handleFeaturedTagsEdit}
edit={hasTags}
item={messages.featuredHashtagsItem}
/>
}
>
{featuredTags.map((tag) => `#${tag.name}`).join(', ')}
</AccountEditSection>
<AccountEditSection <AccountEditSection
title={messages.profileTabTitle} title={messages.profileTabTitle}
description={messages.profileTabSubtitle} description={messages.profileTabSubtitle}
showDescription showDescription
/> />
</Column> </AccountEditColumn>
); );
}; };

View File

@@ -1,15 +1,4 @@
.column { // Profile Edit Page
border: 1px solid var(--color-border-primary);
border-top-width: 0;
}
.columnHeader {
:global(.column-header__buttons) {
align-items: center;
padding-inline-end: 16px;
height: auto;
}
}
.profileImage { .profileImage {
height: 120px; height: 120px;
@@ -35,40 +24,41 @@
border: 1px solid var(--color-border-primary); border: 1px solid var(--color-border-primary);
} }
.section { // Featured Tags Page
padding: 20px;
border-bottom: 1px solid var(--color-border-primary); .wrapper {
font-size: 15px; padding: 24px;
} }
.sectionHeader { .autoComplete,
.tagSuggestions {
margin: 12px 0;
}
.tagSuggestions {
display: flex; display: flex;
gap: 4px;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 8px;
margin-bottom: 8px;
> button { // Add more padding to the suggestions label
border: 1px solid var(--color-border-primary); > span {
border-radius: 8px; margin-right: 4px;
box-sizing: border-box;
padding: 4px;
svg {
width: 20px;
height: 20px;
}
} }
} }
.sectionTitle { .tagItem {
flex-grow: 1; > h4 {
font-size: 17px; font-size: 15px;
font-weight: 600; font-weight: 500;
}
> p {
color: var(--color-text-secondary);
}
} }
.sectionSubtitle { // Modals
color: var(--color-text-secondary);
}
.inputWrapper { .inputWrapper {
position: relative; position: relative;
@@ -100,6 +90,104 @@ textarea.inputText {
} }
} }
// Column component
.column {
border: 1px solid var(--color-border-primary);
border-top-width: 0;
}
.columnHeader {
:global(.column-header__buttons) {
align-items: center;
padding-inline-end: 16px;
height: auto;
}
}
// Edit button component
.editButton {
border: 1px solid var(--color-border-primary);
border-radius: 8px;
box-sizing: border-box;
padding: 4px;
transition:
color 0.2s ease-in-out,
background-color 0.2s ease-in-out;
&:global(.button) {
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
font-size: 13px;
padding: 4px 8px;
&:active,
&:focus,
&:hover {
background-color: var(--color-bg-brand-softer);
}
}
svg {
width: 20px;
height: 20px;
}
}
.deleteButton {
--default-icon-color: var(--color-text-error);
--hover-bg-color: var(--color-bg-error-base-hover);
--hover-icon-color: var(--color-text-on-error-base);
}
// Item list component
.itemList {
> li {
display: flex;
align-items: center;
padding: 12px 0;
> :first-child {
flex-grow: 1;
}
}
}
.itemListButtons {
display: flex;
align-items: center;
gap: 4px;
}
// Section component
.section {
padding: 20px;
border-bottom: 1px solid var(--color-border-primary);
font-size: 15px;
}
.sectionHeader {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.sectionTitle {
flex-grow: 1;
font-size: 17px;
font-weight: 600;
}
.sectionSubtitle {
color: var(--color-text-secondary);
}
// Counter component
.counter { .counter {
margin-top: 4px; margin-top: 4px;
font-size: 13px; font-size: 13px;

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useId, useMemo, useState } from 'react';
import { FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
@@ -18,10 +18,7 @@ import { Button } from 'flavours/glitch/components/button';
import { Callout } from 'flavours/glitch/components/callout'; import { Callout } from 'flavours/glitch/components/callout';
import { DisplayName } from 'flavours/glitch/components/display_name'; import { DisplayName } from 'flavours/glitch/components/display_name';
import { EmptyState } from 'flavours/glitch/components/empty_state'; import { EmptyState } from 'flavours/glitch/components/empty_state';
import { import { FormStack, Combobox } from 'flavours/glitch/components/form_fields';
FormStack,
ComboboxField,
} from 'flavours/glitch/components/form_fields';
import { Icon } from 'flavours/glitch/components/icon'; import { Icon } from 'flavours/glitch/components/icon';
import { IconButton } from 'flavours/glitch/components/icon_button'; import { IconButton } from 'flavours/glitch/components/icon_button';
import ScrollableList from 'flavours/glitch/components/scrollable_list'; import ScrollableList from 'flavours/glitch/components/scrollable_list';
@@ -331,6 +328,12 @@ export const CollectionAccounts: React.FC<{
[canSubmit, id, history, accountIds], [canSubmit, id, history, accountIds],
); );
const inputId = useId();
const inputLabel = intl.formatMessage({
id: 'collections.search_accounts_label',
defaultMessage: 'Search for accounts to add…',
});
return ( return (
<form onSubmit={handleSubmit} className={classes.form}> <form onSubmit={handleSubmit} className={classes.form}>
<FormStack className={classes.formFieldStack}> <FormStack className={classes.formFieldStack}>
@@ -351,21 +354,12 @@ export const CollectionAccounts: React.FC<{
} }
/> />
)} )}
<ComboboxField <label htmlFor={inputId} className='sr-only'>
label={ {inputLabel}
<FormattedMessage </label>
id='collections.search_accounts_label' <Combobox
defaultMessage='Search for accounts to add…' id={inputId}
/> placeholder={inputLabel}
}
hint={
hasMaxAccounts ? (
<FormattedMessage
id='collections.search_accounts_max_reached'
defaultMessage='You have added the maximum number of accounts'
/>
) : undefined
}
value={hasMaxAccounts ? '' : searchValue} value={hasMaxAccounts ? '' : searchValue}
onChange={handleSearchValueChange} onChange={handleSearchValueChange}
onKeyDown={handleSearchKeyDown} onKeyDown={handleSearchKeyDown}
@@ -379,6 +373,12 @@ export const CollectionAccounts: React.FC<{
isEditMode ? instantToggleAccountItem : toggleAccountItem isEditMode ? instantToggleAccountItem : toggleAccountItem
} }
/> />
{hasMaxAccounts && (
<FormattedMessage
id='collections.search_accounts_max_reached'
defaultMessage='You have added the maximum number of accounts'
/>
)}
{hasMinAccounts && ( {hasMinAccounts && (
<Callout> <Callout>

View File

@@ -85,6 +85,7 @@ import {
AccountFeatured, AccountFeatured,
AccountAbout, AccountAbout,
AccountEdit, AccountEdit,
AccountEditFeaturedTags,
Quotes, Quotes,
} from './util/async-components'; } from './util/async-components';
import { ColumnsContextProvider } from './util/columns_context'; import { ColumnsContextProvider } from './util/columns_context';
@@ -172,9 +173,8 @@ class SwitchingColumnsArea extends PureComponent {
redirect = <Redirect from='/' to='/about' exact />; redirect = <Redirect from='/' to='/about' exact />;
} }
const profileRedesignEnabled = isServerFeatureEnabled('profile_redesign');
const profileRedesignRoutes = []; const profileRedesignRoutes = [];
if (profileRedesignEnabled) { if (isServerFeatureEnabled('profile_redesign')) {
profileRedesignRoutes.push( profileRedesignRoutes.push(
<WrappedRoute key="posts" path={['/@:acct/posts', '/accounts/:id/posts']} exact component={AccountTimeline} content={children} />, <WrappedRoute key="posts" path={['/@:acct/posts', '/accounts/:id/posts']} exact component={AccountTimeline} content={children} />,
); );
@@ -196,13 +196,27 @@ class SwitchingColumnsArea extends PureComponent {
); );
} }
} else { } else {
// If the redesign is not enabled but someone shares an /about link, redirect to the root.
profileRedesignRoutes.push( profileRedesignRoutes.push(
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />,
// If the redesign is not enabled but someone shares an /about link, redirect to the root.
<Redirect key="about-acct-redirect" from='/@:acct/about' to='/@:acct' exact />, <Redirect key="about-acct-redirect" from='/@:acct/about' to='/@:acct' exact />,
<Redirect key="about-id-redirect" from='/accounts/:id/about' to='/accounts/:id' exact /> <Redirect key="about-id-redirect" from='/accounts/:id/about' to='/accounts/:id' exact />
); );
} }
if (isClientFeatureEnabled('profile_editing')) {
profileRedesignRoutes.push(
<WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />,
<WrappedRoute key="featured_tags" path='/profile/featured_tags' component={AccountEditFeaturedTags} content={children} />
)
} else {
// If profile editing is not enabled, redirect to the home timeline as the current editing pages are outside React Router.
profileRedesignRoutes.push(
<Redirect key="edit-redirect" from='/profile/edit' to='/' exact />,
<Redirect key="featured-tags-redirect" from='/profile/featured_tags' to='/' exact />,
);
}
return ( return (
<ColumnsContextProvider multiColumn={!singleColumn}> <ColumnsContextProvider multiColumn={!singleColumn}>
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}> <ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
@@ -242,8 +256,6 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} /> <WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} /> <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
{isClientFeatureEnabled('profile_editing') && <WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />}
<WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} /> <WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} />
<WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} /> <WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} />
<WrappedRoute path='/directory' component={Directory} content={children} /> <WrappedRoute path='/directory' component={Directory} content={children} />
@@ -251,8 +263,8 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/search' component={Search} content={children} /> <WrappedRoute path='/search' component={Search} content={children} />
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} /> <WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
{!profileRedesignEnabled && <WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />}
{...profileRedesignRoutes} {...profileRedesignRoutes}
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} /> <WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} /> <WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} /> <WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />

View File

@@ -103,6 +103,11 @@ export function AccountEdit() {
.then((module) => ({ default: module.AccountEdit })); .then((module) => ({ default: module.AccountEdit }));
} }
export function AccountEditFeaturedTags() {
return import('../../account_edit/featured_tags')
.then((module) => ({ default: module.AccountEditFeaturedTags }));
}
export function Followers () { export function Followers () {
return import('../../followers'); return import('../../followers');
} }

View File

@@ -1,7 +1,9 @@
import { annualReport } from './annual_report'; import { annualReport } from './annual_report';
import { collections } from './collections'; import { collections } from './collections';
import { profileEdit } from './profile_edit';
export const sliceReducers = { export const sliceReducers = {
annualReport, annualReport,
collections, collections,
profileEdit,
}; };

View File

@@ -0,0 +1,178 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { debounce } from 'lodash';
import {
apiDeleteFeaturedTag,
apiGetCurrentFeaturedTags,
apiGetTagSuggestions,
apiPostFeaturedTag,
} from '@/flavours/glitch/api/accounts';
import { apiGetSearch } from '@/flavours/glitch/api/search';
import { hashtagToFeaturedTag } from '@/flavours/glitch/api_types/tags';
import type { ApiFeaturedTagJSON } from '@/flavours/glitch/api_types/tags';
import type { AppDispatch } from '@/flavours/glitch/store';
import {
createAppAsyncThunk,
createDataLoadingThunk,
} from '@/flavours/glitch/store/typed_functions';
interface ProfileEditState {
tags: ApiFeaturedTagJSON[];
tagSuggestions: ApiFeaturedTagJSON[];
isLoading: boolean;
isPending: boolean;
search: {
query: string;
isLoading: boolean;
results?: ApiFeaturedTagJSON[];
};
}
const initialState: ProfileEditState = {
tags: [],
tagSuggestions: [],
isLoading: true,
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 = false;
state.search.results = undefined;
},
clearSearch(state) {
state.search.query = '';
state.search.isLoading = false;
state.search.results = undefined;
},
},
extraReducers(builder) {
builder.addCase(fetchSuggestedTags.fulfilled, (state, action) => {
state.tagSuggestions = action.payload.map(hashtagToFeaturedTag);
state.isLoading = false;
});
builder.addCase(fetchFeaturedTags.fulfilled, (state, action) => {
state.tags = action.payload;
state.isLoading = false;
});
builder.addCase(addFeaturedTag.pending, (state) => {
state.isPending = true;
});
builder.addCase(addFeaturedTag.rejected, (state) => {
state.isPending = false;
});
builder.addCase(addFeaturedTag.fulfilled, (state, action) => {
state.tags = [...state.tags, action.payload].toSorted(
(a, b) => b.statuses_count - a.statuses_count,
);
state.tagSuggestions = state.tagSuggestions.filter(
(tag) => tag.name !== action.meta.arg.name,
);
state.isPending = false;
});
builder.addCase(deleteFeaturedTag.pending, (state) => {
state.isPending = true;
});
builder.addCase(deleteFeaturedTag.rejected, (state) => {
state.isPending = false;
});
builder.addCase(deleteFeaturedTag.fulfilled, (state, action) => {
state.tags = state.tags.filter((tag) => tag.id !== action.meta.arg.tagId);
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: ApiFeaturedTagJSON[] = [];
const currentTags = new Set(state.tags.map((tag) => tag.name));
for (const tag of action.payload) {
if (currentTags.has(tag.name)) {
continue;
}
searchResults.push(hashtagToFeaturedTag(tag));
if (searchResults.length >= 10) {
break;
}
}
state.search.results = searchResults;
});
},
});
export const profileEdit = profileEditSlice.reducer;
export const { clearSearch } = profileEditSlice.actions;
export const fetchFeaturedTags = createDataLoadingThunk(
`${profileEditSlice.name}/fetchFeaturedTags`,
apiGetCurrentFeaturedTags,
{ useLoadingBar: false },
);
export const fetchSuggestedTags = createDataLoadingThunk(
`${profileEditSlice.name}/fetchSuggestedTags`,
apiGetTagSuggestions,
{ useLoadingBar: false },
);
export const addFeaturedTag = createDataLoadingThunk(
`${profileEditSlice.name}/addFeaturedTag`,
({ name }: { name: string }) => apiPostFeaturedTag(name),
{
condition(arg, { getState }) {
const state = getState();
return !state.profileEdit.tags.some((tag) => tag.name === arg.name);
},
},
);
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

@@ -77,7 +77,8 @@ const initialState = ImmutableMap({
follow_requests: initialListState, follow_requests: initialListState,
blocks: initialListState, blocks: initialListState,
mutes: initialListState, mutes: initialListState,
featured_tags: initialListState, /** @type {ImmutableMap<string, typeof initialListState>} */
featured_tags: ImmutableMap(),
}); });
const normalizeList = (state, path, accounts, next) => { const normalizeList = (state, path, accounts, next) => {

View File

@@ -377,6 +377,15 @@ $content-width: 840px;
} }
} }
details > summary {
text-transform: uppercase;
font-size: 13px;
font-weight: 700;
color: var(--color-text-secondary);
padding-top: 24px;
margin-bottom: 8px;
}
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
display: block; display: block;

View File

@@ -1733,7 +1733,7 @@ body > [data-popper-placement] {
.detailed-status__display-name { .detailed-status__display-name {
color: var(--color-text-tertiary); color: var(--color-text-tertiary);
span { span:not(.account__avatar) {
display: inline; display: inline;
} }

View File

@@ -1,10 +1,13 @@
import { apiRequestPost, apiRequestGet } from 'mastodon/api'; import { apiRequestPost, apiRequestGet, apiRequestDelete } from 'mastodon/api';
import type { import type {
ApiAccountJSON, ApiAccountJSON,
ApiFamiliarFollowersJSON, ApiFamiliarFollowersJSON,
} from 'mastodon/api_types/accounts'; } from 'mastodon/api_types/accounts';
import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships'; import type { ApiRelationshipJSON } from 'mastodon/api_types/relationships';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags'; import type {
ApiFeaturedTagJSON,
ApiHashtagJSON,
} from 'mastodon/api_types/tags';
export const apiSubmitAccountNote = (id: string, value: string) => export const apiSubmitAccountNote = (id: string, value: string) =>
apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, { apiRequestPost<ApiRelationshipJSON>(`v1/accounts/${id}/note`, {
@@ -30,7 +33,19 @@ export const apiRemoveAccountFromFollowers = (id: string) =>
); );
export const apiGetFeaturedTags = (id: string) => export const apiGetFeaturedTags = (id: string) =>
apiRequestGet<ApiHashtagJSON>(`v1/accounts/${id}/featured_tags`); apiRequestGet<ApiHashtagJSON[]>(`v1/accounts/${id}/featured_tags`);
export const apiGetCurrentFeaturedTags = () =>
apiRequestGet<ApiFeaturedTagJSON[]>(`v1/featured_tags`);
export const apiPostFeaturedTag = (name: string) =>
apiRequestPost<ApiFeaturedTagJSON>('v1/featured_tags', { name });
export const apiDeleteFeaturedTag = (id: string) =>
apiRequestDelete(`v1/featured_tags/${id}`);
export const apiGetTagSuggestions = () =>
apiRequestGet<ApiHashtagJSON[]>('v1/featured_tags/suggestions');
export const apiGetEndorsedAccounts = (id: string) => export const apiGetEndorsedAccounts = (id: string) =>
apiRequestGet<ApiAccountJSON>(`v1/accounts/${id}/endorsements`); apiRequestGet<ApiAccountJSON>(`v1/accounts/${id}/endorsements`);

View File

@@ -4,11 +4,29 @@ interface ApiHistoryJSON {
uses: string; uses: string;
} }
export interface ApiHashtagJSON { interface ApiHashtagBase {
id: string; id: string;
name: string; name: string;
url: string; url: string;
}
export interface ApiHashtagJSON extends ApiHashtagBase {
history: [ApiHistoryJSON, ...ApiHistoryJSON[]]; history: [ApiHistoryJSON, ...ApiHistoryJSON[]];
following?: boolean; following?: boolean;
featuring?: boolean; featuring?: boolean;
} }
export interface ApiFeaturedTagJSON extends ApiHashtagBase {
statuses_count: number;
last_status_at: string | null;
}
export function hashtagToFeaturedTag(tag: ApiHashtagJSON): ApiFeaturedTagJSON {
return {
id: tag.id,
name: tag.name,
url: tag.url,
statuses_count: 0,
last_status_at: null,
};
}

View File

@@ -3,7 +3,7 @@
} }
.input { .input {
padding-right: 45px; padding-inline-end: 45px;
} }
.menuButton { .menuButton {

View File

@@ -82,11 +82,23 @@ const ComboboxDemo: React.FC = () => {
const meta = { const meta = {
title: 'Components/Form Fields/ComboboxField', title: 'Components/Form Fields/ComboboxField',
component: ComboboxDemo, component: ComboboxField,
} satisfies Meta<typeof ComboboxDemo>; render: () => <ComboboxDemo />,
} satisfies Meta<typeof ComboboxField>;
export default meta; export default meta;
type Story = StoryObj<typeof meta>; type Story = StoryObj<typeof meta>;
export const Example: Story = {}; export const Example: Story = {
args: {
// Adding these types to keep TS happy, they're not passed on to `ComboboxDemo`
label: '',
value: '',
onChange: () => undefined,
items: [],
getItemId: () => '',
renderItem: () => <>Nothing</>,
onSelectItem: () => undefined,
},
};

View File

@@ -1,4 +1,3 @@
import type { ComponentPropsWithoutRef } from 'react';
import { forwardRef, useCallback, useId, useRef, useState } from 'react'; import { forwardRef, useCallback, useId, useRef, useState } from 'react';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
@@ -9,6 +8,7 @@ import Overlay from 'react-overlays/Overlay';
import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react'; import KeyboardArrowDownIcon from '@/material-icons/400-24px/keyboard_arrow_down.svg?react';
import KeyboardArrowUpIcon from '@/material-icons/400-24px/keyboard_arrow_up.svg?react'; import KeyboardArrowUpIcon from '@/material-icons/400-24px/keyboard_arrow_up.svg?react';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import { matchWidth } from 'mastodon/components/dropdown/utils'; import { matchWidth } from 'mastodon/components/dropdown/utils';
import { IconButton } from 'mastodon/components/icon_button'; import { IconButton } from 'mastodon/components/icon_button';
import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside'; import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside';
@@ -17,6 +17,7 @@ import classes from './combobox.module.scss';
import { FormFieldWrapper } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper';
import type { CommonFieldWrapperProps } from './form_field_wrapper'; import type { CommonFieldWrapperProps } from './form_field_wrapper';
import { TextInput } from './text_input_field'; import { TextInput } from './text_input_field';
import type { TextInputProps } from './text_input_field';
interface ComboboxItem { interface ComboboxItem {
id: string; id: string;
@@ -27,17 +28,45 @@ export interface ComboboxItemState {
isDisabled: boolean; isDisabled: boolean;
} }
interface ComboboxProps< interface ComboboxProps<T extends ComboboxItem> extends TextInputProps {
T extends ComboboxItem, /**
> extends ComponentPropsWithoutRef<'input'> { * The value of the combobox's text input
*/
value: string; value: string;
/**
* Change handler for the text input field
*/
onChange: React.ChangeEventHandler<HTMLInputElement>; onChange: React.ChangeEventHandler<HTMLInputElement>;
/**
* Set this to true when the list of options is dynamic and currently loading.
* Causes a loading indicator to be displayed inside of the dropdown menu.
*/
isLoading?: boolean; isLoading?: boolean;
/**
* The set of options/suggestions that should be rendered in the dropdown menu.
*/
items: T[]; items: T[];
getItemId: (item: T) => string; /**
* A function that must return a unique id for each option passed via `items`
*/
getItemId?: (item: T) => string;
/**
* Providing this function turns the combobox into a multi-select box that assumes
* multiple options to be selectable. Single-selection is handled automatically.
*/
getIsItemSelected?: (item: T) => boolean; getIsItemSelected?: (item: T) => boolean;
/**
* Use this function to mark items as disabled, if needed
*/
getIsItemDisabled?: (item: T) => boolean; getIsItemDisabled?: (item: T) => boolean;
/**
* Customise the rendering of each option.
* The rendered content must not contain other interactive content!
*/
renderItem: (item: T, state: ComboboxItemState) => React.ReactElement; renderItem: (item: T, state: ComboboxItemState) => React.ReactElement;
/**
* The main selection handler, called when an option is selected or deselected.
*/
onSelectItem: (item: T) => void; onSelectItem: (item: T) => void;
} }
@@ -45,8 +74,12 @@ interface Props<T extends ComboboxItem>
extends ComboboxProps<T>, CommonFieldWrapperProps {} extends ComboboxProps<T>, CommonFieldWrapperProps {}
/** /**
* The combobox field allows users to select one or multiple items * The combobox field allows users to select one or more items
* from a large list of options by searching or filtering. * by searching or filtering a large or dynamic list of options.
*
* It is an implementation of the [APG Combobox pattern](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/),
* with inspiration taken from Sarah Higley's extensive combobox
* [research & implementations](https://sarahmhigley.com/writing/select-your-poison/).
*/ */
export const ComboboxFieldWithRef = <T extends ComboboxItem>( export const ComboboxFieldWithRef = <T extends ComboboxItem>(
@@ -80,7 +113,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
value, value,
isLoading = false, isLoading = false,
items, items,
getItemId, getItemId = (item) => item.id,
getIsItemDisabled, getIsItemDisabled,
getIsItemSelected, getIsItemSelected,
disabled, disabled,
@@ -88,6 +121,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
onSelectItem, onSelectItem,
onChange, onChange,
onKeyDown, onKeyDown,
icon = SearchIcon,
className, className,
...otherProps ...otherProps
}: ComboboxProps<T>, }: ComboboxProps<T>,
@@ -306,6 +340,7 @@ const ComboboxWithRef = <T extends ComboboxItem>(
value={value} value={value}
onChange={handleInputChange} onChange={handleInputChange}
onKeyDown={handleInputKeyDown} onKeyDown={handleInputKeyDown}
icon={icon}
className={classNames(classes.input, className)} className={classNames(classes.input, className)}
ref={mergeRefs} ref={mergeRefs}
/> />

View File

@@ -20,6 +20,15 @@
font-size: 16px; font-size: 16px;
} }
.iconWrapper & {
// Make space for icon displayed at start of input
padding-inline-start: 36px;
}
&::placeholder {
color: var(--color-text-secondary);
}
&:focus { &:focus {
outline-color: var(--color-text-brand); outline-color: var(--color-text-brand);
} }
@@ -40,3 +49,17 @@
cursor: not-allowed; cursor: not-allowed;
} }
} }
.iconWrapper {
position: relative;
}
.icon {
pointer-events: none;
position: absolute;
width: 22px;
height: 22px;
inset-inline-start: 10px;
inset-block-start: 10px;
color: var(--color-text-secondary);
}

View File

@@ -1,5 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react-vite'; import type { Meta, StoryObj } from '@storybook/react-vite';
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
import { TextInputField, TextInput } from './text_input_field'; import { TextInputField, TextInput } from './text_input_field';
const meta = { const meta = {
@@ -42,6 +44,14 @@ export const WithError: Story = {
}, },
}; };
export const WithIcon: Story = {
args: {
label: 'Search',
hint: undefined,
icon: SearchIcon,
},
};
export const Plain: Story = { export const Plain: Story = {
render(args) { render(args) {
return <TextInput {...args} />; return <TextInput {...args} />;

View File

@@ -3,12 +3,18 @@ import { forwardRef } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import type { IconProp } from 'mastodon/components/icon';
import { Icon } from 'mastodon/components/icon';
import { FormFieldWrapper } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper';
import type { CommonFieldWrapperProps } from './form_field_wrapper'; import type { CommonFieldWrapperProps } from './form_field_wrapper';
import classes from './text_input.module.scss'; import classes from './text_input.module.scss';
interface Props export interface TextInputProps extends ComponentPropsWithoutRef<'input'> {
extends ComponentPropsWithoutRef<'input'>, CommonFieldWrapperProps {} icon?: IconProp;
}
interface Props extends TextInputProps, CommonFieldWrapperProps {}
/** /**
* A simple form field for single-line text. * A simple form field for single-line text.
@@ -33,16 +39,33 @@ export const TextInputField = forwardRef<HTMLInputElement, Props>(
TextInputField.displayName = 'TextInputField'; TextInputField.displayName = 'TextInputField';
export const TextInput = forwardRef< export const TextInput = forwardRef<HTMLInputElement, TextInputProps>(
HTMLInputElement, ({ type = 'text', icon, className, ...otherProps }, ref) => (
ComponentPropsWithoutRef<'input'> <WrapFieldWithIcon icon={icon}>
>(({ type = 'text', className, ...otherProps }, ref) => ( <input
<input type={type}
type={type} {...otherProps}
{...otherProps} className={classNames(className, classes.input)}
className={classNames(className, classes.input)} ref={ref}
ref={ref} />
/> </WrapFieldWithIcon>
)); ),
);
TextInput.displayName = 'TextInput'; TextInput.displayName = 'TextInput';
const WrapFieldWithIcon: React.FC<{
icon?: IconProp;
children: React.ReactElement;
}> = ({ icon, children }) => {
if (icon) {
return (
<div className={classes.iconWrapper}>
<Icon icon={icon} id='input-icon' className={classes.icon} />
{children}
</div>
);
}
return children;
};

View File

@@ -0,0 +1,57 @@
import type { FC } from 'react';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';
import { Column } from '@/mastodon/components/column';
import { ColumnHeader } from '@/mastodon/components/column_header';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error';
import { useColumnsContext } from '../../ui/util/columns_context';
import classes from '../styles.module.scss';
export const AccountEditEmptyColumn: FC<{
notFound?: boolean;
}> = ({ notFound }) => {
const { multiColumn } = useColumnsContext();
if (notFound) {
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />;
}
return (
<Column bindToDocument={!multiColumn} className={classes.column}>
<LoadingIndicator />
</Column>
);
};
export const AccountEditColumn: FC<{
title: string;
to: string;
children: React.ReactNode;
}> = ({ to, title, children }) => {
const { multiColumn } = useColumnsContext();
return (
<Column bindToDocument={!multiColumn} className={classes.column}>
<ColumnHeader
title={title}
className={classes.columnHeader}
showBackButton
extraButton={
<Link to={to} className='button'>
<FormattedMessage
id='account_edit.column_button'
defaultMessage='Done'
/>
</Link>
}
/>
{children}
</Column>
);
};

View File

@@ -0,0 +1,100 @@
import type { FC, MouseEventHandler } from 'react';
import type { MessageDescriptor } from 'react-intl';
import { defineMessages, useIntl } from 'react-intl';
import classNames from 'classnames';
import { Button } from '@/mastodon/components/button';
import { IconButton } from '@/mastodon/components/icon_button';
import DeleteIcon from '@/material-icons/400-24px/delete.svg?react';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import classes from '../styles.module.scss';
const messages = defineMessages({
add: {
id: 'account_edit.button.add',
defaultMessage: 'Add {item}',
},
edit: {
id: 'account_edit.button.edit',
defaultMessage: 'Edit {item}',
},
delete: {
id: 'account_edit.button.delete',
defaultMessage: 'Delete {item}',
},
});
export interface EditButtonProps {
onClick: MouseEventHandler;
item: string | MessageDescriptor;
edit?: boolean;
icon?: boolean;
disabled?: boolean;
}
export const EditButton: FC<EditButtonProps> = ({
onClick,
item,
edit = false,
icon = edit,
disabled,
}) => {
const intl = useIntl();
const itemText = typeof item === 'string' ? item : intl.formatMessage(item);
const label = intl.formatMessage(messages[edit ? 'edit' : 'add'], {
item: itemText,
});
if (icon) {
return (
<EditIconButton title={label} onClick={onClick} disabled={disabled} />
);
}
return (
<Button
className={classes.editButton}
onClick={onClick}
disabled={disabled}
>
{label}
</Button>
);
};
export const EditIconButton: FC<{
onClick: MouseEventHandler;
title: string;
disabled?: boolean;
}> = ({ title, onClick, disabled }) => (
<IconButton
icon='pencil'
iconComponent={EditIcon}
onClick={onClick}
className={classes.editButton}
title={title}
disabled={disabled}
/>
);
export const DeleteIconButton: FC<{
onClick: MouseEventHandler;
item: string;
disabled?: boolean;
}> = ({ onClick, item, disabled }) => {
const intl = useIntl();
return (
<IconButton
icon='delete'
iconComponent={DeleteIcon}
onClick={onClick}
className={classNames(classes.editButton, classes.deleteButton)}
title={intl.formatMessage(messages.delete, { item })}
disabled={disabled}
/>
);
};

View File

@@ -0,0 +1,89 @@
import { useCallback } from 'react';
import classes from '../styles.module.scss';
import { DeleteIconButton, EditButton } from './edit_button';
interface AnyItem {
id: string;
name: string;
}
interface AccountEditItemListProps<Item extends AnyItem = AnyItem> {
renderItem?: (item: Item) => React.ReactNode;
items: Item[];
onEdit?: (item: Item) => void;
onDelete?: (item: Item) => void;
disabled?: boolean;
}
export const AccountEditItemList = <Item extends AnyItem>({
renderItem,
items,
onEdit,
onDelete,
disabled,
}: AccountEditItemListProps<Item>) => {
if (items.length === 0) {
return null;
}
return (
<ul className={classes.itemList}>
{items.map((item) => (
<li key={item.id}>
<span>{renderItem?.(item) ?? item.name}</span>
<AccountEditItemButtons
item={item}
onEdit={onEdit}
onDelete={onDelete}
disabled={disabled}
/>
</li>
))}
</ul>
);
};
type AccountEditItemButtonsProps<Item extends AnyItem = AnyItem> = Pick<
AccountEditItemListProps<Item>,
'onEdit' | 'onDelete' | 'disabled'
> & { item: Item };
const AccountEditItemButtons = <Item extends AnyItem>({
item,
onDelete,
onEdit,
disabled,
}: AccountEditItemButtonsProps<Item>) => {
const handleEdit = useCallback(() => {
onEdit?.(item);
}, [item, onEdit]);
const handleDelete = useCallback(() => {
onDelete?.(item);
}, [item, onDelete]);
if (!onEdit && !onDelete) {
return null;
}
return (
<div className={classes.itemListButtons}>
{onEdit && (
<EditButton
edit
item={item.name}
disabled={disabled}
onClick={handleEdit}
/>
)}
{onDelete && (
<DeleteIconButton
item={item.name}
disabled={disabled}
onClick={handleDelete}
/>
)}
</div>
);
};

View File

@@ -1,55 +1,36 @@
import type { FC, ReactNode } from 'react'; import type { FC, ReactNode } from 'react';
import type { MessageDescriptor } from 'react-intl'; import type { MessageDescriptor } from 'react-intl';
import { defineMessage, FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { IconButton } from '@/mastodon/components/icon_button';
import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import classes from '../styles.module.scss'; import classes from '../styles.module.scss';
const buttonMessage = defineMessage({
id: 'account_edit.section_edit_button',
defaultMessage: 'Edit',
});
interface AccountEditSectionProps { interface AccountEditSectionProps {
title: MessageDescriptor; title: MessageDescriptor;
description?: MessageDescriptor; description?: MessageDescriptor;
showDescription?: boolean; showDescription?: boolean;
onEdit?: () => void;
children?: ReactNode; children?: ReactNode;
className?: string; className?: string;
extraButtons?: ReactNode; buttons?: ReactNode;
} }
export const AccountEditSection: FC<AccountEditSectionProps> = ({ export const AccountEditSection: FC<AccountEditSectionProps> = ({
title, title,
description, description,
showDescription, showDescription,
onEdit,
children, children,
className, className,
extraButtons, buttons,
}) => { }) => {
const intl = useIntl();
return ( return (
<section className={classNames(className, classes.section)}> <section className={classNames(className, classes.section)}>
<header className={classes.sectionHeader}> <header className={classes.sectionHeader}>
<h3 className={classes.sectionTitle}> <h3 className={classes.sectionTitle}>
<FormattedMessage {...title} /> <FormattedMessage {...title} />
</h3> </h3>
{onEdit && ( {buttons}
<IconButton
icon='pencil'
iconComponent={EditIcon}
onClick={onEdit}
title={`${intl.formatMessage(buttonMessage)} ${intl.formatMessage(title)}`}
/>
)}
{extraButtons}
</header> </header>
{showDescription && ( {showDescription && (
<p className={classes.sectionSubtitle}> <p className={classes.sectionSubtitle}>

View File

@@ -0,0 +1,60 @@
import type { ChangeEventHandler, FC } from 'react';
import { useCallback } from 'react';
import { useIntl } from 'react-intl';
import type { ApiFeaturedTagJSON } 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 SearchIcon from '@/material-icons/400-24px/search.svg?react';
import classes from '../styles.module.scss';
export const AccountEditTagSearch: FC = () => {
const { query, isLoading, results } = useAppSelector(
(state) => state.profileEdit.search,
);
const dispatch = useAppDispatch();
const handleSearchChange: ChangeEventHandler<HTMLInputElement> = useCallback(
(e) => {
void dispatch(updateSearchQuery(e.target.value));
},
[dispatch],
);
const intl = useIntl();
const handleSelect = useCallback(
(item: ApiFeaturedTagJSON) => {
void dispatch(clearSearch());
void dispatch(addFeaturedTag({ name: item.name }));
},
[dispatch],
);
return (
<Combobox
value={query}
onChange={handleSearchChange}
placeholder={intl.formatMessage({
id: 'account_edit_tags.search_placeholder',
defaultMessage: 'Enter a hashtag…',
})}
items={results ?? []}
isLoading={isLoading}
renderItem={renderItem}
onSelectItem={handleSelect}
className={classes.autoComplete}
icon={SearchIcon}
type='search'
/>
);
};
const renderItem = (item: ApiFeaturedTagJSON) => <p>#{item.name}</p>;

View File

@@ -0,0 +1,117 @@
import { useCallback, useEffect } from 'react';
import type { FC } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import type { ApiFeaturedTagJSON } from '@/mastodon/api_types/tags';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import { Tag } from '@/mastodon/components/tags/tag';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
import {
addFeaturedTag,
deleteFeaturedTag,
fetchFeaturedTags,
fetchSuggestedTags,
} from '@/mastodon/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { AccountEditColumn, AccountEditEmptyColumn } from './components/column';
import { AccountEditItemList } from './components/item_list';
import { AccountEditTagSearch } from './components/tag_search';
import classes from './styles.module.scss';
const messages = defineMessages({
columnTitle: {
id: 'account_edit_tags.column_title',
defaultMessage: 'Edit featured hashtags',
},
});
export const AccountEditFeaturedTags: FC = () => {
const accountId = useCurrentAccountId();
const account = useAccount(accountId);
const intl = useIntl();
const { tags, tagSuggestions, isLoading, isPending } = useAppSelector(
(state) => state.profileEdit,
);
const dispatch = useAppDispatch();
useEffect(() => {
void dispatch(fetchFeaturedTags());
void dispatch(fetchSuggestedTags());
}, [dispatch]);
const handleDeleteTag = useCallback(
({ id }: { id: string }) => {
void dispatch(deleteFeaturedTag({ tagId: id }));
},
[dispatch],
);
if (!accountId || !account) {
return <AccountEditEmptyColumn notFound={!accountId} />;
}
return (
<AccountEditColumn
title={intl.formatMessage(messages.columnTitle)}
to='/profile/edit'
>
<div className={classes.wrapper}>
<FormattedMessage
id='account_edit_tags.help_text'
defaultMessage='Featured hashtags help users discover and interact with your profile. They appear as filters on your Profile pages Activity view.'
tagName='p'
/>
<AccountEditTagSearch />
{tagSuggestions.length > 0 && (
<div className={classes.tagSuggestions}>
<FormattedMessage
id='account_edit_tags.suggestions'
defaultMessage='Suggestions:'
/>
{tagSuggestions.map((tag) => (
<SuggestedTag name={tag.name} key={tag.id} disabled={isPending} />
))}
</div>
)}
{isLoading && <LoadingIndicator />}
<AccountEditItemList
items={tags}
disabled={isPending}
renderItem={renderTag}
onDelete={handleDeleteTag}
/>
</div>
</AccountEditColumn>
);
};
function renderTag(tag: ApiFeaturedTagJSON) {
return (
<div className={classes.tagItem}>
<h4>#{tag.name}</h4>
{tag.statuses_count > 0 && (
<FormattedMessage
id='account_edit_tags.tag_status_count'
defaultMessage='{count} posts'
values={{ count: tag.statuses_count }}
tagName='p'
/>
)}
</div>
);
}
const SuggestedTag: FC<{ name: string; disabled?: boolean }> = ({
name,
disabled,
}) => {
const dispatch = useAppDispatch();
const handleAddTag = useCallback(() => {
void dispatch(addFeaturedTag({ name }));
}, [dispatch, name]);
return <Tag name={name} onClick={handleAddTag} disabled={disabled} />;
};

View File

@@ -1,28 +1,31 @@
import { useCallback } from 'react'; import { useCallback, useEffect } from 'react';
import type { FC } from 'react'; import type { FC } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { defineMessages, useIntl } from 'react-intl';
import { Link } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import type { ModalType } from '@/mastodon/actions/modal'; import type { ModalType } from '@/mastodon/actions/modal';
import { openModal } from '@/mastodon/actions/modal'; import { openModal } from '@/mastodon/actions/modal';
import { AccountBio } from '@/mastodon/components/account_bio'; import { AccountBio } from '@/mastodon/components/account_bio';
import { Avatar } from '@/mastodon/components/avatar'; import { Avatar } from '@/mastodon/components/avatar';
import { Column } from '@/mastodon/components/column';
import { ColumnHeader } from '@/mastodon/components/column_header';
import { DisplayNameSimple } from '@/mastodon/components/display_name/simple'; import { DisplayNameSimple } from '@/mastodon/components/display_name/simple';
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error';
import { useAccount } from '@/mastodon/hooks/useAccount'; import { useAccount } from '@/mastodon/hooks/useAccount';
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId'; import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
import { autoPlayGif } from '@/mastodon/initial_state'; import { autoPlayGif } from '@/mastodon/initial_state';
import { useAppDispatch } from '@/mastodon/store'; import { fetchFeaturedTags } from '@/mastodon/reducers/slices/profile_edit';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { AccountEditColumn, AccountEditEmptyColumn } from './components/column';
import { EditButton } from './components/edit_button';
import { AccountEditSection } from './components/section'; import { AccountEditSection } from './components/section';
import classes from './styles.module.scss'; import classes from './styles.module.scss';
const messages = defineMessages({ const messages = defineMessages({
columnTitle: {
id: 'account_edit.column_title',
defaultMessage: 'Edit Profile',
},
displayNameTitle: { displayNameTitle: {
id: 'account_edit.display_name.title', id: 'account_edit.display_name.title',
defaultMessage: 'Display name', defaultMessage: 'Display name',
@@ -58,6 +61,10 @@ const messages = defineMessages({
defaultMessage: defaultMessage:
'Help others identify, and have quick access to, your favorite topics.', 'Help others identify, and have quick access to, your favorite topics.',
}, },
featuredHashtagsItem: {
id: 'account_edit.featured_hashtags.item',
defaultMessage: 'hashtags',
},
profileTabTitle: { profileTabTitle: {
id: 'account_edit.profile_tab.title', id: 'account_edit.profile_tab.title',
defaultMessage: 'Profile tab settings', defaultMessage: 'Profile tab settings',
@@ -68,12 +75,20 @@ const messages = defineMessages({
}, },
}); });
export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => { export const AccountEdit: FC = () => {
const accountId = useCurrentAccountId(); const accountId = useCurrentAccountId();
const account = useAccount(accountId); const account = useAccount(accountId);
const intl = useIntl(); const intl = useIntl();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const { tags: featuredTags, isLoading: isTagsLoading } = useAppSelector(
(state) => state.profileEdit,
);
useEffect(() => {
void dispatch(fetchFeaturedTags());
}, [dispatch]);
const handleOpenModal = useCallback( const handleOpenModal = useCallback(
(type: ModalType, props?: Record<string, unknown>) => { (type: ModalType, props?: Record<string, unknown>) => {
dispatch(openModal({ modalType: type, modalProps: props ?? {} })); dispatch(openModal({ modalType: type, modalProps: props ?? {} }));
@@ -87,38 +102,25 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
handleOpenModal('ACCOUNT_EDIT_BIO'); handleOpenModal('ACCOUNT_EDIT_BIO');
}, [handleOpenModal]); }, [handleOpenModal]);
if (!accountId) { const history = useHistory();
return <BundleColumnError multiColumn={multiColumn} errorType='routing' />; const handleFeaturedTagsEdit = useCallback(() => {
} history.push('/profile/featured_tags');
}, [history]);
if (!account) { if (!accountId || !account) {
return ( return <AccountEditEmptyColumn notFound={!accountId} />;
<Column bindToDocument={!multiColumn} className={classes.column}>
<LoadingIndicator />
</Column>
);
} }
const headerSrc = autoPlayGif ? account.header : account.header_static; const headerSrc = autoPlayGif ? account.header : account.header_static;
const hasName = !!account.display_name;
const hasBio = !!account.note_plain;
const hasTags = !isTagsLoading && featuredTags.length > 0;
return ( return (
<Column bindToDocument={!multiColumn} className={classes.column}> <AccountEditColumn
<ColumnHeader title={intl.formatMessage(messages.columnTitle)}
title={intl.formatMessage({ to={`/@${account.acct}`}
id: 'account_edit.column_title', >
defaultMessage: 'Edit Profile',
})}
className={classes.columnHeader}
showBackButton
extraButton={
<Link to={`/@${account.acct}`} className='button'>
<FormattedMessage
id='account_edit.column_button'
defaultMessage='Done'
/>
</Link>
}
/>
<header> <header>
<div className={classes.profileImage}> <div className={classes.profileImage}>
{headerSrc && <img src={headerSrc} alt='' />} {headerSrc && <img src={headerSrc} alt='' />}
@@ -129,8 +131,14 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.displayNameTitle} title={messages.displayNameTitle}
description={messages.displayNamePlaceholder} description={messages.displayNamePlaceholder}
showDescription={account.display_name.length === 0} showDescription={!hasName}
onEdit={handleNameEdit} buttons={
<EditButton
onClick={handleNameEdit}
item={messages.displayNameTitle}
edit={hasName}
/>
}
> >
<DisplayNameSimple account={account} /> <DisplayNameSimple account={account} />
</AccountEditSection> </AccountEditSection>
@@ -138,8 +146,14 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.bioTitle} title={messages.bioTitle}
description={messages.bioPlaceholder} description={messages.bioPlaceholder}
showDescription={!account.note_plain} showDescription={!hasBio}
onEdit={handleBioEdit} buttons={
<EditButton
onClick={handleBioEdit}
item={messages.bioTitle}
edit={hasBio}
/>
}
> >
<AccountBio accountId={accountId} /> <AccountBio accountId={accountId} />
</AccountEditSection> </AccountEditSection>
@@ -153,14 +167,23 @@ export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
<AccountEditSection <AccountEditSection
title={messages.featuredHashtagsTitle} title={messages.featuredHashtagsTitle}
description={messages.featuredHashtagsPlaceholder} description={messages.featuredHashtagsPlaceholder}
showDescription showDescription={!hasTags}
/> buttons={
<EditButton
onClick={handleFeaturedTagsEdit}
edit={hasTags}
item={messages.featuredHashtagsItem}
/>
}
>
{featuredTags.map((tag) => `#${tag.name}`).join(', ')}
</AccountEditSection>
<AccountEditSection <AccountEditSection
title={messages.profileTabTitle} title={messages.profileTabTitle}
description={messages.profileTabSubtitle} description={messages.profileTabSubtitle}
showDescription showDescription
/> />
</Column> </AccountEditColumn>
); );
}; };

View File

@@ -1,15 +1,4 @@
.column { // Profile Edit Page
border: 1px solid var(--color-border-primary);
border-top-width: 0;
}
.columnHeader {
:global(.column-header__buttons) {
align-items: center;
padding-inline-end: 16px;
height: auto;
}
}
.profileImage { .profileImage {
height: 120px; height: 120px;
@@ -35,40 +24,41 @@
border: 1px solid var(--color-border-primary); border: 1px solid var(--color-border-primary);
} }
.section { // Featured Tags Page
padding: 20px;
border-bottom: 1px solid var(--color-border-primary); .wrapper {
font-size: 15px; padding: 24px;
} }
.sectionHeader { .autoComplete,
.tagSuggestions {
margin: 12px 0;
}
.tagSuggestions {
display: flex; display: flex;
gap: 4px;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 8px;
margin-bottom: 8px;
> button { // Add more padding to the suggestions label
border: 1px solid var(--color-border-primary); > span {
border-radius: 8px; margin-right: 4px;
box-sizing: border-box;
padding: 4px;
svg {
width: 20px;
height: 20px;
}
} }
} }
.sectionTitle { .tagItem {
flex-grow: 1; > h4 {
font-size: 17px; font-size: 15px;
font-weight: 600; font-weight: 500;
}
> p {
color: var(--color-text-secondary);
}
} }
.sectionSubtitle { // Modals
color: var(--color-text-secondary);
}
.inputWrapper { .inputWrapper {
position: relative; position: relative;
@@ -100,6 +90,104 @@ textarea.inputText {
} }
} }
// Column component
.column {
border: 1px solid var(--color-border-primary);
border-top-width: 0;
}
.columnHeader {
:global(.column-header__buttons) {
align-items: center;
padding-inline-end: 16px;
height: auto;
}
}
// Edit button component
.editButton {
border: 1px solid var(--color-border-primary);
border-radius: 8px;
box-sizing: border-box;
padding: 4px;
transition:
color 0.2s ease-in-out,
background-color 0.2s ease-in-out;
&:global(.button) {
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
font-size: 13px;
padding: 4px 8px;
&:active,
&:focus,
&:hover {
background-color: var(--color-bg-brand-softer);
}
}
svg {
width: 20px;
height: 20px;
}
}
.deleteButton {
--default-icon-color: var(--color-text-error);
--hover-bg-color: var(--color-bg-error-base-hover);
--hover-icon-color: var(--color-text-on-error-base);
}
// Item list component
.itemList {
> li {
display: flex;
align-items: center;
padding: 12px 0;
> :first-child {
flex-grow: 1;
}
}
}
.itemListButtons {
display: flex;
align-items: center;
gap: 4px;
}
// Section component
.section {
padding: 20px;
border-bottom: 1px solid var(--color-border-primary);
font-size: 15px;
}
.sectionHeader {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 16px;
}
.sectionTitle {
flex-grow: 1;
font-size: 17px;
font-weight: 600;
}
.sectionSubtitle {
color: var(--color-text-secondary);
}
// Counter component
.counter { .counter {
margin-top: 4px; margin-top: 4px;
font-size: 13px; font-size: 13px;

View File

@@ -1,4 +1,4 @@
import { useCallback, useMemo, useState } from 'react'; import { useCallback, useId, useMemo, useState } from 'react';
import { FormattedMessage, useIntl } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
@@ -18,7 +18,7 @@ import { Button } from 'mastodon/components/button';
import { Callout } from 'mastodon/components/callout'; import { Callout } from 'mastodon/components/callout';
import { DisplayName } from 'mastodon/components/display_name'; import { DisplayName } from 'mastodon/components/display_name';
import { EmptyState } from 'mastodon/components/empty_state'; import { EmptyState } from 'mastodon/components/empty_state';
import { FormStack, ComboboxField } from 'mastodon/components/form_fields'; import { FormStack, Combobox } from 'mastodon/components/form_fields';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { IconButton } from 'mastodon/components/icon_button'; import { IconButton } from 'mastodon/components/icon_button';
import ScrollableList from 'mastodon/components/scrollable_list'; import ScrollableList from 'mastodon/components/scrollable_list';
@@ -328,6 +328,12 @@ export const CollectionAccounts: React.FC<{
[canSubmit, id, history, accountIds], [canSubmit, id, history, accountIds],
); );
const inputId = useId();
const inputLabel = intl.formatMessage({
id: 'collections.search_accounts_label',
defaultMessage: 'Search for accounts to add…',
});
return ( return (
<form onSubmit={handleSubmit} className={classes.form}> <form onSubmit={handleSubmit} className={classes.form}>
<FormStack className={classes.formFieldStack}> <FormStack className={classes.formFieldStack}>
@@ -348,21 +354,12 @@ export const CollectionAccounts: React.FC<{
} }
/> />
)} )}
<ComboboxField <label htmlFor={inputId} className='sr-only'>
label={ {inputLabel}
<FormattedMessage </label>
id='collections.search_accounts_label' <Combobox
defaultMessage='Search for accounts to add…' id={inputId}
/> placeholder={inputLabel}
}
hint={
hasMaxAccounts ? (
<FormattedMessage
id='collections.search_accounts_max_reached'
defaultMessage='You have added the maximum number of accounts'
/>
) : undefined
}
value={hasMaxAccounts ? '' : searchValue} value={hasMaxAccounts ? '' : searchValue}
onChange={handleSearchValueChange} onChange={handleSearchValueChange}
onKeyDown={handleSearchKeyDown} onKeyDown={handleSearchKeyDown}
@@ -376,6 +373,12 @@ export const CollectionAccounts: React.FC<{
isEditMode ? instantToggleAccountItem : toggleAccountItem isEditMode ? instantToggleAccountItem : toggleAccountItem
} }
/> />
{hasMaxAccounts && (
<FormattedMessage
id='collections.search_accounts_max_reached'
defaultMessage='You have added the maximum number of accounts'
/>
)}
{hasMinAccounts && ( {hasMinAccounts && (
<Callout> <Callout>

View File

@@ -82,6 +82,7 @@ import {
AccountFeatured, AccountFeatured,
AccountAbout, AccountAbout,
AccountEdit, AccountEdit,
AccountEditFeaturedTags,
Quotes, Quotes,
} from './util/async-components'; } from './util/async-components';
import { ColumnsContextProvider } from './util/columns_context'; import { ColumnsContextProvider } from './util/columns_context';
@@ -164,9 +165,8 @@ class SwitchingColumnsArea extends PureComponent {
redirect = <Redirect from='/' to='/about' exact />; redirect = <Redirect from='/' to='/about' exact />;
} }
const profileRedesignEnabled = isServerFeatureEnabled('profile_redesign');
const profileRedesignRoutes = []; const profileRedesignRoutes = [];
if (profileRedesignEnabled) { if (isServerFeatureEnabled('profile_redesign')) {
profileRedesignRoutes.push( profileRedesignRoutes.push(
<WrappedRoute key="posts" path={['/@:acct/posts', '/accounts/:id/posts']} exact component={AccountTimeline} content={children} />, <WrappedRoute key="posts" path={['/@:acct/posts', '/accounts/:id/posts']} exact component={AccountTimeline} content={children} />,
); );
@@ -188,13 +188,27 @@ class SwitchingColumnsArea extends PureComponent {
); );
} }
} else { } else {
// If the redesign is not enabled but someone shares an /about link, redirect to the root.
profileRedesignRoutes.push( profileRedesignRoutes.push(
<WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />,
// If the redesign is not enabled but someone shares an /about link, redirect to the root.
<Redirect key="about-acct-redirect" from='/@:acct/about' to='/@:acct' exact />, <Redirect key="about-acct-redirect" from='/@:acct/about' to='/@:acct' exact />,
<Redirect key="about-id-redirect" from='/accounts/:id/about' to='/accounts/:id' exact /> <Redirect key="about-id-redirect" from='/accounts/:id/about' to='/accounts/:id' exact />
); );
} }
if (isClientFeatureEnabled('profile_editing')) {
profileRedesignRoutes.push(
<WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />,
<WrappedRoute key="featured_tags" path='/profile/featured_tags' component={AccountEditFeaturedTags} content={children} />
)
} else {
// If profile editing is not enabled, redirect to the home timeline as the current editing pages are outside React Router.
profileRedesignRoutes.push(
<Redirect key="edit-redirect" from='/profile/edit' to='/' exact />,
<Redirect key="featured-tags-redirect" from='/profile/featured_tags' to='/' exact />,
);
}
return ( return (
<ColumnsContextProvider multiColumn={!singleColumn}> <ColumnsContextProvider multiColumn={!singleColumn}>
<ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}> <ColumnsAreaContainer ref={this.setRef} singleColumn={singleColumn}>
@@ -234,8 +248,6 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} /> <WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} />
<WrappedRoute path='/pinned' component={PinnedStatuses} content={children} /> <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} />
{isClientFeatureEnabled('profile_editing') && <WrappedRoute key="edit" path='/profile/edit' component={AccountEdit} content={children} />}
<WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} /> <WrappedRoute path={['/start', '/start/profile']} exact component={OnboardingProfile} content={children} />
<WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} /> <WrappedRoute path='/start/follows' component={OnboardingFollows} content={children} />
<WrappedRoute path='/directory' component={Directory} content={children} /> <WrappedRoute path='/directory' component={Directory} content={children} />
@@ -243,8 +255,8 @@ class SwitchingColumnsArea extends PureComponent {
<WrappedRoute path='/search' component={Search} content={children} /> <WrappedRoute path='/search' component={Search} content={children} />
<WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} /> <WrappedRoute path={['/publish', '/statuses/new']} component={Compose} content={children} />
{!profileRedesignEnabled && <WrappedRoute path={['/@:acct', '/accounts/:id']} exact component={AccountTimeline} content={children} />}
{...profileRedesignRoutes} {...profileRedesignRoutes}
<WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} /> <WrappedRoute path={['/@:acct/featured', '/accounts/:id/featured']} component={AccountFeatured} content={children} />
<WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} /> <WrappedRoute path='/@:acct/tagged/:tagged?' exact component={AccountTimeline} content={children} />
<WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} /> <WrappedRoute path={['/@:acct/with_replies', '/accounts/:id/with_replies']} component={AccountTimeline} content={children} componentParams={{ withReplies: true }} />

View File

@@ -103,6 +103,11 @@ export function AccountEdit() {
.then((module) => ({ default: module.AccountEdit })); .then((module) => ({ default: module.AccountEdit }));
} }
export function AccountEditFeaturedTags() {
return import('../../account_edit/featured_tags')
.then((module) => ({ default: module.AccountEditFeaturedTags }));
}
export function Followers () { export function Followers () {
return import('../../followers'); return import('../../followers');
} }

View File

@@ -145,6 +145,7 @@
"account_edit.char_counter": "{currentLength}/{maxLength} znaků", "account_edit.char_counter": "{currentLength}/{maxLength} znaků",
"account_edit.column_button": "Hotovo", "account_edit.column_button": "Hotovo",
"account_edit.column_title": "Upravit profil", "account_edit.column_title": "Upravit profil",
"account_edit.custom_fields.placeholder": "Přidejte svá zájmena, externí odkazy nebo cokoliv jiného, co chcete sdílet.",
"account_edit.custom_fields.title": "Vlastní pole", "account_edit.custom_fields.title": "Vlastní pole",
"account_edit.save": "Uložit", "account_edit.save": "Uložit",
"account_edit.section_edit_button": "Upravit", "account_edit.section_edit_button": "Upravit",
@@ -250,12 +251,14 @@
"closed_registrations_modal.find_another_server": "Najít jiný server", "closed_registrations_modal.find_another_server": "Najít jiný server",
"closed_registrations_modal.preamble": "Mastodon je decentralizovaný, takže bez ohledu na to, kde vytvoříte svůj účet, budete moci sledovat a komunikovat s kýmkoli na tomto serveru. Můžete ho dokonce hostovat!", "closed_registrations_modal.preamble": "Mastodon je decentralizovaný, takže bez ohledu na to, kde vytvoříte svůj účet, budete moci sledovat a komunikovat s kýmkoli na tomto serveru. Můžete ho dokonce hostovat!",
"closed_registrations_modal.title": "Registrace na Mastodon", "closed_registrations_modal.title": "Registrace na Mastodon",
"collections.collection_description": "Popis",
"collections.collection_name": "Název", "collections.collection_name": "Název",
"collections.collection_topic": "Téma", "collections.collection_topic": "Téma",
"collections.confirm_account_removal": "Jste si jisti, že chcete odstranit tento účet z této sbírky?", "collections.confirm_account_removal": "Jste si jisti, že chcete odstranit tento účet z této sbírky?",
"collections.content_warning": "Varování o obsahu", "collections.content_warning": "Varování o obsahu",
"collections.continue": "Pokračovat", "collections.continue": "Pokračovat",
"collections.mark_as_sensitive_hint": "Skryje popis kolekce a účty za varováním obsahu. Název kolekce bude stále viditelný.", "collections.mark_as_sensitive_hint": "Skryje popis kolekce a účty za varováním obsahu. Název kolekce bude stále viditelný.",
"collections.name_length_hint": "Limit 40 znaků",
"collections.new_collection": "Nová sbírka", "collections.new_collection": "Nová sbírka",
"collections.no_collections_yet": "Ještě nemáte žádné sbírky.", "collections.no_collections_yet": "Ještě nemáte žádné sbírky.",
"collections.remove_account": "Odstranit tento účet", "collections.remove_account": "Odstranit tento účet",
@@ -335,6 +338,8 @@
"confirmations.delete.confirm": "Smazat", "confirmations.delete.confirm": "Smazat",
"confirmations.delete.message": "Opravdu chcete smazat tento příspěvek?", "confirmations.delete.message": "Opravdu chcete smazat tento příspěvek?",
"confirmations.delete.title": "Smazat příspěvek?", "confirmations.delete.title": "Smazat příspěvek?",
"confirmations.delete_collection.confirm": "Smazat",
"confirmations.delete_collection.message": "Tuto akci nelze vrátit zpět.",
"confirmations.delete_collection.title": "Smazat „{name}“?", "confirmations.delete_collection.title": "Smazat „{name}“?",
"confirmations.delete_list.confirm": "Smazat", "confirmations.delete_list.confirm": "Smazat",
"confirmations.delete_list.message": "Opravdu chcete tento seznam navždy smazat?", "confirmations.delete_list.message": "Opravdu chcete tento seznam navždy smazat?",

View File

@@ -390,6 +390,9 @@
"confirmations.discard_draft.post.title": "Dileu drafft eich postiad?", "confirmations.discard_draft.post.title": "Dileu drafft eich postiad?",
"confirmations.discard_edit_media.confirm": "Dileu", "confirmations.discard_edit_media.confirm": "Dileu",
"confirmations.discard_edit_media.message": "Mae gennych newidiadau heb eu cadw i'r disgrifiad cyfryngau neu'r rhagolwg - eu dileu beth bynnag?", "confirmations.discard_edit_media.message": "Mae gennych newidiadau heb eu cadw i'r disgrifiad cyfryngau neu'r rhagolwg - eu dileu beth bynnag?",
"confirmations.follow_to_collection.confirm": "Dilyn ac ychwanegu at y casgliad",
"confirmations.follow_to_collection.message": "Mae angen i chi fod yn dilyn {name} i'w hychwanegu at gasgliad.",
"confirmations.follow_to_collection.title": "Dilyn cyfrif?",
"confirmations.follow_to_list.confirm": "Dilyn ac ychwanegu at y rhestr", "confirmations.follow_to_list.confirm": "Dilyn ac ychwanegu at y rhestr",
"confirmations.follow_to_list.message": "Mae angen i chi fod yn dilyn {name} i'w ychwanegu at restr.", "confirmations.follow_to_list.message": "Mae angen i chi fod yn dilyn {name} i'w ychwanegu at restr.",
"confirmations.follow_to_list.title": "Dilyn defnyddiwr?", "confirmations.follow_to_list.title": "Dilyn defnyddiwr?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Begrænset til 40 tegn", "collections.name_length_hint": "Begrænset til 40 tegn",
"collections.new_collection": "Ny samling", "collections.new_collection": "Ny samling",
"collections.no_collections_yet": "Ingen samlinger endnu.", "collections.no_collections_yet": "Ingen samlinger endnu.",
"collections.old_last_post_note": "Seneste indlæg er fra over en uge siden",
"collections.remove_account": "Fjern denne konto", "collections.remove_account": "Fjern denne konto",
"collections.search_accounts_label": "Søg efter konti for at tilføje…", "collections.search_accounts_label": "Søg efter konti for at tilføje…",
"collections.search_accounts_max_reached": "Du har tilføjet det maksimale antal konti", "collections.search_accounts_max_reached": "Du har tilføjet det maksimale antal konti",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Kassér dit indlægsudkast?", "confirmations.discard_draft.post.title": "Kassér dit indlægsudkast?",
"confirmations.discard_edit_media.confirm": "Kassér", "confirmations.discard_edit_media.confirm": "Kassér",
"confirmations.discard_edit_media.message": "Der er ugemte ændringer i mediebeskrivelsen eller forhåndsvisningen, kassér dem alligevel?", "confirmations.discard_edit_media.message": "Der er ugemte ændringer i mediebeskrivelsen eller forhåndsvisningen, kassér dem alligevel?",
"confirmations.follow_to_collection.confirm": "Følg og føj til samling",
"confirmations.follow_to_collection.message": "Du skal følge {name} for at føje vedkommende til en samling.",
"confirmations.follow_to_collection.title": "Følg konto?",
"confirmations.follow_to_list.confirm": "Følg og føj til liste", "confirmations.follow_to_list.confirm": "Følg og føj til liste",
"confirmations.follow_to_list.message": "Du skal følge {name} for at føje vedkommende til en liste.", "confirmations.follow_to_list.message": "Du skal følge {name} for at føje vedkommende til en liste.",
"confirmations.follow_to_list.title": "Følg bruger?", "confirmations.follow_to_list.title": "Følg bruger?",

View File

@@ -152,7 +152,7 @@
"account_edit.custom_fields.title": "Zusatzfelder", "account_edit.custom_fields.title": "Zusatzfelder",
"account_edit.display_name.placeholder": "Dein Anzeigename wird auf deinem Profil und in Timelines angezeigt.", "account_edit.display_name.placeholder": "Dein Anzeigename wird auf deinem Profil und in Timelines angezeigt.",
"account_edit.display_name.title": "Anzeigename", "account_edit.display_name.title": "Anzeigename",
"account_edit.featured_hashtags.placeholder": "Hilf anderen dabei, deine Lieblingsthemen zu identifizieren und diese leicht zugänglich zu machen.", "account_edit.featured_hashtags.placeholder": "Präsentiere deine Lieblingsthemen und ermögliche anderen einen schnellen Zugriff darauf.",
"account_edit.featured_hashtags.title": "Vorgestellte Hashtags", "account_edit.featured_hashtags.title": "Vorgestellte Hashtags",
"account_edit.name_modal.add_title": "Anzeigenamen hinzufügen", "account_edit.name_modal.add_title": "Anzeigenamen hinzufügen",
"account_edit.name_modal.edit_title": "Anzeigenamen bearbeiten", "account_edit.name_modal.edit_title": "Anzeigenamen bearbeiten",
@@ -296,6 +296,7 @@
"collections.name_length_hint": "Maximal 40 Zeichen", "collections.name_length_hint": "Maximal 40 Zeichen",
"collections.new_collection": "Neue Sammlung", "collections.new_collection": "Neue Sammlung",
"collections.no_collections_yet": "Bisher keine Sammlungen vorhanden.", "collections.no_collections_yet": "Bisher keine Sammlungen vorhanden.",
"collections.old_last_post_note": "Neuester Beitrag mehr als eine Woche alt",
"collections.remove_account": "Dieses Konto entfernen", "collections.remove_account": "Dieses Konto entfernen",
"collections.search_accounts_label": "Suche nach Konten, um sie hinzuzufügen …", "collections.search_accounts_label": "Suche nach Konten, um sie hinzuzufügen …",
"collections.search_accounts_max_reached": "Du hast die Höchstzahl an Konten hinzugefügt", "collections.search_accounts_max_reached": "Du hast die Höchstzahl an Konten hinzugefügt",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Entwurf verwerfen?", "confirmations.discard_draft.post.title": "Entwurf verwerfen?",
"confirmations.discard_edit_media.confirm": "Verwerfen", "confirmations.discard_edit_media.confirm": "Verwerfen",
"confirmations.discard_edit_media.message": "Du hast Änderungen an der Medienbeschreibung oder -vorschau vorgenommen, die noch nicht gespeichert sind. Trotzdem verwerfen?", "confirmations.discard_edit_media.message": "Du hast Änderungen an der Medienbeschreibung oder -vorschau vorgenommen, die noch nicht gespeichert sind. Trotzdem verwerfen?",
"confirmations.follow_to_collection.confirm": "Folgen und zur Sammlung hinzufügen",
"confirmations.follow_to_collection.message": "Du musst {name} folgen, um das Profil zu einer Sammlung hinzufügen zu können.",
"confirmations.follow_to_collection.title": "Konto folgen?",
"confirmations.follow_to_list.confirm": "Folgen und zur Liste hinzufügen", "confirmations.follow_to_list.confirm": "Folgen und zur Liste hinzufügen",
"confirmations.follow_to_list.message": "Du musst {name} folgen, um das Profil zu einer Liste hinzufügen zu können.", "confirmations.follow_to_list.message": "Du musst {name} folgen, um das Profil zu einer Liste hinzufügen zu können.",
"confirmations.follow_to_list.title": "Profil folgen?", "confirmations.follow_to_list.title": "Profil folgen?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Όριο 40 χαρακτήρων", "collections.name_length_hint": "Όριο 40 χαρακτήρων",
"collections.new_collection": "Νέα συλλογή", "collections.new_collection": "Νέα συλλογή",
"collections.no_collections_yet": "Καμία συλλογή ακόμη.", "collections.no_collections_yet": "Καμία συλλογή ακόμη.",
"collections.old_last_post_note": "Τελευταία ανάρτηση πριν από μια εβδομάδα",
"collections.remove_account": "Αφαίρεση λογαριασμού", "collections.remove_account": "Αφαίρεση λογαριασμού",
"collections.search_accounts_label": "Αναζήτηση λογαριασμών για προσθήκη…", "collections.search_accounts_label": "Αναζήτηση λογαριασμών για προσθήκη…",
"collections.search_accounts_max_reached": "Έχετε προσθέσει τον μέγιστο αριθμό λογαριασμών", "collections.search_accounts_max_reached": "Έχετε προσθέσει τον μέγιστο αριθμό λογαριασμών",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Απόρριψη της πρόχειρης ανάρτησης σας;", "confirmations.discard_draft.post.title": "Απόρριψη της πρόχειρης ανάρτησης σας;",
"confirmations.discard_edit_media.confirm": "Απόρριψη", "confirmations.discard_edit_media.confirm": "Απόρριψη",
"confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;", "confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;",
"confirmations.follow_to_collection.confirm": "Ακολουθήστε και προσθέστε στη συλλογή",
"confirmations.follow_to_collection.message": "Πρέπει να ακολουθήσετε τον χρήστη {name} για να τους προσθέσετε σε μια συλλογή.",
"confirmations.follow_to_collection.title": "Ακολουθήστε τον λογαριασμό;",
"confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα", "confirmations.follow_to_list.confirm": "Ακολούθησε και πρόσθεσε στη λίστα",
"confirmations.follow_to_list.message": "Πρέπει να ακολουθήσεις τον χρήστη {name} για να τον προσθέσεις σε μια λίστα.", "confirmations.follow_to_list.message": "Πρέπει να ακολουθήσεις τον χρήστη {name} για να τον προσθέσεις σε μια λίστα.",
"confirmations.follow_to_list.title": "Ακολούθηση χρήστη;", "confirmations.follow_to_list.title": "Ακολούθηση χρήστη;",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "40 characters limit", "collections.name_length_hint": "40 characters limit",
"collections.new_collection": "New collection", "collections.new_collection": "New collection",
"collections.no_collections_yet": "No collections yet.", "collections.no_collections_yet": "No collections yet.",
"collections.old_last_post_note": "Last posted over a week ago",
"collections.remove_account": "Remove this account", "collections.remove_account": "Remove this account",
"collections.search_accounts_label": "Search for accounts to add…", "collections.search_accounts_label": "Search for accounts to add…",
"collections.search_accounts_max_reached": "You have added the maximum number of accounts", "collections.search_accounts_max_reached": "You have added the maximum number of accounts",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Discard your draft post?", "confirmations.discard_draft.post.title": "Discard your draft post?",
"confirmations.discard_edit_media.confirm": "Discard", "confirmations.discard_edit_media.confirm": "Discard",
"confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?", "confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
"confirmations.follow_to_collection.confirm": "Follow and add to collection",
"confirmations.follow_to_collection.message": "You need to be following {name} to add them to a collection.",
"confirmations.follow_to_collection.title": "Follow account?",
"confirmations.follow_to_list.confirm": "Follow and add to list", "confirmations.follow_to_list.confirm": "Follow and add to list",
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.", "confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
"confirmations.follow_to_list.title": "Follow user?", "confirmations.follow_to_list.title": "Follow user?",

View File

@@ -145,6 +145,9 @@
"account_edit.bio.title": "Bio", "account_edit.bio.title": "Bio",
"account_edit.bio_modal.add_title": "Add bio", "account_edit.bio_modal.add_title": "Add bio",
"account_edit.bio_modal.edit_title": "Edit bio", "account_edit.bio_modal.edit_title": "Edit bio",
"account_edit.button.add": "Add {item}",
"account_edit.button.delete": "Delete {item}",
"account_edit.button.edit": "Edit {item}",
"account_edit.char_counter": "{currentLength}/{maxLength} characters", "account_edit.char_counter": "{currentLength}/{maxLength} characters",
"account_edit.column_button": "Done", "account_edit.column_button": "Done",
"account_edit.column_title": "Edit Profile", "account_edit.column_title": "Edit Profile",
@@ -152,6 +155,7 @@
"account_edit.custom_fields.title": "Custom fields", "account_edit.custom_fields.title": "Custom fields",
"account_edit.display_name.placeholder": "Your display name is how your name appears on your profile and in timelines.", "account_edit.display_name.placeholder": "Your display name is how your name appears on your profile and in timelines.",
"account_edit.display_name.title": "Display name", "account_edit.display_name.title": "Display name",
"account_edit.featured_hashtags.item": "hashtags",
"account_edit.featured_hashtags.placeholder": "Help others identify, and have quick access to, your favorite topics.", "account_edit.featured_hashtags.placeholder": "Help others identify, and have quick access to, your favorite topics.",
"account_edit.featured_hashtags.title": "Featured hashtags", "account_edit.featured_hashtags.title": "Featured hashtags",
"account_edit.name_modal.add_title": "Add display name", "account_edit.name_modal.add_title": "Add display name",
@@ -159,7 +163,11 @@
"account_edit.profile_tab.subtitle": "Customize the tabs on your profile and what they display.", "account_edit.profile_tab.subtitle": "Customize the tabs on your profile and what they display.",
"account_edit.profile_tab.title": "Profile tab settings", "account_edit.profile_tab.title": "Profile tab settings",
"account_edit.save": "Save", "account_edit.save": "Save",
"account_edit.section_edit_button": "Edit", "account_edit_tags.column_title": "Edit featured hashtags",
"account_edit_tags.help_text": "Featured hashtags help users discover and interact with your profile. They appear as filters on your Profile pages Activity view.",
"account_edit_tags.search_placeholder": "Enter a hashtag…",
"account_edit_tags.suggestions": "Suggestions:",
"account_edit_tags.tag_status_count": "{count} posts",
"account_note.placeholder": "Click to add note", "account_note.placeholder": "Click to add note",
"admin.dashboard.daily_retention": "User retention rate by day after sign-up", "admin.dashboard.daily_retention": "User retention rate by day after sign-up",
"admin.dashboard.monthly_retention": "User retention rate by month after sign-up", "admin.dashboard.monthly_retention": "User retention rate by month after sign-up",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Límite de 40 caracteres", "collections.name_length_hint": "Límite de 40 caracteres",
"collections.new_collection": "Nueva colección", "collections.new_collection": "Nueva colección",
"collections.no_collections_yet": "No hay colecciones aún.", "collections.no_collections_yet": "No hay colecciones aún.",
"collections.old_last_post_note": "Último mensaje hace más de una semana",
"collections.remove_account": "Eliminar esta cuenta", "collections.remove_account": "Eliminar esta cuenta",
"collections.search_accounts_label": "Buscar cuentas para agregar…", "collections.search_accounts_label": "Buscar cuentas para agregar…",
"collections.search_accounts_max_reached": "Agregaste el número máximo de cuentas", "collections.search_accounts_max_reached": "Agregaste el número máximo de cuentas",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "¿Descartar tu borrador?", "confirmations.discard_draft.post.title": "¿Descartar tu borrador?",
"confirmations.discard_edit_media.confirm": "Descartar", "confirmations.discard_edit_media.confirm": "Descartar",
"confirmations.discard_edit_media.message": "Tenés cambios sin guardar en la descripción de medios o en la vista previa, ¿querés descartarlos de todos modos?", "confirmations.discard_edit_media.message": "Tenés cambios sin guardar en la descripción de medios o en la vista previa, ¿querés descartarlos de todos modos?",
"confirmations.follow_to_collection.confirm": "Seguir y agregar a la colección",
"confirmations.follow_to_collection.message": "Necesitás seguir a {name} para agregarle a una colección.",
"confirmations.follow_to_collection.title": "¿Seguir cuenta?",
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista", "confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
"confirmations.follow_to_list.message": "Necesitás seguir a {name} para agregarle a una lista.", "confirmations.follow_to_list.message": "Necesitás seguir a {name} para agregarle a una lista.",
"confirmations.follow_to_list.title": "¿Querés seguirle?", "confirmations.follow_to_list.title": "¿Querés seguirle?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Limitado a 40 caracteres", "collections.name_length_hint": "Limitado a 40 caracteres",
"collections.new_collection": "Nueva colección", "collections.new_collection": "Nueva colección",
"collections.no_collections_yet": "No hay colecciones todavía.", "collections.no_collections_yet": "No hay colecciones todavía.",
"collections.old_last_post_note": "Última publicación hace más de una semana",
"collections.remove_account": "Eliminar esta cuenta", "collections.remove_account": "Eliminar esta cuenta",
"collections.search_accounts_label": "Buscar cuentas para añadir…", "collections.search_accounts_label": "Buscar cuentas para añadir…",
"collections.search_accounts_max_reached": "Has añadido el número máximo de cuentas", "collections.search_accounts_max_reached": "Has añadido el número máximo de cuentas",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "¿Deseas descartar tu borrador?", "confirmations.discard_draft.post.title": "¿Deseas descartar tu borrador?",
"confirmations.discard_edit_media.confirm": "Descartar", "confirmations.discard_edit_media.confirm": "Descartar",
"confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo, ¿deseas descartarlos de cualquier manera?", "confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo, ¿deseas descartarlos de cualquier manera?",
"confirmations.follow_to_collection.confirm": "Seguir y añadir a la colección",
"confirmations.follow_to_collection.message": "Debes seguir a {name} para agregarlo a una colección.",
"confirmations.follow_to_collection.title": "¿Seguir cuenta?",
"confirmations.follow_to_list.confirm": "Seguir y agregar a la lista", "confirmations.follow_to_list.confirm": "Seguir y agregar a la lista",
"confirmations.follow_to_list.message": "Tienes que seguir a {name} para añadirlo a una lista.", "confirmations.follow_to_list.message": "Tienes que seguir a {name} para añadirlo a una lista.",
"confirmations.follow_to_list.title": "¿Seguir a usuario?", "confirmations.follow_to_list.title": "¿Seguir a usuario?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "Dejar de silenciar a @{name}", "account.unmute": "Dejar de silenciar a @{name}",
"account.unmute_notifications_short": "Dejar de silenciar notificaciones", "account.unmute_notifications_short": "Dejar de silenciar notificaciones",
"account.unmute_short": "Dejar de silenciar", "account.unmute_short": "Dejar de silenciar",
"account_edit.bio.placeholder": "Añade una breve introducción para ayudar a los demás a identificarte.",
"account_edit.bio.title": "Biografía",
"account_edit.bio_modal.add_title": "Añadir biografía",
"account_edit.bio_modal.edit_title": "Editar biografía",
"account_edit.char_counter": "{currentLength}/{maxLength} caracteres",
"account_edit.column_button": "Hecho", "account_edit.column_button": "Hecho",
"account_edit.column_title": "Editar perfil", "account_edit.column_title": "Editar perfil",
"account_edit.custom_fields.placeholder": "Añade tus pronombres, enlaces externos o cualquier otra cosa que quieras compartir.",
"account_edit.custom_fields.title": "Campos personalizados",
"account_edit.display_name.placeholder": "Tu nombre de usuario es el nombre que aparece en tu perfil y en las cronologías.",
"account_edit.display_name.title": "Nombre para mostrar",
"account_edit.featured_hashtags.placeholder": "Ayuda a otros a identificar tus temas favoritos y a acceder rápidamente a ellos.",
"account_edit.featured_hashtags.title": "Etiquetas destacadas",
"account_edit.name_modal.add_title": "Añadir nombre para mostrar",
"account_edit.name_modal.edit_title": "Editar nombre para mostrar",
"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.section_edit_button": "Editar",
"account_note.placeholder": "Haz clic para añadir nota", "account_note.placeholder": "Haz clic para añadir nota",
"admin.dashboard.daily_retention": "Tasa de retención de usuarios por día después del registro", "admin.dashboard.daily_retention": "Tasa de retención de usuarios por día después del registro",
"admin.dashboard.monthly_retention": "Tasa de retención de usuarios por mes después del registro", "admin.dashboard.monthly_retention": "Tasa de retención de usuarios por mes después del registro",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "Seleccionado por ti", "collections.detail.curated_by_you": "Seleccionado por ti",
"collections.detail.loading": "Cargando colección…", "collections.detail.loading": "Cargando colección…",
"collections.detail.share": "Compartir esta colección", "collections.detail.share": "Compartir esta colección",
"collections.edit_details": "Editar detalles",
"collections.error_loading_collections": "Se ha producido un error al intentar cargar tus colecciones.", "collections.error_loading_collections": "Se ha producido un error al intentar cargar tus colecciones.",
"collections.hints.accounts_counter": "{count} / {max} cuentas", "collections.hints.accounts_counter": "{count} / {max} cuentas",
"collections.hints.add_more_accounts": "¡Añade al menos {count, plural, one {# cuenta} other {# cuentas}} para continuar", "collections.hints.add_more_accounts": "¡Añade al menos {count, plural, one {# cuenta} other {# cuentas}} para continuar",
@@ -275,11 +293,14 @@
"collections.manage_accounts": "Administrar cuentas", "collections.manage_accounts": "Administrar cuentas",
"collections.mark_as_sensitive": "Marcar como sensible", "collections.mark_as_sensitive": "Marcar como sensible",
"collections.mark_as_sensitive_hint": "Oculta la descripción de la colección y las cuentas detrás de una advertencia de contenido. El nombre de la colección seguirá siendo visible.", "collections.mark_as_sensitive_hint": "Oculta la descripción de la colección y las cuentas detrás de una advertencia de contenido. El nombre de la colección seguirá siendo visible.",
"collections.name_length_hint": "Límite de 40 caracteres",
"collections.new_collection": "Nueva colección", "collections.new_collection": "Nueva colección",
"collections.no_collections_yet": "Aún no hay colecciones.", "collections.no_collections_yet": "Aún no hay colecciones.",
"collections.old_last_post_note": "Última publicación hace más de una semana",
"collections.remove_account": "Borrar esta cuenta", "collections.remove_account": "Borrar esta cuenta",
"collections.search_accounts_label": "Buscar cuentas para añadir…", "collections.search_accounts_label": "Buscar cuentas para añadir…",
"collections.search_accounts_max_reached": "Has añadido el número máximo de cuentas", "collections.search_accounts_max_reached": "Has añadido el número máximo de cuentas",
"collections.sensitive": "Sensible",
"collections.topic_hint": "Añadir una etiqueta que ayude a otros a entender el tema principal de esta colección.", "collections.topic_hint": "Añadir una etiqueta que ayude a otros a entender el tema principal de esta colección.",
"collections.view_collection": "Ver colección", "collections.view_collection": "Ver colección",
"collections.visibility_public": "Pública", "collections.visibility_public": "Pública",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "¿Descartar tu borrador?", "confirmations.discard_draft.post.title": "¿Descartar tu borrador?",
"confirmations.discard_edit_media.confirm": "Descartar", "confirmations.discard_edit_media.confirm": "Descartar",
"confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo audiovisual, ¿descartarlos de todos modos?", "confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo audiovisual, ¿descartarlos de todos modos?",
"confirmations.follow_to_collection.confirm": "Seguir y añadir a la colección",
"confirmations.follow_to_collection.message": "Debes seguir a {name} para añadirlo a una colección.",
"confirmations.follow_to_collection.title": "¿Seguir cuenta?",
"confirmations.follow_to_list.confirm": "Seguir y añadir a la lista", "confirmations.follow_to_list.confirm": "Seguir y añadir a la lista",
"confirmations.follow_to_list.message": "Necesitas seguir a {name} para agregarlo a una lista.", "confirmations.follow_to_list.message": "Necesitas seguir a {name} para agregarlo a una lista.",
"confirmations.follow_to_list.title": "¿Seguir usuario?", "confirmations.follow_to_list.title": "¿Seguir usuario?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "40 merkin rajoitus", "collections.name_length_hint": "40 merkin rajoitus",
"collections.new_collection": "Uusi kokoelma", "collections.new_collection": "Uusi kokoelma",
"collections.no_collections_yet": "Ei vielä kokoelmia.", "collections.no_collections_yet": "Ei vielä kokoelmia.",
"collections.old_last_post_note": "Julkaissut viimeksi yli viikko sitten",
"collections.remove_account": "Poista tämä tili", "collections.remove_account": "Poista tämä tili",
"collections.search_accounts_label": "Hae lisättäviä tilejä…", "collections.search_accounts_label": "Hae lisättäviä tilejä…",
"collections.search_accounts_max_reached": "Olet lisännyt enimmäismäärän tilejä", "collections.search_accounts_max_reached": "Olet lisännyt enimmäismäärän tilejä",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Hylätäänkö luonnosjulkaisusi?", "confirmations.discard_draft.post.title": "Hylätäänkö luonnosjulkaisusi?",
"confirmations.discard_edit_media.confirm": "Hylkää", "confirmations.discard_edit_media.confirm": "Hylkää",
"confirmations.discard_edit_media.message": "Sinulla on tallentamattomia muutoksia median kuvaukseen tai esikatseluun. Hylätäänkö ne silti?", "confirmations.discard_edit_media.message": "Sinulla on tallentamattomia muutoksia median kuvaukseen tai esikatseluun. Hylätäänkö ne silti?",
"confirmations.follow_to_collection.confirm": "Seuraa ja lisää kokoelmaan",
"confirmations.follow_to_collection.message": "Sinun on seurattava tiliä {name}, jotta voit lisätä sen kokoelmaan.",
"confirmations.follow_to_collection.title": "Seurataanko tiliä?",
"confirmations.follow_to_list.confirm": "Seuraa ja lisää listaan", "confirmations.follow_to_list.confirm": "Seuraa ja lisää listaan",
"confirmations.follow_to_list.message": "Sinun on seurattava käyttäjää {name}, jotta voit lisätä hänet listaan.", "confirmations.follow_to_list.message": "Sinun on seurattava käyttäjää {name}, jotta voit lisätä hänet listaan.",
"confirmations.follow_to_list.title": "Seurataanko käyttäjää?", "confirmations.follow_to_list.title": "Seurataanko käyttäjää?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "Doyv ikki @{name}", "account.unmute": "Doyv ikki @{name}",
"account.unmute_notifications_short": "Tendra fráboðanir", "account.unmute_notifications_short": "Tendra fráboðanir",
"account.unmute_short": "Doyv ikki", "account.unmute_short": "Doyv ikki",
"account_edit.bio.placeholder": "Legg eina stutta kunning afturat soleiðis at onnur kunnu eyðmerkja teg.",
"account_edit.bio.title": "Ævilýsing",
"account_edit.bio_modal.add_title": "Legg ævilýsing afturat",
"account_edit.bio_modal.edit_title": "Rætta ævilýsing",
"account_edit.char_counter": "{currentLength}/{maxLength} tekn",
"account_edit.column_button": "Liðugt", "account_edit.column_button": "Liðugt",
"account_edit.column_title": "Rætta vanga", "account_edit.column_title": "Rætta vanga",
"account_edit.custom_fields.placeholder": "Legg tíni forheiti, uttanhýsis leinki ella okkurt annað, sum tú kundi hugsað tær at deilt.",
"account_edit.custom_fields.title": "Serfelt",
"account_edit.display_name.placeholder": "Títt vísta navn er soleiðis sum navnið hjá tær verður víst á vanganum og á tíðarrásum.",
"account_edit.display_name.title": "Víst navn",
"account_edit.featured_hashtags.placeholder": "Hjálp øðrum at eyðmekja og hava skjóta atgongd til tíni yndisevni.",
"account_edit.featured_hashtags.title": "Sermerkt frámerki",
"account_edit.name_modal.add_title": "Legg víst navn afturat",
"account_edit.name_modal.edit_title": "Rætta víst navn",
"account_edit.profile_tab.subtitle": "Tillaga spjøldrini á vanganum hjá tær og tað, tey vísa.",
"account_edit.profile_tab.title": "Stillingar fyri spjøldur á vanga",
"account_edit.save": "Goym",
"account_edit.section_edit_button": "Rætta",
"account_note.placeholder": "Klikka fyri at leggja viðmerking afturat", "account_note.placeholder": "Klikka fyri at leggja viðmerking afturat",
"admin.dashboard.daily_retention": "Hvussu nógvir brúkarar eru eftir, síðani tey skrásettu seg, roknað í døgum", "admin.dashboard.daily_retention": "Hvussu nógvir brúkarar eru eftir, síðani tey skrásettu seg, roknað í døgum",
"admin.dashboard.monthly_retention": "Hvussu nógvir brúkarar eru eftir síðani tey skrásettu seg, roknað í mánaðum", "admin.dashboard.monthly_retention": "Hvussu nógvir brúkarar eru eftir síðani tey skrásettu seg, roknað í mánaðum",
@@ -262,6 +279,12 @@
"collections.create_collection": "Ger savn", "collections.create_collection": "Ger savn",
"collections.delete_collection": "Strika savn", "collections.delete_collection": "Strika savn",
"collections.description_length_hint": "Í mesta lagi 100 tekn", "collections.description_length_hint": "Í mesta lagi 100 tekn",
"collections.detail.accounts_heading": "Kontur",
"collections.detail.curated_by_author": "Snikkað til av {author}",
"collections.detail.curated_by_you": "Snikkað til av tær",
"collections.detail.loading": "Innlesi savn…",
"collections.detail.share": "Deil hetta savnið",
"collections.edit_details": "Rætta smálutir",
"collections.error_loading_collections": "Ein feilur hendi, tá tú royndi at finna fram søvnini hjá tær.", "collections.error_loading_collections": "Ein feilur hendi, tá tú royndi at finna fram søvnini hjá tær.",
"collections.hints.accounts_counter": "{count} / {max} kontur", "collections.hints.accounts_counter": "{count} / {max} kontur",
"collections.hints.add_more_accounts": "Legg minst {count, plural, one {# kontu} other {# kontur}} afturat fyri at halda fram", "collections.hints.add_more_accounts": "Legg minst {count, plural, one {# kontu} other {# kontur}} afturat fyri at halda fram",
@@ -270,11 +293,14 @@
"collections.manage_accounts": "Umsit kontur", "collections.manage_accounts": "Umsit kontur",
"collections.mark_as_sensitive": "Merk sum viðkvæmt", "collections.mark_as_sensitive": "Merk sum viðkvæmt",
"collections.mark_as_sensitive_hint": "Fjalið lýsingina av og konturnar hjá savninum aftan fyri eina innihaldsávaring. Savnsnavnið verður framvegis sjónligt.", "collections.mark_as_sensitive_hint": "Fjalið lýsingina av og konturnar hjá savninum aftan fyri eina innihaldsávaring. Savnsnavnið verður framvegis sjónligt.",
"collections.name_length_hint": "Í mesta lagi 40 tekn",
"collections.new_collection": "Nýtt savn", "collections.new_collection": "Nýtt savn",
"collections.no_collections_yet": "Eingi søvn enn.", "collections.no_collections_yet": "Eingi søvn enn.",
"collections.old_last_post_note": "Postaði seinast fyri meira enn einari viku síðani",
"collections.remove_account": "Strika hesa kontuna", "collections.remove_account": "Strika hesa kontuna",
"collections.search_accounts_label": "Leita eftir kontum at leggja afturat…", "collections.search_accounts_label": "Leita eftir kontum at leggja afturat…",
"collections.search_accounts_max_reached": "Tú hevur lagt afturat mesta talið av kontum", "collections.search_accounts_max_reached": "Tú hevur lagt afturat mesta talið av kontum",
"collections.sensitive": "Viðkvæmt",
"collections.topic_hint": "Legg afturat eitt frámerki, sum hjálpir øðrum at skilja høvuðevnið í hesum savninum.", "collections.topic_hint": "Legg afturat eitt frámerki, sum hjálpir øðrum at skilja høvuðevnið í hesum savninum.",
"collections.view_collection": "Vís savn", "collections.view_collection": "Vís savn",
"collections.visibility_public": "Alment", "collections.visibility_public": "Alment",
@@ -365,6 +391,9 @@
"confirmations.discard_draft.post.title": "Vraka kladdupostin?", "confirmations.discard_draft.post.title": "Vraka kladdupostin?",
"confirmations.discard_edit_media.confirm": "Vraka", "confirmations.discard_edit_media.confirm": "Vraka",
"confirmations.discard_edit_media.message": "Tú hevur broytingar í miðlalýsingini ella undansýningini, sum ikki eru goymdar. Vilt tú kortini vraka?", "confirmations.discard_edit_media.message": "Tú hevur broytingar í miðlalýsingini ella undansýningini, sum ikki eru goymdar. Vilt tú kortini vraka?",
"confirmations.follow_to_collection.confirm": "Fylg og legg afturat savni",
"confirmations.follow_to_collection.message": "Tú mást fylgja {name} fyri at leggja tey afturat einum savni.",
"confirmations.follow_to_collection.title": "Fylg kontu?",
"confirmations.follow_to_list.confirm": "Fylg og legg afturat lista", "confirmations.follow_to_list.confirm": "Fylg og legg afturat lista",
"confirmations.follow_to_list.message": "Tú mást fylgja {name} fyri at leggja tey afturat einum lista.", "confirmations.follow_to_list.message": "Tú mást fylgja {name} fyri at leggja tey afturat einum lista.",
"confirmations.follow_to_list.title": "Fylg brúkara?", "confirmations.follow_to_list.title": "Fylg brúkara?",

View File

@@ -141,15 +141,25 @@
"account.unmute": "Ne plus masquer @{name}", "account.unmute": "Ne plus masquer @{name}",
"account.unmute_notifications_short": "Ne plus masquer les notifications", "account.unmute_notifications_short": "Ne plus masquer les notifications",
"account.unmute_short": "Ne plus masquer", "account.unmute_short": "Ne plus masquer",
"account_edit.bio.placeholder": "Ajouter une courte introduction pour aider à vous connaître.", "account_edit.bio.placeholder": "Ajouter une courte introduction pour aider les autres à vous connaître.",
"account_edit.bio.title": "Présentation", "account_edit.bio.title": "Présentation",
"account_edit.bio_modal.add_title": "Ajouter une présentation", "account_edit.bio_modal.add_title": "Ajouter une présentation",
"account_edit.bio_modal.edit_title": "Modifier la présentation", "account_edit.bio_modal.edit_title": "Modifier la présentation",
"account_edit.char_counter": "{currentLength}/{maxLength} caractères", "account_edit.char_counter": "{currentLength}/{maxLength} caractères",
"account_edit.column_button": "Terminé", "account_edit.column_button": "Terminé",
"account_edit.column_title": "Modifier le profil", "account_edit.column_title": "Modifier le profil",
"account_edit.custom_fields.placeholder": "Ajouter vos pronoms, vos sites, ou tout ce que vous voulez partager.",
"account_edit.custom_fields.title": "Champs personnalisés",
"account_edit.display_name.placeholder": "Votre nom public est le nom qui apparaît sur votre profil et dans les fils d'actualités.",
"account_edit.display_name.title": "Nom public",
"account_edit.featured_hashtags.placeholder": "Aider les autres à identifier et à accéder rapidement à vos sujets préférés.",
"account_edit.featured_hashtags.title": "Hashtags mis en avant",
"account_edit.name_modal.add_title": "Ajouter un nom public",
"account_edit.name_modal.edit_title": "Modifier le nom public",
"account_edit.profile_tab.subtitle": "Personnaliser les onglets de votre profil et leur contenu.",
"account_edit.profile_tab.title": "Paramètres de l'onglet du profil",
"account_edit.save": "Enregistrer", "account_edit.save": "Enregistrer",
"account_edit.section_edit_button": "Éditer", "account_edit.section_edit_button": "Modifier",
"account_note.placeholder": "Cliquez pour ajouter une note", "account_note.placeholder": "Cliquez pour ajouter une note",
"admin.dashboard.daily_retention": "Taux de rétention des comptes par jour après inscription", "admin.dashboard.daily_retention": "Taux de rétention des comptes par jour après inscription",
"admin.dashboard.monthly_retention": "Taux de rétention des comptes par mois après inscription", "admin.dashboard.monthly_retention": "Taux de rétention des comptes par mois après inscription",
@@ -242,7 +252,7 @@
"bundle_column_error.routing.body": "La page demandée est introuvable. Êtes-vous sûr que lURL dans la barre dadresse est correcte?", "bundle_column_error.routing.body": "La page demandée est introuvable. Êtes-vous sûr que lURL dans la barre dadresse est correcte?",
"bundle_column_error.routing.title": "404", "bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "Fermer", "bundle_modal_error.close": "Fermer",
"bundle_modal_error.message": "Un problème s'est produit lors du chargement de cet écran.", "bundle_modal_error.message": "Une erreur sest produite lors du chargement de cet écran.",
"bundle_modal_error.retry": "Réessayer", "bundle_modal_error.retry": "Réessayer",
"callout.dismiss": "Rejeter", "callout.dismiss": "Rejeter",
"carousel.current": "<sr>Diapositive</sr> {current, number} / {max, number}", "carousel.current": "<sr>Diapositive</sr> {current, number} / {max, number}",
@@ -274,6 +284,7 @@
"collections.detail.curated_by_you": "Organisée par vous", "collections.detail.curated_by_you": "Organisée par vous",
"collections.detail.loading": "Chargement de la collection…", "collections.detail.loading": "Chargement de la collection…",
"collections.detail.share": "Partager la collection", "collections.detail.share": "Partager la collection",
"collections.edit_details": "Modifier les détails",
"collections.error_loading_collections": "Une erreur s'est produite durant le chargement de vos collections.", "collections.error_loading_collections": "Une erreur s'est produite durant le chargement de vos collections.",
"collections.hints.accounts_counter": "{count} / {max} comptes", "collections.hints.accounts_counter": "{count} / {max} comptes",
"collections.hints.add_more_accounts": "Ajouter au moins {count, plural, one {# compte} other {# comptes}} pour continuer", "collections.hints.add_more_accounts": "Ajouter au moins {count, plural, one {# compte} other {# comptes}} pour continuer",
@@ -282,11 +293,14 @@
"collections.manage_accounts": "Gérer les comptes", "collections.manage_accounts": "Gérer les comptes",
"collections.mark_as_sensitive": "Marquer comme sensible", "collections.mark_as_sensitive": "Marquer comme sensible",
"collections.mark_as_sensitive_hint": "Masque la description et les comptes de la collection derrière un avertissement au public. Le titre reste visible.", "collections.mark_as_sensitive_hint": "Masque la description et les comptes de la collection derrière un avertissement au public. Le titre reste visible.",
"collections.name_length_hint": "Maximum 40 caractères",
"collections.new_collection": "Nouvelle collection", "collections.new_collection": "Nouvelle collection",
"collections.no_collections_yet": "Aucune collection pour le moment.", "collections.no_collections_yet": "Aucune collection pour le moment.",
"collections.old_last_post_note": "Dernière publication il y a plus d'une semaine",
"collections.remove_account": "Supprimer ce compte", "collections.remove_account": "Supprimer ce compte",
"collections.search_accounts_label": "Chercher des comptes à ajouter…", "collections.search_accounts_label": "Chercher des comptes à ajouter…",
"collections.search_accounts_max_reached": "Vous avez ajouté le nombre maximum de comptes", "collections.search_accounts_max_reached": "Vous avez ajouté le nombre maximum de comptes",
"collections.sensitive": "Sensible",
"collections.topic_hint": "Ajouter un hashtag pour aider les autres personnes à comprendre le sujet de la collection.", "collections.topic_hint": "Ajouter un hashtag pour aider les autres personnes à comprendre le sujet de la collection.",
"collections.view_collection": "Voir la collection", "collections.view_collection": "Voir la collection",
"collections.visibility_public": "Publique", "collections.visibility_public": "Publique",
@@ -332,7 +346,7 @@
"community.column_settings.local_only": "Local seulement", "community.column_settings.local_only": "Local seulement",
"community.column_settings.media_only": "Média seulement", "community.column_settings.media_only": "Média seulement",
"community.column_settings.remote_only": "À distance seulement", "community.column_settings.remote_only": "À distance seulement",
"compose.error.blank_post": "Le message ne peut être laissé vide.", "compose.error.blank_post": "Le message ne peut pas être vide.",
"compose.language.change": "Changer de langue", "compose.language.change": "Changer de langue",
"compose.language.search": "Rechercher des langues…", "compose.language.search": "Rechercher des langues…",
"compose.published.body": "Publiée.", "compose.published.body": "Publiée.",
@@ -369,24 +383,27 @@
"confirmations.delete_list.message": "Voulez-vous vraiment supprimer définitivement cette liste?", "confirmations.delete_list.message": "Voulez-vous vraiment supprimer définitivement cette liste?",
"confirmations.delete_list.title": "Supprimer la liste ?", "confirmations.delete_list.title": "Supprimer la liste ?",
"confirmations.discard_draft.confirm": "Effacer et continuer", "confirmations.discard_draft.confirm": "Effacer et continuer",
"confirmations.discard_draft.edit.cancel": "Retour vers l'éditeur", "confirmations.discard_draft.edit.cancel": "Reprendre l'édition",
"confirmations.discard_draft.edit.message": "Continued va perdre les changements que vous avez faits dans le message courant.", "confirmations.discard_draft.edit.message": "Si vous continuez, toutes les modifications apportées au message en cours d'édition seront annulées.",
"confirmations.discard_draft.edit.title": "Jeter les changements faits au message?", "confirmations.discard_draft.edit.title": "Annuler les modifications apportées à votre message?",
"confirmations.discard_draft.post.cancel": "Retour au brouillon", "confirmations.discard_draft.post.cancel": "Retour au brouillon",
"confirmations.discard_draft.post.message": "En continuant, vous perdez le message que vous êtes en train d'écrire.", "confirmations.discard_draft.post.message": "Si vous continuez, vous supprimerez le message que vous êtes en train de composer.",
"confirmations.discard_draft.post.title": "Jeter le brouillon de message?", "confirmations.discard_draft.post.title": "Abandonner votre brouillon ?",
"confirmations.discard_edit_media.confirm": "Rejeter", "confirmations.discard_edit_media.confirm": "Rejeter",
"confirmations.discard_edit_media.message": "Vous avez des modifications non enregistrées de la description ou de l'aperçu du média, voulez-vous quand même les supprimer?", "confirmations.discard_edit_media.message": "Vous avez des modifications non enregistrées de la description ou de l'aperçu du média, voulez-vous quand même les supprimer?",
"confirmations.follow_to_collection.confirm": "Suivre et ajouter à la collection",
"confirmations.follow_to_collection.message": "Vous devez suivre {name} pour l'ajouter à une collection.",
"confirmations.follow_to_collection.title": "Suivre le compte ?",
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste", "confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.", "confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
"confirmations.follow_to_list.title": "Suivre l'utilisateur ?", "confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
"confirmations.logout.confirm": "Se déconnecter", "confirmations.logout.confirm": "Se déconnecter",
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter?", "confirmations.logout.message": "Voulez-vous vraiment vous déconnecter?",
"confirmations.logout.title": "Se déconnecter ?", "confirmations.logout.title": "Se déconnecter ?",
"confirmations.missing_alt_text.confirm": "Ajouter un texte alternatif", "confirmations.missing_alt_text.confirm": "Ajouter un texte alternatif",
"confirmations.missing_alt_text.message": "Votre post contient des médias sans texte alternatif. Ajouter des descriptions rend votre contenu accessible à un plus grand nombre de personnes.", "confirmations.missing_alt_text.message": "Votre message contient des médias sans texte alternatif. L'ajout de descriptions aide à rendre votre contenu accessible à plus de personnes.",
"confirmations.missing_alt_text.secondary": "Publier quand-même", "confirmations.missing_alt_text.secondary": "Publier quand même",
"confirmations.missing_alt_text.title": "Ajouter un texte alternatif?", "confirmations.missing_alt_text.title": "Ajouter un texte alternatif?",
"confirmations.mute.confirm": "Masquer", "confirmations.mute.confirm": "Masquer",
"confirmations.private_quote_notify.cancel": "Retour à l'édition", "confirmations.private_quote_notify.cancel": "Retour à l'édition",
"confirmations.private_quote_notify.confirm": "Publier", "confirmations.private_quote_notify.confirm": "Publier",
@@ -395,17 +412,17 @@
"confirmations.private_quote_notify.title": "Partager avec les personnes abonnées et mentionnées?", "confirmations.private_quote_notify.title": "Partager avec les personnes abonnées et mentionnées?",
"confirmations.quiet_post_quote_info.dismiss": "Ne plus me rappeler", "confirmations.quiet_post_quote_info.dismiss": "Ne plus me rappeler",
"confirmations.quiet_post_quote_info.got_it": "Compris", "confirmations.quiet_post_quote_info.got_it": "Compris",
"confirmations.quiet_post_quote_info.message": "Lorsque vous citez un message public silencieux, votre message sera caché des fils tendances.", "confirmations.quiet_post_quote_info.message": "Lorsque vous citez un message public discret, votre message sera caché des fils tendances.",
"confirmations.quiet_post_quote_info.title": "Citation de messages publics silencieux", "confirmations.quiet_post_quote_info.title": "Citation d'un message public discret",
"confirmations.redraft.confirm": "Supprimer et réécrire", "confirmations.redraft.confirm": "Supprimer et réécrire",
"confirmations.redraft.message": "Êtes-vous sûr·e de vouloir effacer cette publication pour la réécrire? Ses ses mises en favori et boosts seront perdus et ses réponses seront orphelines.", "confirmations.redraft.message": "Êtes-vous sûr·e de vouloir effacer cette publication pour la réécrire? Ses ses mises en favori et boosts seront perdus et ses réponses seront orphelines.",
"confirmations.redraft.title": "Supprimer et réécrire le message ?", "confirmations.redraft.title": "Supprimer et réécrire le message ?",
"confirmations.remove_from_followers.confirm": "Supprimer l'abonné·e", "confirmations.remove_from_followers.confirm": "Supprimer l'abonné·e",
"confirmations.remove_from_followers.message": "{name} cessera de vous suivre. Êtes-vous sûr de vouloir continuer ?", "confirmations.remove_from_followers.message": "{name} cessera de vous suivre. Voulez-vous vraiment continuer ?",
"confirmations.remove_from_followers.title": "Supprimer l'abonné·e ?", "confirmations.remove_from_followers.title": "Supprimer l'abonné·e ?",
"confirmations.revoke_quote.confirm": "Retirer la publication", "confirmations.revoke_quote.confirm": "Retirer le message",
"confirmations.revoke_quote.message": "Cette action ne peut pas être annulée.", "confirmations.revoke_quote.message": "Cette action ne peut pas être annulée.",
"confirmations.revoke_quote.title": "Retirer la publication ?", "confirmations.revoke_quote.title": "Retirer le message ?",
"confirmations.unblock.confirm": "Débloquer", "confirmations.unblock.confirm": "Débloquer",
"confirmations.unblock.title": "Débloquer {name} ?", "confirmations.unblock.title": "Débloquer {name} ?",
"confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.confirm": "Ne plus suivre",
@@ -430,7 +447,7 @@
"disabled_account_banner.text": "Votre compte {disabledAccount} est présentement désactivé.", "disabled_account_banner.text": "Votre compte {disabledAccount} est présentement désactivé.",
"dismissable_banner.community_timeline": "Voici les publications publiques les plus récentes de personnes dont les comptes sont hébergés par {domain}.", "dismissable_banner.community_timeline": "Voici les publications publiques les plus récentes de personnes dont les comptes sont hébergés par {domain}.",
"dismissable_banner.dismiss": "Rejeter", "dismissable_banner.dismiss": "Rejeter",
"dismissable_banner.public_timeline": "Il s'agit des messages publics les plus récents publiés par des personnes sur le fediverse que les personnes sur {domain} suivent.", "dismissable_banner.public_timeline": "Il s'agit des messages publics les plus récents publiés par des personnes sur le fédivers que les personnes sur {domain} suivent.",
"domain_block_modal.block": "Bloquer le serveur", "domain_block_modal.block": "Bloquer le serveur",
"domain_block_modal.block_account_instead": "Bloquer @{name} à la place", "domain_block_modal.block_account_instead": "Bloquer @{name} à la place",
"domain_block_modal.they_can_interact_with_old_posts": "Les personnes de ce serveur peuvent interagir avec vos anciens messages.", "domain_block_modal.they_can_interact_with_old_posts": "Les personnes de ce serveur peuvent interagir avec vos anciens messages.",
@@ -444,12 +461,12 @@
"domain_pill.activitypub_like_language": "ActivityPub est comme une langue que Mastodon utilise pour communiquer avec les autres réseaux sociaux.", "domain_pill.activitypub_like_language": "ActivityPub est comme une langue que Mastodon utilise pour communiquer avec les autres réseaux sociaux.",
"domain_pill.server": "Serveur", "domain_pill.server": "Serveur",
"domain_pill.their_handle": "Son identifiant :", "domain_pill.their_handle": "Son identifiant :",
"domain_pill.their_server": "Son foyer numérique, là où tous ses posts résident.", "domain_pill.their_server": "Son foyer numérique, là où tous ses messages résident.",
"domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.", "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.",
"domain_pill.username": "Nom dutilisateur", "domain_pill.username": "Nom dutilisateur·rice",
"domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?", "domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?",
"domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.", "domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.",
"domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, vous pouvez interagir avec <button>les autres plateformes sociales implémentant ActivityPub</button>.", "domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, tout le monde peut interagir avec vous à l'aide de <button>plateformes sociales implémentant ActivityPub</button>.",
"domain_pill.your_handle": "Votre identifiant :", "domain_pill.your_handle": "Votre identifiant :",
"domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.", "domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.",
"domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.", "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.",
@@ -1018,7 +1035,7 @@
"server_banner.about_active_users": "Personnes utilisant ce serveur au cours des 30 derniers jours (Comptes actifs mensuellement)", "server_banner.about_active_users": "Personnes utilisant ce serveur au cours des 30 derniers jours (Comptes actifs mensuellement)",
"server_banner.active_users": "comptes actifs", "server_banner.active_users": "comptes actifs",
"server_banner.administered_by": "Administré par:", "server_banner.administered_by": "Administré par:",
"server_banner.is_one_of_many": "{domain} est l'un des nombreux serveurs Mastodon indépendants que vous pouvez utiliser pour participer au fédiverse.", "server_banner.is_one_of_many": "{domain} est l'un des nombreux serveurs Mastodon indépendants que vous pouvez utiliser pour participer au fédivers.",
"server_banner.server_stats": "Statistiques du serveur:", "server_banner.server_stats": "Statistiques du serveur:",
"sign_in_banner.create_account": "Créer un compte", "sign_in_banner.create_account": "Créer un compte",
"sign_in_banner.follow_anyone": "Suivez n'importe qui à travers le fédivers et affichez tout dans un ordre chronologique. Ni algorithmes, ni publicités, ni appâts à clics en perspective.", "sign_in_banner.follow_anyone": "Suivez n'importe qui à travers le fédivers et affichez tout dans un ordre chronologique. Ni algorithmes, ni publicités, ni appâts à clics en perspective.",

View File

@@ -141,15 +141,25 @@
"account.unmute": "Ne plus masquer @{name}", "account.unmute": "Ne plus masquer @{name}",
"account.unmute_notifications_short": "Réactiver les notifications", "account.unmute_notifications_short": "Réactiver les notifications",
"account.unmute_short": "Ne plus masquer", "account.unmute_short": "Ne plus masquer",
"account_edit.bio.placeholder": "Ajouter une courte introduction pour aider à vous connaître.", "account_edit.bio.placeholder": "Ajouter une courte introduction pour aider les autres à vous connaître.",
"account_edit.bio.title": "Présentation", "account_edit.bio.title": "Présentation",
"account_edit.bio_modal.add_title": "Ajouter une présentation", "account_edit.bio_modal.add_title": "Ajouter une présentation",
"account_edit.bio_modal.edit_title": "Modifier la présentation", "account_edit.bio_modal.edit_title": "Modifier la présentation",
"account_edit.char_counter": "{currentLength}/{maxLength} caractères", "account_edit.char_counter": "{currentLength}/{maxLength} caractères",
"account_edit.column_button": "Terminé", "account_edit.column_button": "Terminé",
"account_edit.column_title": "Modifier le profil", "account_edit.column_title": "Modifier le profil",
"account_edit.custom_fields.placeholder": "Ajouter vos pronoms, vos sites, ou tout ce que vous voulez partager.",
"account_edit.custom_fields.title": "Champs personnalisés",
"account_edit.display_name.placeholder": "Votre nom public est le nom qui apparaît sur votre profil et dans les fils d'actualités.",
"account_edit.display_name.title": "Nom public",
"account_edit.featured_hashtags.placeholder": "Aider les autres à identifier et à accéder rapidement à vos sujets préférés.",
"account_edit.featured_hashtags.title": "Hashtags mis en avant",
"account_edit.name_modal.add_title": "Ajouter un nom public",
"account_edit.name_modal.edit_title": "Modifier le nom public",
"account_edit.profile_tab.subtitle": "Personnaliser les onglets de votre profil et leur contenu.",
"account_edit.profile_tab.title": "Paramètres de l'onglet du profil",
"account_edit.save": "Enregistrer", "account_edit.save": "Enregistrer",
"account_edit.section_edit_button": "Éditer", "account_edit.section_edit_button": "Modifier",
"account_note.placeholder": "Cliquez pour ajouter une note", "account_note.placeholder": "Cliquez pour ajouter une note",
"admin.dashboard.daily_retention": "Taux de rétention des utilisateur·rice·s par jour après inscription", "admin.dashboard.daily_retention": "Taux de rétention des utilisateur·rice·s par jour après inscription",
"admin.dashboard.monthly_retention": "Taux de rétention des utilisateur·rice·s par mois après inscription", "admin.dashboard.monthly_retention": "Taux de rétention des utilisateur·rice·s par mois après inscription",
@@ -157,7 +167,7 @@
"admin.dashboard.retention.cohort": "Mois d'inscription", "admin.dashboard.retention.cohort": "Mois d'inscription",
"admin.dashboard.retention.cohort_size": "Nouveaux comptes", "admin.dashboard.retention.cohort_size": "Nouveaux comptes",
"admin.impact_report.instance_accounts": "Profils de comptes que cela supprimerait", "admin.impact_report.instance_accounts": "Profils de comptes que cela supprimerait",
"admin.impact_report.instance_followers": "Abonnées que nos utilisateurs perdraient", "admin.impact_report.instance_followers": "Abonné·e·s que nos utilisateur·rice·s perdraient",
"admin.impact_report.instance_follows": "Abonné·e·s que leurs utilisateur·rice·s perdraient", "admin.impact_report.instance_follows": "Abonné·e·s que leurs utilisateur·rice·s perdraient",
"admin.impact_report.title": "Résumé de l'impact", "admin.impact_report.title": "Résumé de l'impact",
"alert.rate_limited.message": "Veuillez réessayer après {retry_time, time, medium}.", "alert.rate_limited.message": "Veuillez réessayer après {retry_time, time, medium}.",
@@ -238,11 +248,11 @@
"bundle_column_error.network.body": "Une erreur s'est produite lors du chargement de cette page. Cela peut être dû à un problème temporaire avec votre connexion internet ou avec ce serveur.", "bundle_column_error.network.body": "Une erreur s'est produite lors du chargement de cette page. Cela peut être dû à un problème temporaire avec votre connexion internet ou avec ce serveur.",
"bundle_column_error.network.title": "Erreur réseau", "bundle_column_error.network.title": "Erreur réseau",
"bundle_column_error.retry": "Réessayer", "bundle_column_error.retry": "Réessayer",
"bundle_column_error.return": "Retour à l'accueil", "bundle_column_error.return": "Retourner à l'accueil",
"bundle_column_error.routing.body": "La page demandée est introuvable. Êtes-vous sûr que lURL dans la barre dadresse est correcte ?", "bundle_column_error.routing.body": "La page demandée est introuvable. Est-ce que l'URL dans la barre dadresse est correcte ?",
"bundle_column_error.routing.title": "404", "bundle_column_error.routing.title": "404",
"bundle_modal_error.close": "Fermer", "bundle_modal_error.close": "Fermer",
"bundle_modal_error.message": "Un problème s'est produit lors du chargement de cet écran.", "bundle_modal_error.message": "Une erreur sest produite lors du chargement de cet écran.",
"bundle_modal_error.retry": "Réessayer", "bundle_modal_error.retry": "Réessayer",
"callout.dismiss": "Rejeter", "callout.dismiss": "Rejeter",
"carousel.current": "<sr>Diapositive</sr> {current, number} / {max, number}", "carousel.current": "<sr>Diapositive</sr> {current, number} / {max, number}",
@@ -274,6 +284,7 @@
"collections.detail.curated_by_you": "Organisée par vous", "collections.detail.curated_by_you": "Organisée par vous",
"collections.detail.loading": "Chargement de la collection…", "collections.detail.loading": "Chargement de la collection…",
"collections.detail.share": "Partager la collection", "collections.detail.share": "Partager la collection",
"collections.edit_details": "Modifier les détails",
"collections.error_loading_collections": "Une erreur s'est produite durant le chargement de vos collections.", "collections.error_loading_collections": "Une erreur s'est produite durant le chargement de vos collections.",
"collections.hints.accounts_counter": "{count} / {max} comptes", "collections.hints.accounts_counter": "{count} / {max} comptes",
"collections.hints.add_more_accounts": "Ajouter au moins {count, plural, one {# compte} other {# comptes}} pour continuer", "collections.hints.add_more_accounts": "Ajouter au moins {count, plural, one {# compte} other {# comptes}} pour continuer",
@@ -282,11 +293,14 @@
"collections.manage_accounts": "Gérer les comptes", "collections.manage_accounts": "Gérer les comptes",
"collections.mark_as_sensitive": "Marquer comme sensible", "collections.mark_as_sensitive": "Marquer comme sensible",
"collections.mark_as_sensitive_hint": "Masque la description et les comptes de la collection derrière un avertissement au public. Le titre reste visible.", "collections.mark_as_sensitive_hint": "Masque la description et les comptes de la collection derrière un avertissement au public. Le titre reste visible.",
"collections.name_length_hint": "Maximum 40 caractères",
"collections.new_collection": "Nouvelle collection", "collections.new_collection": "Nouvelle collection",
"collections.no_collections_yet": "Aucune collection pour le moment.", "collections.no_collections_yet": "Aucune collection pour le moment.",
"collections.old_last_post_note": "Dernière publication il y a plus d'une semaine",
"collections.remove_account": "Supprimer ce compte", "collections.remove_account": "Supprimer ce compte",
"collections.search_accounts_label": "Chercher des comptes à ajouter…", "collections.search_accounts_label": "Chercher des comptes à ajouter…",
"collections.search_accounts_max_reached": "Vous avez ajouté le nombre maximum de comptes", "collections.search_accounts_max_reached": "Vous avez ajouté le nombre maximum de comptes",
"collections.sensitive": "Sensible",
"collections.topic_hint": "Ajouter un hashtag pour aider les autres personnes à comprendre le sujet de la collection.", "collections.topic_hint": "Ajouter un hashtag pour aider les autres personnes à comprendre le sujet de la collection.",
"collections.view_collection": "Voir la collection", "collections.view_collection": "Voir la collection",
"collections.visibility_public": "Publique", "collections.visibility_public": "Publique",
@@ -295,10 +309,10 @@
"collections.visibility_unlisted": "Non listée", "collections.visibility_unlisted": "Non listée",
"collections.visibility_unlisted_hint": "Visible pour les personnes ayant le lien. N'apparaît pas dans les résultats de recherche et les recommandations.", "collections.visibility_unlisted_hint": "Visible pour les personnes ayant le lien. N'apparaît pas dans les résultats de recherche et les recommandations.",
"column.about": "À propos", "column.about": "À propos",
"column.blocks": "Utilisateurs bloqués", "column.blocks": "Comptes bloqués",
"column.bookmarks": "Marque-pages", "column.bookmarks": "Marque-pages",
"column.collections": "Mes collections", "column.collections": "Mes collections",
"column.community": "Fil public local", "column.community": "Fil local",
"column.create_list": "Créer une liste", "column.create_list": "Créer une liste",
"column.direct": "Mentions privées", "column.direct": "Mentions privées",
"column.directory": "Parcourir les profils", "column.directory": "Parcourir les profils",
@@ -332,10 +346,10 @@
"community.column_settings.local_only": "Local seulement", "community.column_settings.local_only": "Local seulement",
"community.column_settings.media_only": "Média uniquement", "community.column_settings.media_only": "Média uniquement",
"community.column_settings.remote_only": "Distant seulement", "community.column_settings.remote_only": "Distant seulement",
"compose.error.blank_post": "Le message ne peut être laissé vide.", "compose.error.blank_post": "Le message ne peut pas être vide.",
"compose.language.change": "Changer de langue", "compose.language.change": "Modifier la langue",
"compose.language.search": "Rechercher des langues...", "compose.language.search": "Rechercher langue",
"compose.published.body": "Message Publié.", "compose.published.body": "Message publié.",
"compose.published.open": "Ouvrir", "compose.published.open": "Ouvrir",
"compose.saved.body": "Message enregistré.", "compose.saved.body": "Message enregistré.",
"compose_form.direct_message_warning_learn_more": "En savoir plus", "compose_form.direct_message_warning_learn_more": "En savoir plus",
@@ -348,8 +362,8 @@
"compose_form.poll.multiple": "Choix multiple", "compose_form.poll.multiple": "Choix multiple",
"compose_form.poll.option_placeholder": "Option {number}", "compose_form.poll.option_placeholder": "Option {number}",
"compose_form.poll.single": "Choix unique", "compose_form.poll.single": "Choix unique",
"compose_form.poll.switch_to_multiple": "Changer le sondage pour autoriser plusieurs choix", "compose_form.poll.switch_to_multiple": "Modifier le sondage pour autoriser plusieurs choix",
"compose_form.poll.switch_to_single": "Modifier le sondage pour autoriser qu'un seul choix", "compose_form.poll.switch_to_single": "Modifier le sondage pour autoriser un seul choix",
"compose_form.poll.type": "Style", "compose_form.poll.type": "Style",
"compose_form.publish": "Publier", "compose_form.publish": "Publier",
"compose_form.reply": "Répondre", "compose_form.reply": "Répondre",
@@ -369,24 +383,27 @@
"confirmations.delete_list.message": "Voulez-vous vraiment supprimer définitivement cette liste?", "confirmations.delete_list.message": "Voulez-vous vraiment supprimer définitivement cette liste?",
"confirmations.delete_list.title": "Supprimer la liste ?", "confirmations.delete_list.title": "Supprimer la liste ?",
"confirmations.discard_draft.confirm": "Effacer et continuer", "confirmations.discard_draft.confirm": "Effacer et continuer",
"confirmations.discard_draft.edit.cancel": "Retour vers l'éditeur", "confirmations.discard_draft.edit.cancel": "Reprendre l'édition",
"confirmations.discard_draft.edit.message": "Continued va perdre les changements que vous avez faits dans le message courant.", "confirmations.discard_draft.edit.message": "Si vous continuez, toutes les modifications apportées au message en cours d'édition seront annulées.",
"confirmations.discard_draft.edit.title": "Jeter les changements faits au message?", "confirmations.discard_draft.edit.title": "Annuler les modifications apportées à votre message?",
"confirmations.discard_draft.post.cancel": "Retour au brouillon", "confirmations.discard_draft.post.cancel": "Retour au brouillon",
"confirmations.discard_draft.post.message": "En continuant, vous perdez le message que vous êtes en train d'écrire.", "confirmations.discard_draft.post.message": "Si vous continuez, vous supprimerez le message que vous êtes en train de composer.",
"confirmations.discard_draft.post.title": "Jeter le brouillon de message?", "confirmations.discard_draft.post.title": "Abandonner votre brouillon ?",
"confirmations.discard_edit_media.confirm": "Rejeter", "confirmations.discard_edit_media.confirm": "Supprimer",
"confirmations.discard_edit_media.message": "Vous avez des modifications non enregistrées de la description ou de l'aperçu du média, les supprimer quand même ?", "confirmations.discard_edit_media.message": "Vous avez des modifications non enregistrées de la description ou de l'aperçu du média. Voulez-vous les supprimer?",
"confirmations.follow_to_collection.confirm": "Suivre et ajouter à la collection",
"confirmations.follow_to_collection.message": "Vous devez suivre {name} pour l'ajouter à une collection.",
"confirmations.follow_to_collection.title": "Suivre le compte ?",
"confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste", "confirmations.follow_to_list.confirm": "Suivre et ajouter à la liste",
"confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.", "confirmations.follow_to_list.message": "Vous devez suivre {name} pour l'ajouter à une liste.",
"confirmations.follow_to_list.title": "Suivre l'utilisateur ?", "confirmations.follow_to_list.title": "Suivre l'utilisateur·rice ?",
"confirmations.logout.confirm": "Se déconnecter", "confirmations.logout.confirm": "Se déconnecter",
"confirmations.logout.message": "Voulez-vous vraiment vous déconnecter ?", "confirmations.logout.message": "Voulez-vous vraiment vous déconnecter ?",
"confirmations.logout.title": "Se déconnecter ?", "confirmations.logout.title": "Se déconnecter ?",
"confirmations.missing_alt_text.confirm": "Ajouter un texte alternatif", "confirmations.missing_alt_text.confirm": "Ajouter un texte alternatif",
"confirmations.missing_alt_text.message": "Votre post contient des médias sans texte alternatif. Ajouter des descriptions rend votre contenu accessible à un plus grand nombre de personnes.", "confirmations.missing_alt_text.message": "Votre message contient des médias sans texte alternatif. L'ajout de descriptions aide à rendre votre contenu accessible à plus de personnes.",
"confirmations.missing_alt_text.secondary": "Publier quand-même", "confirmations.missing_alt_text.secondary": "Publier quand même",
"confirmations.missing_alt_text.title": "Ajouter un texte alternatif?", "confirmations.missing_alt_text.title": "Ajouter un texte alternatif?",
"confirmations.mute.confirm": "Masquer", "confirmations.mute.confirm": "Masquer",
"confirmations.private_quote_notify.cancel": "Retour à l'édition", "confirmations.private_quote_notify.cancel": "Retour à l'édition",
"confirmations.private_quote_notify.confirm": "Publier", "confirmations.private_quote_notify.confirm": "Publier",
@@ -395,17 +412,17 @@
"confirmations.private_quote_notify.title": "Partager avec les personnes abonnées et mentionnées?", "confirmations.private_quote_notify.title": "Partager avec les personnes abonnées et mentionnées?",
"confirmations.quiet_post_quote_info.dismiss": "Ne plus me rappeler", "confirmations.quiet_post_quote_info.dismiss": "Ne plus me rappeler",
"confirmations.quiet_post_quote_info.got_it": "Compris", "confirmations.quiet_post_quote_info.got_it": "Compris",
"confirmations.quiet_post_quote_info.message": "Lorsque vous citez un message public silencieux, votre message sera caché des fils tendances.", "confirmations.quiet_post_quote_info.message": "Lorsque vous citez un message public discret, votre message sera caché des fils tendances.",
"confirmations.quiet_post_quote_info.title": "Citation de messages publics silencieux", "confirmations.quiet_post_quote_info.title": "Citation d'un message public discret",
"confirmations.redraft.confirm": "Supprimer et ré-écrire", "confirmations.redraft.confirm": "Supprimer et réécrire",
"confirmations.redraft.message": "Voulez-vous vraiment supprimer le message pour le réécrire? Ses partages ainsi que ses mises en favori seront perdues, et ses réponses seront orphelines.", "confirmations.redraft.message": "Voulez-vous vraiment supprimer le message pour le réécrire? Ses partages ainsi que ses mises en favori seront perdus, et ses réponses seront orphelines.",
"confirmations.redraft.title": "Supprimer et réécrire le message ?", "confirmations.redraft.title": "Supprimer et réécrire le message ?",
"confirmations.remove_from_followers.confirm": "Supprimer l'abonné·e", "confirmations.remove_from_followers.confirm": "Supprimer l'abonné·e",
"confirmations.remove_from_followers.message": "{name} cessera de vous suivre. Êtes-vous sûr de vouloir continuer ?", "confirmations.remove_from_followers.message": "{name} cessera de vous suivre. Voulez-vous vraiment continuer ?",
"confirmations.remove_from_followers.title": "Supprimer l'abonné·e ?", "confirmations.remove_from_followers.title": "Supprimer l'abonné·e ?",
"confirmations.revoke_quote.confirm": "Retirer la publication", "confirmations.revoke_quote.confirm": "Retirer le message",
"confirmations.revoke_quote.message": "Cette action ne peut pas être annulée.", "confirmations.revoke_quote.message": "Cette action ne peut pas être annulée.",
"confirmations.revoke_quote.title": "Retirer la publication ?", "confirmations.revoke_quote.title": "Retirer le message ?",
"confirmations.unblock.confirm": "Débloquer", "confirmations.unblock.confirm": "Débloquer",
"confirmations.unblock.title": "Débloquer {name} ?", "confirmations.unblock.title": "Débloquer {name} ?",
"confirmations.unfollow.confirm": "Ne plus suivre", "confirmations.unfollow.confirm": "Ne plus suivre",
@@ -422,15 +439,15 @@
"copy_icon_button.copied": "Copié dans le presse-papier", "copy_icon_button.copied": "Copié dans le presse-papier",
"copypaste.copied": "Copié", "copypaste.copied": "Copié",
"copypaste.copy_to_clipboard": "Copier dans le presse-papiers", "copypaste.copy_to_clipboard": "Copier dans le presse-papiers",
"directory.federated": "Du fédiverse connu", "directory.federated": "Du fédivers connu",
"directory.local": "De {domain} seulement", "directory.local": "De {domain} seulement",
"directory.new_arrivals": "Inscrit·e·s récemment", "directory.new_arrivals": "Inscrit·e·s récemment",
"directory.recently_active": "Actif·ve·s récemment", "directory.recently_active": "Actif·ve·s récemment",
"disabled_account_banner.account_settings": "Paramètres du compte", "disabled_account_banner.account_settings": "Paramètres du compte",
"disabled_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé.", "disabled_account_banner.text": "Votre compte {disabledAccount} est actuellement désactivé.",
"dismissable_banner.community_timeline": "Voici les messages publics les plus récents des comptes hébergés par {domain}.", "dismissable_banner.community_timeline": "Voici les messages publics les plus récents des comptes hébergés par {domain}.",
"dismissable_banner.dismiss": "Rejeter", "dismissable_banner.dismiss": "Fermer",
"dismissable_banner.public_timeline": "Il s'agit des messages publics les plus récents publiés par des personnes sur le fediverse que les personnes sur {domain} suivent.", "dismissable_banner.public_timeline": "Il s'agit des messages publics les plus récents publiés par des personnes sur le fédivers que les personnes sur {domain} suivent.",
"domain_block_modal.block": "Bloquer le serveur", "domain_block_modal.block": "Bloquer le serveur",
"domain_block_modal.block_account_instead": "Bloquer @{name} à la place", "domain_block_modal.block_account_instead": "Bloquer @{name} à la place",
"domain_block_modal.they_can_interact_with_old_posts": "Les personnes de ce serveur peuvent interagir avec vos anciens messages.", "domain_block_modal.they_can_interact_with_old_posts": "Les personnes de ce serveur peuvent interagir avec vos anciens messages.",
@@ -444,17 +461,17 @@
"domain_pill.activitypub_like_language": "ActivityPub est comme une langue que Mastodon utilise pour communiquer avec les autres réseaux sociaux.", "domain_pill.activitypub_like_language": "ActivityPub est comme une langue que Mastodon utilise pour communiquer avec les autres réseaux sociaux.",
"domain_pill.server": "Serveur", "domain_pill.server": "Serveur",
"domain_pill.their_handle": "Son identifiant :", "domain_pill.their_handle": "Son identifiant :",
"domain_pill.their_server": "Son foyer numérique, là où tous ses posts résident.", "domain_pill.their_server": "Son foyer numérique, là où tous ses messages résident.",
"domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.", "domain_pill.their_username": "Son identifiant unique sur leur serveur. Il est possible de rencontrer des utilisateur·rice·s avec le même nom sur différents serveurs.",
"domain_pill.username": "Nom dutilisateur", "domain_pill.username": "Nom dutilisateur·rice",
"domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?", "domain_pill.whats_in_a_handle": "Qu'est-ce qu'un identifiant ?",
"domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.", "domain_pill.who_they_are": "Comme un identifiant contient le nom et le service hébergeant une personne, vous pouvez interagir sur <button>les plateformes sociales implémentant ActivityPub</button>.",
"domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, vous pouvez interagir avec <button>les autres plateformes sociales implémentant ActivityPub</button>.", "domain_pill.who_you_are": "Comme un identifiant indique votre nom et le service vous hébergeant, tout le monde peut interagir avec vous à l'aide de <button>plateformes sociales implémentant ActivityPub</button>.",
"domain_pill.your_handle": "Votre identifiant :", "domain_pill.your_handle": "Votre identifiant :",
"domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.", "domain_pill.your_server": "Votre foyer numérique, là où vos messages résident. Vous souhaitez changer ? Lancez un transfert vers un autre serveur quand vous le voulez et vos abonné·e·s suivront automatiquement.",
"domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.", "domain_pill.your_username": "Votre identifiant unique sur ce serveur. Il est possible de rencontrer des utilisateur·rice·s ayant le même nom d'utilisateur sur différents serveurs.",
"dropdown.empty": "Sélectionner une option", "dropdown.empty": "Sélectionner une option",
"embed.instructions": "Intégrez ce message à votre site en copiant le code ci-dessous.", "embed.instructions": "Intégrer ce message à votre site en copiant le code ci-dessous.",
"embed.preview": "Il apparaîtra comme cela:", "embed.preview": "Il apparaîtra comme cela:",
"emoji_button.activity": "Activités", "emoji_button.activity": "Activités",
"emoji_button.clear": "Effacer", "emoji_button.clear": "Effacer",
@@ -1018,7 +1035,7 @@
"server_banner.about_active_users": "Personnes utilisant ce serveur au cours des 30 derniers jours (Comptes actifs mensuellement)", "server_banner.about_active_users": "Personnes utilisant ce serveur au cours des 30 derniers jours (Comptes actifs mensuellement)",
"server_banner.active_users": "comptes actifs", "server_banner.active_users": "comptes actifs",
"server_banner.administered_by": "Administré par :", "server_banner.administered_by": "Administré par :",
"server_banner.is_one_of_many": "{domain} est l'un des nombreux serveurs Mastodon indépendants que vous pouvez utiliser pour participer au fédiverse.", "server_banner.is_one_of_many": "{domain} est l'un des nombreux serveurs Mastodon indépendants que vous pouvez utiliser pour participer au fédivers.",
"server_banner.server_stats": "Statistiques du serveur :", "server_banner.server_stats": "Statistiques du serveur :",
"sign_in_banner.create_account": "Créer un compte", "sign_in_banner.create_account": "Créer un compte",
"sign_in_banner.follow_anyone": "Suivez n'importe qui à travers le fédivers et affichez tout dans un ordre chronologique. Ni algorithmes, ni publicités, ni appâts à clics en perspective.", "sign_in_banner.follow_anyone": "Suivez n'importe qui à travers le fédivers et affichez tout dans un ordre chronologique. Ni algorithmes, ni publicités, ni appâts à clics en perspective.",
@@ -1120,7 +1137,7 @@
"status.unpin": "Retirer du profil", "status.unpin": "Retirer du profil",
"subscribed_languages.lead": "Seuls les messages dans les langues sélectionnées apparaîtront sur votre fil principal et vos listes de fils après le changement. Sélectionnez aucune pour recevoir les messages dans toutes les langues.", "subscribed_languages.lead": "Seuls les messages dans les langues sélectionnées apparaîtront sur votre fil principal et vos listes de fils après le changement. Sélectionnez aucune pour recevoir les messages dans toutes les langues.",
"subscribed_languages.save": "Enregistrer les modifications", "subscribed_languages.save": "Enregistrer les modifications",
"subscribed_languages.target": "Changer les langues abonnées pour {target}", "subscribed_languages.target": "Modifier les langues d'abonnements pour {target}",
"tabs_bar.home": "Accueil", "tabs_bar.home": "Accueil",
"tabs_bar.menu": "Menu", "tabs_bar.menu": "Menu",
"tabs_bar.notifications": "Notifications", "tabs_bar.notifications": "Notifications",

View File

@@ -141,8 +141,25 @@
"account.unmute": "Deixar de silenciar a @{name}", "account.unmute": "Deixar de silenciar a @{name}",
"account.unmute_notifications_short": "Reactivar notificacións", "account.unmute_notifications_short": "Reactivar notificacións",
"account.unmute_short": "Non silenciar", "account.unmute_short": "Non silenciar",
"account_edit.bio.placeholder": "Escribe unha breve presentación para que te coñezan mellor.",
"account_edit.bio.title": "Sobre ti",
"account_edit.bio_modal.add_title": "Engadir biografía",
"account_edit.bio_modal.edit_title": "Editar biografía",
"account_edit.char_counter": "{currentLength}/{maxLength} caracteres",
"account_edit.column_button": "Feito", "account_edit.column_button": "Feito",
"account_edit.column_title": "Editar perfil", "account_edit.column_title": "Editar perfil",
"account_edit.custom_fields.placeholder": "Engade os teus pronomes, ligazóns externas, ou o que queiras compartir.",
"account_edit.custom_fields.title": "Campos personalizados",
"account_edit.display_name.placeholder": "O nome público é o nome que aparece no perfil e nas cronoloxías.",
"account_edit.display_name.title": "Nome público",
"account_edit.featured_hashtags.placeholder": "Facilita que te identifiquen, e da acceso rápido aos teus intereses favoritos.",
"account_edit.featured_hashtags.title": "Cancelos destacados",
"account_edit.name_modal.add_title": "Engadir nome público",
"account_edit.name_modal.edit_title": "Editar o nome público",
"account_edit.profile_tab.subtitle": "Personaliza as pestanas e o seu contido no teu perfil.",
"account_edit.profile_tab.title": "Perfil e axustes das pestanas",
"account_edit.save": "Gardar",
"account_edit.section_edit_button": "Editar",
"account_note.placeholder": "Preme para engadir nota", "account_note.placeholder": "Preme para engadir nota",
"admin.dashboard.daily_retention": "Ratio de retención de usuarias diaria após rexistrarse", "admin.dashboard.daily_retention": "Ratio de retención de usuarias diaria após rexistrarse",
"admin.dashboard.monthly_retention": "Ratio de retención de usuarias mensual após o rexistro", "admin.dashboard.monthly_retention": "Ratio de retención de usuarias mensual após o rexistro",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "Seleccionadas por ti", "collections.detail.curated_by_you": "Seleccionadas por ti",
"collections.detail.loading": "Cargando colección…", "collections.detail.loading": "Cargando colección…",
"collections.detail.share": "Compartir esta colección", "collections.detail.share": "Compartir esta colección",
"collections.edit_details": "Editar detalles",
"collections.error_loading_collections": "Houbo un erro ao intentar cargar as túas coleccións.", "collections.error_loading_collections": "Houbo un erro ao intentar cargar as túas coleccións.",
"collections.hints.accounts_counter": "{count} / {max} contas", "collections.hints.accounts_counter": "{count} / {max} contas",
"collections.hints.add_more_accounts": "Engade polo menos {count, plural, one {# conta} other {# contas}} para continuar", "collections.hints.add_more_accounts": "Engade polo menos {count, plural, one {# conta} other {# contas}} para continuar",
@@ -275,11 +293,14 @@
"collections.manage_accounts": "Xestionar contas", "collections.manage_accounts": "Xestionar contas",
"collections.mark_as_sensitive": "Marcar como sensible", "collections.mark_as_sensitive": "Marcar como sensible",
"collections.mark_as_sensitive_hint": "Oculta a descrición e contas da colección detrás dun aviso sobre o contido. O nome da colección permanece visible.", "collections.mark_as_sensitive_hint": "Oculta a descrición e contas da colección detrás dun aviso sobre o contido. O nome da colección permanece visible.",
"collections.name_length_hint": "Límite de 40 caracteres",
"collections.new_collection": "Nova colección", "collections.new_collection": "Nova colección",
"collections.no_collections_yet": "Aínda non tes coleccións.", "collections.no_collections_yet": "Aínda non tes coleccións.",
"collections.old_last_post_note": "Hai máis dunha semana da última publicación",
"collections.remove_account": "Retirar esta conta", "collections.remove_account": "Retirar esta conta",
"collections.search_accounts_label": "Buscar contas para engadir…", "collections.search_accounts_label": "Buscar contas para engadir…",
"collections.search_accounts_max_reached": "Acadaches o máximo de contas permitidas", "collections.search_accounts_max_reached": "Acadaches o máximo de contas permitidas",
"collections.sensitive": "Sensible",
"collections.topic_hint": "Engadir un cancelo para que axudar a que outras persoas coñezan a temática desta colección.", "collections.topic_hint": "Engadir un cancelo para que axudar a que outras persoas coñezan a temática desta colección.",
"collections.view_collection": "Ver colección", "collections.view_collection": "Ver colección",
"collections.visibility_public": "Pública", "collections.visibility_public": "Pública",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "Desbotar o borrador?", "confirmations.discard_draft.post.title": "Desbotar o borrador?",
"confirmations.discard_edit_media.confirm": "Descartar", "confirmations.discard_edit_media.confirm": "Descartar",
"confirmations.discard_edit_media.message": "Tes cambios sen gardar para a vista previa ou descrición do multimedia, descartamos os cambios?", "confirmations.discard_edit_media.message": "Tes cambios sen gardar para a vista previa ou descrición do multimedia, descartamos os cambios?",
"confirmations.follow_to_collection.confirm": "Seguir e engadir á colección",
"confirmations.follow_to_collection.message": "Tes que seguir a {name} para poder engadila a unha colección.",
"confirmations.follow_to_collection.title": "Seguir a conta?",
"confirmations.follow_to_list.confirm": "Seguir e engadir á lista", "confirmations.follow_to_list.confirm": "Seguir e engadir á lista",
"confirmations.follow_to_list.message": "Tes que seguir a {name} para poder engadila a unha lista.", "confirmations.follow_to_list.message": "Tes que seguir a {name} para poder engadila a unha lista.",
"confirmations.follow_to_list.title": "Seguir á usuaria?", "confirmations.follow_to_list.title": "Seguir á usuaria?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "הפסקת השתקת @{name}", "account.unmute": "הפסקת השתקת @{name}",
"account.unmute_notifications_short": "הפעלת הודעות", "account.unmute_notifications_short": "הפעלת הודעות",
"account.unmute_short": "ביטול השתקה", "account.unmute_short": "ביטול השתקה",
"account_edit.bio.placeholder": "הוסיפו הצגה קצרה כדי לעזור לאחרים לזהות אותך.",
"account_edit.bio.title": "ביוגרפיה",
"account_edit.bio_modal.add_title": "הוסיפו ביוגרפיה",
"account_edit.bio_modal.edit_title": "עריכת ביוגרפיה",
"account_edit.char_counter": "{currentLength}/{maxLength} תווים",
"account_edit.column_button": "סיום", "account_edit.column_button": "סיום",
"account_edit.column_title": "עריכת הפרופיל", "account_edit.column_title": "עריכת הפרופיל",
"account_edit.custom_fields.placeholder": "הוסיפו צורת פניה, קישורים חיצוניים וכל דבר שתרצו לשתף.",
"account_edit.custom_fields.title": "שדות בהתאמה אישית",
"account_edit.display_name.placeholder": "שם התצוגה שלכן הוא איך שהשם יופיע בפרופיל ובצירי הזמנים.",
"account_edit.display_name.title": "שם תצוגה",
"account_edit.featured_hashtags.placeholder": "עזרו לאחרים לזהות ולגשת בקלות לנושאים החביבים עליכם.",
"account_edit.featured_hashtags.title": "תגיות נבחרות",
"account_edit.name_modal.add_title": "הוספת שם תצוגה",
"account_edit.name_modal.edit_title": "עריכת שם תצוגה",
"account_edit.profile_tab.subtitle": "התאימו את הטאבים בפרופיל שלכם ומה שהם יציגו.",
"account_edit.profile_tab.title": "הגדרות טאבים לפרופיל",
"account_edit.save": "שמירה",
"account_edit.section_edit_button": "עריכה",
"account_note.placeholder": "יש ללחוץ כדי להוסיף הערות", "account_note.placeholder": "יש ללחוץ כדי להוסיף הערות",
"admin.dashboard.daily_retention": "קצב שימור משתמשים יומי אחרי ההרשמה", "admin.dashboard.daily_retention": "קצב שימור משתמשים יומי אחרי ההרשמה",
"admin.dashboard.monthly_retention": "קצב שימור משתמשים (פר חודש) אחרי ההרשמה", "admin.dashboard.monthly_retention": "קצב שימור משתמשים (פר חודש) אחרי ההרשמה",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "נאצר על ידיך", "collections.detail.curated_by_you": "נאצר על ידיך",
"collections.detail.loading": "טוען אוסף…", "collections.detail.loading": "טוען אוסף…",
"collections.detail.share": "שיתוף אוסף", "collections.detail.share": "שיתוף אוסף",
"collections.edit_details": "עריכת פרטים",
"collections.error_loading_collections": "חלה שגיאה בנסיון לטעון את אוספיך.", "collections.error_loading_collections": "חלה שגיאה בנסיון לטעון את אוספיך.",
"collections.hints.accounts_counter": "{count} \\ {max} חשבונות", "collections.hints.accounts_counter": "{count} \\ {max} חשבונות",
"collections.hints.add_more_accounts": "הוסיפו לפחות {count, plural,one {חשבון אחד}other {# חשבונות}} כדי להמשיך", "collections.hints.add_more_accounts": "הוסיפו לפחות {count, plural,one {חשבון אחד}other {# חשבונות}} כדי להמשיך",
@@ -275,11 +293,14 @@
"collections.manage_accounts": "ניהול חשבונות", "collections.manage_accounts": "ניהול חשבונות",
"collections.mark_as_sensitive": "מסומנים כרגישים", "collections.mark_as_sensitive": "מסומנים כרגישים",
"collections.mark_as_sensitive_hint": "הסתרת תיאור וחשבונות האוסף מאחורי אזהרת תוכן. שם האוסף עדיין ישאר גלוי.", "collections.mark_as_sensitive_hint": "הסתרת תיאור וחשבונות האוסף מאחורי אזהרת תוכן. שם האוסף עדיין ישאר גלוי.",
"collections.name_length_hint": "מגבלה של 40 תווים",
"collections.new_collection": "אוסף חדש", "collections.new_collection": "אוסף חדש",
"collections.no_collections_yet": "עוד אין אוספים.", "collections.no_collections_yet": "עוד אין אוספים.",
"collections.old_last_post_note": "פרסמו לאחרונה לפני יותר משבוע",
"collections.remove_account": "הסר חשבון זה", "collections.remove_account": "הסר חשבון זה",
"collections.search_accounts_label": "לחפש חשבונות להוספה…", "collections.search_accounts_label": "לחפש חשבונות להוספה…",
"collections.search_accounts_max_reached": "הגעת למספר החשבונות המירבי", "collections.search_accounts_max_reached": "הגעת למספר החשבונות המירבי",
"collections.sensitive": "רגיש",
"collections.topic_hint": "הוספת תגית שמסייעת לאחרים להבין את הנושא הראשי של האוסף.", "collections.topic_hint": "הוספת תגית שמסייעת לאחרים להבין את הנושא הראשי של האוסף.",
"collections.view_collection": "צפיה באוסף", "collections.view_collection": "צפיה באוסף",
"collections.visibility_public": "פומבי", "collections.visibility_public": "פומבי",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "לוותר על הטיוטא?", "confirmations.discard_draft.post.title": "לוותר על הטיוטא?",
"confirmations.discard_edit_media.confirm": "השלך", "confirmations.discard_edit_media.confirm": "השלך",
"confirmations.discard_edit_media.message": "יש לך שינויים לא שמורים לתיאור המדיה. להשליך אותם בכל זאת?", "confirmations.discard_edit_media.message": "יש לך שינויים לא שמורים לתיאור המדיה. להשליך אותם בכל זאת?",
"confirmations.follow_to_collection.confirm": "עקיבה והוספה לאוסף",
"confirmations.follow_to_collection.message": "כדי להכניס את {name} לאוסף, ראשית יש לעקוב אחריהם.",
"confirmations.follow_to_collection.title": "לעקוב אחר החשבון?",
"confirmations.follow_to_list.confirm": "עקיבה והוספה לרשימה", "confirmations.follow_to_list.confirm": "עקיבה והוספה לרשימה",
"confirmations.follow_to_list.message": "כדי להכניס את {name} לרשימה, ראשית יש לעקוב אחריהם.", "confirmations.follow_to_list.message": "כדי להכניס את {name} לרשימה, ראשית יש לעקוב אחריהם.",
"confirmations.follow_to_list.title": "לעקוב אחר המשתמש.ת?", "confirmations.follow_to_list.title": "לעקוב אחר המשתמש.ת?",

View File

@@ -8,10 +8,13 @@
"about.domain_blocks.silenced.title": "Ograničen", "about.domain_blocks.silenced.title": "Ograničen",
"about.domain_blocks.suspended.explanation": "Podatci s ovog poslužitelja neće se obrađivati, pohranjivati ili razmjenjivati, što onemogućuje bilo kakvu interakciju ili komunikaciju s korisnicima s ovog poslužitelja.", "about.domain_blocks.suspended.explanation": "Podatci s ovog poslužitelja neće se obrađivati, pohranjivati ili razmjenjivati, što onemogućuje bilo kakvu interakciju ili komunikaciju s korisnicima s ovog poslužitelja.",
"about.domain_blocks.suspended.title": "Suspendiran", "about.domain_blocks.suspended.title": "Suspendiran",
"about.language_label": "Jezik",
"about.not_available": "Te informacije nisu dostupne na ovom poslužitelju.", "about.not_available": "Te informacije nisu dostupne na ovom poslužitelju.",
"about.powered_by": "Decentralizirani društveni mediji koje pokreće {mastodon}", "about.powered_by": "Decentralizirani društveni mediji koje pokreće {mastodon}",
"about.rules": "Pravila servera", "about.rules": "Pravila servera",
"account.activity": "Aktivnost",
"account.add_or_remove_from_list": "Dodaj ili ukloni s liste", "account.add_or_remove_from_list": "Dodaj ili ukloni s liste",
"account.badges.admin": "Admin",
"account.badges.bot": "Bot", "account.badges.bot": "Bot",
"account.badges.group": "Grupa", "account.badges.group": "Grupa",
"account.block": "Blokiraj @{name}", "account.block": "Blokiraj @{name}",
@@ -23,12 +26,16 @@
"account.direct": "Privatno spomeni @{name}", "account.direct": "Privatno spomeni @{name}",
"account.disable_notifications": "Nemoj me obavjestiti kada @{name} napravi objavu", "account.disable_notifications": "Nemoj me obavjestiti kada @{name} napravi objavu",
"account.edit_profile": "Uredi profil", "account.edit_profile": "Uredi profil",
"account.edit_profile_short": "Uredi",
"account.enable_notifications": "Obavjesti me kada @{name} napravi objavu", "account.enable_notifications": "Obavjesti me kada @{name} napravi objavu",
"account.endorse": "Istakni na profilu", "account.endorse": "Istakni na profilu",
"account.featured_tags.last_status_at": "Zadnji post {date}", "account.featured_tags.last_status_at": "Zadnji post {date}",
"account.featured_tags.last_status_never": "Nema postova", "account.featured_tags.last_status_never": "Nema postova",
"account.follow": "Prati", "account.follow": "Prati",
"account.follow_back": "Slijedi natrag", "account.follow_back": "Slijedi natrag",
"account.follow_request_cancel": "Poništi zahtjev",
"account.follow_request_cancel_short": "Odustani",
"account.follow_request_short": "Zatraži",
"account.followers": "Pratitelji", "account.followers": "Pratitelji",
"account.followers.empty": "Nitko još ne prati korisnika/cu.", "account.followers.empty": "Nitko još ne prati korisnika/cu.",
"account.following": "Pratim", "account.following": "Pratim",
@@ -42,11 +49,19 @@
"account.locked_info": "Status privatnosti ovog računa postavljen je na zaključano. Vlasnik ručno pregledava tko ih može pratiti.", "account.locked_info": "Status privatnosti ovog računa postavljen je na zaključano. Vlasnik ručno pregledava tko ih može pratiti.",
"account.media": "Medijski sadržaj", "account.media": "Medijski sadržaj",
"account.mention": "Spomeni @{name}", "account.mention": "Spomeni @{name}",
"account.menu.block": "Blokiraj račun",
"account.menu.block_domain": "Blokiraj {domain}",
"account.menu.copy": "Kopiraj poveznicu",
"account.menu.mention": "Spomeni",
"account.menu.remove_follower": "Ukloni pratitelja",
"account.menu.report": "Prijavi račun",
"account.mute": "Utišaj @{name}", "account.mute": "Utišaj @{name}",
"account.mute_notifications_short": "Utišaj obavijesti", "account.mute_notifications_short": "Utišaj obavijesti",
"account.mute_short": "Utišaj", "account.mute_short": "Utišaj",
"account.muted": "Utišano", "account.muted": "Utišano",
"account.no_bio": "Nije dan opis.", "account.no_bio": "Nije dan opis.",
"account.node_modal.save": "Spremi",
"account.note.edit_button": "Uredi",
"account.open_original_page": "Otvori originalnu stranicu", "account.open_original_page": "Otvori originalnu stranicu",
"account.posts": "Objave", "account.posts": "Objave",
"account.posts_with_replies": "Objave i odgovori", "account.posts_with_replies": "Objave i odgovori",
@@ -62,6 +77,17 @@
"account.unmute": "Poništi utišavanje @{name}", "account.unmute": "Poništi utišavanje @{name}",
"account.unmute_notifications_short": "Uključi utišane obavijesti", "account.unmute_notifications_short": "Uključi utišane obavijesti",
"account.unmute_short": "Poništi utišavanje", "account.unmute_short": "Poništi utišavanje",
"account_edit.bio.title": "Biografija",
"account_edit.bio_modal.add_title": "Dodaj biografiju",
"account_edit.bio_modal.edit_title": "Uredi biografiju",
"account_edit.char_counter": "{currentLength}/{maxLength} znakova",
"account_edit.column_button": "Završi",
"account_edit.column_title": "Uredi profil",
"account_edit.custom_fields.title": "Prilagođena polja",
"account_edit.featured_hashtags.title": "Istaknuti hashtagovi",
"account_edit.profile_tab.title": "Prikaz kartice profila",
"account_edit.save": "Spremi",
"account_edit.section_edit_button": "Uredi",
"account_note.placeholder": "Kliknite za dodavanje bilješke", "account_note.placeholder": "Kliknite za dodavanje bilješke",
"admin.dashboard.daily_retention": "Stopa zadržavanja korisnika po danu nakon prijave", "admin.dashboard.daily_retention": "Stopa zadržavanja korisnika po danu nakon prijave",
"admin.dashboard.monthly_retention": "Stopa zadržavanja korisnika po mjesecu nakon prijave", "admin.dashboard.monthly_retention": "Stopa zadržavanja korisnika po mjesecu nakon prijave",
@@ -76,7 +102,15 @@
"alert.rate_limited.title": "Ograničenje učestalosti", "alert.rate_limited.title": "Ograničenje učestalosti",
"alert.unexpected.message": "Dogodila se neočekivana greška.", "alert.unexpected.message": "Dogodila se neočekivana greška.",
"alert.unexpected.title": "Ups!", "alert.unexpected.title": "Ups!",
"alt_text_badge.title": "Alternativni tekst",
"alt_text_modal.add_alt_text": "Dodaj altenativni tekst",
"alt_text_modal.add_text_from_image": "Dodaj tekst iz slike",
"alt_text_modal.cancel": "Odustani",
"alt_text_modal.done": "Gotovo",
"announcement.announcement": "Najava", "announcement.announcement": "Najava",
"annual_report.announcement.action_dismiss": "Ne hvala",
"annual_report.nav_item.badge": "Novi",
"annual_report.shared_page.donate": "Doniraj",
"attachments_list.unprocessed": "(neobrađeno)", "attachments_list.unprocessed": "(neobrađeno)",
"audio.hide": "Sakrij audio", "audio.hide": "Sakrij audio",
"boost_modal.combo": "Možete pritisnuti {combo} kako biste preskočili ovo sljedeći put", "boost_modal.combo": "Možete pritisnuti {combo} kako biste preskočili ovo sljedeći put",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "40 stafa takmörk", "collections.name_length_hint": "40 stafa takmörk",
"collections.new_collection": "Nýtt safn", "collections.new_collection": "Nýtt safn",
"collections.no_collections_yet": "Engin söfn ennþá.", "collections.no_collections_yet": "Engin söfn ennþá.",
"collections.old_last_post_note": "Birti síðast fyrir meira en viku síðan",
"collections.remove_account": "Fjarlægja þennan aðgang", "collections.remove_account": "Fjarlægja þennan aðgang",
"collections.search_accounts_label": "Leita að aðgöngum til að bæta við…", "collections.search_accounts_label": "Leita að aðgöngum til að bæta við…",
"collections.search_accounts_max_reached": "Þú hefur þegar bætt við leyfilegum hámarksfjölda aðganga", "collections.search_accounts_max_reached": "Þú hefur þegar bætt við leyfilegum hámarksfjölda aðganga",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?", "confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?",
"confirmations.discard_edit_media.confirm": "Henda", "confirmations.discard_edit_media.confirm": "Henda",
"confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?", "confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?",
"confirmations.follow_to_collection.confirm": "Fylgjast með og bæta í safn",
"confirmations.follow_to_collection.message": "Þú þarft að fylgjast með {name} til að geta bætt viðkomandi í safn.",
"confirmations.follow_to_collection.title": "Fylgjast með notandaaðgangnum?",
"confirmations.follow_to_list.confirm": "Fylgjast með og bæta á lista", "confirmations.follow_to_list.confirm": "Fylgjast með og bæta á lista",
"confirmations.follow_to_list.message": "Þú þarft að fylgjast með {name} til að bæta viðkomandi á lista.", "confirmations.follow_to_list.message": "Þú þarft að fylgjast með {name} til að bæta viðkomandi á lista.",
"confirmations.follow_to_list.title": "Fylgjast með notanda?", "confirmations.follow_to_list.title": "Fylgjast með notanda?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Limite di 40 caratteri", "collections.name_length_hint": "Limite di 40 caratteri",
"collections.new_collection": "Nuova collezione", "collections.new_collection": "Nuova collezione",
"collections.no_collections_yet": "Nessuna collezione ancora.", "collections.no_collections_yet": "Nessuna collezione ancora.",
"collections.old_last_post_note": "Ultimo post più di una settimana fa",
"collections.remove_account": "Rimuovi questo account", "collections.remove_account": "Rimuovi questo account",
"collections.search_accounts_label": "Cerca account da aggiungere…", "collections.search_accounts_label": "Cerca account da aggiungere…",
"collections.search_accounts_max_reached": "Hai aggiunto il numero massimo di account", "collections.search_accounts_max_reached": "Hai aggiunto il numero massimo di account",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Scartare la tua bozza del post?", "confirmations.discard_draft.post.title": "Scartare la tua bozza del post?",
"confirmations.discard_edit_media.confirm": "Scarta", "confirmations.discard_edit_media.confirm": "Scarta",
"confirmations.discard_edit_media.message": "Hai delle modifiche non salvate alla descrizione o anteprima del media, scartarle comunque?", "confirmations.discard_edit_media.message": "Hai delle modifiche non salvate alla descrizione o anteprima del media, scartarle comunque?",
"confirmations.follow_to_collection.confirm": "Segui e aggiungi alla collezione",
"confirmations.follow_to_collection.message": "Devi seguire {name} per aggiungerlo/a ad una collezione.",
"confirmations.follow_to_collection.title": "Seguire l'account?",
"confirmations.follow_to_list.confirm": "Segui e aggiungi alla lista", "confirmations.follow_to_list.confirm": "Segui e aggiungi alla lista",
"confirmations.follow_to_list.message": "Devi seguire {name} per aggiungerli a una lista.", "confirmations.follow_to_list.message": "Devi seguire {name} per aggiungerli a una lista.",
"confirmations.follow_to_list.title": "Seguire l'utente?", "confirmations.follow_to_list.title": "Seguire l'utente?",

View File

@@ -141,6 +141,25 @@
"account.unmute": "取消消音 @{name}", "account.unmute": "取消消音 @{name}",
"account.unmute_notifications_short": "Kā通知取消消音", "account.unmute_notifications_short": "Kā通知取消消音",
"account.unmute_short": "取消消音", "account.unmute_short": "取消消音",
"account_edit.bio.placeholder": "加一段短紹介幫tsān別lâng認捌lí。",
"account_edit.bio.title": "個人紹介",
"account_edit.bio_modal.add_title": "加添個人紹介",
"account_edit.bio_modal.edit_title": "編個人紹介",
"account_edit.char_counter": "{currentLength}/{maxLength} ê字",
"account_edit.column_button": "做好ah",
"account_edit.column_title": "編輯個人資料",
"account_edit.custom_fields.placeholder": "加lí ê代名詞、外部連結á是其他lí beh分享ê。",
"account_edit.custom_fields.title": "自訂欄",
"account_edit.display_name.placeholder": "Lí ê顯示ê名是lí ê名佇lí ê個人資料kap時間線出現ê方式。",
"account_edit.display_name.title": "顯示ê名",
"account_edit.featured_hashtags.placeholder": "幫tsān別lâng認捌kap緊緊接近使用lí收藏ê主題。",
"account_edit.featured_hashtags.title": "特色ê hashtag",
"account_edit.name_modal.add_title": "加添顯示ê名",
"account_edit.name_modal.edit_title": "編顯示ê名",
"account_edit.profile_tab.subtitle": "自訂lí ê個人資料ê分頁kap顯示ê內容。",
"account_edit.profile_tab.title": "個人資料分頁設定",
"account_edit.save": "儲存",
"account_edit.section_edit_button": "編輯",
"account_note.placeholder": "Tshi̍h tse加註kha", "account_note.placeholder": "Tshi̍h tse加註kha",
"admin.dashboard.daily_retention": "註冊以後ê用者維持率用kang計算", "admin.dashboard.daily_retention": "註冊以後ê用者維持率用kang計算",
"admin.dashboard.monthly_retention": "註冊以後ê用者維持率", "admin.dashboard.monthly_retention": "註冊以後ê用者維持率",
@@ -244,9 +263,12 @@
"closed_registrations_modal.preamble": "因為Mastodon非中心化所以bô論tī tá tsi̍t ê服侍器建立口座lí lóng ē當跟tuè tsi̍t ê服侍器ê逐ê lângkap hām in交流。Lí iā ē當ka-tī起tsi̍t ê站!", "closed_registrations_modal.preamble": "因為Mastodon非中心化所以bô論tī tá tsi̍t ê服侍器建立口座lí lóng ē當跟tuè tsi̍t ê服侍器ê逐ê lângkap hām in交流。Lí iā ē當ka-tī起tsi̍t ê站!",
"closed_registrations_modal.title": "註冊 Mastodon ê口座", "closed_registrations_modal.title": "註冊 Mastodon ê口座",
"collections.account_count": "{count, plural, other {# ê口座}}", "collections.account_count": "{count, plural, other {# ê口座}}",
"collections.accounts.empty_description": "加lí跟tuè ê口座上tsē {count} ê",
"collections.accounts.empty_title": "收藏內底無半項",
"collections.collection_description": "說明", "collections.collection_description": "說明",
"collections.collection_name": "名", "collections.collection_name": "名",
"collections.collection_topic": "主題", "collections.collection_topic": "主題",
"collections.confirm_account_removal": "Lí確定beh對收藏suá掉tsit ê口座?",
"collections.content_warning": "內容警告", "collections.content_warning": "內容警告",
"collections.continue": "繼續", "collections.continue": "繼續",
"collections.create.accounts_subtitle": "Kan-ta通加lí所綴而且選擇加入探索ê。", "collections.create.accounts_subtitle": "Kan-ta通加lí所綴而且選擇加入探索ê。",
@@ -257,13 +279,28 @@
"collections.create_collection": "建立收藏", "collections.create_collection": "建立收藏",
"collections.delete_collection": "Thâi掉收藏", "collections.delete_collection": "Thâi掉收藏",
"collections.description_length_hint": "限制 100 字", "collections.description_length_hint": "限制 100 字",
"collections.detail.accounts_heading": "口座",
"collections.detail.curated_by_author": "{author} 揀ê",
"collections.detail.curated_by_you": "Lí揀ê",
"collections.detail.loading": "載入收藏……",
"collections.detail.share": "分享tsit ê收藏",
"collections.edit_details": "編輯詳細",
"collections.error_loading_collections": "佇載入lí ê收藏ê時陣出tshê。", "collections.error_loading_collections": "佇載入lí ê收藏ê時陣出tshê。",
"collections.hints.accounts_counter": "{count} / {max} ê口座",
"collections.hints.add_more_accounts": "加上無 {count, plural, other {# ê口座}}來繼續",
"collections.hints.can_not_remove_more_accounts": "收藏定著愛上無 {count, plural, other {# ê口座}}。Bē當suá掉koh較tsē口座。",
"collections.last_updated_at": "上尾更新tī{date}", "collections.last_updated_at": "上尾更新tī{date}",
"collections.manage_accounts": "管理口座", "collections.manage_accounts": "管理口座",
"collections.mark_as_sensitive": "標做敏感ê", "collections.mark_as_sensitive": "標做敏感ê",
"collections.mark_as_sensitive_hint": "Kā收藏ê描述kap口座tshàng佇內容警告ê後壁。收藏ê名猶原會當看。", "collections.mark_as_sensitive_hint": "Kā收藏ê描述kap口座tshàng佇內容警告ê後壁。收藏ê名猶原會當看。",
"collections.name_length_hint": "限制 40 字",
"collections.new_collection": "新ê收藏", "collections.new_collection": "新ê收藏",
"collections.no_collections_yet": "Iáu無收藏。", "collections.no_collections_yet": "Iáu無收藏。",
"collections.old_last_post_note": "頂改佇超過一禮拜進前PO文",
"collections.remove_account": "Suá掉tsit ê口座",
"collections.search_accounts_label": "Tshuē口座來加添……",
"collections.search_accounts_max_reached": "Lí已經加kàu口座數ê盡磅ah。",
"collections.sensitive": "敏感ê",
"collections.topic_hint": "加 hashtag幫tsān別lâng了解tsit ê收藏ê主題。", "collections.topic_hint": "加 hashtag幫tsān別lâng了解tsit ê收藏ê主題。",
"collections.view_collection": "看收藏", "collections.view_collection": "看收藏",
"collections.visibility_public": "公共ê", "collections.visibility_public": "公共ê",
@@ -354,6 +391,9 @@
"confirmations.discard_draft.post.title": "Kám beh棄sak lí PO文ê草稿", "confirmations.discard_draft.post.title": "Kám beh棄sak lí PO文ê草稿",
"confirmations.discard_edit_media.confirm": "棄sak", "confirmations.discard_edit_media.confirm": "棄sak",
"confirmations.discard_edit_media.message": "Lí佇媒體敘述á是先看māi ê所在有iáu buē儲存ê改變kám beh kā in棄sak", "confirmations.discard_edit_media.message": "Lí佇媒體敘述á是先看māi ê所在有iáu buē儲存ê改變kám beh kā in棄sak",
"confirmations.follow_to_collection.confirm": "跟tuè加入kàu收藏",
"confirmations.follow_to_collection.message": "Beh kā {name} 加添kàu收藏lí tio̍h先跟tuè伊。",
"confirmations.follow_to_collection.title": "敢beh跟tuè口座",
"confirmations.follow_to_list.confirm": "跟tuè加入kàu列單", "confirmations.follow_to_list.confirm": "跟tuè加入kàu列單",
"confirmations.follow_to_list.message": "Beh kā {name} 加添kàu列單lí tio̍h先跟tuè伊。", "confirmations.follow_to_list.message": "Beh kā {name} 加添kàu列單lí tio̍h先跟tuè伊。",
"confirmations.follow_to_list.title": "Kám beh跟tuè tsit ê用者?", "confirmations.follow_to_list.title": "Kám beh跟tuè tsit ê用者?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "@{name} niet langer negeren", "account.unmute": "@{name} niet langer negeren",
"account.unmute_notifications_short": "Meldingen niet langer negeren", "account.unmute_notifications_short": "Meldingen niet langer negeren",
"account.unmute_short": "Niet langer negeren", "account.unmute_short": "Niet langer negeren",
"account_edit.bio.placeholder": "Voeg een korte introductie toe om anderen te helpen je te identificeren.",
"account_edit.bio.title": "Biografie",
"account_edit.bio_modal.add_title": "Biografie toevoegen",
"account_edit.bio_modal.edit_title": "Biografie bewerken",
"account_edit.char_counter": "{currentLength}/{maxLength} tekens",
"account_edit.column_button": "Klaar", "account_edit.column_button": "Klaar",
"account_edit.column_title": "Profiel bewerken", "account_edit.column_title": "Profiel bewerken",
"account_edit.custom_fields.placeholder": "Voeg je voornaamwoorden, externe links of iets anders toe dat je wilt delen.",
"account_edit.custom_fields.title": "Aangepaste velden",
"account_edit.display_name.placeholder": "Je weergavenaam wordt weergegeven op jouw profiel en in tijdlijnen.",
"account_edit.display_name.title": "Weergavenaam",
"account_edit.featured_hashtags.placeholder": "Help anderen je favoriete onderwerpen te identificeren en er snel toegang toe te hebben.",
"account_edit.featured_hashtags.title": "Uitgelichte hashtags",
"account_edit.name_modal.add_title": "Weergavenaam toevoegen",
"account_edit.name_modal.edit_title": "Weergavenaam bewerken",
"account_edit.profile_tab.subtitle": "Pas de tabbladen op je profiel aan en wat ze weergeven.",
"account_edit.profile_tab.title": "Instellingen voor tabblad Profiel",
"account_edit.save": "Opslaan",
"account_edit.section_edit_button": "Bewerken",
"account_note.placeholder": "Klik om een opmerking toe te voegen", "account_note.placeholder": "Klik om een opmerking toe te voegen",
"admin.dashboard.daily_retention": "Retentiegraad van gebruikers per dag, vanaf registratie", "admin.dashboard.daily_retention": "Retentiegraad van gebruikers per dag, vanaf registratie",
"admin.dashboard.monthly_retention": "Retentiegraad van gebruikers per maand, vanaf registratie", "admin.dashboard.monthly_retention": "Retentiegraad van gebruikers per maand, vanaf registratie",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "Samengesteld door jou", "collections.detail.curated_by_you": "Samengesteld door jou",
"collections.detail.loading": "Verzameling laden…", "collections.detail.loading": "Verzameling laden…",
"collections.detail.share": "Deze verzameling delen", "collections.detail.share": "Deze verzameling delen",
"collections.edit_details": "Gegevens bewerken",
"collections.error_loading_collections": "Er is een fout opgetreden bij het laden van je verzamelingen.", "collections.error_loading_collections": "Er is een fout opgetreden bij het laden van je verzamelingen.",
"collections.hints.accounts_counter": "{count} / {max} accounts", "collections.hints.accounts_counter": "{count} / {max} accounts",
"collections.hints.add_more_accounts": "Voeg ten minste {count, plural, one {# account} other {# accounts}} toe om door te gaan", "collections.hints.add_more_accounts": "Voeg ten minste {count, plural, one {# account} other {# accounts}} toe om door te gaan",
@@ -275,12 +293,15 @@
"collections.manage_accounts": "Accounts beheren", "collections.manage_accounts": "Accounts beheren",
"collections.mark_as_sensitive": "Als gevoelig markeren", "collections.mark_as_sensitive": "Als gevoelig markeren",
"collections.mark_as_sensitive_hint": "Verbergt de omschrijving en de accounts van de verzameling achter een waarschuwing. De naam van de verzameling blijft zichtbaar.", "collections.mark_as_sensitive_hint": "Verbergt de omschrijving en de accounts van de verzameling achter een waarschuwing. De naam van de verzameling blijft zichtbaar.",
"collections.name_length_hint": "Limiet van 40 tekens",
"collections.new_collection": "Nieuwe verzameling", "collections.new_collection": "Nieuwe verzameling",
"collections.no_collections_yet": "Nog geen verzamelingen.", "collections.no_collections_yet": "Nog geen verzamelingen.",
"collections.old_last_post_note": "Laatst gepost over een week geleden",
"collections.remove_account": "Deze account verwijderen", "collections.remove_account": "Deze account verwijderen",
"collections.search_accounts_label": "Zoek naar accounts om toe te voegen…", "collections.search_accounts_label": "Zoek naar accounts om toe te voegen…",
"collections.search_accounts_max_reached": "Je hebt het maximum aantal accounts toegevoegd", "collections.search_accounts_max_reached": "Je hebt het maximum aantal accounts toegevoegd",
"collections.topic_hint": "Voeg een hashtag toe die anderen helpt het hoofdonderwerp van deze collectie te begrijpen.", "collections.sensitive": "Gevoelig",
"collections.topic_hint": "Voeg een hashtag toe die anderen helpt het hoofdonderwerp van deze verzameling te begrijpen.",
"collections.view_collection": "Verzameling bekijken", "collections.view_collection": "Verzameling bekijken",
"collections.visibility_public": "Openbaar", "collections.visibility_public": "Openbaar",
"collections.visibility_public_hint": "Te zien onder zoekresultaten en in andere gebieden waar aanbevelingen verschijnen.", "collections.visibility_public_hint": "Te zien onder zoekresultaten en in andere gebieden waar aanbevelingen verschijnen.",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "Conceptbericht verwijderen?", "confirmations.discard_draft.post.title": "Conceptbericht verwijderen?",
"confirmations.discard_edit_media.confirm": "Verwijderen", "confirmations.discard_edit_media.confirm": "Verwijderen",
"confirmations.discard_edit_media.message": "Je hebt niet-opgeslagen wijzigingen in de mediabeschrijving of voorvertonning, wil je deze toch verwijderen?", "confirmations.discard_edit_media.message": "Je hebt niet-opgeslagen wijzigingen in de mediabeschrijving of voorvertonning, wil je deze toch verwijderen?",
"confirmations.follow_to_collection.confirm": "Volgen en toevoegen aan verzameling",
"confirmations.follow_to_collection.message": "Je moet {name} volgen om ze aan een verzameling toe te voegen.",
"confirmations.follow_to_collection.title": "Account volgen?",
"confirmations.follow_to_list.confirm": "Volgen en toevoegen aan de lijst", "confirmations.follow_to_list.confirm": "Volgen en toevoegen aan de lijst",
"confirmations.follow_to_list.message": "Je moet {name} volgen om ze toe te voegen aan een lijst.", "confirmations.follow_to_list.message": "Je moet {name} volgen om ze toe te voegen aan een lijst.",
"confirmations.follow_to_list.title": "Gebruiker volgen?", "confirmations.follow_to_list.title": "Gebruiker volgen?",

View File

@@ -141,6 +141,25 @@
"account.unmute": "Opphev demping av @{name}", "account.unmute": "Opphev demping av @{name}",
"account.unmute_notifications_short": "Opphev demping av varslingar", "account.unmute_notifications_short": "Opphev demping av varslingar",
"account.unmute_short": "Opphev demping", "account.unmute_short": "Opphev demping",
"account_edit.bio.placeholder": "Skriv ei kort innleiing slik at andre kan sjå kven du er.",
"account_edit.bio.title": "Om meg",
"account_edit.bio_modal.add_title": "Skriv om deg sjølv",
"account_edit.bio_modal.edit_title": "Endre bio",
"account_edit.char_counter": "{currentLength}/{maxLength} teikn",
"account_edit.column_button": "Ferdig",
"account_edit.column_title": "Rediger profil",
"account_edit.custom_fields.placeholder": "Legg til pronomen, lenkjer eller kva du elles vil dela.",
"account_edit.custom_fields.title": "Eigne felt",
"account_edit.display_name.placeholder": "Det synlege namnet ditt er det som syner på profilen din og i tidsliner.",
"account_edit.display_name.title": "Synleg namn",
"account_edit.featured_hashtags.placeholder": "Hjelp andre å finna og få rask tilgang til favorittemna dine.",
"account_edit.featured_hashtags.title": "Utvalde emneknaggar",
"account_edit.name_modal.add_title": "Legg til synleg namn",
"account_edit.name_modal.edit_title": "Endre synleg namn",
"account_edit.profile_tab.subtitle": "Tilpass fanene på profilen din og kva dei syner.",
"account_edit.profile_tab.title": "Innstillingar for profilfane",
"account_edit.save": "Lagre",
"account_edit.section_edit_button": "Rediger",
"account_note.placeholder": "Klikk for å leggja til merknad", "account_note.placeholder": "Klikk for å leggja til merknad",
"admin.dashboard.daily_retention": "Mengda brukarar aktive ved dagar etter registrering", "admin.dashboard.daily_retention": "Mengda brukarar aktive ved dagar etter registrering",
"admin.dashboard.monthly_retention": "Mengda brukarar aktive ved månader etter registrering", "admin.dashboard.monthly_retention": "Mengda brukarar aktive ved månader etter registrering",
@@ -260,6 +279,12 @@
"collections.create_collection": "Lag ei samling", "collections.create_collection": "Lag ei samling",
"collections.delete_collection": "Slett samlinga", "collections.delete_collection": "Slett samlinga",
"collections.description_length_hint": "Maks 100 teikn", "collections.description_length_hint": "Maks 100 teikn",
"collections.detail.accounts_heading": "Kontoar",
"collections.detail.curated_by_author": "Kuratert av {author}",
"collections.detail.curated_by_you": "Kuratert av deg",
"collections.detail.loading": "Lastar inn samling…",
"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.", "collections.error_loading_collections": "Noko gjekk gale då me prøvde å henta samlingane dine.",
"collections.hints.accounts_counter": "{count} av {max} kontoar", "collections.hints.accounts_counter": "{count} av {max} kontoar",
"collections.hints.add_more_accounts": "Legg til minst {count, plural, one {# konto} other {# kontoar}} for å halda fram", "collections.hints.add_more_accounts": "Legg til minst {count, plural, one {# konto} other {# kontoar}} for å halda fram",
@@ -268,11 +293,14 @@
"collections.manage_accounts": "Handter kontoar", "collections.manage_accounts": "Handter kontoar",
"collections.mark_as_sensitive": "Merk som ømtolig", "collections.mark_as_sensitive": "Merk som ømtolig",
"collections.mark_as_sensitive_hint": "Gøymer skildringa og kontoane i samlinga bak ei innhaldsåtvaring. Namnet på samlinga blir framleis synleg.", "collections.mark_as_sensitive_hint": "Gøymer skildringa og kontoane i samlinga bak ei innhaldsåtvaring. Namnet på samlinga blir framleis synleg.",
"collections.name_length_hint": "Maks 40 teikn",
"collections.new_collection": "Ny samling", "collections.new_collection": "Ny samling",
"collections.no_collections_yet": "Du har ingen samlingar enno.", "collections.no_collections_yet": "Du har ingen samlingar enno.",
"collections.old_last_post_note": "Sist lagt ut for over ei veke sidan",
"collections.remove_account": "Fjern denne kontoen", "collections.remove_account": "Fjern denne kontoen",
"collections.search_accounts_label": "Søk etter kontoar å leggja til…", "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.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_hint": "Legg til ein emneknagg som hjelper andre å forstå hovudemnet for denne samlinga.",
"collections.view_collection": "Sjå samlinga", "collections.view_collection": "Sjå samlinga",
"collections.visibility_public": "Offentleg", "collections.visibility_public": "Offentleg",
@@ -363,6 +391,9 @@
"confirmations.discard_draft.post.title": "Forkast kladden?", "confirmations.discard_draft.post.title": "Forkast kladden?",
"confirmations.discard_edit_media.confirm": "Forkast", "confirmations.discard_edit_media.confirm": "Forkast",
"confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkasta dei likevel?", "confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkasta dei likevel?",
"confirmations.follow_to_collection.confirm": "Fylg og legg til samlinga",
"confirmations.follow_to_collection.message": "Du må fylgja {name} for å leggja dei til ei samling.",
"confirmations.follow_to_collection.title": "Fylg kontoen?",
"confirmations.follow_to_list.confirm": "Fylg og legg til lista", "confirmations.follow_to_list.confirm": "Fylg og legg til lista",
"confirmations.follow_to_list.message": "Du må fylgja {name} for å leggja dei til ei liste.", "confirmations.follow_to_list.message": "Du må fylgja {name} for å leggja dei til ei liste.",
"confirmations.follow_to_list.title": "Vil du fylgja brukaren?", "confirmations.follow_to_list.title": "Vil du fylgja brukaren?",

View File

@@ -293,6 +293,7 @@
"collections.name_length_hint": "Kufi 40 shenja", "collections.name_length_hint": "Kufi 40 shenja",
"collections.new_collection": "Koleksion i ri", "collections.new_collection": "Koleksion i ri",
"collections.no_collections_yet": "Ende pa koleksione.", "collections.no_collections_yet": "Ende pa koleksione.",
"collections.old_last_post_note": "Të postuarat e fundit gjatë një jave më parë",
"collections.remove_account": "Hiqe këtë llogari", "collections.remove_account": "Hiqe këtë llogari",
"collections.search_accounts_label": "Kërkoni për llogari për shtim…", "collections.search_accounts_label": "Kërkoni për llogari për shtim…",
"collections.search_accounts_max_reached": "Keni shtuar numrin maksimum të llogarive", "collections.search_accounts_max_reached": "Keni shtuar numrin maksimum të llogarive",
@@ -387,6 +388,9 @@
"confirmations.discard_draft.post.title": "Të hidhet tej skica e postimit tuaj?", "confirmations.discard_draft.post.title": "Të hidhet tej skica e postimit tuaj?",
"confirmations.discard_edit_media.confirm": "Hidhe tej", "confirmations.discard_edit_media.confirm": "Hidhe tej",
"confirmations.discard_edit_media.message": "Keni ndryshime të paruajtura te përshkrimi ose paraparja e medias, të hidhen tej, sido qoftë?", "confirmations.discard_edit_media.message": "Keni ndryshime të paruajtura te përshkrimi ose paraparja e medias, të hidhen tej, sido qoftë?",
"confirmations.follow_to_collection.confirm": "Ndiqe dhe shtoje në koleksion",
"confirmations.follow_to_collection.message": "Që ta shtoni te një koleksion, duhet të jeni duke e ndjekur {name}.",
"confirmations.follow_to_collection.title": "Të ndiqet llogaria?",
"confirmations.follow_to_list.confirm": "Ndiqe dhe shtoje te listë", "confirmations.follow_to_list.confirm": "Ndiqe dhe shtoje te listë",
"confirmations.follow_to_list.message": "Lypset të jeni duke e ndjekur {name}, që të shtohte te një listë.", "confirmations.follow_to_list.message": "Lypset të jeni duke e ndjekur {name}, që të shtohte te një listë.",
"confirmations.follow_to_list.title": "Të ndiqet përdoruesi?", "confirmations.follow_to_list.title": "Të ndiqet përdoruesi?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "@{name} adlı kişinin sesini aç", "account.unmute": "@{name} adlı kişinin sesini aç",
"account.unmute_notifications_short": "Bildirimlerin sesini aç", "account.unmute_notifications_short": "Bildirimlerin sesini aç",
"account.unmute_short": "Susturmayı kaldır", "account.unmute_short": "Susturmayı kaldır",
"account_edit.bio.placeholder": "Diğerlerinin sizi tanımasına yardımcı olmak için kısa bir tanıtım ekleyin.",
"account_edit.bio.title": "Kişisel bilgiler",
"account_edit.bio_modal.add_title": "Kişisel bilgi ekle",
"account_edit.bio_modal.edit_title": "Kişisel bilgiyi düzenle",
"account_edit.char_counter": "{currentLength}/{maxLength} karakter",
"account_edit.column_button": "Tamamlandı", "account_edit.column_button": "Tamamlandı",
"account_edit.column_title": "Profili Düzenle", "account_edit.column_title": "Profili Düzenle",
"account_edit.custom_fields.placeholder": "Zamirlerinizi, harici bağlantılarınızı veya paylaşmak istediğiniz diğer bilgileri ekleyin.",
"account_edit.custom_fields.title": "Özel alanlar",
"account_edit.display_name.placeholder": "Görünen adınız profilinizde ve zaman akışlarında adınızın nasıl göründüğüdür.",
"account_edit.display_name.title": "Görünen ad",
"account_edit.featured_hashtags.placeholder": "Başkalarının favori konularınızı tanımlamasına ve bunlara hızlı bir şekilde erişmesine yardımcı olun.",
"account_edit.featured_hashtags.title": "Öne çıkan etiketler",
"account_edit.name_modal.add_title": "Görünen ad ekle",
"account_edit.name_modal.edit_title": "Görünen adı düzenle",
"account_edit.profile_tab.subtitle": "Profilinizdeki sekmeleri ve bunların görüntülediği bilgileri özelleştirin.",
"account_edit.profile_tab.title": "Profil sekme ayarları",
"account_edit.save": "Kaydet",
"account_edit.section_edit_button": "Düzenle",
"account_note.placeholder": "Not eklemek için tıklayın", "account_note.placeholder": "Not eklemek için tıklayın",
"admin.dashboard.daily_retention": "Kayıttan sonra günlük kullanıcı saklama oranı", "admin.dashboard.daily_retention": "Kayıttan sonra günlük kullanıcı saklama oranı",
"admin.dashboard.monthly_retention": "Kayıttan sonra aylık kullanıcı saklama oranı", "admin.dashboard.monthly_retention": "Kayıttan sonra aylık kullanıcı saklama oranı",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "Sizin derledikleriniz", "collections.detail.curated_by_you": "Sizin derledikleriniz",
"collections.detail.loading": "Koleksiyon yükleniyor…", "collections.detail.loading": "Koleksiyon yükleniyor…",
"collections.detail.share": "Bu koleksiyonu paylaş", "collections.detail.share": "Bu koleksiyonu paylaş",
"collections.edit_details": "Ayrıntıları düzenle",
"collections.error_loading_collections": "Koleksiyonlarınızı yüklemeye çalışırken bir hata oluştu.", "collections.error_loading_collections": "Koleksiyonlarınızı yüklemeye çalışırken bir hata oluştu.",
"collections.hints.accounts_counter": "{count} / {max} hesap", "collections.hints.accounts_counter": "{count} / {max} hesap",
"collections.hints.add_more_accounts": "Devam etmek için en az {count, plural, one {# hesap} other {# hesap}} ekleyin", "collections.hints.add_more_accounts": "Devam etmek için en az {count, plural, one {# hesap} other {# hesap}} ekleyin",
@@ -275,11 +293,14 @@
"collections.manage_accounts": "Hesapları yönet", "collections.manage_accounts": "Hesapları yönet",
"collections.mark_as_sensitive": "Hassas olarak işaretle", "collections.mark_as_sensitive": "Hassas olarak işaretle",
"collections.mark_as_sensitive_hint": "Koleksiyonun açıklamasını ve hesaplarını içerik uyarısının arkasında gizler. Koleksiyon adı hala görünür olacaktır.", "collections.mark_as_sensitive_hint": "Koleksiyonun açıklamasını ve hesaplarını içerik uyarısının arkasında gizler. Koleksiyon adı hala görünür olacaktır.",
"collections.name_length_hint": "40 karakterle sınırlı",
"collections.new_collection": "Yeni koleksiyon", "collections.new_collection": "Yeni koleksiyon",
"collections.no_collections_yet": "Henüz hiçbir koleksiyon yok.", "collections.no_collections_yet": "Henüz hiçbir koleksiyon yok.",
"collections.old_last_post_note": "Son gönderi bir haftadan önce",
"collections.remove_account": "Bu hesabı çıkar", "collections.remove_account": "Bu hesabı çıkar",
"collections.search_accounts_label": "Eklemek için hesap arayın…", "collections.search_accounts_label": "Eklemek için hesap arayın…",
"collections.search_accounts_max_reached": "Maksimum hesabı eklediniz", "collections.search_accounts_max_reached": "Maksimum hesabı eklediniz",
"collections.sensitive": "Hassas",
"collections.topic_hint": "Bu koleksiyonun ana konusunu başkalarının anlamasına yardımcı olacak bir etiket ekleyin.", "collections.topic_hint": "Bu koleksiyonun ana konusunu başkalarının anlamasına yardımcı olacak bir etiket ekleyin.",
"collections.view_collection": "Koleksiyonu görüntüle", "collections.view_collection": "Koleksiyonu görüntüle",
"collections.visibility_public": "Herkese açık", "collections.visibility_public": "Herkese açık",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "Taslak gönderiniz silinsin mi?", "confirmations.discard_draft.post.title": "Taslak gönderiniz silinsin mi?",
"confirmations.discard_edit_media.confirm": "Vazgeç", "confirmations.discard_edit_media.confirm": "Vazgeç",
"confirmations.discard_edit_media.message": "Medya açıklaması veya ön izlemede kaydedilmemiş değişiklikleriniz var, yine de vazgeçmek istiyor musunuz?", "confirmations.discard_edit_media.message": "Medya açıklaması veya ön izlemede kaydedilmemiş değişiklikleriniz var, yine de vazgeçmek istiyor musunuz?",
"confirmations.follow_to_collection.confirm": "Takip et ve koleksiyona ekle",
"confirmations.follow_to_collection.message": "Bir koleksiyona eklemek için {name} kişisini takip etmeniz gerekiyor.",
"confirmations.follow_to_collection.title": "Hesabı takip et?",
"confirmations.follow_to_list.confirm": "Takip et ve yapılacaklar listesine ekle", "confirmations.follow_to_list.confirm": "Takip et ve yapılacaklar listesine ekle",
"confirmations.follow_to_list.message": "Bir listeye eklemek için {name} kişisini takip etmeniz gerekiyor.", "confirmations.follow_to_list.message": "Bir listeye eklemek için {name} kişisini takip etmeniz gerekiyor.",
"confirmations.follow_to_list.title": "Kullanıcıyı takip et?", "confirmations.follow_to_list.title": "Kullanıcıyı takip et?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "Giới hạn 40 ký tự", "collections.name_length_hint": "Giới hạn 40 ký tự",
"collections.new_collection": "Collection mới", "collections.new_collection": "Collection mới",
"collections.no_collections_yet": "Chưa có collection.", "collections.no_collections_yet": "Chưa có collection.",
"collections.old_last_post_note": "Đăng lần cuối hơn một tuần trước",
"collections.remove_account": "Gỡ tài khoản này", "collections.remove_account": "Gỡ tài khoản này",
"collections.search_accounts_label": "Tìm tài khoản để thêm…", "collections.search_accounts_label": "Tìm tài khoản để thêm…",
"collections.search_accounts_max_reached": "Bạn đã đạt đến số lượng tài khoản tối đa", "collections.search_accounts_max_reached": "Bạn đã đạt đến số lượng tài khoản tối đa",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "Bỏ tút đang soạn?", "confirmations.discard_draft.post.title": "Bỏ tút đang soạn?",
"confirmations.discard_edit_media.confirm": "Bỏ qua", "confirmations.discard_edit_media.confirm": "Bỏ qua",
"confirmations.discard_edit_media.message": "Bạn chưa lưu thay đổi của phần mô tả hoặc bản xem trước của media, vẫn bỏ qua?", "confirmations.discard_edit_media.message": "Bạn chưa lưu thay đổi của phần mô tả hoặc bản xem trước của media, vẫn bỏ qua?",
"confirmations.follow_to_collection.confirm": "Theo dõi & thêm vào collection",
"confirmations.follow_to_collection.message": "Bạn cần theo dõi {name} trước khi thêm họ vào collection.",
"confirmations.follow_to_collection.title": "Theo dõi tài khoản?",
"confirmations.follow_to_list.confirm": "Theo dõi & thêm vào danh sách", "confirmations.follow_to_list.confirm": "Theo dõi & thêm vào danh sách",
"confirmations.follow_to_list.message": "Bạn cần theo dõi {name} trước khi thêm họ vào danh sách.", "confirmations.follow_to_list.message": "Bạn cần theo dõi {name} trước khi thêm họ vào danh sách.",
"confirmations.follow_to_list.title": "Theo dõi tài khoản?", "confirmations.follow_to_list.title": "Theo dõi tài khoản?",

View File

@@ -141,8 +141,25 @@
"account.unmute": "不再隐藏 @{name}", "account.unmute": "不再隐藏 @{name}",
"account.unmute_notifications_short": "恢复通知", "account.unmute_notifications_short": "恢复通知",
"account.unmute_short": "取消隐藏", "account.unmute_short": "取消隐藏",
"account_edit.bio.placeholder": "添加一段简短介绍,帮助其他人认识你。",
"account_edit.bio.title": "简介",
"account_edit.bio_modal.add_title": "添加个人简介",
"account_edit.bio_modal.edit_title": "编辑个人简介",
"account_edit.char_counter": "{currentLength}/{maxLength} 个字",
"account_edit.column_button": "完成", "account_edit.column_button": "完成",
"account_edit.column_title": "修改个人资料", "account_edit.column_title": "修改个人资料",
"account_edit.custom_fields.placeholder": "添加你的人称代词、外部链接,或其他你想分享的内容。",
"account_edit.custom_fields.title": "自定义字段",
"account_edit.display_name.placeholder": "你的显示名称是指你的名字在个人资料及时间线上出现时的样子。",
"account_edit.display_name.title": "显示名称",
"account_edit.featured_hashtags.placeholder": "帮助其他人认识并快速访问你最喜欢的话题。",
"account_edit.featured_hashtags.title": "精选话题标签",
"account_edit.name_modal.add_title": "添加显示名称",
"account_edit.name_modal.edit_title": "编辑显示名称",
"account_edit.profile_tab.subtitle": "自定义你个人资料的标签页及其显示的内容。",
"account_edit.profile_tab.title": "个人资料标签页设置",
"account_edit.save": "保存",
"account_edit.section_edit_button": "编辑",
"account_note.placeholder": "点击添加备注", "account_note.placeholder": "点击添加备注",
"admin.dashboard.daily_retention": "注册后用户留存率(按日计算)", "admin.dashboard.daily_retention": "注册后用户留存率(按日计算)",
"admin.dashboard.monthly_retention": "注册后用户留存率(按月计算)", "admin.dashboard.monthly_retention": "注册后用户留存率(按月计算)",
@@ -267,6 +284,7 @@
"collections.detail.curated_by_you": "由你精心挑选", "collections.detail.curated_by_you": "由你精心挑选",
"collections.detail.loading": "正在加载收藏列表…", "collections.detail.loading": "正在加载收藏列表…",
"collections.detail.share": "分享此收藏列表", "collections.detail.share": "分享此收藏列表",
"collections.edit_details": "编辑详情",
"collections.error_loading_collections": "加载你的收藏列表时发生错误。", "collections.error_loading_collections": "加载你的收藏列表时发生错误。",
"collections.hints.accounts_counter": "{count} / {max} 个账号", "collections.hints.accounts_counter": "{count} / {max} 个账号",
"collections.hints.add_more_accounts": "添加至少 {count, plural, other {# 个账号}}以继续", "collections.hints.add_more_accounts": "添加至少 {count, plural, other {# 个账号}}以继续",
@@ -275,11 +293,14 @@
"collections.manage_accounts": "管理账户", "collections.manage_accounts": "管理账户",
"collections.mark_as_sensitive": "标记为敏感内容", "collections.mark_as_sensitive": "标记为敏感内容",
"collections.mark_as_sensitive_hint": "将此收藏列表的说明用内容警告隐藏。此收藏列表的名称仍将可见。", "collections.mark_as_sensitive_hint": "将此收藏列表的说明用内容警告隐藏。此收藏列表的名称仍将可见。",
"collections.name_length_hint": "40 字限制",
"collections.new_collection": "新建收藏列表", "collections.new_collection": "新建收藏列表",
"collections.no_collections_yet": "尚无收藏列表。", "collections.no_collections_yet": "尚无收藏列表。",
"collections.old_last_post_note": "上次发言于一周多以前",
"collections.remove_account": "移除此账号", "collections.remove_account": "移除此账号",
"collections.search_accounts_label": "搜索要添加的账号…", "collections.search_accounts_label": "搜索要添加的账号…",
"collections.search_accounts_max_reached": "你添加的账号数量已达上限", "collections.search_accounts_max_reached": "你添加的账号数量已达上限",
"collections.sensitive": "敏感内容",
"collections.topic_hint": "添加话题标签,帮助他人了解此收藏列表的主题。", "collections.topic_hint": "添加话题标签,帮助他人了解此收藏列表的主题。",
"collections.view_collection": "查看收藏列表", "collections.view_collection": "查看收藏列表",
"collections.visibility_public": "公开", "collections.visibility_public": "公开",
@@ -370,6 +391,9 @@
"confirmations.discard_draft.post.title": "丢弃你的嘟文草稿?", "confirmations.discard_draft.post.title": "丢弃你的嘟文草稿?",
"confirmations.discard_edit_media.confirm": "丢弃", "confirmations.discard_edit_media.confirm": "丢弃",
"confirmations.discard_edit_media.message": "你还有未保存的媒体描述或预览修改,仍要丢弃吗?", "confirmations.discard_edit_media.message": "你还有未保存的媒体描述或预览修改,仍要丢弃吗?",
"confirmations.follow_to_collection.confirm": "关注并添加到收藏列表",
"confirmations.follow_to_collection.message": "你需要先关注 {name},才能将其添加到收藏列表。",
"confirmations.follow_to_collection.title": "要关注账号吗?",
"confirmations.follow_to_list.confirm": "关注并添加到列表", "confirmations.follow_to_list.confirm": "关注并添加到列表",
"confirmations.follow_to_list.message": "你需要先关注 {name},才能将其添加到列表。", "confirmations.follow_to_list.message": "你需要先关注 {name},才能将其添加到列表。",
"confirmations.follow_to_list.title": "确定要关注此用户?", "confirmations.follow_to_list.title": "确定要关注此用户?",

View File

@@ -296,6 +296,7 @@
"collections.name_length_hint": "40 字限制", "collections.name_length_hint": "40 字限制",
"collections.new_collection": "新增收藏名單", "collections.new_collection": "新增收藏名單",
"collections.no_collections_yet": "您沒有任何收藏名單。", "collections.no_collections_yet": "您沒有任何收藏名單。",
"collections.old_last_post_note": "上次發表嘟文已超過一週",
"collections.remove_account": "移除此帳號", "collections.remove_account": "移除此帳號",
"collections.search_accounts_label": "搜尋帳號以加入...", "collections.search_accounts_label": "搜尋帳號以加入...",
"collections.search_accounts_max_reached": "您新增之帳號數已達上限", "collections.search_accounts_max_reached": "您新增之帳號數已達上限",
@@ -390,6 +391,9 @@
"confirmations.discard_draft.post.title": "是否捨棄您的嘟文草稿?", "confirmations.discard_draft.post.title": "是否捨棄您的嘟文草稿?",
"confirmations.discard_edit_media.confirm": "捨棄", "confirmations.discard_edit_media.confirm": "捨棄",
"confirmations.discard_edit_media.message": "您於媒體描述或預覽區塊有未儲存的變更。是否要捨棄這些變更?", "confirmations.discard_edit_media.message": "您於媒體描述或預覽區塊有未儲存的變更。是否要捨棄這些變更?",
"confirmations.follow_to_collection.confirm": "跟隨並加入至收藏名單",
"confirmations.follow_to_collection.message": "您必須先跟隨 {name} 以將其加入至收藏名單。",
"confirmations.follow_to_collection.title": "是否跟隨此帳號?",
"confirmations.follow_to_list.confirm": "跟隨並加入至列表", "confirmations.follow_to_list.confirm": "跟隨並加入至列表",
"confirmations.follow_to_list.message": "您必須先跟隨 {name} 以將其加入至列表。", "confirmations.follow_to_list.message": "您必須先跟隨 {name} 以將其加入至列表。",
"confirmations.follow_to_list.title": "是否跟隨該使用者?", "confirmations.follow_to_list.title": "是否跟隨該使用者?",

View File

@@ -1,7 +1,9 @@
import { annualReport } from './annual_report'; import { annualReport } from './annual_report';
import { collections } from './collections'; import { collections } from './collections';
import { profileEdit } from './profile_edit';
export const sliceReducers = { export const sliceReducers = {
annualReport, annualReport,
collections, collections,
profileEdit,
}; };

View File

@@ -0,0 +1,178 @@
import type { PayloadAction } from '@reduxjs/toolkit';
import { createSlice } from '@reduxjs/toolkit';
import { debounce } from 'lodash';
import {
apiDeleteFeaturedTag,
apiGetCurrentFeaturedTags,
apiGetTagSuggestions,
apiPostFeaturedTag,
} from '@/mastodon/api/accounts';
import { apiGetSearch } from '@/mastodon/api/search';
import { hashtagToFeaturedTag } from '@/mastodon/api_types/tags';
import type { ApiFeaturedTagJSON } from '@/mastodon/api_types/tags';
import type { AppDispatch } from '@/mastodon/store';
import {
createAppAsyncThunk,
createDataLoadingThunk,
} from '@/mastodon/store/typed_functions';
interface ProfileEditState {
tags: ApiFeaturedTagJSON[];
tagSuggestions: ApiFeaturedTagJSON[];
isLoading: boolean;
isPending: boolean;
search: {
query: string;
isLoading: boolean;
results?: ApiFeaturedTagJSON[];
};
}
const initialState: ProfileEditState = {
tags: [],
tagSuggestions: [],
isLoading: true,
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 = false;
state.search.results = undefined;
},
clearSearch(state) {
state.search.query = '';
state.search.isLoading = false;
state.search.results = undefined;
},
},
extraReducers(builder) {
builder.addCase(fetchSuggestedTags.fulfilled, (state, action) => {
state.tagSuggestions = action.payload.map(hashtagToFeaturedTag);
state.isLoading = false;
});
builder.addCase(fetchFeaturedTags.fulfilled, (state, action) => {
state.tags = action.payload;
state.isLoading = false;
});
builder.addCase(addFeaturedTag.pending, (state) => {
state.isPending = true;
});
builder.addCase(addFeaturedTag.rejected, (state) => {
state.isPending = false;
});
builder.addCase(addFeaturedTag.fulfilled, (state, action) => {
state.tags = [...state.tags, action.payload].toSorted(
(a, b) => b.statuses_count - a.statuses_count,
);
state.tagSuggestions = state.tagSuggestions.filter(
(tag) => tag.name !== action.meta.arg.name,
);
state.isPending = false;
});
builder.addCase(deleteFeaturedTag.pending, (state) => {
state.isPending = true;
});
builder.addCase(deleteFeaturedTag.rejected, (state) => {
state.isPending = false;
});
builder.addCase(deleteFeaturedTag.fulfilled, (state, action) => {
state.tags = state.tags.filter((tag) => tag.id !== action.meta.arg.tagId);
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: ApiFeaturedTagJSON[] = [];
const currentTags = new Set(state.tags.map((tag) => tag.name));
for (const tag of action.payload) {
if (currentTags.has(tag.name)) {
continue;
}
searchResults.push(hashtagToFeaturedTag(tag));
if (searchResults.length >= 10) {
break;
}
}
state.search.results = searchResults;
});
},
});
export const profileEdit = profileEditSlice.reducer;
export const { clearSearch } = profileEditSlice.actions;
export const fetchFeaturedTags = createDataLoadingThunk(
`${profileEditSlice.name}/fetchFeaturedTags`,
apiGetCurrentFeaturedTags,
{ useLoadingBar: false },
);
export const fetchSuggestedTags = createDataLoadingThunk(
`${profileEditSlice.name}/fetchSuggestedTags`,
apiGetTagSuggestions,
{ useLoadingBar: false },
);
export const addFeaturedTag = createDataLoadingThunk(
`${profileEditSlice.name}/addFeaturedTag`,
({ name }: { name: string }) => apiPostFeaturedTag(name),
{
condition(arg, { getState }) {
const state = getState();
return !state.profileEdit.tags.some((tag) => tag.name === arg.name);
},
},
);
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

@@ -77,7 +77,8 @@ const initialState = ImmutableMap({
follow_requests: initialListState, follow_requests: initialListState,
blocks: initialListState, blocks: initialListState,
mutes: initialListState, mutes: initialListState,
featured_tags: initialListState, /** @type {ImmutableMap<string, typeof initialListState>} */
featured_tags: ImmutableMap(),
}); });
const normalizeList = (state, path, accounts, next) => { const normalizeList = (state, path, accounts, next) => {

View File

@@ -378,6 +378,15 @@ $content-width: 840px;
} }
} }
details > summary {
text-transform: uppercase;
font-size: 13px;
font-weight: 700;
color: var(--color-text-secondary);
padding-top: 24px;
margin-bottom: 8px;
}
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
display: block; display: block;

View File

@@ -1670,7 +1670,7 @@ body > [data-popper-placement] {
.detailed-status__display-name { .detailed-status__display-name {
color: var(--color-text-tertiary); color: var(--color-text-tertiary);
span { span:not(.account__avatar) {
display: inline; display: inline;
} }

View File

@@ -41,41 +41,43 @@
%p %p
= t 'admin.reports.statuses_description_html' = t 'admin.reports.statuses_description_html'
%h4 %details{ open: @report.status_ids.any? }
= t 'admin.reports.statuses' %summary
= t 'admin.reports.statuses', count: @report.status_ids.size
= form_with model: @form, url: batch_admin_account_statuses_path(@report.target_account_id, report_id: @report.id) do |f| = form_with model: @form, url: batch_admin_account_statuses_path(@report.target_account_id, report_id: @report.id) do |f|
.batch-table
.batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all
= check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions
= link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]),
admin_account_statuses_path(@report.target_account_id, report_id: @report.id),
class: 'table-action-link'
- if !@statuses.empty? && @report.unresolved?
= f.button safe_join([material_symbol('close'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
.batch-table__body
- if @statuses.empty?
= nothing_here 'nothing-here--under-tabs'
- else
= render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f }
- if Mastodon::Feature.collections_enabled?
%h4
= t 'admin.reports.collections'
%form
.batch-table .batch-table
.batch-table__toolbar .batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all %label.batch-table__toolbar__select.batch-checkbox-all
-# = check_box_tag :batch_checkbox_all, nil, false = check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions .batch-table__toolbar__actions
= link_to safe_join([material_symbol('add'), t('admin.reports.add_to_report')]),
admin_account_statuses_path(@report.target_account_id, report_id: @report.id),
class: 'table-action-link'
- if !@statuses.empty? && @report.unresolved?
= f.button safe_join([material_symbol('close'), t('admin.statuses.batch.remove_from_report')]), name: :remove_from_report, class: 'table-action-link', type: :submit
.batch-table__body .batch-table__body
- if @report.collections.empty? - if @statuses.empty?
= nothing_here 'nothing-here--under-tabs' = nothing_here 'nothing-here--under-tabs'
- else - else
= render partial: 'admin/shared/collection_batch_row', collection: @report.collections, as: :collection = render partial: 'admin/shared/status_batch_row', collection: @statuses, as: :status, locals: { f: f }
- if Mastodon::Feature.collections_enabled?
%details{ open: @report.collections.any? }
%summary
= t 'admin.reports.collections', count: @report.collections.size
%form
.batch-table
.batch-table__toolbar
%label.batch-table__toolbar__select.batch-checkbox-all
-# = check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions
.batch-table__body
- if @report.collections.empty?
= nothing_here 'nothing-here--under-tabs'
- else
= render partial: 'admin/shared/collection_batch_row', collection: @report.collections, as: :collection
- if @report.unresolved? - if @report.unresolved?
%hr.spacer/ %hr.spacer/

View File

@@ -64,7 +64,7 @@ de:
date_of_birth: date_of_birth:
below_limit: liegt unterhalb des Mindestalters below_limit: liegt unterhalb des Mindestalters
email: email:
blocked: verwendet einen unerlaubten E-Mail-Anbieter blocked: verwendet einen unerlaubten E-Mail-Provider
unreachable: scheint nicht zu existieren unreachable: scheint nicht zu existieren
role_id: role_id:
elevated: kann nicht höher als deine derzeitige Rolle sein elevated: kann nicht höher als deine derzeitige Rolle sein

View File

@@ -717,7 +717,7 @@ cs:
cancel: Zrušit cancel: Zrušit
category: Kategorie category: Kategorie
category_description_html: Důvod nahlášení tohoto účtu a/nebo obsahu bude uveden v komunikaci s nahlášeným účtem category_description_html: Důvod nahlášení tohoto účtu a/nebo obsahu bude uveden v komunikaci s nahlášeným účtem
collections: Sbírky collections: Sbírky (%{count})
comment: comment:
none: Žádné none: Žádné
comment_description_html: 'Pro upřesnění uživatel %{name} napsal:' comment_description_html: 'Pro upřesnění uživatel %{name} napsal:'
@@ -753,7 +753,7 @@ cs:
resolved_msg: Hlášení úspěšně vyřešeno! resolved_msg: Hlášení úspěšně vyřešeno!
skip_to_actions: Přeskočit k akcím skip_to_actions: Přeskočit k akcím
status: Stav status: Stav
statuses: Příspěvky statuses: Příspěvky (%{count})
statuses_description_html: Obsah porušující pravidla bude uveden v komunikaci s nahlášeným účtem statuses_description_html: Obsah porušující pravidla bude uveden v komunikaci s nahlášeným účtem
summary: summary:
action_preambles: action_preambles:

View File

@@ -30,12 +30,12 @@ cy:
pin_errors: pin_errors:
following: Rhaid i chi fod yn dilyn y person rydych am ei gymeradwyo, yn barod following: Rhaid i chi fod yn dilyn y person rydych am ei gymeradwyo, yn barod
posts: posts:
few: Postiadau few: Postiad
many: Postiadau many: Postiad
one: Postiad one: Postiad
other: Postiadau other: Postiad
two: Postiadau two: Bostiad
zero: Postiadau zero: Postiad
posts_tab_heading: Postiadau posts_tab_heading: Postiadau
self_follow_error: Chewch chi ddim dilyn eich cyfrif eich hun self_follow_error: Chewch chi ddim dilyn eich cyfrif eich hun
admin: admin:
@@ -745,7 +745,7 @@ cy:
cancel: Canslo cancel: Canslo
category: Categori category: Categori
category_description_html: Bydd y rheswm dros adrodd am y cyfrif a/neur cynnwys hwn yn cael ei ddyfynnu wrth gyfathrebu âr cyfrif a adroddwyd category_description_html: Bydd y rheswm dros adrodd am y cyfrif a/neur cynnwys hwn yn cael ei ddyfynnu wrth gyfathrebu âr cyfrif a adroddwyd
collections: Casgliadau collections: Casgliadau (%{count})
comment: comment:
none: Dim none: Dim
comment_description_html: 'I ddarparu rhagor o wybodaeth, ysgrifennodd %{name}:' comment_description_html: 'I ddarparu rhagor o wybodaeth, ysgrifennodd %{name}:'
@@ -781,7 +781,7 @@ cy:
resolved_msg: Llwyddwyd i ddatrys yr adroddiad! resolved_msg: Llwyddwyd i ddatrys yr adroddiad!
skip_to_actions: Mynd i gamau gweithredu skip_to_actions: Mynd i gamau gweithredu
status: Statws status: Statws
statuses: Postiadau statuses: Postiadau (%{count})
statuses_description_html: Bydd cynnwys tramgwyddus yn cael ei ddyfynnu wrth gyfathrebu â'r cyfrif a adroddwyd statuses_description_html: Bydd cynnwys tramgwyddus yn cael ei ddyfynnu wrth gyfathrebu â'r cyfrif a adroddwyd
summary: summary:
action_preambles: action_preambles:
@@ -2213,6 +2213,8 @@ cy:
past_preamble_html: Rydym wedi newid ein telerau gwasanaeth ers eich ymweliad diwethaf. Rydym yn eich annog i ddarllen y telerau wedi'u diweddaru. past_preamble_html: Rydym wedi newid ein telerau gwasanaeth ers eich ymweliad diwethaf. Rydym yn eich annog i ddarllen y telerau wedi'u diweddaru.
review_link: Darllen y telerau gwasanaeth review_link: Darllen y telerau gwasanaeth
title: Mae telerau gwasanaeth %{domain} yn newid title: Mae telerau gwasanaeth %{domain} yn newid
themes:
default: Mastodon
time: time:
formats: formats:
default: "%b %d, %Y, %H:%M" default: "%b %d, %Y, %H:%M"

View File

@@ -689,7 +689,7 @@ da:
cancel: Afbryd cancel: Afbryd
category: Kategori category: Kategori
category_description_html: Årsagen til anmeldelsen af denne konto og/eller indhold refereres i kommunikationen med den anmeldte konto category_description_html: Årsagen til anmeldelsen af denne konto og/eller indhold refereres i kommunikationen med den anmeldte konto
collections: Samlinger collections: Samlinger (%{count})
comment: comment:
none: Ingen none: Ingen
comment_description_html: 'For at give mere information, skrev %{name}:' comment_description_html: 'For at give mere information, skrev %{name}:'
@@ -725,7 +725,7 @@ da:
resolved_msg: Anmeldelse løst! resolved_msg: Anmeldelse løst!
skip_to_actions: Overspring til foranstaltninger skip_to_actions: Overspring til foranstaltninger
status: Status status: Status
statuses: Indlæg statuses: Indlæg (%{count})
statuses_description_html: Krænkende indhold citeres i kommunikationen med den anmeldte konto statuses_description_html: Krænkende indhold citeres i kommunikationen med den anmeldte konto
summary: summary:
action_preambles: action_preambles:

View File

@@ -541,7 +541,7 @@ de:
instances: instances:
audit_log: audit_log:
title: Neueste Protokolle title: Neueste Protokolle
view_all: Alle Protokolle anzeigen view_all: Protokolle
availability: availability:
description_html: description_html:
one: Wenn die Zustellung an die Domain <strong>%{count} Tag</strong> lang erfolglos bleibt, werden keine weiteren Zustellversuche unternommen, bis eine Zustellung <em>von</em> der Domain empfangen wird. one: Wenn die Zustellung an die Domain <strong>%{count} Tag</strong> lang erfolglos bleibt, werden keine weiteren Zustellversuche unternommen, bis eine Zustellung <em>von</em> der Domain empfangen wird.
@@ -689,7 +689,7 @@ de:
cancel: Abbrechen cancel: Abbrechen
category: Kategorie category: Kategorie
category_description_html: Der Grund, weshalb dieses Konto und/oder der Inhalt gemeldet worden ist, wird in der Kommunikation mit dem gemeldeten Konto erwähnt category_description_html: Der Grund, weshalb dieses Konto und/oder der Inhalt gemeldet worden ist, wird in der Kommunikation mit dem gemeldeten Konto erwähnt
collections: Sammlungen collections: Sammlungen (%{count})
comment: comment:
none: Ohne ergänzenden Kommentar none: Ohne ergänzenden Kommentar
comment_description_html: "%{name} ergänzte die Meldung um folgende Hinweis:" comment_description_html: "%{name} ergänzte die Meldung um folgende Hinweis:"
@@ -725,7 +725,7 @@ de:
resolved_msg: Meldung erfolgreich geklärt! resolved_msg: Meldung erfolgreich geklärt!
skip_to_actions: Zur Maßnahme springen skip_to_actions: Zur Maßnahme springen
status: Status status: Status
statuses: Beiträge statuses: Beiträge (%{count})
statuses_description_html: Beanstandete Inhalte werden in der Kommunikation mit dem gemeldeten Konto erwähnt statuses_description_html: Beanstandete Inhalte werden in der Kommunikation mit dem gemeldeten Konto erwähnt
summary: summary:
action_preambles: action_preambles:
@@ -773,47 +773,47 @@ de:
other: "%{count} Berechtigungen" other: "%{count} Berechtigungen"
privileges: privileges:
administrator: Administrator*in administrator: Administrator*in
administrator_description: Benutzer*innen mit dieser Berechtigung werden alle Beschränkungen umgehen administrator_description: Beschränkung aller Berechtigungen umgehen
delete_user_data: Kontodaten löschen delete_user_data: Kontodaten löschen
delete_user_data_description: Erlaubt Benutzer*innen, die Daten anderer Benutzer*innen sofort zu löschen delete_user_data_description: Daten anderer Profile ohne Verzögerung löschen
invite_users: Leute einladen invite_users: Einladungen
invite_users_description: Erlaubt bereits registrierten Benutzer*innen, neue Leute zum Server einzuladen invite_users_description: Erlaubt bereits registrierten Benutzer*innen, neue Leute zum Server einzuladen
manage_announcements: Ankündigungen verwalten manage_announcements: Ankündigungen
manage_announcements_description: Erlaubt Profilen, Ankündigungen auf dem Server zu verwalten manage_announcements_description: Ankündigungen dieses Servers verwalten
manage_appeals: Einsprüche verwalten manage_appeals: Einsprüche
manage_appeals_description: Erlaubt es Benutzer*innen, Entscheidungen der Moderator*innen zu widersprechen manage_appeals_description: Entscheidungen von Moderator*innen bzgl. Einsprüchen von Benutzer*innen überarbeiten
manage_blocks: Sperrungen verwalten manage_blocks: Sperren
manage_blocks_description: Erlaubt Nutzer*innen das Sperren von E-Mail-Anbietern und IP-Adressen manage_blocks_description: E-Mail-Provider und IP-Adressen sperren
manage_custom_emojis: Eigene Emojis verwalten manage_custom_emojis: Emojis
manage_custom_emojis_description: Erlaubt es Benutzer*innen, eigene Emojis auf dem Server zu verwalten manage_custom_emojis_description: Spezielle Emojis dieses Servers verwalten
manage_federation: Föderation verwalten manage_federation: Föderation
manage_federation_description: Erlaubt Benutzer*innen, Domains anderer Mastodon-Server zu sperren oder zuzulassen und die Zustellbarkeit zu steuern manage_federation_description: Domains anderer Mastodon-Server sperren/zulassen und Zustellbarkeit kontrollieren
manage_invites: Einladungen verwalten manage_invites: Einladungen
manage_invites_description: Erlaubt es Benutzer*innen, Einladungslinks zu durchsuchen und zu deaktivieren manage_invites_description: Einladungslinks durchsuchen und deaktivieren
manage_reports: Meldungen verwalten manage_reports: Meldungen
manage_reports_description: Erlaubt es Benutzer*innen, Meldungen zu überprüfen und Vorfälle zu moderieren manage_reports_description: Meldungen überprüfen und Vorfälle moderieren
manage_roles: Rollen verwalten manage_roles: Rollen verwalten
manage_roles_description: Erlaubt es Benutzer*innen, Rollen, die sich unterhalb der eigenen Rolle befinden, zu verwalten und zuzuweisen manage_roles_description: Rollen, die sich unterhalb der eigenen Rolle befinden, verwalten und zuweisen
manage_rules: Serverregeln verwalten manage_rules: Serverregeln
manage_rules_description: Erlaubt es Benutzer*innen, Serverregeln zu ändern manage_rules_description: Serverregeln ändern
manage_settings: Einstellungen verwalten manage_settings: Einstellungen
manage_settings_description: Erlaubt Nutzer*innen, Einstellungen dieses Servers zu ändern manage_settings_description: Einstellungen dieses Servers ändern
manage_taxonomies: Hashtags verwalten manage_taxonomies: Hashtags
manage_taxonomies_description: Ermöglicht Benutzer*innen, die Trends zu überprüfen und die Hashtag-Einstellungen zu aktualisieren manage_taxonomies_description: Trends überprüfen und Einstellungen für Hashtags
manage_user_access: Kontozugriff verwalten manage_user_access: Kontozugriff
manage_user_access_description: Erlaubt Nutzer*innen, die Zwei-Faktor-Authentisierung anderer zu deaktivieren, ihre E-Mail-Adresse zu ändern und ihr Passwort zurückzusetzen manage_user_access_description: Zwei-Faktor-Authentisierungen anderer können deaktiviert, E-Mail-Adressen geändert und Passwörter zurückgesetzt werden
manage_users: Konten verwalten manage_users: Konten
manage_users_description: Erlaubt es Benutzer*innen, die Details anderer Profile einzusehen und diese Accounts zu moderieren manage_users_description: Erlaubt es Benutzer*innen, die Details anderer Profile einzusehen und diese Accounts zu moderieren
manage_webhooks: Webhooks verwalten manage_webhooks: Webhooks
manage_webhooks_description: Erlaubt es Benutzer*innen, Webhooks für administrative Vorkommnisse einzurichten manage_webhooks_description: Webhooks für administrative Vorgänge einrichten
view_audit_log: Protokoll anzeigen view_audit_log: Protokoll anzeigen
view_audit_log_description: Erlaubt es Benutzer*innen, den Verlauf der administrativen Handlungen auf diesem Server einzusehen view_audit_log_description: Verlauf der administrativen Vorgänge auf diesem Server
view_dashboard: Dashboard anzeigen view_dashboard: Dashboard
view_dashboard_description: Gewährt Benutzer*innen den Zugriff auf das Dashboard und verschiedene Metriken view_dashboard_description: Dashboard und verschiedene Metriken
view_devops: DevOps view_devops: DevOps
view_devops_description: Erlaubt es Benutzer*innen, auf die Sidekiq- und pgHero-Dashboards zuzugreifen view_devops_description: Auf Sidekiq- und pgHero-Dashboards zugreifen
view_feeds: Live-Feeds und Hashtags anzeigen view_feeds: Live-Feeds und Hashtags anzeigen
view_feeds_description: Ermöglicht Nutzer*innen unabhängig von den Servereinstellungen den Zugriff auf die Live-Feeds und Hashtags view_feeds_description: Zugriff auf Live-Feeds und Hashtags unabhängig der Servereinstellungen
requires_2fa: Zwei-Faktor-Authentisierung erforderlich requires_2fa: Zwei-Faktor-Authentisierung erforderlich
title: Rollen title: Rollen
rules: rules:
@@ -1972,7 +1972,7 @@ de:
pending_approval: Veröffentlichung ausstehend pending_approval: Veröffentlichung ausstehend
revoked: Beitrag durch Autor*in entfernt revoked: Beitrag durch Autor*in entfernt
quote_policies: quote_policies:
followers: Nur Follower und ich followers: Nur Follower
nobody: Nur ich nobody: Nur ich
public: Alle public: Alle
quote_post_author: Zitierte %{acct} quote_post_author: Zitierte %{acct}

View File

@@ -83,6 +83,10 @@ fr-CA:
access_denied: Le/la propriétaire de la ressource ou le serveur dautorisation a refusé la requête. access_denied: Le/la propriétaire de la ressource ou le serveur dautorisation a refusé la requête.
credential_flow_not_configured: Le flux des identifiants du mot de passe du/de la propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_from_credentials nest pas configuré. credential_flow_not_configured: Le flux des identifiants du mot de passe du/de la propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_from_credentials nest pas configuré.
invalid_client: Lauthentification du client a échoué à cause dun client inconnu, daucune authentification de client incluse ou dune méthode dauthentification non prise en charge. invalid_client: Lauthentification du client a échoué à cause dun client inconnu, daucune authentification de client incluse ou dune méthode dauthentification non prise en charge.
invalid_code_challenge_method:
one: Le code de la méthode de défi doit être %{challenge_methods}.
other: 'Le code de la méthode de défi doit être l''une de ces valeurs : %{challenge_methods}.'
zero: Le serveur d'autorisation ne supporte pas PKCE car il n'y a aucune valeur de code de méthode de défi acceptée.
invalid_grant: Lautorisation accordée est invalide, expirée, révoquée, ne concorde pas avec lURI de redirection utilisée dans la requête dautorisation, ou a été délivrée à un autre client. invalid_grant: Lautorisation accordée est invalide, expirée, révoquée, ne concorde pas avec lURI de redirection utilisée dans la requête dautorisation, ou a été délivrée à un autre client.
invalid_redirect_uri: LURI de redirection nest pas valide. invalid_redirect_uri: LURI de redirection nest pas valide.
invalid_request: invalid_request:

View File

@@ -83,6 +83,10 @@ fr:
access_denied: Le propriétaire de la ressource ou le serveur dautorisation a refusé la requête. access_denied: Le propriétaire de la ressource ou le serveur dautorisation a refusé la requête.
credential_flow_not_configured: Le flux des identifiants du mot de passe du propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_from_credentials nest pas configuré. credential_flow_not_configured: Le flux des identifiants du mot de passe du propriétaire de la ressource a échoué car Doorkeeper.configure.resource_owner_from_credentials nest pas configuré.
invalid_client: Lauthentification du client a échoué à cause dun client inconnu, daucune authentification de client incluse ou dune méthode dauthentification non prise en charge. invalid_client: Lauthentification du client a échoué à cause dun client inconnu, daucune authentification de client incluse ou dune méthode dauthentification non prise en charge.
invalid_code_challenge_method:
one: Le code de la méthode de défi doit être %{challenge_methods}.
other: 'Le code de la méthode de défi doit être l''une de ces valeurs : %{challenge_methods}.'
zero: Le serveur d'autorisation ne supporte pas PKCE car il n'y a aucune valeur de code de méthode de défi acceptée.
invalid_grant: Lautorisation accordée est invalide, expirée, annulée, ne concorde pas avec lURL de redirection utilisée dans la requête dautorisation, ou a été délivrée à un autre client. invalid_grant: Lautorisation accordée est invalide, expirée, annulée, ne concorde pas avec lURL de redirection utilisée dans la requête dautorisation, ou a été délivrée à un autre client.
invalid_redirect_uri: LURL de redirection nest pas valide. invalid_redirect_uri: LURL de redirection nest pas valide.
invalid_request: invalid_request:

View File

@@ -83,6 +83,10 @@ nn:
access_denied: Ressurseigaren eller autorisasjonstenaren avviste førespurnaden. access_denied: Ressurseigaren eller autorisasjonstenaren avviste førespurnaden.
credential_flow_not_configured: Flyten «Resource Owner Password Credentials» kunne ikkje fullførast sidan «Doorkeeper.configure.resource_owner_from_credentials» ikkje er konfigurert. credential_flow_not_configured: Flyten «Resource Owner Password Credentials» kunne ikkje fullførast sidan «Doorkeeper.configure.resource_owner_from_credentials» ikkje er konfigurert.
invalid_client: Klientautentisering feila på grunn av ukjent klient, ingen inkludert autentisering, eller ikkje støtta autentiseringsmetode. invalid_client: Klientautentisering feila på grunn av ukjent klient, ingen inkludert autentisering, eller ikkje støtta autentiseringsmetode.
invalid_code_challenge_method:
one: code_challenge_method må vera %{challenge_methods}.
other: code_challenge_method må vera ein av %{challenge_methods}.
zero: Godkjenningstenaren støttar ikkje PKCE fordi det ikkje er nokon aksepterte verdiar av code_challenge_method.
invalid_grant: Autoriseringa er ugyldig, utløpt, oppheva, stemmer ikkje med omdirigerings-URIen eller var tildelt ein annan klient. invalid_grant: Autoriseringa er ugyldig, utløpt, oppheva, stemmer ikkje med omdirigerings-URIen eller var tildelt ein annan klient.
invalid_redirect_uri: Omdirigerings-URLen er ikkje gyldig. invalid_redirect_uri: Omdirigerings-URLen er ikkje gyldig.
invalid_request: invalid_request:

View File

@@ -689,7 +689,7 @@ el:
cancel: Άκυρο cancel: Άκυρο
category: Κατηγορία category: Κατηγορία
category_description_html: Ο λόγος για τον οποίο αναφέρθηκε αυτός ο λογαριασμός και/ή το περιεχόμενο θα εσωκλείεται σε επικοινωνία με τον αναφερόμενο λογαριασμό category_description_html: Ο λόγος για τον οποίο αναφέρθηκε αυτός ο λογαριασμός και/ή το περιεχόμενο θα εσωκλείεται σε επικοινωνία με τον αναφερόμενο λογαριασμό
collections: Συλλογές collections: Συλλογές (%{count})
comment: comment:
none: Κανένα none: Κανένα
comment_description_html: 'Για να δώσει περισσότερες πληροφορίες, ο/η %{name} έγραψε:' comment_description_html: 'Για να δώσει περισσότερες πληροφορίες, ο/η %{name} έγραψε:'
@@ -725,7 +725,7 @@ el:
resolved_msg: Η αναφορά επιλύθηκε επιτυχώς! resolved_msg: Η αναφορά επιλύθηκε επιτυχώς!
skip_to_actions: Μετάβαση στις ενέργειες skip_to_actions: Μετάβαση στις ενέργειες
status: Κατάσταση status: Κατάσταση
statuses: Αναρτήσεις statuses: Αναρτήσεις (%{count})
statuses_description_html: Το προσβλητικό περιεχόμενο θα εσωκλείεται στην επικοινωνία με τον αναφερόμενο λογαριασμό statuses_description_html: Το προσβλητικό περιεχόμενο θα εσωκλείεται στην επικοινωνία με τον αναφερόμενο λογαριασμό
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ en-GB:
cancel: Cancel cancel: Cancel
category: Category category: Category
category_description_html: The reason this account and/or content was reported will be cited in communication with the reported account category_description_html: The reason this account and/or content was reported will be cited in communication with the reported account
collections: Collections collections: Collections (%{count})
comment: comment:
none: None none: None
comment_description_html: 'To provide more information, %{name} wrote:' comment_description_html: 'To provide more information, %{name} wrote:'
@@ -725,7 +725,7 @@ en-GB:
resolved_msg: Report successfully resolved! resolved_msg: Report successfully resolved!
skip_to_actions: Skip to actions skip_to_actions: Skip to actions
status: Status status: Status
statuses: Posts statuses: Posts (%{count})
statuses_description_html: Offending content will be cited in communication with the reported account statuses_description_html: Offending content will be cited in communication with the reported account
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ en:
cancel: Cancel cancel: Cancel
category: Category category: Category
category_description_html: The reason this account and/or content was reported will be cited in communication with the reported account category_description_html: The reason this account and/or content was reported will be cited in communication with the reported account
collections: Collections collections: Collections (%{count})
comment: comment:
none: None none: None
comment_description_html: 'To provide more information, %{name} wrote:' comment_description_html: 'To provide more information, %{name} wrote:'
@@ -725,7 +725,7 @@ en:
resolved_msg: Report successfully resolved! resolved_msg: Report successfully resolved!
skip_to_actions: Skip to actions skip_to_actions: Skip to actions
status: Status status: Status
statuses: Posts statuses: Posts (%{count})
statuses_description_html: Offending content will be cited in communication with the reported account statuses_description_html: Offending content will be cited in communication with the reported account
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ es-AR:
cancel: Cancelar cancel: Cancelar
category: Categoría category: Categoría
category_description_html: El motivo por el que se denunció esta cuenta o contenido será citado en las comunicaciones con la cuenta denunciada category_description_html: El motivo por el que se denunció esta cuenta o contenido será citado en las comunicaciones con la cuenta denunciada
collections: Colecciones collections: Colecciones (%{count})
comment: comment:
none: Ninguno none: Ninguno
comment_description_html: 'Para proporcionar más información, %{name} escribió:' comment_description_html: 'Para proporcionar más información, %{name} escribió:'
@@ -725,7 +725,7 @@ es-AR:
resolved_msg: "¡Denuncia exitosamente resuelta!" resolved_msg: "¡Denuncia exitosamente resuelta!"
skip_to_actions: Ir directamente a las acciones skip_to_actions: Ir directamente a las acciones
status: Estado status: Estado
statuses: Mensajes statuses: Mensajes (%{count})
statuses_description_html: El contenido ofensivo se citará en la comunicación con la cuenta denunciada statuses_description_html: El contenido ofensivo se citará en la comunicación con la cuenta denunciada
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ es-MX:
cancel: Cancelar cancel: Cancelar
category: Categoría category: Categoría
category_description_html: La razón por la que se reportó esta cuenta o contenido será citada en las comunicaciones con la cuenta reportada category_description_html: La razón por la que se reportó esta cuenta o contenido será citada en las comunicaciones con la cuenta reportada
collections: Colecciones collections: Colecciones (%{count})
comment: comment:
none: Ninguno none: Ninguno
comment_description_html: 'Para proporcionar más información, %{name} escribió:' comment_description_html: 'Para proporcionar más información, %{name} escribió:'
@@ -725,7 +725,7 @@ es-MX:
resolved_msg: "¡La denuncia se ha resuelto correctamente!" resolved_msg: "¡La denuncia se ha resuelto correctamente!"
skip_to_actions: Ir directamente a las acciones skip_to_actions: Ir directamente a las acciones
status: Estado status: Estado
statuses: Publicaciones statuses: Publicaciones (%{count})
statuses_description_html: El contenido ofensivo se citará en comunicación con la cuenta reportada statuses_description_html: El contenido ofensivo se citará en comunicación con la cuenta reportada
summary: summary:
action_preambles: action_preambles:

View File

@@ -348,8 +348,8 @@ es:
number_of_accounts: number_of_accounts:
one: 1 cuenta one: 1 cuenta
other: "%{count} cuentas" other: "%{count} cuentas"
open: Pública open: Abrir
view_publicly: Vista pública view_publicly: Ver públicamente
critical_update_pending: Actualización crítica pendiente critical_update_pending: Actualización crítica pendiente
custom_emojis: custom_emojis:
assign_category: Asignar categoría assign_category: Asignar categoría
@@ -689,7 +689,7 @@ es:
cancel: Cancelar cancel: Cancelar
category: Categoría category: Categoría
category_description_html: La razón por la que se reportó esta cuenta o contenido será citada en las comunicaciones con la cuenta reportada category_description_html: La razón por la que se reportó esta cuenta o contenido será citada en las comunicaciones con la cuenta reportada
collections: Colecciones collections: Colecciones (%{count})
comment: comment:
none: Ninguno none: Ninguno
comment_description_html: 'Para proporcionar más información, %{name} escribió:' comment_description_html: 'Para proporcionar más información, %{name} escribió:'
@@ -725,7 +725,7 @@ es:
resolved_msg: "¡La denuncia se ha resuelto correctamente!" resolved_msg: "¡La denuncia se ha resuelto correctamente!"
skip_to_actions: Ir directamente a las acciones skip_to_actions: Ir directamente a las acciones
status: Estado status: Estado
statuses: Publicaciones statuses: Publicaciones (%{count})
statuses_description_html: El contenido ofensivo se citará en la comunicación con la cuenta reportada statuses_description_html: El contenido ofensivo se citará en la comunicación con la cuenta reportada
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ fi:
cancel: Peruuta cancel: Peruuta
category: Luokka category: Luokka
category_description_html: Syy siihen, miksi tämä tili ja/tai sisältö raportoitiin, mainitaan ilmoitetun tilin kanssa viestiessä category_description_html: Syy siihen, miksi tämä tili ja/tai sisältö raportoitiin, mainitaan ilmoitetun tilin kanssa viestiessä
collections: Kokoelmat collections: Kokoelmat (%{count})
comment: comment:
none: Ei mitään none: Ei mitään
comment_description_html: 'Antaakseen lisätietoja %{name} kirjoitti:' comment_description_html: 'Antaakseen lisätietoja %{name} kirjoitti:'
@@ -725,7 +725,7 @@ fi:
resolved_msg: Raportin ratkaisu onnistui! resolved_msg: Raportin ratkaisu onnistui!
skip_to_actions: Siirry toimiin skip_to_actions: Siirry toimiin
status: Tila status: Tila
statuses: Julkaisut statuses: Julkaisut (%{count})
statuses_description_html: Loukkaava sisältö mainitaan raportoidun tilin yhteydessä statuses_description_html: Loukkaava sisältö mainitaan raportoidun tilin yhteydessä
summary: summary:
action_preambles: action_preambles:
@@ -2090,7 +2090,7 @@ fi:
subject: Kaksivaiheisen todennuksen virhe subject: Kaksivaiheisen todennuksen virhe
title: Kaksivaiheisen todennuksen toinen vaihe epäonnistui title: Kaksivaiheisen todennuksen toinen vaihe epäonnistui
suspicious_sign_in: suspicious_sign_in:
change_password: vaihda salasanasi change_password: vaihdat salasanasi
details: 'Tässä on tiedot kirjautumisesta:' details: 'Tässä on tiedot kirjautumisesta:'
explanation: Olemme havainneet kirjautumisen tilillesi uudesta IP-osoitteesta. explanation: Olemme havainneet kirjautumisen tilillesi uudesta IP-osoitteesta.
further_actions_html: Jos tämä et ollut sinä, suosittelemme, että %{action} heti ja otat käyttöön kaksivaiheisen todennuksen pitääksesi tilisi turvassa. further_actions_html: Jos tämä et ollut sinä, suosittelemme, että %{action} heti ja otat käyttöön kaksivaiheisen todennuksen pitääksesi tilisi turvassa.

View File

@@ -53,6 +53,7 @@ fo:
label: Broyt leiklut label: Broyt leiklut
no_role: Eingin leiklutur no_role: Eingin leiklutur
title: Broyt leiklut hjá %{username} title: Broyt leiklut hjá %{username}
collections: Søvn
confirm: Vátta confirm: Vátta
confirmed: Váttað confirmed: Váttað
confirming: Váttar confirming: Váttar
@@ -337,6 +338,12 @@ fo:
unpublish: Tak útgávu aftur unpublish: Tak útgávu aftur
unpublished_msg: Kunngerð tikin aftur! unpublished_msg: Kunngerð tikin aftur!
updated_msg: Kunngerð dagførd! updated_msg: Kunngerð dagførd!
collections:
accounts: Kontur
collection_title: Savn hjá %{name}
contents: Innihald
open: Opin
view_publicly: Vís fyri øllum
critical_update_pending: Kritisk dagføring bíðar critical_update_pending: Kritisk dagføring bíðar
custom_emojis: custom_emojis:
assign_category: Tilluta bólk assign_category: Tilluta bólk
@@ -676,6 +683,7 @@ fo:
cancel: Angra cancel: Angra
category: Bólkur category: Bólkur
category_description_html: Orsøkin, at hendan kontan og/ella tilfarið var melda verður fráboðað í samskifti við meldaðu kontuni category_description_html: Orsøkin, at hendan kontan og/ella tilfarið var melda verður fráboðað í samskifti við meldaðu kontuni
collections: Søvn
comment: comment:
none: Eingin none: Eingin
comment_description_html: 'Fyri at veita fleiri upplýsingar skrivaði %{name}:' comment_description_html: 'Fyri at veita fleiri upplýsingar skrivaði %{name}:'
@@ -705,11 +713,13 @@ fo:
report: 'Melding #%{id}' report: 'Melding #%{id}'
reported_account: Meldað konta reported_account: Meldað konta
reported_by: Meldað av reported_by: Meldað av
reported_content: Meldað innihald
reported_with_application: Fráboðað við umsókn reported_with_application: Fráboðað við umsókn
resolved: Loyst resolved: Loyst
resolved_msg: Melding avgreidd! resolved_msg: Melding avgreidd!
skip_to_actions: Leyp til atgerðir skip_to_actions: Leyp til atgerðir
status: Støða status: Støða
statuses: Postar
statuses_description_html: Tilfarið, sum brotið viðvíkur, fer at vera siterað í samskifti við meldaðu kontuni statuses_description_html: Tilfarið, sum brotið viðvíkur, fer at vera siterað í samskifti við meldaðu kontuni
summary: summary:
action_preambles: action_preambles:

View File

@@ -692,7 +692,7 @@ fr-CA:
cancel: Annuler cancel: Annuler
category: Catégorie category: Catégorie
category_description_html: La raison pour laquelle ce compte et/ou ce contenu a été signalé sera citée dans la communication avec le compte signalé category_description_html: La raison pour laquelle ce compte et/ou ce contenu a été signalé sera citée dans la communication avec le compte signalé
collections: Collections collections: Collections (%{count})
comment: comment:
none: Aucun none: Aucun
comment_description_html: 'Pour fournir plus d''informations, %{name} a écrit :' comment_description_html: 'Pour fournir plus d''informations, %{name} a écrit :'
@@ -728,7 +728,7 @@ fr-CA:
resolved_msg: Signalement résolu avec succès! resolved_msg: Signalement résolu avec succès!
skip_to_actions: Passer aux actions skip_to_actions: Passer aux actions
status: Statut status: Statut
statuses: Messages statuses: Messages (%{count})
statuses_description_html: Le contenu offensant sera cité dans la communication avec le compte signalé statuses_description_html: Le contenu offensant sera cité dans la communication avec le compte signalé
summary: summary:
action_preambles: action_preambles:

View File

@@ -59,7 +59,7 @@ fr:
collections: Collections collections: Collections
confirm: Confirmer confirm: Confirmer
confirmed: Confirmé confirmed: Confirmé
confirming: Confirmation confirming: Confirmation en attente
custom: Personnaliser custom: Personnaliser
delete: Supprimer les données delete: Supprimer les données
deleted: Supprimé deleted: Supprimé
@@ -692,7 +692,7 @@ fr:
cancel: Annuler cancel: Annuler
category: Catégorie category: Catégorie
category_description_html: La raison pour laquelle ce compte et/ou ce contenu a été signalé sera citée dans la communication avec le compte signalé category_description_html: La raison pour laquelle ce compte et/ou ce contenu a été signalé sera citée dans la communication avec le compte signalé
collections: Collections collections: Collections (%{count})
comment: comment:
none: Aucun none: Aucun
comment_description_html: 'Pour fournir plus d''informations, %{name} a écrit :' comment_description_html: 'Pour fournir plus d''informations, %{name} a écrit :'
@@ -728,7 +728,7 @@ fr:
resolved_msg: Signalement résolu avec succès! resolved_msg: Signalement résolu avec succès!
skip_to_actions: Passer aux actions skip_to_actions: Passer aux actions
status: Statut status: Statut
statuses: Messages statuses: Messages (%{count})
statuses_description_html: Le contenu offensant sera cité dans la communication avec le compte signalé statuses_description_html: Le contenu offensant sera cité dans la communication avec le compte signalé
summary: summary:
action_preambles: action_preambles:

View File

@@ -731,7 +731,7 @@ ga:
cancel: Cealaigh cancel: Cealaigh
category: Catagóir category: Catagóir
category_description_html: Luafar an chúis ar tuairiscíodh an cuntas seo agus/nó an t-ábhar seo i gcumarsáid leis an gcuntas tuairiscithe category_description_html: Luafar an chúis ar tuairiscíodh an cuntas seo agus/nó an t-ábhar seo i gcumarsáid leis an gcuntas tuairiscithe
collections: Bailiúcháin collections: Bailiúcháin (%{count})
comment: comment:
none: Dada none: Dada
comment_description_html: 'Chun tuilleadh eolais a sholáthar, scríobh %{name}:' comment_description_html: 'Chun tuilleadh eolais a sholáthar, scríobh %{name}:'
@@ -767,7 +767,7 @@ ga:
resolved_msg: D'éirigh le réiteach an tuairisc! resolved_msg: D'éirigh le réiteach an tuairisc!
skip_to_actions: Léim ar ghníomhartha skip_to_actions: Léim ar ghníomhartha
status: Stádas status: Stádas
statuses: Poist statuses: Poist (%{count})
statuses_description_html: Luafar ábhar ciontach i gcumarsáid leis an gcuntas tuairiscithe statuses_description_html: Luafar ábhar ciontach i gcumarsáid leis an gcuntas tuairiscithe
summary: summary:
action_preambles: action_preambles:

View File

@@ -689,7 +689,7 @@ gl:
cancel: Cancelar cancel: Cancelar
category: Categoría category: Categoría
category_description_html: A razón para denunciar esta conta ou contido será citada na comunicación coa conta denunciada category_description_html: A razón para denunciar esta conta ou contido será citada na comunicación coa conta denunciada
collections: Coleccións collections: Coleccións (%{count})
comment: comment:
none: Ningún none: Ningún
comment_description_html: 'Como información engadida, %{name} escribiu:' comment_description_html: 'Como información engadida, %{name} escribiu:'
@@ -725,7 +725,7 @@ gl:
resolved_msg: Resolveuse con éxito a denuncia! resolved_msg: Resolveuse con éxito a denuncia!
skip_to_actions: Ir a accións skip_to_actions: Ir a accións
status: Estado status: Estado
statuses: Publicacións statuses: Publicacións (%{count})
statuses_description_html: O contido ofensivo será citado na comunicación coa conta denunciada statuses_description_html: O contido ofensivo será citado na comunicación coa conta denunciada
summary: summary:
action_preambles: action_preambles:

View File

@@ -62,6 +62,7 @@ he:
label: שינוי תפקיד label: שינוי תפקיד
no_role: ללא תפקיד no_role: ללא תפקיד
title: שינוי תפקיד עבור %{username} title: שינוי תפקיד עבור %{username}
collections: אוספים
confirm: אישור confirm: אישור
confirmed: אושר confirmed: אושר
confirming: בתהליך אישור confirming: בתהליך אישור
@@ -348,6 +349,17 @@ he:
unpublish: ביטול פרסום unpublish: ביטול פרסום
unpublished_msg: פרסום ההכרזה בוטל בהצלחה! unpublished_msg: פרסום ההכרזה בוטל בהצלחה!
updated_msg: ההכרזה עודכנה בהצלחה! updated_msg: ההכרזה עודכנה בהצלחה!
collections:
accounts: חשבונות
collection_title: אוספים מאת %{name}
contents: תוכן
number_of_accounts:
many: "%{count} חשבונות"
one: חשבון אחד
other: "%{count} חשבונות"
two: חשבונותיים
open: פתיחה
view_publicly: צפיה בפומבי
critical_update_pending: עידכון קריטי ממתין critical_update_pending: עידכון קריטי ממתין
custom_emojis: custom_emojis:
assign_category: הקצאת קטגוריה assign_category: הקצאת קטגוריה
@@ -705,6 +717,7 @@ he:
cancel: ביטול cancel: ביטול
category: קטגוריה category: קטגוריה
category_description_html: הסיבה בגללה חשבון זה ו/או תוכנו דווחו תצוטט בתקשורת עם החשבון המדווח category_description_html: הסיבה בגללה חשבון זה ו/או תוכנו דווחו תצוטט בתקשורת עם החשבון המדווח
collections: אוספים
comment: comment:
none: ללא none: ללא
comment_description_html: 'על מנת לספק עוד מידע, %{name} כתב\ה:' comment_description_html: 'על מנת לספק עוד מידע, %{name} כתב\ה:'
@@ -734,11 +747,13 @@ he:
report: 'דווח על #%{id}' report: 'דווח על #%{id}'
reported_account: חשבון מדווח reported_account: חשבון מדווח
reported_by: דווח על ידי reported_by: דווח על ידי
reported_content: התוכן עליו דווח
reported_with_application: דיווחים באמצעות יישומון reported_with_application: דיווחים באמצעות יישומון
resolved: פתור resolved: פתור
resolved_msg: הדו"ח נפתר בהצלחה! resolved_msg: הדו"ח נפתר בהצלחה!
skip_to_actions: דלג/י לפעולות skip_to_actions: דלג/י לפעולות
status: מצב status: מצב
statuses: הודעות
statuses_description_html: התוכן הפוגע יצוטט בתקשורת עם החשבון המדווח statuses_description_html: התוכן הפוגע יצוטט בתקשורת עם החשבון המדווח
summary: summary:
action_preambles: action_preambles:

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