Merge commit 'b902c825054b953599cd0341acf428332fca5044' into glitch-soc/merge-upstream
This commit is contained in:
commit
08027edb10
76 files changed
+914
-690
No files matched your search
@@ -30,8 +30,8 @@ export const HoverCardController: React.FC = () => {
|
||||
const cardRef = useRef<HTMLDivElement | null>(null);
|
||||
const [setLeaveTimeout, cancelLeaveTimeout] = useTimeout();
|
||||
const [setEnterTimeout, cancelEnterTimeout, delayEnterTimeout] = useTimeout();
|
||||
const [setMoveTimeout, cancelMoveTimeout] = useTimeout();
|
||||
const [setScrollTimeout] = useTimeout();
|
||||
const lastMouseMoveTime = useRef<number>(0);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
cancelEnterTimeout();
|
||||
@@ -50,7 +50,6 @@ export const HoverCardController: React.FC = () => {
|
||||
useEffect(() => {
|
||||
let isScrolling = false;
|
||||
let isUsingTouch = false;
|
||||
let isActiveMouseMovement = false;
|
||||
let currentAnchor: HTMLElement | null = null;
|
||||
let currentTitle: string | null = null;
|
||||
|
||||
@@ -84,31 +83,40 @@ export const HoverCardController: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail out if we're scrolling, a touch is active,
|
||||
// or if there was no active mouse movement
|
||||
if (isScrolling || !isActiveMouseMovement || isUsingTouch) {
|
||||
return;
|
||||
}
|
||||
// This 0ms timeout is needed to push processing of this code
|
||||
// until after the mousemove event was run, in order to be able
|
||||
// to track the most recent value of lastMouseMoveTime.current
|
||||
setTimeout(() => {
|
||||
// Check if mouse moved within the active movement threshold
|
||||
const timeSinceLastMove = Date.now() - lastMouseMoveTime.current;
|
||||
const hasRecentMovement = timeSinceLastMove < activeMovementThreshold;
|
||||
|
||||
// We've entered an anchor
|
||||
if (isHoverCardAnchor(target)) {
|
||||
cancelLeaveTimeout();
|
||||
// Bail out if we're scrolling, a touch is active,
|
||||
// or if there was no active mouse movement
|
||||
if (isScrolling || !hasRecentMovement || isUsingTouch) {
|
||||
return;
|
||||
}
|
||||
|
||||
currentAnchor?.removeAttribute('aria-describedby');
|
||||
currentAnchor = target;
|
||||
// We've entered an anchor
|
||||
if (isHoverCardAnchor(target)) {
|
||||
cancelLeaveTimeout();
|
||||
|
||||
currentTitle = target.getAttribute('title');
|
||||
target.removeAttribute('title');
|
||||
currentAnchor?.removeAttribute('aria-describedby');
|
||||
currentAnchor = target;
|
||||
|
||||
setEnterTimeout(() => {
|
||||
open(target);
|
||||
}, enterDelay);
|
||||
}
|
||||
currentTitle = target.getAttribute('title');
|
||||
target.removeAttribute('title');
|
||||
|
||||
// We've entered the hover card
|
||||
if (target === currentAnchor || target === cardRef.current) {
|
||||
cancelLeaveTimeout();
|
||||
}
|
||||
setEnterTimeout(() => {
|
||||
open(target);
|
||||
}, enterDelay);
|
||||
}
|
||||
|
||||
// We've entered the hover card
|
||||
if (target === currentAnchor || target === cardRef.current) {
|
||||
cancelLeaveTimeout();
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const handleMouseLeave = (e: MouseEvent) => {
|
||||
@@ -149,18 +157,15 @@ export const HoverCardController: React.FC = () => {
|
||||
isUsingTouch = false;
|
||||
}
|
||||
|
||||
const hasMoved = Math.max(e.movementX, e.movementY) > 0;
|
||||
const hasMoved =
|
||||
Math.max(Math.abs(e.movementX), Math.abs(e.movementY)) > 0;
|
||||
|
||||
if (!hasMoved) {
|
||||
return;
|
||||
}
|
||||
|
||||
delayEnterTimeout(enterDelay);
|
||||
|
||||
cancelMoveTimeout();
|
||||
isActiveMouseMovement = true;
|
||||
setMoveTimeout(() => {
|
||||
isActiveMouseMovement = false;
|
||||
}, activeMovementThreshold);
|
||||
lastMouseMoveTime.current = Date.now();
|
||||
};
|
||||
|
||||
document.body.addEventListener('touchstart', handleTouchStart, {
|
||||
@@ -204,8 +209,6 @@ export const HoverCardController: React.FC = () => {
|
||||
setOpen,
|
||||
setAccountId,
|
||||
setAnchor,
|
||||
setMoveTimeout,
|
||||
cancelMoveTimeout,
|
||||
]);
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useCallback, useId, useState } from 'react';
|
||||
import { FormattedMessage, useIntl, defineMessages } from 'react-intl';
|
||||
|
||||
import type { ApiCollectionJSON } from '@/mastodon/api_types/collections';
|
||||
import { EmptyState } from '@/mastodon/components/empty_state';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { NavigationFocusTarget } from '@/mastodon/components/navigation_focus_target';
|
||||
import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId';
|
||||
@@ -16,7 +17,10 @@ import { IconButton } from 'mastodon/components/icon_button';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import { MAX_COLLECTION_ACCOUNT_COUNT } from '../collections/editor/accounts';
|
||||
import { useCollectionsCreatedBy } from '../collections/overview/created_by_account';
|
||||
import {
|
||||
NewCollectionButton,
|
||||
useCollectionsCreatedBy,
|
||||
} from '../collections/overview/created_by_account';
|
||||
|
||||
import { CollectionToggle } from './collection_toggle';
|
||||
|
||||
@@ -136,6 +140,23 @@ export const CollectionAdder: React.FC<{
|
||||
>
|
||||
{status === 'loading' || !account ? (
|
||||
<LoadingIndicator />
|
||||
) : collections.length === 0 ? (
|
||||
<EmptyState
|
||||
title={
|
||||
<FormattedMessage
|
||||
id='empty_column.collections_self'
|
||||
defaultMessage='You have not created any collections yet.'
|
||||
/>
|
||||
}
|
||||
message={
|
||||
<FormattedMessage
|
||||
id='empty_column.account_featured_self.showcase_accounts_desc'
|
||||
defaultMessage='Collections are curated lists of accounts to help others discover more of the Fediverse.'
|
||||
/>
|
||||
}
|
||||
>
|
||||
<NewCollectionButton onClick={onClose} />
|
||||
</EmptyState>
|
||||
) : (
|
||||
collections.map((item) => (
|
||||
<ListItem key={item.id} collection={item} account={account} />
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ const messages = defineMessages({
|
||||
revokeCollectionInclusionMessage: {
|
||||
id: 'confirmations.revoke_collection_inclusion.message',
|
||||
defaultMessage:
|
||||
"This action is permanent, and the curator won't be able to re-add you to the collection later on.",
|
||||
"The curator won't be able to re-add you to this collection for 24 hours. To prevent them from adding you to collections permanently, you can block them.",
|
||||
},
|
||||
revokeCollectionInclusionConfirm: {
|
||||
id: 'confirmations.revoke_collection_inclusion.confirm',
|
||||
|
||||
@@ -26,8 +26,14 @@ import {
|
||||
} from '../editor';
|
||||
import classes from '../styles.module.scss';
|
||||
|
||||
const CreateButton: React.FC = () => (
|
||||
<Link to='/collections/new' className='button button--compact'>
|
||||
export const NewCollectionButton: React.FC<{ onClick?: () => void }> = ({
|
||||
onClick,
|
||||
}) => (
|
||||
<Link
|
||||
to='/collections/new'
|
||||
className='button button--compact'
|
||||
onClick={onClick}
|
||||
>
|
||||
<Icon id='plus' icon={AddIcon} />
|
||||
<FormattedMessage {...editorMessages.newCollection} />
|
||||
</Link>
|
||||
@@ -97,7 +103,7 @@ export const CollectionsCreatedByAccount: React.FC = () => {
|
||||
/>
|
||||
}
|
||||
>
|
||||
<CreateButton />
|
||||
<NewCollectionButton />
|
||||
</EmptyState>
|
||||
);
|
||||
} else {
|
||||
@@ -129,7 +135,7 @@ export const CollectionsCreatedByAccount: React.FC = () => {
|
||||
}}
|
||||
/>
|
||||
</h2>
|
||||
{showCreateButton && <CreateButton />}
|
||||
{showCreateButton && <NewCollectionButton />}
|
||||
</div>
|
||||
<ItemList>
|
||||
{isOwnCollectionPage && !canCreateMoreCollections && (
|
||||
|
||||
@@ -316,8 +316,8 @@ class ComposeForm extends ImmutablePureComponent {
|
||||
className='compose-form__input'
|
||||
/>
|
||||
|
||||
<UploadForm />
|
||||
<PollForm />
|
||||
<UploadForm />
|
||||
<ComposeQuotedStatus />
|
||||
|
||||
<div className='compose-form__footer'>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { customEmojiFactory, unicodeEmojiFactory } from '@/testing/factories';
|
||||
|
||||
import {
|
||||
putEmojiData,
|
||||
search,
|
||||
loadEmojiByHexcode,
|
||||
testClear,
|
||||
testGet,
|
||||
@@ -31,6 +32,108 @@ describe('emoji database', () => {
|
||||
indexedDB = new IDBFactory();
|
||||
});
|
||||
|
||||
describe('search', () => {
|
||||
beforeEach(async () => {
|
||||
await putEmojiData([], 'en');
|
||||
});
|
||||
|
||||
test('test no query tokens', async () => {
|
||||
await putEmojiData([rawEmojiFactory()], 'en');
|
||||
await expect(search({ query: ' ', locale: 'en' })).resolves.toEqual([]);
|
||||
});
|
||||
|
||||
test('unicode results', async () => {
|
||||
await putEmojiData(
|
||||
[
|
||||
rawEmojiFactory({
|
||||
hexcode: 'unicode_hex',
|
||||
label: 'Party Popper',
|
||||
shortcodes: ['party_popper'],
|
||||
unicode: '🎉',
|
||||
}),
|
||||
],
|
||||
'en',
|
||||
);
|
||||
|
||||
await expect(
|
||||
search({ query: 'party', locale: 'en' }),
|
||||
).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
hexcode: 'unicode_hex',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('custom results', async () => {
|
||||
await putCustomEmojiData({
|
||||
emojis: [customEmojiFactory({ shortcode: 'party_custom' })],
|
||||
});
|
||||
|
||||
await expect(
|
||||
search({ query: 'party', locale: 'en' }),
|
||||
).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
shortcode: 'party_custom',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('shortcode results', async () => {
|
||||
await putEmojiData([rawEmojiFactory()], 'en');
|
||||
await putLegacyShortcodes({
|
||||
test: ['legacy_smile'],
|
||||
});
|
||||
|
||||
await expect(
|
||||
search({ query: 'legacy', locale: 'en' }),
|
||||
).resolves.toContainEqual(
|
||||
expect.objectContaining({
|
||||
hexcode: 'test',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('full custom emoji search', async () => {
|
||||
await putCustomEmojiData({
|
||||
emojis: [
|
||||
customEmojiFactory({ shortcode: 'arrow' }),
|
||||
customEmojiFactory({ shortcode: 'party_parrot' }),
|
||||
],
|
||||
});
|
||||
|
||||
const result = await search({ query: 'arro', locale: 'en' });
|
||||
expect(result).toContainEqual(
|
||||
// Test for ordinary IDB search
|
||||
expect.objectContaining({
|
||||
shortcode: 'arrow',
|
||||
}),
|
||||
);
|
||||
expect(result).toContainEqual(
|
||||
// Test for manual iteration search
|
||||
expect.objectContaining({
|
||||
shortcode: 'party_parrot',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('limit test', async () => {
|
||||
await putCustomEmojiData({
|
||||
emojis: [
|
||||
customEmojiFactory({ shortcode: 'limit' }),
|
||||
customEmojiFactory({ shortcode: 'limit_extra' }),
|
||||
],
|
||||
});
|
||||
|
||||
await expect(
|
||||
search({ query: 'limit', locale: 'en', limit: 1 }),
|
||||
).resolves.toEqual([
|
||||
expect.objectContaining({
|
||||
shortcode: 'limit',
|
||||
}),
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('putEmojiData', () => {
|
||||
test('adds to loaded locales', async () => {
|
||||
const { loadedLocales } = await testGet();
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
transformCustomEmojiData,
|
||||
transformEmojiData,
|
||||
} from './normalize';
|
||||
import type { AnyEmojiData, CacheKey } from './types';
|
||||
import type { AnyEmojiData, CacheKey, CustomEmojiData } from './types';
|
||||
import { emojiLogger } from './utils';
|
||||
|
||||
const loadedLocales = new Set<Locale>();
|
||||
@@ -78,6 +78,8 @@ export async function search({
|
||||
// Create an array of emoji results
|
||||
const db = await loadDB();
|
||||
const resultArrays: ScoreMap[] = [];
|
||||
const existingCustomShortcodes = new Set<string>();
|
||||
|
||||
for (let i = 0; i < queryTokens.length; i++) {
|
||||
const token = queryTokens[i];
|
||||
if (!token) continue;
|
||||
@@ -96,6 +98,7 @@ export async function search({
|
||||
],
|
||||
);
|
||||
const resultMap: ScoreMap = new Map();
|
||||
|
||||
for (const emoji of unicodeResults) {
|
||||
const score = getScoreForEmoji(emoji, token);
|
||||
if (score === null) {
|
||||
@@ -103,11 +106,13 @@ export async function search({
|
||||
}
|
||||
resultMap.set(emoji.hexcode, { ...emoji, score });
|
||||
}
|
||||
|
||||
for (const emoji of customResults) {
|
||||
const score = getScoreForEmoji(emoji, token);
|
||||
if (score === null) {
|
||||
continue;
|
||||
}
|
||||
existingCustomShortcodes.add(emoji.shortcode);
|
||||
resultMap.set(emoji.shortcode, { ...emoji, score });
|
||||
}
|
||||
|
||||
@@ -119,7 +124,14 @@ export async function search({
|
||||
if (!emoji) {
|
||||
continue;
|
||||
}
|
||||
const score = getScoreForEmoji(emoji, token);
|
||||
// Score the emoji with the legacy shortcode, even though it's not part of the emoji.
|
||||
const score = getScoreForEmoji(
|
||||
{
|
||||
...emoji,
|
||||
shortcodes: [...shortcodeResult.shortcodes, ...emoji.shortcodes],
|
||||
},
|
||||
token,
|
||||
);
|
||||
if (score === null) {
|
||||
continue;
|
||||
}
|
||||
@@ -146,21 +158,19 @@ export async function search({
|
||||
);
|
||||
|
||||
// If there are no results, try a cursor-based custom emoji search instead.
|
||||
if (results.length === 0) {
|
||||
const trx = db.transaction('custom', 'readonly');
|
||||
const foundEmojis = new Set<string>();
|
||||
for await (const cursor of trx.store) {
|
||||
const emoji = cursor.value;
|
||||
const score = getScoreForEmoji(emoji, query, false);
|
||||
if (score === null || foundEmojis.has(emoji.shortcode)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
results.push({ ...emoji, score });
|
||||
foundEmojis.add(emoji.shortcode);
|
||||
if (results.length === 0 || results.length < limit) {
|
||||
const customEmojisFound = await fullCustomSearch(
|
||||
query,
|
||||
existingCustomShortcodes,
|
||||
);
|
||||
if (customEmojisFound.length > 0) {
|
||||
log(
|
||||
'cursor search found %d results for "%s"',
|
||||
customEmojisFound.length,
|
||||
query,
|
||||
);
|
||||
results.push(...customEmojisFound);
|
||||
}
|
||||
log('cursor search found %d results for "%s"', foundEmojis.size, query);
|
||||
await trx.done;
|
||||
}
|
||||
|
||||
// Sort by score, descending.
|
||||
@@ -191,7 +201,14 @@ function getScoreForEmoji(
|
||||
}
|
||||
|
||||
let index = 1;
|
||||
const searchTokens = checkTokens ? [id, ...emoji.tokens] : [id];
|
||||
const searchTokens = [id];
|
||||
if (checkTokens) {
|
||||
// Check shortcodes before tokens as they are more important.
|
||||
if ('shortcodes' in emoji) {
|
||||
searchTokens.push(...emoji.shortcodes);
|
||||
}
|
||||
searchTokens.push(...emoji.tokens);
|
||||
}
|
||||
for (const token of searchTokens) {
|
||||
const tokenIndex = token.indexOf(query);
|
||||
if (tokenIndex !== -1) {
|
||||
@@ -203,6 +220,51 @@ function getScoreForEmoji(
|
||||
return null;
|
||||
}
|
||||
|
||||
async function fullCustomSearch(query: string, existing = new Set<string>()) {
|
||||
const db = await loadDB();
|
||||
const trx = db.transaction('custom', 'readonly');
|
||||
const foundEmojis = new Set<string>();
|
||||
|
||||
// First iterate over chunks of 1,000 custom emoji keys and find any matches.
|
||||
const chunkSize = 1_000;
|
||||
let lastKey: string | null = null;
|
||||
let keys: string[] = [];
|
||||
do {
|
||||
const keyRange = lastKey ? IDBKeyRange.lowerBound(lastKey, true) : null;
|
||||
keys = await trx.store.getAllKeys(keyRange, chunkSize);
|
||||
|
||||
if (keys.length === 0) {
|
||||
break;
|
||||
}
|
||||
log('cursor search got batch of %d emojis', keys.length);
|
||||
lastKey = keys.at(-1) ?? null;
|
||||
|
||||
for (const key of keys) {
|
||||
if (!foundEmojis.has(key) && !existing.has(key) && key.includes(query)) {
|
||||
foundEmojis.add(key);
|
||||
}
|
||||
}
|
||||
} while (keys.length === chunkSize);
|
||||
|
||||
// Next get the full emojis for all matches.
|
||||
const emojis = await Promise.all(
|
||||
foundEmojis.keys().map((key) => trx.store.get(key)),
|
||||
);
|
||||
const results: (CustomEmojiData & { score: number })[] = [];
|
||||
for (const emoji of emojis) {
|
||||
if (emoji) {
|
||||
const score = getScoreForEmoji(emoji, query, false);
|
||||
if (score && score > 0) {
|
||||
results.push({
|
||||
score,
|
||||
...emoji,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
export async function putEmojiData(emojis: CompactEmoji[], locale: Locale) {
|
||||
loadedLocales.add(locale);
|
||||
const db = await loadDB();
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} пакуль не стварыў(-ла) аніводнай калекцыі.",
|
||||
"empty_column.collections.featured_in": "Вас пакуль не дадалі ў ніякія калекцыі.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Каб людзі маглі дадаваць Вас у калекцыі, Вам трэба даць ім дазвол знаходзіць Вас у <link>Налады > Прыватнасць і пошук</link>",
|
||||
"empty_column.collections_self": "Вы пакуль не стварылі ніводнай калекцыі.",
|
||||
"empty_column.community": "Мясцовая стужка пустая. Напішыце нешта публічнае, каб разварушыць справу!",
|
||||
"empty_column.direct": "Пакуль у Вас няма асабістых згадванняў. Калі Вы дашляце або атрымаеце штосьці, яно з’явіцца тут.",
|
||||
"empty_column.disabled_feed": "Гэта стужка была адключаная Вашымі адміністратарамі сервера.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} har endnu ikke oprettet nogen samlinger.",
|
||||
"empty_column.collections.featured_in": "Du er ikke blevet tilføjet til nogen samlinger endnu.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "For at andre kan føje dig til samlinger, skal du give tilladelse til at blive vist i opdagelsesfunktioner under <link>Præferencer > Fortrolighed og rækkevidde</link>",
|
||||
"empty_column.collections_self": "Du har endnu ikke oprettet nogen samlinger.",
|
||||
"empty_column.community": "Den lokale tidslinje er tom. Skriv noget offentligt for at sætte tingene i gang!",
|
||||
"empty_column.direct": "Du har ikke nogen private omtaler endnu. Når du sender eller modtager en, vil den blive vist her.",
|
||||
"empty_column.disabled_feed": "Dette feed er blevet deaktiveret af dine serveradministratorer.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} hat noch keine Sammlungen erstellt.",
|
||||
"empty_column.collections.featured_in": "Du wurdest noch keiner Sammlung hinzugefügt.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Damit du zu Sammlungen hinzugefügt werden kannst, muss „Mich beim Entdecken berücksichtigen“ unter <link>Einstellungen > Datenschutz und Reichweite</link> aktiviert werden",
|
||||
"empty_column.collections_self": "Du hast noch keine Sammlungen erstellt.",
|
||||
"empty_column.community": "Die lokale Timeline ist leer. Schreibe einen öffentlichen Beitrag, um den Stein ins Rollen zu bringen!",
|
||||
"empty_column.direct": "Du hast noch keine privaten Erwähnungen. Sobald du eine sendest oder erhältst, wird sie hier erscheinen.",
|
||||
"empty_column.disabled_feed": "Diesen Feed haben deine Server-Administrator*innen deaktiviert.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "Ο χρήστης {acct} δεν έχει δημιουργήσει ακόμη καμία συλλογή.",
|
||||
"empty_column.collections.featured_in": "Δεν έχετε προστεθεί ακόμη σε καμία συλλογή.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Προκειμένου ο κόσμος να σας προσθέσει σε συλλογές, πρέπει να επιτρέψετε την ανάδειξή σας σε εμπειρίες ανακάλυψης από τις <link>Προτιμήσεις > Ιδιωτικότητα και προσιτότητα</link>",
|
||||
"empty_column.collections_self": "Δεν έχετε δημιουργήσει ακόμη καμία συλλογή.",
|
||||
"empty_column.community": "Η τοπική ροή είναι κενή. Γράψε κάτι δημόσια για να αρχίσει να κυλά η μπάλα!",
|
||||
"empty_column.direct": "Δεν έχεις καμία ιδιωτική επισήμανση ακόμη. Όταν στείλεις ή λάβεις μία, θα εμφανιστεί εδώ.",
|
||||
"empty_column.disabled_feed": "Αυτή η ροή έχει απενεργοποιηθεί από τους διαχειριστές του διακομιστή σας.",
|
||||
|
||||
@@ -561,7 +561,7 @@
|
||||
"confirmations.remove_from_followers.message": "{name} will stop following you. Are you sure you want to proceed?",
|
||||
"confirmations.remove_from_followers.title": "Remove follower?",
|
||||
"confirmations.revoke_collection_inclusion.confirm": "Remove me",
|
||||
"confirmations.revoke_collection_inclusion.message": "This action is permanent, and the curator won't be able to re-add you to the collection later on.",
|
||||
"confirmations.revoke_collection_inclusion.message": "The curator won't be able to re-add you to this collection for 24 hours. To prevent them from adding you to collections permanently, you can block them.",
|
||||
"confirmations.revoke_collection_inclusion.title": "Remove yourself from this collection?",
|
||||
"confirmations.revoke_quote.confirm": "Remove post",
|
||||
"confirmations.revoke_quote.message": "This action cannot be undone.",
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} has not created any collections yet.",
|
||||
"empty_column.collections.featured_in": "You have not been added to any collections yet.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "In order for people to add you to collections, you need to allow featuring in discovery experiences from <link>Preferences > Privacy and reach</link>",
|
||||
"empty_column.collections_self": "You have not created any collections yet.",
|
||||
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
|
||||
"empty_column.direct": "You don't have any private mentions yet. When you send or receive one, it will show up here.",
|
||||
"empty_column.disabled_feed": "This feed has been disabled by your server administrators.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} todavía no creó ninguna colección.",
|
||||
"empty_column.collections.featured_in": "Todavía no te agregaron a ninguna colección.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Para que la gente pueda agregarte a colecciones, tenés que permitir que te destacen en las experiencias de descubrimiento en <link>Configuración > Privacidad y alcance</link>",
|
||||
"empty_column.collections_self": "Aún no has creado ninguna colección.",
|
||||
"empty_column.community": "La línea temporal local está vacía. ¡Escribí algo en modo público para que se empiece a correr la bola!",
|
||||
"empty_column.direct": "Todavía no tenés ninguna mención privada. Cuando enviés o recibás una, se mostrará acá.",
|
||||
"empty_column.disabled_feed": "Esta línea temporal fue deshabilitada por los administradores de tu servidor.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} todavía no ha creado ninguna colección.",
|
||||
"empty_column.collections.featured_in": "Aún no te han añadido a ninguna colección.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Para que los usuarios puedan añadirte a sus colecciones, debes habilitar la opción de aparecer en las experiencias de descubrimiento desde <link>Preferencias > Privacidad y alcance</link>",
|
||||
"empty_column.collections_self": "Aún no has creado ninguna colección.",
|
||||
"empty_column.community": "La cronología local está vacía. ¡Escribe algo públicamente para ponerla en marcha!",
|
||||
"empty_column.direct": "Aún no tienes ninguna mención privada. Cuando envíes o recibas una, aparecerá aquí.",
|
||||
"empty_column.disabled_feed": "Esta cronología fue desactivada por los administradores de tu servidor.",
|
||||
@@ -780,7 +781,7 @@
|
||||
"home.pending_critical_update.link": "Ver actualizaciones",
|
||||
"home.pending_critical_update.title": "¡Actualización de seguridad crítica disponible!",
|
||||
"home.show_announcements": "Mostrar anuncios",
|
||||
"ignore_notifications_modal.bots_title": "¿Ignorar notificaciones de bots?",
|
||||
"ignore_notifications_modal.bots_title": "¿Ignorar las notificaciones de los bots?",
|
||||
"ignore_notifications_modal.disclaimer": "Mastodon no puede informar a los usuarios que has ignorado sus notificaciones. Ignorar notificaciones no impedirá que se sigan enviando los mensajes.",
|
||||
"ignore_notifications_modal.filter_instead": "Filtrar en su lugar",
|
||||
"ignore_notifications_modal.filter_to_act_users": "Aún podrás aceptar, rechazar o reportar usuarios",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} aún no ha creado ninguna colección.",
|
||||
"empty_column.collections.featured_in": "Aún no te han añadido a ninguna colección.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Para que la gente pueda añadirte a colecciones, debes permitir ser destacado en algoritmos de descubrimiento desde <link>Preferencias > Privacidad y alcance</link>",
|
||||
"empty_column.collections_self": "Aún no has creado ninguna colección.",
|
||||
"empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!",
|
||||
"empty_column.direct": "Aún no tienes menciones privadas. Cuando envíes o recibas una, aparecerán aquí.",
|
||||
"empty_column.disabled_feed": "Esta cronología ha sido desactivada por los administradores del servidor.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} ei ole luonut vielä yhtään kokoelmaa.",
|
||||
"empty_column.collections.featured_in": "Sinua ei ole vielä lisätty mihinkään kokoelmaan.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Jotta sinut voi lisätä kokoelmiin, esittely löydettävyyskokemuksissa on sallittava kohdassa <link>Asetukset > Yksityisyys ja tavoittavuus</link>",
|
||||
"empty_column.collections_self": "Et ole luonut vielä yhtään kokoelmaa.",
|
||||
"empty_column.community": "Paikallinen aikajana on tyhjä. Kirjoita jotain julkista, niin homma lähtee käyntiin!",
|
||||
"empty_column.direct": "Yksityismainintoja ei vielä ole. Jos lähetät tai sinulle lähetetään sellaisia, näet ne täällä.",
|
||||
"empty_column.disabled_feed": "Palvelimen ylläpito on poistanut käytöstä tämän syötteen.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} n'a pas encore créé de collection.",
|
||||
"empty_column.collections.featured_in": "Vous n'avez pas encore été ajouté·e à une collection.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Afin que l'on puisse vous ajouter à des collections, vous devez autoriser d'apparaître dans les expériences de découverte depuis <link>Vie privée et visibilité</link>",
|
||||
"empty_column.collections_self": "Vous n'avez pas encore créé de collection.",
|
||||
"empty_column.community": "Le fil local est vide. Écrivez donc quelque chose pour le remplir!",
|
||||
"empty_column.direct": "Vous n'avez pas encore de mentions privées. Quand vous en envoyez ou en recevez, elles apparaîtront ici.",
|
||||
"empty_column.disabled_feed": "Ce flux a été désactivé par les administrateur·rice·s de votre serveur.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} n'a pas encore créé de collection.",
|
||||
"empty_column.collections.featured_in": "Vous n'avez pas encore été ajouté·e à une collection.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Afin que l'on puisse vous ajouter à des collections, vous devez autoriser d'apparaître dans les expériences de découverte depuis <link>Vie privée et visibilité</link>",
|
||||
"empty_column.collections_self": "Vous n'avez pas encore créé de collection.",
|
||||
"empty_column.community": "Le fil public local est vide. Écrivez donc quelque chose pour le remplir !",
|
||||
"empty_column.direct": "Vous n'avez pas encore de mentions privées. Quand vous en enverrez ou recevrez, elles apparaîtront ici.",
|
||||
"empty_column.disabled_feed": "Ce flux a été désactivé par les administrateur·rice·s de votre serveur.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "Níl aon bhailiúcháin cruthaithe ag {acct} go fóill.",
|
||||
"empty_column.collections.featured_in": "Níor cuireadh le haon bhailiúchán thú go fóill.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Chun go mbeidh daoine in ann tú a chur le bailiúcháin, ní mór duit cead a thabhairt duit a bheith le feiceáil i dtaithí fionnachtana ó <link>Sainroghanna > Príobháideacht agus raon feidhme</link>",
|
||||
"empty_column.collections_self": "Níl aon bhailiúcháin cruthaithe agat go fóill.",
|
||||
"empty_column.community": "Tá an amlíne áitiúil folamh. Foilsigh rud éigin go poiblí le tús a chur le cúrsaí!",
|
||||
"empty_column.direct": "Níl aon tagairtí príobháideacha agat fós. Nuair a sheolann tú nó a gheobhaidh tú ceann, beidh sé le feiceáil anseo.",
|
||||
"empty_column.disabled_feed": "Tá an fotha seo díchumasaithe ag riarthóirí do fhreastalaí.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} non ha ancora creato alcuna collezione.",
|
||||
"empty_column.collections.featured_in": "Non sei ancora stato/a aggiunto/a ad alcuna collezione.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Affinché le persone possano aggiungerti alle collezioni, è necessario consentire che il profilo sia visibile nelle esperienze di scoperta tramite <link>Preferenze > Privacy e visibilità</link>",
|
||||
"empty_column.collections_self": "Non hai ancora creato alcuna collezione.",
|
||||
"empty_column.community": "La cronologia locale è vuota. Scrivi qualcosa pubblicamente per dare inizio alla festa!",
|
||||
"empty_column.direct": "Non hai ancora alcuna menzione privata. Quando ne invierai o riceverai una, apparirà qui.",
|
||||
"empty_column.disabled_feed": "Questo feed è stato disabilitato dagli amministratori del tuo server.",
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
"account.media": "Multivide",
|
||||
"account.mention": "Pieminēt @{name}",
|
||||
"account.menu.add_to_list": "Pievienot sarakstam…",
|
||||
"account.menu.block": "Bloķēt kontu",
|
||||
"account.menu.block": "Liegt kontu",
|
||||
"account.menu.block_domain": "Liegt {domain}",
|
||||
"account.menu.copy": "Kopēt saiti",
|
||||
"account.menu.mute": "Apklusināt kontu",
|
||||
@@ -112,7 +112,7 @@
|
||||
"account.unblock": "Atcelt liegšanu @{name}",
|
||||
"account.unblock_domain": "Atcelt domēna {domain} liegšanu",
|
||||
"account.unblock_domain_short": "Atcelt liegšanu",
|
||||
"account.unblock_short": "Atbloķēt",
|
||||
"account.unblock_short": "Atcelt liegšanu",
|
||||
"account.unendorse": "Neizcelt profilā",
|
||||
"account.unfollow": "Pārstāt sekot",
|
||||
"account.unmute": "Noņemt apklusinājumu @{name}",
|
||||
@@ -178,11 +178,11 @@
|
||||
"annual_report.summary.percentile.we_wont_tell_bernie": "Mēs neteiksim Bērnijam.",
|
||||
"attachments_list.unprocessed": "(neapstrādāti)",
|
||||
"audio.hide": "Slēpt audio",
|
||||
"block_modal.remote_users_caveat": "Mēs lūgsim serverim {domain} ņemt vērā Tavu lēmumu. Tomēr sadarbība nav garantēta, jo atsevišķi serveri bloķēšanu var apstrādāt citādi. Publiski ieraksti, iespējams, joprojām būs redzami lietotājiem, kuri nav pieteikušies.",
|
||||
"block_modal.remote_users_caveat": "Mēs vaicāsim serverim {domain} ņemt vērā Tavu lēmumu. Tomēr atbilstība nav nodrošināta, jo atsevišķi serveri liegšanu var apstrādāt citādi. Publiski ieraksti joprojām var būt redzami lietotājiem, kuri nav pieteikušies.",
|
||||
"block_modal.show_less": "Rādīt mazāk",
|
||||
"block_modal.show_more": "Rādīt vairāk",
|
||||
"block_modal.they_will_know": "Lietotājs varēs redzēt, ka ir bloķēts.",
|
||||
"block_modal.title": "Bloķēt lietotāju?",
|
||||
"block_modal.they_will_know": "Lietotājs varēs redzēt, ka ir liegts.",
|
||||
"block_modal.title": "Liegt lietotāju?",
|
||||
"boost_modal.combo": "Nospied {combo}, lai nākamreiz šo izlaistu",
|
||||
"boost_modal.reblog": "Pastiprināt ierakstu?",
|
||||
"boost_modal.undo_reblog": "Atcelt ieraksta pastiprināšanu?",
|
||||
@@ -204,7 +204,7 @@
|
||||
"closed_registrations_modal.preamble": "Mastodon ir decentralizēts, tāpēc neatkarīgi no tā, kur Tu izveido savu kontu, varēsi sekot un mijiedarboties ar ikvienu šajā serverī. Tu pat vari to pašizvietot!",
|
||||
"closed_registrations_modal.title": "Reģistrēšanās Mastodon",
|
||||
"collections.accounts.empty_title": "Šī kolekcija ir tukša",
|
||||
"collections.block_collection_owner": "Bloķēt kontu",
|
||||
"collections.block_collection_owner": "Liegt kontu",
|
||||
"collections.collection_description": "Apraksts",
|
||||
"collections.collection_language": "Valoda",
|
||||
"collections.collection_language_none": "Nav",
|
||||
@@ -316,8 +316,8 @@
|
||||
"confirmations.revoke_quote.confirm": "Noņemt ierakstu",
|
||||
"confirmations.revoke_quote.message": "Šo darbību nevar atsaukt.",
|
||||
"confirmations.revoke_quote.title": "Noņemt ierakstu?",
|
||||
"confirmations.unblock.confirm": "Atbloķēt",
|
||||
"confirmations.unblock.title": "Atbloķēt {name}?",
|
||||
"confirmations.unblock.confirm": "Atcelt liegšanu",
|
||||
"confirmations.unblock.title": "Atcelt {name} liegumu?",
|
||||
"confirmations.unfollow.confirm": "Pārstāt sekot",
|
||||
"confirmations.unfollow.title": "Pārtraukt sekot {name}?",
|
||||
"confirmations.withdraw_request.confirm": "Atsaukt pieprasījumu",
|
||||
@@ -341,7 +341,7 @@
|
||||
"dismissable_banner.dismiss": "Atcelt",
|
||||
"dismissable_banner.public_timeline": "Šie ir jaunākie Fediverse lietotāju publiskie ieraksti, kuriem {domain} seko cilvēki.",
|
||||
"domain_block_modal.block": "Liegt serveri",
|
||||
"domain_block_modal.block_account_instead": "Tā vietā bloķēt @{name}",
|
||||
"domain_block_modal.block_account_instead": "Tā vietā liegt @{name}",
|
||||
"domain_block_modal.they_cant_follow": "Neviens no šī servera nevarēs Tev sekot.",
|
||||
"domain_block_modal.they_wont_know": "Viņi nezinās, ka tikuši liegti.",
|
||||
"domain_block_modal.title": "Liegt domēnu?",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} não criou nenhuma coleção ainda.",
|
||||
"empty_column.collections.featured_in": "Você ainda não foi adicionado a uma coleção.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Para as pessoas adicionarem você às coleções, você precisa permitir destaque de experiências de descoberta através de <link>Preferências > Privacidade e alcance</link>",
|
||||
"empty_column.collections_self": "Você ainda não criou nenhuma coleção.",
|
||||
"empty_column.community": "A linha local está vazia. Publique algo para começar!",
|
||||
"empty_column.direct": "Você ainda não possui menções privadas. Caso você enviar ou receber uma, ela aparecerá aqui.",
|
||||
"empty_column.disabled_feed": "Este feed foi desativado pelos administradores de seu servidor.",
|
||||
|
||||
@@ -644,6 +644,7 @@
|
||||
"empty_column.collections": "{acct} s’ka krijuar ende ndonjë koleksion.",
|
||||
"empty_column.collections.featured_in": "S’jeni shtuar ende te ndonjë koleksion.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Që njerëzit t’ju shtojnë te koleksione, lypset të lejoni shfaqjen si i zgjedhur në raste zbulimi, që nga <link>Parapëlqime > Privatësi dhe shtrirje</link>",
|
||||
"empty_column.collections_self": "S’keni krijuar ende ndonjë koleksion.",
|
||||
"empty_column.community": "Rrjedha kohore vendore është e zbrazët. Shkruani diçka publikisht që t’i hyhet valles!",
|
||||
"empty_column.direct": "S’keni ende ndonjë përmendje private. Kur dërgoni ose merrni një të tillë, do të shfaqet këtu.",
|
||||
"empty_column.disabled_feed": "Kjo prurje është çaktivizuar nga përgjegjësit e shërbyesit tuaj.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} har ännu inte skapat några samlingar.",
|
||||
"empty_column.collections.featured_in": "Du har inte lagts till i några samlingar än.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "För att personer ska kunna lägga till dig i samlingar, måste du tillåta att inkluderas i upptäcktsupplevelser från <link>Inställningar> Sekretess och räckvidd</link>",
|
||||
"empty_column.collections_self": "Du har inte skapat några samlingar än.",
|
||||
"empty_column.community": "Den lokala tidslinjen är tom. Skriv något offentligt för att sätta bollen i rullning!",
|
||||
"empty_column.direct": "Du har inga privata omnämnanden. När du skickar eller tar emot ett direktmeddelande kommer det att visas här.",
|
||||
"empty_column.disabled_feed": "Detta flöde har inaktiverats av dina serveradministratörer.",
|
||||
@@ -780,6 +781,7 @@
|
||||
"home.pending_critical_update.link": "Se uppdateringar",
|
||||
"home.pending_critical_update.title": "En kritisk säkerhetsuppdatering är tillgänglig!",
|
||||
"home.show_announcements": "Visa notiser",
|
||||
"ignore_notifications_modal.bots_title": "Ignorera aviseringar från botar?",
|
||||
"ignore_notifications_modal.disclaimer": "Mastodon kan inte informera användarna om att du har ignorerat deras meddelanden. Ignorering av aviseringar kommer inte att stoppa själva meddelandena från att skickas.",
|
||||
"ignore_notifications_modal.filter_instead": "Filtrera istället",
|
||||
"ignore_notifications_modal.filter_to_act_users": "Du kommer fortfarande att kunna acceptera, avvisa eller rapportera användare",
|
||||
@@ -846,6 +848,7 @@
|
||||
"keyboard_shortcuts.toggle_sensitivity": "Visa/gömma media",
|
||||
"keyboard_shortcuts.toot": "Starta nytt inlägg",
|
||||
"keyboard_shortcuts.top": "Flytta till början av listan",
|
||||
"keyboard_shortcuts.translate": "Översätt ett inlägg",
|
||||
"keyboard_shortcuts.unfocus": "Avfokusera skrivfält/sökfält",
|
||||
"keyboard_shortcuts.up": "Flytta uppåt i listan",
|
||||
"learn_more_link.got_it": "Jag förstår",
|
||||
@@ -1041,6 +1044,8 @@
|
||||
"notifications.policy.drop": "Ignorera",
|
||||
"notifications.policy.drop_hint": "Skicka ut i tomrummet för aldrig synas till igen",
|
||||
"notifications.policy.filter": "Filtrera",
|
||||
"notifications.policy.filter_bots_hint": "Konton markerade som automatiserade",
|
||||
"notifications.policy.filter_bots_title": "Botar",
|
||||
"notifications.policy.filter_hint": "Skicka till inkorgen för filtrerade aviserings",
|
||||
"notifications.policy.filter_limited_accounts_hint": "Begränsade av servermoderatorer",
|
||||
"notifications.policy.filter_limited_accounts_title": "Modererade konton",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} henüz bir koleksiyon oluşturmadı.",
|
||||
"empty_column.collections.featured_in": "Henüz herhangi bir koleksiyona eklenmediniz.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Kullanıcıların sizi koleksiyonlarına ekleyebilmesi için, <link>Tercihler > Gizlilik ve erişim</link> bölümünden keşif deneyimlerinde öne çıkarılmaya izin vermeniz gerekir",
|
||||
"empty_column.collections_self": "Henüz bir koleksiyon oluşturmadınız.",
|
||||
"empty_column.community": "Yerel zaman çizelgesi boş. Daha fazla eğlence için herkese açık bir gönderi paylaşın!",
|
||||
"empty_column.direct": "Henüz doğrudan değinmeniz yok. Bir tane gönderdiğinizde veya aldığınızda burada listelenecek.",
|
||||
"empty_column.disabled_feed": "Bu akış sunucu yöneticileri tarafından devre dışı bırakılmıştır.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} chưa tạo gói khởi đầu nào.",
|
||||
"empty_column.collections.featured_in": "Bạn chưa được thêm vào gói khởi đầu nào.",
|
||||
"empty_column.collections.featured_in_undiscoverable": "Để mọi người có thể thêm bạn vào gói khởi đầu, bạn cần cho phép hiển thị trong trải nghiệm khám phá ở <link>Thiết lập > Riêng tư và tiếp cận</link>",
|
||||
"empty_column.collections_self": "Bạn chưa tạo gói khởi đầu nào.",
|
||||
"empty_column.community": "Máy chủ của bạn chưa có tút nào công khai. Bạn hãy thử viết gì đó đi!",
|
||||
"empty_column.direct": "Bạn chưa có tin nhắn riêng nào. Khi bạn gửi hoặc nhận một tin nhắn riêng, nó sẽ xuất hiện ở đây.",
|
||||
"empty_column.disabled_feed": "Bảng tin này bị vô hiệu hóa bởi quản trị viên máy chủ của bạn.",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} 尚未创建任何收藏列表。",
|
||||
"empty_column.collections.featured_in": "你还没有被添加到收藏列表过。",
|
||||
"empty_column.collections.featured_in_undiscoverable": "如果想让其他人将你添加到收藏列表,请前往<link>偏好设置 > 隐私与可达性</link>在发现功能中允许推荐",
|
||||
"empty_column.collections_self": "你尚未创建任何收藏列表。",
|
||||
"empty_column.community": "本站时间线还没有内容,写点什么并公开发布,让它活跃起来吧!",
|
||||
"empty_column.direct": "你还未使用过私下提及。当你发出或者收到私下提及时,它将显示在此。",
|
||||
"empty_column.disabled_feed": "此动态已被你的服务器管理员禁用。",
|
||||
|
||||
@@ -649,6 +649,7 @@
|
||||
"empty_column.collections": "{acct} 尚未建立任何收藏名單。",
|
||||
"empty_column.collections.featured_in": "您尚未被加入至任何收藏名單。",
|
||||
"empty_column.collections.featured_in_undiscoverable": "如欲被其他人將您加入至收藏名單,您必須於 <link>偏好設定 > 隱私權與觸及</link> 啟用探索相關功能",
|
||||
"empty_column.collections_self": "您尚未建立任何收藏名單。",
|
||||
"empty_column.community": "本站時間軸是空的。快公開嘟些文搶頭香啊!",
|
||||
"empty_column.direct": "您還沒有收到任何私訊。當您私訊別人或收到私訊時,它將於此顯示。",
|
||||
"empty_column.disabled_feed": "此內容已被您的伺服器管理員停用。",
|
||||
|
||||
@@ -2498,7 +2498,7 @@ a.account__display-name {
|
||||
overflow: hidden;
|
||||
|
||||
strong,
|
||||
span {
|
||||
span:not(.emojione) {
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
|
||||
Reference in new issue
Block a user