mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-18 18:48:20 +00:00
Merge commit '366856f3bcdc2ff008b04e493a5de317ab83d5d0' into glitch-soc/merge-upstream
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -24,7 +24,7 @@ gem 'ruby-vips', '~> 2.2', require: false
|
|||||||
|
|
||||||
gem 'active_model_serializers', '~> 0.10'
|
gem 'active_model_serializers', '~> 0.10'
|
||||||
gem 'addressable', '~> 2.8'
|
gem 'addressable', '~> 2.8'
|
||||||
gem 'bootsnap', '~> 1.18.0', require: false
|
gem 'bootsnap', '~> 1.19.0', require: false
|
||||||
gem 'browser'
|
gem 'browser'
|
||||||
gem 'charlock_holmes', '~> 0.7.7'
|
gem 'charlock_holmes', '~> 0.7.7'
|
||||||
gem 'chewy', '~> 7.3'
|
gem 'chewy', '~> 7.3'
|
||||||
|
|||||||
16
Gemfile.lock
16
Gemfile.lock
@@ -129,7 +129,7 @@ GEM
|
|||||||
binding_of_caller (1.0.1)
|
binding_of_caller (1.0.1)
|
||||||
debug_inspector (>= 1.2.0)
|
debug_inspector (>= 1.2.0)
|
||||||
blurhash (0.1.8)
|
blurhash (0.1.8)
|
||||||
bootsnap (1.18.6)
|
bootsnap (1.19.0)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (7.1.1)
|
brakeman (7.1.1)
|
||||||
racc
|
racc
|
||||||
@@ -349,7 +349,7 @@ GEM
|
|||||||
azure-blob (~> 0.5.2)
|
azure-blob (~> 0.5.2)
|
||||||
hashie (~> 5.0)
|
hashie (~> 5.0)
|
||||||
jmespath (1.6.2)
|
jmespath (1.6.2)
|
||||||
json (2.15.2)
|
json (2.16.0)
|
||||||
json-canonicalization (1.0.0)
|
json-canonicalization (1.0.0)
|
||||||
json-jwt (1.17.0)
|
json-jwt (1.17.0)
|
||||||
activesupport (>= 4.2)
|
activesupport (>= 4.2)
|
||||||
@@ -446,7 +446,7 @@ GEM
|
|||||||
mime-types-data (3.2025.0924)
|
mime-types-data (3.2025.0924)
|
||||||
mini_mime (1.1.5)
|
mini_mime (1.1.5)
|
||||||
mini_portile2 (2.8.9)
|
mini_portile2 (2.8.9)
|
||||||
minitest (5.26.0)
|
minitest (5.26.1)
|
||||||
msgpack (1.8.0)
|
msgpack (1.8.0)
|
||||||
multi_json (1.17.0)
|
multi_json (1.17.0)
|
||||||
mutex_m (0.3.0)
|
mutex_m (0.3.0)
|
||||||
@@ -759,7 +759,7 @@ GEM
|
|||||||
rubocop-ast (>= 1.47.1, < 2.0)
|
rubocop-ast (>= 1.47.1, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 2.4.0, < 4.0)
|
unicode-display_width (>= 2.4.0, < 4.0)
|
||||||
rubocop-ast (1.47.1)
|
rubocop-ast (1.48.0)
|
||||||
parser (>= 3.3.7.2)
|
parser (>= 3.3.7.2)
|
||||||
prism (~> 1.4)
|
prism (~> 1.4)
|
||||||
rubocop-capybara (2.22.1)
|
rubocop-capybara (2.22.1)
|
||||||
@@ -778,10 +778,10 @@ GEM
|
|||||||
rack (>= 1.1)
|
rack (>= 1.1)
|
||||||
rubocop (>= 1.75.0, < 2.0)
|
rubocop (>= 1.75.0, < 2.0)
|
||||||
rubocop-ast (>= 1.44.0, < 2.0)
|
rubocop-ast (>= 1.44.0, < 2.0)
|
||||||
rubocop-rspec (3.7.0)
|
rubocop-rspec (3.8.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop (~> 1.72, >= 1.72.1)
|
rubocop (~> 1.81)
|
||||||
rubocop-rspec_rails (2.31.0)
|
rubocop-rspec_rails (2.32.0)
|
||||||
lint_roller (~> 1.1)
|
lint_roller (~> 1.1)
|
||||||
rubocop (~> 1.72, >= 1.72.1)
|
rubocop (~> 1.72, >= 1.72.1)
|
||||||
rubocop-rspec (~> 3.5)
|
rubocop-rspec (~> 3.5)
|
||||||
@@ -941,7 +941,7 @@ DEPENDENCIES
|
|||||||
better_errors (~> 2.9)
|
better_errors (~> 2.9)
|
||||||
binding_of_caller (~> 1.0)
|
binding_of_caller (~> 1.0)
|
||||||
blurhash (~> 0.1)
|
blurhash (~> 0.1)
|
||||||
bootsnap (~> 1.18.0)
|
bootsnap (~> 1.19.0)
|
||||||
brakeman (~> 7.0)
|
brakeman (~> 7.0)
|
||||||
browser
|
browser
|
||||||
bundler-audit (~> 0.9)
|
bundler-audit (~> 0.9)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module Admin
|
|||||||
|
|
||||||
@site_upload.destroy!
|
@site_upload.destroy!
|
||||||
|
|
||||||
redirect_back fallback_location: admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
redirect_back_or_to admin_settings_path, notice: I18n.t('admin.site_uploads.destroyed_msg')
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -180,15 +180,15 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
|||||||
|
|
||||||
if (shouldHandleEvent) {
|
if (shouldHandleEvent) {
|
||||||
const matchCandidates: {
|
const matchCandidates: {
|
||||||
handler: (event: KeyboardEvent) => void;
|
// A candidate will be have an undefined handler if it's matched,
|
||||||
|
// but handled in a parent component rather than this one.
|
||||||
|
handler: ((event: KeyboardEvent) => void) | undefined;
|
||||||
priority: number;
|
priority: number;
|
||||||
}[] = [];
|
}[] = [];
|
||||||
|
|
||||||
(Object.keys(hotkeyMatcherMap) as HotkeyName[]).forEach(
|
(Object.keys(hotkeyMatcherMap) as HotkeyName[]).forEach(
|
||||||
(handlerName) => {
|
(handlerName) => {
|
||||||
const handler = handlersRef.current[handlerName];
|
const handler = handlersRef.current[handlerName];
|
||||||
|
|
||||||
if (handler) {
|
|
||||||
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
|
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
|
||||||
|
|
||||||
const { isMatch, priority } = hotkeyMatcher(
|
const { isMatch, priority } = hotkeyMatcher(
|
||||||
@@ -199,7 +199,6 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
|||||||
if (isMatch) {
|
if (isMatch) {
|
||||||
matchCandidates.push({ handler, priority });
|
matchCandidates.push({ handler, priority });
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
|
|||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
className={classNames('mention hashtag', className)}
|
className={classNames('mention hashtag', className)}
|
||||||
to={`/tags/${hashtag}`}
|
to={`/tags/${encodeURIComponent(hashtag)}`}
|
||||||
rel='tag'
|
rel='tag'
|
||||||
data-menu-hashtag={hashtagAccountId}
|
data-menu-hashtag={hashtagAccountId}
|
||||||
>
|
>
|
||||||
@@ -71,7 +71,7 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
|
|||||||
return (
|
return (
|
||||||
<a
|
<a
|
||||||
{...props}
|
{...props}
|
||||||
href={encodeURI(href)}
|
href={href}
|
||||||
title={href}
|
title={href}
|
||||||
className={classNames('unhandled-link', className)}
|
className={classNames('unhandled-link', className)}
|
||||||
target='_blank'
|
target='_blank'
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { pasteLinkCompose } from 'mastodon/actions/compose_typed';
|
import { pasteLinkCompose } from 'mastodon/actions/compose_typed';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import { PRIVATE_QUOTE_MODAL_ID } from 'mastodon/features/ui/components/confirmation_modals/private_quote_notify';
|
import { PRIVATE_QUOTE_MODAL_ID } from 'mastodon/features/ui/components/confirmation_modals/private_quote_notify';
|
||||||
|
import { me } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import ComposeForm from '../components/compose_form';
|
import ComposeForm from '../components/compose_form';
|
||||||
|
|
||||||
@@ -53,6 +54,7 @@ const mapStateToProps = state => ({
|
|||||||
quoteToPrivate:
|
quoteToPrivate:
|
||||||
!!state.getIn(['compose', 'quoted_status_id'])
|
!!state.getIn(['compose', 'quoted_status_id'])
|
||||||
&& state.getIn(['compose', 'privacy']) === 'private'
|
&& state.getIn(['compose', 'privacy']) === 'private'
|
||||||
|
&& state.getIn(['statuses', state.getIn(['compose', 'quoted_status_id']), 'account']) !== me
|
||||||
&& !state.getIn(['settings', 'dismissed_banners', PRIVATE_QUOTE_MODAL_ID]),
|
&& !state.getIn(['settings', 'dismissed_banners', PRIVATE_QUOTE_MODAL_ID]),
|
||||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||||
lang: state.getIn(['compose', 'language']),
|
lang: state.getIn(['compose', 'language']),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { initialState } from '@/mastodon/initial_state';
|
import { initialState } from '@/mastodon/initial_state';
|
||||||
|
|
||||||
import { toSupportedLocale } from './locale';
|
import { toSupportedLocale } from './locale';
|
||||||
|
import type { LocaleOrCustom } from './types';
|
||||||
import { emojiLogger } from './utils';
|
import { emojiLogger } from './utils';
|
||||||
// eslint-disable-next-line import/default -- Importing via worker loader.
|
// eslint-disable-next-line import/default -- Importing via worker loader.
|
||||||
import EmojiWorker from './worker?worker&inline';
|
import EmojiWorker from './worker?worker&inline';
|
||||||
@@ -24,19 +25,17 @@ export function initializeEmoji() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (worker) {
|
if (worker) {
|
||||||
// Assign worker to const to make TS happy inside the event listener.
|
|
||||||
const thisWorker = worker;
|
|
||||||
const timeoutId = setTimeout(() => {
|
const timeoutId = setTimeout(() => {
|
||||||
log('worker is not ready after timeout');
|
log('worker is not ready after timeout');
|
||||||
worker = null;
|
worker = null;
|
||||||
void fallbackLoad();
|
void fallbackLoad();
|
||||||
}, WORKER_TIMEOUT);
|
}, WORKER_TIMEOUT);
|
||||||
thisWorker.addEventListener('message', (event: MessageEvent<string>) => {
|
worker.addEventListener('message', (event: MessageEvent<string>) => {
|
||||||
const { data: message } = event;
|
const { data: message } = event;
|
||||||
if (message === 'ready') {
|
if (message === 'ready') {
|
||||||
log('worker ready, loading data');
|
log('worker ready, loading data');
|
||||||
clearTimeout(timeoutId);
|
clearTimeout(timeoutId);
|
||||||
thisWorker.postMessage('custom');
|
messageWorker('custom');
|
||||||
void loadEmojiLocale(userLocale);
|
void loadEmojiLocale(userLocale);
|
||||||
// Load English locale as well, because people are still used to
|
// Load English locale as well, because people are still used to
|
||||||
// using it from before we supported other locales.
|
// using it from before we supported other locales.
|
||||||
@@ -55,20 +54,35 @@ export function initializeEmoji() {
|
|||||||
async function fallbackLoad() {
|
async function fallbackLoad() {
|
||||||
log('falling back to main thread for loading');
|
log('falling back to main thread for loading');
|
||||||
const { importCustomEmojiData } = await import('./loader');
|
const { importCustomEmojiData } = await import('./loader');
|
||||||
await importCustomEmojiData();
|
const emojis = await importCustomEmojiData();
|
||||||
|
if (emojis) {
|
||||||
|
log('loaded %d custom emojis', emojis.length);
|
||||||
|
}
|
||||||
await loadEmojiLocale(userLocale);
|
await loadEmojiLocale(userLocale);
|
||||||
if (userLocale !== 'en') {
|
if (userLocale !== 'en') {
|
||||||
await loadEmojiLocale('en');
|
await loadEmojiLocale('en');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function loadEmojiLocale(localeString: string) {
|
async function loadEmojiLocale(localeString: string) {
|
||||||
const locale = toSupportedLocale(localeString);
|
const locale = toSupportedLocale(localeString);
|
||||||
|
const { importEmojiData, localeToPath } = await import('./loader');
|
||||||
|
|
||||||
if (worker) {
|
if (worker) {
|
||||||
worker.postMessage(locale);
|
const path = await localeToPath(locale);
|
||||||
|
log('asking worker to load locale %s from %s', locale, path);
|
||||||
|
messageWorker(locale, path);
|
||||||
} else {
|
} else {
|
||||||
const { importEmojiData } = await import('./loader');
|
const emojis = await importEmojiData(locale);
|
||||||
await importEmojiData(locale);
|
if (emojis) {
|
||||||
|
log('loaded %d emojis to locale %s', emojis.length, locale);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function messageWorker(locale: LocaleOrCustom, path?: string) {
|
||||||
|
if (!worker) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
worker.postMessage({ locale, path });
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,44 +8,64 @@ import {
|
|||||||
putLatestEtag,
|
putLatestEtag,
|
||||||
} from './database';
|
} from './database';
|
||||||
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
||||||
import type { CustomEmojiData, LocaleOrCustom } from './types';
|
import type { CustomEmojiData } from './types';
|
||||||
import { emojiLogger } from './utils';
|
|
||||||
|
|
||||||
const log = emojiLogger('loader');
|
export async function importEmojiData(localeString: string, path?: string) {
|
||||||
|
|
||||||
export async function importEmojiData(localeString: string) {
|
|
||||||
const locale = toSupportedLocale(localeString);
|
const locale = toSupportedLocale(localeString);
|
||||||
const emojis = await fetchAndCheckEtag<CompactEmoji[]>(locale);
|
|
||||||
|
// Validate the provided path.
|
||||||
|
if (path && !/^[/a-z]*\/packs\/assets\/compact-\w+\.json$/.test(path)) {
|
||||||
|
throw new Error('Invalid path for emoji data');
|
||||||
|
} else {
|
||||||
|
// Otherwise get the path if not provided.
|
||||||
|
path ??= await localeToPath(locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojis = await fetchAndCheckEtag<CompactEmoji[]>(locale, path);
|
||||||
if (!emojis) {
|
if (!emojis) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
||||||
log('loaded %d for %s locale', flattenedEmojis.length, locale);
|
|
||||||
await putEmojiData(flattenedEmojis, locale);
|
await putEmojiData(flattenedEmojis, locale);
|
||||||
|
return flattenedEmojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importCustomEmojiData() {
|
export async function importCustomEmojiData() {
|
||||||
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>('custom');
|
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>(
|
||||||
|
'custom',
|
||||||
|
'/api/v1/custom_emojis',
|
||||||
|
);
|
||||||
if (!emojis) {
|
if (!emojis) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log('loaded %d custom emojis', emojis.length);
|
|
||||||
await putCustomEmojiData(emojis);
|
await putCustomEmojiData(emojis);
|
||||||
|
return emojis;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchAndCheckEtag<ResultType extends object[]>(
|
const modules = import.meta.glob<string>(
|
||||||
localeOrCustom: LocaleOrCustom,
|
'../../../../../node_modules/emojibase-data/**/compact.json',
|
||||||
|
{
|
||||||
|
query: '?url',
|
||||||
|
import: 'default',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export function localeToPath(locale: Locale) {
|
||||||
|
const key = `../../../../../node_modules/emojibase-data/${locale}/compact.json`;
|
||||||
|
if (!modules[key] || typeof modules[key] !== 'function') {
|
||||||
|
throw new Error(`Unsupported locale: ${locale}`);
|
||||||
|
}
|
||||||
|
return modules[key]();
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchAndCheckEtag<ResultType extends object[]>(
|
||||||
|
localeString: string,
|
||||||
|
path: string,
|
||||||
): Promise<ResultType | null> {
|
): Promise<ResultType | null> {
|
||||||
const locale = toSupportedLocaleOrCustom(localeOrCustom);
|
const locale = toSupportedLocaleOrCustom(localeString);
|
||||||
|
|
||||||
// Use location.origin as this script may be loaded from a CDN domain.
|
// Use location.origin as this script may be loaded from a CDN domain.
|
||||||
const url = new URL(location.origin);
|
const url = new URL(path, location.origin);
|
||||||
if (locale === 'custom') {
|
|
||||||
url.pathname = '/api/v1/custom_emojis';
|
|
||||||
} else {
|
|
||||||
const modulePath = await localeToPath(locale);
|
|
||||||
url.pathname = modulePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const oldEtag = await loadLatestEtag(locale);
|
const oldEtag = await loadLatestEtag(locale);
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
@@ -60,38 +80,20 @@ async function fetchAndCheckEtag<ResultType extends object[]>(
|
|||||||
}
|
}
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to fetch emoji data for ${localeOrCustom}: ${response.statusText}`,
|
`Failed to fetch emoji data for ${locale}: ${response.statusText}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = (await response.json()) as ResultType;
|
const data = (await response.json()) as ResultType;
|
||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
throw new Error(
|
throw new Error(`Unexpected data format for ${locale}: expected an array`);
|
||||||
`Unexpected data format for ${localeOrCustom}: expected an array`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the ETag for future requests
|
// Store the ETag for future requests
|
||||||
const etag = response.headers.get('ETag');
|
const etag = response.headers.get('ETag');
|
||||||
if (etag) {
|
if (etag) {
|
||||||
await putLatestEtag(etag, localeOrCustom);
|
await putLatestEtag(etag, localeString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modules = import.meta.glob<string>(
|
|
||||||
'../../../../../node_modules/emojibase-data/**/compact.json',
|
|
||||||
{
|
|
||||||
query: '?url',
|
|
||||||
import: 'default',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
function localeToPath(locale: Locale) {
|
|
||||||
const key = `../../../../../node_modules/emojibase-data/${locale}/compact.json`;
|
|
||||||
if (!modules[key] || typeof modules[key] !== 'function') {
|
|
||||||
throw new Error(`Unsupported locale: ${locale}`);
|
|
||||||
}
|
|
||||||
return modules[key]();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ describe('loadEmojiDataToState', () => {
|
|||||||
const dbCall = vi
|
const dbCall = vi
|
||||||
.spyOn(db, 'loadEmojiByHexcode')
|
.spyOn(db, 'loadEmojiByHexcode')
|
||||||
.mockRejectedValue(new db.LocaleNotLoadedError('en'));
|
.mockRejectedValue(new db.LocaleNotLoadedError('en'));
|
||||||
vi.spyOn(loader, 'importEmojiData').mockResolvedValueOnce();
|
vi.spyOn(loader, 'importEmojiData').mockResolvedValueOnce(undefined);
|
||||||
const consoleCall = vi
|
const consoleCall = vi
|
||||||
.spyOn(console, 'warn')
|
.spyOn(console, 'warn')
|
||||||
.mockImplementationOnce(() => null);
|
.mockImplementationOnce(() => null);
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
import { importEmojiData, importCustomEmojiData } from './loader';
|
import { importCustomEmojiData, importEmojiData } from './loader';
|
||||||
|
|
||||||
addEventListener('message', handleMessage);
|
addEventListener('message', handleMessage);
|
||||||
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
||||||
|
|
||||||
function handleMessage(event: MessageEvent<string>) {
|
function handleMessage(event: MessageEvent<{ locale: string; path?: string }>) {
|
||||||
const { data: locale } = event;
|
const {
|
||||||
void loadData(locale);
|
data: { locale, path },
|
||||||
|
} = event;
|
||||||
|
void loadData(locale, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadData(locale: string) {
|
async function loadData(locale: string, path?: string) {
|
||||||
if (locale !== 'custom') {
|
let importCount: number | undefined;
|
||||||
await importEmojiData(locale);
|
if (locale === 'custom') {
|
||||||
|
importCount = (await importCustomEmojiData())?.length;
|
||||||
|
} else if (path) {
|
||||||
|
importCount = (await importEmojiData(locale, path))?.length;
|
||||||
} else {
|
} else {
|
||||||
await importCustomEmojiData();
|
throw new Error('Path is required for loading locale emoji data');
|
||||||
|
}
|
||||||
|
if (importCount) {
|
||||||
|
self.postMessage(`loaded ${importCount} emojis into ${locale}`);
|
||||||
}
|
}
|
||||||
self.postMessage(`loaded ${locale}`);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
@typescript-eslint/no-unsafe-assignment */
|
@typescript-eslint/no-unsafe-assignment */
|
||||||
|
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import { useState, useRef, useCallback } from 'react';
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||||
|
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
@@ -55,6 +55,8 @@ export const DetailedStatus: React.FC<{
|
|||||||
pictureInPicture: any;
|
pictureInPicture: any;
|
||||||
onToggleHidden?: (status: any) => void;
|
onToggleHidden?: (status: any) => void;
|
||||||
onToggleMediaVisibility?: () => void;
|
onToggleMediaVisibility?: () => void;
|
||||||
|
ancestors?: number;
|
||||||
|
multiColumn?: boolean;
|
||||||
}> = ({
|
}> = ({
|
||||||
status,
|
status,
|
||||||
onOpenMedia,
|
onOpenMedia,
|
||||||
@@ -69,6 +71,8 @@ export const DetailedStatus: React.FC<{
|
|||||||
pictureInPicture,
|
pictureInPicture,
|
||||||
onToggleMediaVisibility,
|
onToggleMediaVisibility,
|
||||||
onToggleHidden,
|
onToggleHidden,
|
||||||
|
ancestors = 0,
|
||||||
|
multiColumn = false,
|
||||||
}) => {
|
}) => {
|
||||||
const properStatus = status?.get('reblog') ?? status;
|
const properStatus = status?.get('reblog') ?? status;
|
||||||
const [height, setHeight] = useState(0);
|
const [height, setHeight] = useState(0);
|
||||||
@@ -123,6 +127,30 @@ export const DetailedStatus: React.FC<{
|
|||||||
if (onTranslate) onTranslate(status);
|
if (onTranslate) onTranslate(status);
|
||||||
}, [onTranslate, status]);
|
}, [onTranslate, status]);
|
||||||
|
|
||||||
|
// The component is managed and will change if the status changes
|
||||||
|
// Ancestors can increase when loading a thread, in which case we want to scroll,
|
||||||
|
// or decrease if a post is deleted, in which case we don't want to mess with it
|
||||||
|
const previousAncestors = useRef(-1);
|
||||||
|
useEffect(() => {
|
||||||
|
if (nodeRef.current && previousAncestors.current < ancestors) {
|
||||||
|
nodeRef.current.scrollIntoView(true);
|
||||||
|
|
||||||
|
// In the single-column interface, `scrollIntoView` will put the post behind the header, so compensate for that.
|
||||||
|
if (!multiColumn) {
|
||||||
|
const offset = document
|
||||||
|
.querySelector('.column-header__wrapper')
|
||||||
|
?.getBoundingClientRect().bottom;
|
||||||
|
|
||||||
|
if (offset) {
|
||||||
|
const scrollingElement = document.scrollingElement ?? document.body;
|
||||||
|
scrollingElement.scrollBy(0, -offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
previousAncestors.current = ancestors;
|
||||||
|
}, [ancestors, multiColumn]);
|
||||||
|
|
||||||
if (!properStatus) {
|
if (!properStatus) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -164,8 +164,6 @@ class Status extends ImmutablePureComponent {
|
|||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
attachFullscreenListener(this.onFullScreenChange);
|
attachFullscreenListener(this.onFullScreenChange);
|
||||||
|
|
||||||
this._scrollStatusIntoView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||||
@@ -487,35 +485,11 @@ class Status extends ImmutablePureComponent {
|
|||||||
this.statusNode = c;
|
this.statusNode = c;
|
||||||
};
|
};
|
||||||
|
|
||||||
_scrollStatusIntoView () {
|
|
||||||
const { status, multiColumn } = this.props;
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
requestIdleCallback(() => {
|
|
||||||
this.statusNode?.scrollIntoView(true);
|
|
||||||
|
|
||||||
// In the single-column interface, `scrollIntoView` will put the post behind the header,
|
|
||||||
// so compensate for that.
|
|
||||||
if (!multiColumn) {
|
|
||||||
const offset = document.querySelector('.column-header__wrapper')?.getBoundingClientRect()?.bottom;
|
|
||||||
if (offset) {
|
|
||||||
const scrollingElement = document.scrollingElement || document.body;
|
|
||||||
scrollingElement.scrollBy(0, -offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
const { status, ancestorsIds, descendantsIds } = this.props;
|
const { status, descendantsIds } = this.props;
|
||||||
|
|
||||||
const isSameStatus = status && (prevProps.status?.get('id') === status.get('id'));
|
const isSameStatus = status && (prevProps.status?.get('id') === status.get('id'));
|
||||||
|
|
||||||
if (status && (ancestorsIds.length > prevProps.ancestorsIds.length || !isSameStatus)) {
|
|
||||||
this._scrollStatusIntoView();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only highlight replies after the initial load
|
// Only highlight replies after the initial load
|
||||||
if (prevProps.descendantsIds.length && isSameStatus) {
|
if (prevProps.descendantsIds.length && isSameStatus) {
|
||||||
const newRepliesIds = difference(descendantsIds, prevProps.descendantsIds);
|
const newRepliesIds = difference(descendantsIds, prevProps.descendantsIds);
|
||||||
@@ -619,6 +593,8 @@ class Status extends ImmutablePureComponent {
|
|||||||
showMedia={this.state.showMedia}
|
showMedia={this.state.showMedia}
|
||||||
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
||||||
pictureInPicture={pictureInPicture}
|
pictureInPicture={pictureInPicture}
|
||||||
|
ancestors={this.props.ancestorsIds.length}
|
||||||
|
multiColumn={multiColumn}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ActionBar
|
<ActionBar
|
||||||
|
|||||||
@@ -903,6 +903,7 @@
|
|||||||
"status.edited_x_times": "Upraveno {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
|
"status.edited_x_times": "Upraveno {count, plural, one {{count}krát} few {{count}krát} many {{count}krát} other {{count}krát}}",
|
||||||
"status.embed": "Získejte kód pro vložení",
|
"status.embed": "Získejte kód pro vložení",
|
||||||
"status.favourite": "Oblíbit",
|
"status.favourite": "Oblíbit",
|
||||||
|
"status.favourites_count": "{count, plural, one {{counter} oblíbený} few {{counter} oblíbené} many {{counter} oblíbených} other {{counter} oblíbených}}",
|
||||||
"status.filter": "Filtrovat tento příspěvek",
|
"status.filter": "Filtrovat tento příspěvek",
|
||||||
"status.history.created": "Uživatel {name} vytvořil {date}",
|
"status.history.created": "Uživatel {name} vytvořil {date}",
|
||||||
"status.history.edited": "Uživatel {name} upravil {date}",
|
"status.history.edited": "Uživatel {name} upravil {date}",
|
||||||
@@ -937,12 +938,14 @@
|
|||||||
"status.quotes.empty": "Tento příspěvek zatím nikdo necitoval. Pokud tak někdo učiní, uvidíte to zde.",
|
"status.quotes.empty": "Tento příspěvek zatím nikdo necitoval. Pokud tak někdo učiní, uvidíte to zde.",
|
||||||
"status.quotes.local_other_disclaimer": "Citace zamítnuté autorem nebudou zobrazeny.",
|
"status.quotes.local_other_disclaimer": "Citace zamítnuté autorem nebudou zobrazeny.",
|
||||||
"status.quotes.remote_other_disclaimer": "Pouze citace z {domain} zde budou zaručeně ukázány. Citace zamítnuté autorem nebudou zobrazeny.",
|
"status.quotes.remote_other_disclaimer": "Pouze citace z {domain} zde budou zaručeně ukázány. Citace zamítnuté autorem nebudou zobrazeny.",
|
||||||
|
"status.quotes_count": "{count, plural, one {{counter} citace} few {{counter} citace} many {{counter} citací} other {{counter} citací}}",
|
||||||
"status.read_more": "Číst více",
|
"status.read_more": "Číst více",
|
||||||
"status.reblog": "Boostnout",
|
"status.reblog": "Boostnout",
|
||||||
"status.reblog_or_quote": "Boostnout nebo citovat",
|
"status.reblog_or_quote": "Boostnout nebo citovat",
|
||||||
"status.reblog_private": "Sdílejte znovu se svými sledujícími",
|
"status.reblog_private": "Sdílejte znovu se svými sledujícími",
|
||||||
"status.reblogged_by": "Uživatel {name} boostnul",
|
"status.reblogged_by": "Uživatel {name} boostnul",
|
||||||
"status.reblogs.empty": "Tento příspěvek ještě nikdo neboostnul. Pokud to někdo udělá, zobrazí se zde.",
|
"status.reblogs.empty": "Tento příspěvek ještě nikdo neboostnul. Pokud to někdo udělá, zobrazí se zde.",
|
||||||
|
"status.reblogs_count": "{count, plural, one {{counter} boost} few {{counter} boosty} many {{counter} boostů} other {{counter} boostů}}",
|
||||||
"status.redraft": "Smazat a přepsat",
|
"status.redraft": "Smazat a přepsat",
|
||||||
"status.remove_bookmark": "Odstranit ze záložek",
|
"status.remove_bookmark": "Odstranit ze záložek",
|
||||||
"status.remove_favourite": "Odebrat z oblíbených",
|
"status.remove_favourite": "Odebrat z oblíbených",
|
||||||
|
|||||||
@@ -903,6 +903,7 @@
|
|||||||
"status.edited_x_times": "Golygwyd {count, plural, one {{count} gwaith} other {{count} gwaith}}",
|
"status.edited_x_times": "Golygwyd {count, plural, one {{count} gwaith} other {{count} gwaith}}",
|
||||||
"status.embed": "Cael y cod mewnblannu",
|
"status.embed": "Cael y cod mewnblannu",
|
||||||
"status.favourite": "Ffafrio",
|
"status.favourite": "Ffafrio",
|
||||||
|
"status.favourites_count": "{count, plural, one {{counter} ffefryn} other {{counter} ffefryn}}",
|
||||||
"status.filter": "Hidlo'r postiad hwn",
|
"status.filter": "Hidlo'r postiad hwn",
|
||||||
"status.history.created": "Crëwyd gan {name} {date}",
|
"status.history.created": "Crëwyd gan {name} {date}",
|
||||||
"status.history.edited": "Golygwyd gan {name} {date}",
|
"status.history.edited": "Golygwyd gan {name} {date}",
|
||||||
@@ -937,12 +938,14 @@
|
|||||||
"status.quotes.empty": "Does neb wedi dyfynnu'r postiad hwn eto. Pan fydd rhywun yn gwneud hynny, bydd yn ymddangos yma.",
|
"status.quotes.empty": "Does neb wedi dyfynnu'r postiad hwn eto. Pan fydd rhywun yn gwneud hynny, bydd yn ymddangos yma.",
|
||||||
"status.quotes.local_other_disclaimer": "Bydd dyfyniadau wedi'u gwrthod gan yr awdur ddim yn cael eu dangos.",
|
"status.quotes.local_other_disclaimer": "Bydd dyfyniadau wedi'u gwrthod gan yr awdur ddim yn cael eu dangos.",
|
||||||
"status.quotes.remote_other_disclaimer": "Dim ond dyfyniadau o {domain} sy'n siŵr o gael eu dangos yma. Bydd dyfyniadau wedi'u gwrthod gan yr awdur ddim yn cael eu dangos.",
|
"status.quotes.remote_other_disclaimer": "Dim ond dyfyniadau o {domain} sy'n siŵr o gael eu dangos yma. Bydd dyfyniadau wedi'u gwrthod gan yr awdur ddim yn cael eu dangos.",
|
||||||
|
"status.quotes_count": "{count, plural, one {{counter} dyfyniad} other {{counter} dyfyniad}}",
|
||||||
"status.read_more": "Darllen rhagor",
|
"status.read_more": "Darllen rhagor",
|
||||||
"status.reblog": "Hybu",
|
"status.reblog": "Hybu",
|
||||||
"status.reblog_or_quote": "Hybu neu ddyfynnu",
|
"status.reblog_or_quote": "Hybu neu ddyfynnu",
|
||||||
"status.reblog_private": "Rhannwch eto gyda'ch dilynwyr",
|
"status.reblog_private": "Rhannwch eto gyda'ch dilynwyr",
|
||||||
"status.reblogged_by": "Hybodd {name}",
|
"status.reblogged_by": "Hybodd {name}",
|
||||||
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
"status.reblogs.empty": "Does neb wedi hybio'r post yma eto. Pan y bydd rhywun yn gwneud, byddent yn ymddangos yma.",
|
||||||
|
"status.reblogs_count": "{count, plural, one {{counter} hwb} other {{counter} hwb}}",
|
||||||
"status.redraft": "Dileu ac ail lunio",
|
"status.redraft": "Dileu ac ail lunio",
|
||||||
"status.remove_bookmark": "Tynnu nod tudalen",
|
"status.remove_bookmark": "Tynnu nod tudalen",
|
||||||
"status.remove_favourite": "Tynnu o'r ffefrynnau",
|
"status.remove_favourite": "Tynnu o'r ffefrynnau",
|
||||||
|
|||||||
@@ -231,7 +231,7 @@
|
|||||||
"confirmations.delete_list.title": "Slet liste?",
|
"confirmations.delete_list.title": "Slet liste?",
|
||||||
"confirmations.discard_draft.confirm": "Kassér og fortsæt",
|
"confirmations.discard_draft.confirm": "Kassér og fortsæt",
|
||||||
"confirmations.discard_draft.edit.cancel": "Fortsæt redigering",
|
"confirmations.discard_draft.edit.cancel": "Fortsæt redigering",
|
||||||
"confirmations.discard_draft.edit.message": "Hvis du fortsætter, kasseres alle ændringer, du har foretaget i det indlæg, du er i gang med at redigere.",
|
"confirmations.discard_draft.edit.message": "Hvis du fortsætter, vil alle ændringer, du har foretaget i det indlæg, du er er ved at redigere, blive slettet.",
|
||||||
"confirmations.discard_draft.edit.title": "Kassér ændringer til dit indlæg?",
|
"confirmations.discard_draft.edit.title": "Kassér ændringer til dit indlæg?",
|
||||||
"confirmations.discard_draft.post.cancel": "Genoptag udkast",
|
"confirmations.discard_draft.post.cancel": "Genoptag udkast",
|
||||||
"confirmations.discard_draft.post.message": "Hvis du fortsætter, kasseres det indlæg, du er i gang med at udforme.",
|
"confirmations.discard_draft.post.message": "Hvis du fortsætter, kasseres det indlæg, du er i gang med at udforme.",
|
||||||
@@ -507,7 +507,7 @@
|
|||||||
"keyboard_shortcuts.pinned": "Åbn liste over fastgjorte indlæg",
|
"keyboard_shortcuts.pinned": "Åbn liste over fastgjorte indlæg",
|
||||||
"keyboard_shortcuts.profile": "Åbn forfatters profil",
|
"keyboard_shortcuts.profile": "Åbn forfatters profil",
|
||||||
"keyboard_shortcuts.quote": "Citér indlæg",
|
"keyboard_shortcuts.quote": "Citér indlæg",
|
||||||
"keyboard_shortcuts.reply": "Besvar indlægget",
|
"keyboard_shortcuts.reply": "Besvar indlæg",
|
||||||
"keyboard_shortcuts.requests": "Åbn liste over følgeanmodninger",
|
"keyboard_shortcuts.requests": "Åbn liste over følgeanmodninger",
|
||||||
"keyboard_shortcuts.search": "Fokusér søgebjælke",
|
"keyboard_shortcuts.search": "Fokusér søgebjælke",
|
||||||
"keyboard_shortcuts.spoilers": "Vis/skjul indholdsadvarsel-felt",
|
"keyboard_shortcuts.spoilers": "Vis/skjul indholdsadvarsel-felt",
|
||||||
@@ -675,7 +675,7 @@
|
|||||||
"notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
|
"notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
|
||||||
"notifications.column_settings.follow": "Nye følgere:",
|
"notifications.column_settings.follow": "Nye følgere:",
|
||||||
"notifications.column_settings.follow_request": "Nye følgeanmodninger:",
|
"notifications.column_settings.follow_request": "Nye følgeanmodninger:",
|
||||||
"notifications.column_settings.group": "Gruppere",
|
"notifications.column_settings.group": "Gruppér",
|
||||||
"notifications.column_settings.mention": "Omtaler:",
|
"notifications.column_settings.mention": "Omtaler:",
|
||||||
"notifications.column_settings.poll": "Afstemningsresultater:",
|
"notifications.column_settings.poll": "Afstemningsresultater:",
|
||||||
"notifications.column_settings.push": "Push-notifikationer",
|
"notifications.column_settings.push": "Push-notifikationer",
|
||||||
@@ -764,7 +764,7 @@
|
|||||||
"privacy_policy.last_updated": "Senest opdateret {date}",
|
"privacy_policy.last_updated": "Senest opdateret {date}",
|
||||||
"privacy_policy.title": "Privatlivspolitik",
|
"privacy_policy.title": "Privatlivspolitik",
|
||||||
"quote_error.edit": "Citater kan ikke tilføjes ved redigering af et indlæg.",
|
"quote_error.edit": "Citater kan ikke tilføjes ved redigering af et indlæg.",
|
||||||
"quote_error.poll": "Citering ikke tilladt i afstemninger.",
|
"quote_error.poll": "Citering er ikke tilladt med afstemninger.",
|
||||||
"quote_error.private_mentions": "Citering er ikke tilladt med direkte omtaler.",
|
"quote_error.private_mentions": "Citering er ikke tilladt med direkte omtaler.",
|
||||||
"quote_error.quote": "Kun ét citat ad gangen er tilladt.",
|
"quote_error.quote": "Kun ét citat ad gangen er tilladt.",
|
||||||
"quote_error.unauthorized": "Du har ikke tilladelse til at citere dette indlæg.",
|
"quote_error.unauthorized": "Du har ikke tilladelse til at citere dette indlæg.",
|
||||||
@@ -867,7 +867,7 @@
|
|||||||
"search_results.title": "Søg efter \"{q}\"",
|
"search_results.title": "Søg efter \"{q}\"",
|
||||||
"server_banner.about_active_users": "Personer, som brugte denne server de seneste 30 dage (månedlige aktive brugere)",
|
"server_banner.about_active_users": "Personer, som brugte denne server de seneste 30 dage (månedlige aktive brugere)",
|
||||||
"server_banner.active_users": "aktive brugere",
|
"server_banner.active_users": "aktive brugere",
|
||||||
"server_banner.administered_by": "Håndteres af:",
|
"server_banner.administered_by": "Administreret af:",
|
||||||
"server_banner.is_one_of_many": "{domain} er en af de mange uafhængige Mastodon-servere, du kan bruge for at deltage i fediverset.",
|
"server_banner.is_one_of_many": "{domain} er en af de mange uafhængige Mastodon-servere, du kan bruge for at deltage i fediverset.",
|
||||||
"server_banner.server_stats": "Serverstatstik:",
|
"server_banner.server_stats": "Serverstatstik:",
|
||||||
"sign_in_banner.create_account": "Opret konto",
|
"sign_in_banner.create_account": "Opret konto",
|
||||||
@@ -902,7 +902,7 @@
|
|||||||
"status.edited": "Senest redigeret {date}",
|
"status.edited": "Senest redigeret {date}",
|
||||||
"status.edited_x_times": "Redigeret {count, plural, one {{count} gang} other {{count} gange}}",
|
"status.edited_x_times": "Redigeret {count, plural, one {{count} gang} other {{count} gange}}",
|
||||||
"status.embed": "Hent indlejringskode",
|
"status.embed": "Hent indlejringskode",
|
||||||
"status.favourite": "Favorit",
|
"status.favourite": "Favoritmarkér",
|
||||||
"status.favourites_count": "{count, plural, one {{counter} favorit} other {{counter} favoritter}}",
|
"status.favourites_count": "{count, plural, one {{counter} favorit} other {{counter} favoritter}}",
|
||||||
"status.filter": "Filtrér dette indlæg",
|
"status.filter": "Filtrér dette indlæg",
|
||||||
"status.history.created": "{name} oprettet {date}",
|
"status.history.created": "{name} oprettet {date}",
|
||||||
@@ -991,7 +991,7 @@
|
|||||||
"units.short.million": "{count} mio.",
|
"units.short.million": "{count} mio.",
|
||||||
"units.short.thousand": "{count} tusind",
|
"units.short.thousand": "{count} tusind",
|
||||||
"upload_area.title": "Træk og slip for at uploade",
|
"upload_area.title": "Træk og slip for at uploade",
|
||||||
"upload_button.label": "Tilføj billed-, video- eller lydfil(er)",
|
"upload_button.label": "Tilføj billeder, en video- eller lydfil",
|
||||||
"upload_error.limit": "Grænse for filupload nået.",
|
"upload_error.limit": "Grænse for filupload nået.",
|
||||||
"upload_error.poll": "Filupload ikke tilladt for afstemninger.",
|
"upload_error.poll": "Filupload ikke tilladt for afstemninger.",
|
||||||
"upload_error.quote": "Fil-upload ikke tilladt i citater.",
|
"upload_error.quote": "Fil-upload ikke tilladt i citater.",
|
||||||
|
|||||||
@@ -242,7 +242,7 @@
|
|||||||
"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?",
|
||||||
"confirmations.logout.confirm": "Abmelden",
|
"confirmations.logout.confirm": "Abmelden",
|
||||||
"confirmations.logout.message": "Möchtest du dich wirklich abmelden?",
|
"confirmations.logout.message": "Bist du sicher, dass du dich abmelden möchtest?",
|
||||||
"confirmations.logout.title": "Abmelden?",
|
"confirmations.logout.title": "Abmelden?",
|
||||||
"confirmations.missing_alt_text.confirm": "Bildbeschreibung hinzufügen",
|
"confirmations.missing_alt_text.confirm": "Bildbeschreibung hinzufügen",
|
||||||
"confirmations.missing_alt_text.message": "Dein Beitrag enthält Medien ohne Bildbeschreibung. Mit ALT-Texten erreichst Du auch Menschen, die blind oder sehbehindert sind.",
|
"confirmations.missing_alt_text.message": "Dein Beitrag enthält Medien ohne Bildbeschreibung. Mit ALT-Texten erreichst Du auch Menschen, die blind oder sehbehindert sind.",
|
||||||
@@ -584,8 +584,8 @@
|
|||||||
"navigation_bar.follows_and_followers": "Follower und Folge ich",
|
"navigation_bar.follows_and_followers": "Follower und Folge ich",
|
||||||
"navigation_bar.import_export": "Importieren und exportieren",
|
"navigation_bar.import_export": "Importieren und exportieren",
|
||||||
"navigation_bar.lists": "Listen",
|
"navigation_bar.lists": "Listen",
|
||||||
"navigation_bar.live_feed_local": "Live-Feed (lokal)",
|
"navigation_bar.live_feed_local": "Live-Feed (Dieser Server)",
|
||||||
"navigation_bar.live_feed_public": "Live-Feed (öffentlich)",
|
"navigation_bar.live_feed_public": "Live-Feed (Alle Server)",
|
||||||
"navigation_bar.logout": "Abmelden",
|
"navigation_bar.logout": "Abmelden",
|
||||||
"navigation_bar.moderation": "Moderation",
|
"navigation_bar.moderation": "Moderation",
|
||||||
"navigation_bar.more": "Mehr",
|
"navigation_bar.more": "Mehr",
|
||||||
|
|||||||
@@ -233,7 +233,7 @@
|
|||||||
"confirmations.discard_draft.edit.cancel": "Palaa muokkaamaan",
|
"confirmations.discard_draft.edit.cancel": "Palaa muokkaamaan",
|
||||||
"confirmations.discard_draft.edit.message": "Jatkaminen tuhoaa kaikki muutokset, joita olet tehnyt julkaisuun, jota olet parhaillaan muokkaamassa.",
|
"confirmations.discard_draft.edit.message": "Jatkaminen tuhoaa kaikki muutokset, joita olet tehnyt julkaisuun, jota olet parhaillaan muokkaamassa.",
|
||||||
"confirmations.discard_draft.edit.title": "Hylätäänkö luonnosjulkaisusi muutokset?",
|
"confirmations.discard_draft.edit.title": "Hylätäänkö luonnosjulkaisusi muutokset?",
|
||||||
"confirmations.discard_draft.post.cancel": "Palaa lunnokseen",
|
"confirmations.discard_draft.post.cancel": "Palaa luonnokseen",
|
||||||
"confirmations.discard_draft.post.message": "Jatkaminen tuhoaa julkaisun, jota olet parhaillaan laatimassa.",
|
"confirmations.discard_draft.post.message": "Jatkaminen tuhoaa julkaisun, jota olet parhaillaan laatimassa.",
|
||||||
"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ää",
|
||||||
|
|||||||
@@ -528,7 +528,7 @@
|
|||||||
"limited_account_hint.action": "Afficher le profil quand même",
|
"limited_account_hint.action": "Afficher le profil quand même",
|
||||||
"limited_account_hint.title": "Ce profil a été masqué par la modération de {domain}.",
|
"limited_account_hint.title": "Ce profil a été masqué par la modération de {domain}.",
|
||||||
"link_preview.author": "Par {name}",
|
"link_preview.author": "Par {name}",
|
||||||
"link_preview.more_from_author": "Plus via {name}",
|
"link_preview.more_from_author": "Voir plus de {name}",
|
||||||
"link_preview.shares": "{count, plural, one {{counter} message} other {{counter} messages}}",
|
"link_preview.shares": "{count, plural, one {{counter} message} other {{counter} messages}}",
|
||||||
"lists.add_member": "Ajouter",
|
"lists.add_member": "Ajouter",
|
||||||
"lists.add_to_list": "Ajouter à la liste",
|
"lists.add_to_list": "Ajouter à la liste",
|
||||||
|
|||||||
@@ -528,7 +528,7 @@
|
|||||||
"limited_account_hint.action": "Afficher le profil quand même",
|
"limited_account_hint.action": "Afficher le profil quand même",
|
||||||
"limited_account_hint.title": "Ce profil a été masqué par la modération de {domain}.",
|
"limited_account_hint.title": "Ce profil a été masqué par la modération de {domain}.",
|
||||||
"link_preview.author": "Par {name}",
|
"link_preview.author": "Par {name}",
|
||||||
"link_preview.more_from_author": "Plus via {name}",
|
"link_preview.more_from_author": "Voir plus de {name}",
|
||||||
"link_preview.shares": "{count, plural, one {{counter} message} other {{counter} messages}}",
|
"link_preview.shares": "{count, plural, one {{counter} message} other {{counter} messages}}",
|
||||||
"lists.add_member": "Ajouter",
|
"lists.add_member": "Ajouter",
|
||||||
"lists.add_to_list": "Ajouter à la liste",
|
"lists.add_to_list": "Ajouter à la liste",
|
||||||
|
|||||||
@@ -189,7 +189,7 @@
|
|||||||
"notification.update": "{name} nuntium correxit",
|
"notification.update": "{name} nuntium correxit",
|
||||||
"notification_requests.accept": "Accipe",
|
"notification_requests.accept": "Accipe",
|
||||||
"notification_requests.confirm_accept_multiple.message": "Tu es accepturus {count, plural, one {una notitia petitionem} other {# notitia petitiones}}. Certus esne procedere vis?",
|
"notification_requests.confirm_accept_multiple.message": "Tu es accepturus {count, plural, one {una notitia petitionem} other {# notitia petitiones}}. Certus esne procedere vis?",
|
||||||
"notification_requests.confirm_dismiss_multiple.message": "Tu {count, plural, one {unam petitionem notificationis} other {# petitiones notificationum}} abrogāre prōximum es. {count, plural, one {Illa} other {Eae}} facile accessū nōn erit. Certus es tē procedere velle?",
|
"notification_requests.confirm_dismiss_multiple.message": "Tu {count, plural, one {unam petitionem notificationis} other {# petitiones notificationum}} abrogāre prōximum es. {count, plural, one {it} other {Eae}} facile accessū nōn erit. Certus es tē procedere velle?",
|
||||||
"notifications.filter.all": "Omnia",
|
"notifications.filter.all": "Omnia",
|
||||||
"notifications.filter.polls": "Eventus electionis",
|
"notifications.filter.polls": "Eventus electionis",
|
||||||
"notifications.group": "{count} Notificātiōnēs",
|
"notifications.group": "{count} Notificātiōnēs",
|
||||||
@@ -246,19 +246,102 @@
|
|||||||
"status.history.created": "{name} creatum {date}",
|
"status.history.created": "{name} creatum {date}",
|
||||||
"status.history.edited": "{name} correxit {date}",
|
"status.history.edited": "{name} correxit {date}",
|
||||||
"status.open": "Expand this status",
|
"status.open": "Expand this status",
|
||||||
|
"status.quotes.empty": "Nemo hanc commentationem adhuc citavit. Cum quis citaverit, hic apparebit.",
|
||||||
|
"status.quotes.local_other_disclaimer": "Citationes ab auctore reiectæ non monstrabuntur.",
|
||||||
|
"status.quotes.remote_other_disclaimer": "Tantum citae ex {domain} hic exhiberi praestantur. Citae ab auctore reiectae non exhibebuntur.",
|
||||||
|
"status.quotes_count": "{count, plural, one {{counter} citatio} other {{counter} citationes}}",
|
||||||
|
"status.read_more": "Plura lege",
|
||||||
|
"status.reblog": "Promovere",
|
||||||
|
"status.reblog_or_quote": "Promovere aut cita",
|
||||||
|
"status.reblog_private": "Iterum cum sectatoribus tuis communica",
|
||||||
"status.reblogged_by": "{name} adiuvavit",
|
"status.reblogged_by": "{name} adiuvavit",
|
||||||
|
"status.reblogs.empty": "Nemo hanc publicationem adhuc promovit. Cum quis eam promoveat, hic apparebunt.",
|
||||||
|
"status.reblogs_count": "{count, plural, one {{counter} incrementum} other {{counter} incrementa}}",
|
||||||
|
"status.redraft": "Dele et redig",
|
||||||
|
"status.remove_bookmark": "Tolle signum",
|
||||||
|
"status.remove_favourite": "Tolle ad delectis",
|
||||||
|
"status.remove_quote": "Tolle",
|
||||||
|
"status.replied_in_thread": "In filo responsum",
|
||||||
|
"status.replied_to": "{name} respondit",
|
||||||
|
"status.reply": "Respondere",
|
||||||
|
"status.replyAll": "Responde ad filum",
|
||||||
|
"status.report": "Referre @{name}",
|
||||||
|
"status.request_quote": "Pretium petere",
|
||||||
|
"status.revoke_quote": "Tolle nuntium meum ex nuntio @{name}",
|
||||||
|
"status.sensitive_warning": "Materia delicata",
|
||||||
|
"status.share": "Communica",
|
||||||
|
"status.show_less_all": "Omnibus minus monstra",
|
||||||
|
"status.show_more_all": "Omnibus plura monstra",
|
||||||
|
"status.show_original": "Monstra originalem",
|
||||||
"status.title.with_attachments": "{user} publicavit {attachmentCount, plural, one {unum annexum} other {{attachmentCount} annexa}}",
|
"status.title.with_attachments": "{user} publicavit {attachmentCount, plural, one {unum annexum} other {{attachmentCount} annexa}}",
|
||||||
|
"status.translate": "Converte",
|
||||||
|
"status.translated_from_with": "Translatum ex {lang} per {provider}",
|
||||||
|
"status.uncached_media_warning": "Praevisum non praesto est",
|
||||||
|
"status.unmute_conversation": "Conversationem reserare",
|
||||||
|
"subscribed_languages.lead": "Tantum epistolae in linguis selectis in domo tua apparebunt et indices temporum post mutationem. Neminem eligatis qui epistolas in omnibus linguis recipiat.",
|
||||||
|
"subscribed_languages.save": "Servare mutationes",
|
||||||
|
"subscribed_languages.target": "Muta linguas subscriptas pro {target}",
|
||||||
"tabs_bar.home": "Domi",
|
"tabs_bar.home": "Domi",
|
||||||
|
"tabs_bar.menu": "Elenchus",
|
||||||
|
"tabs_bar.notifications": "Acta Vicimediorum",
|
||||||
|
"tabs_bar.publish": "Nova publicatio",
|
||||||
|
"tabs_bar.search": "Quaere",
|
||||||
|
"terms_of_service.effective_as_of": "Valet ex {date}",
|
||||||
|
"terms_of_service.title": "Termini servitii",
|
||||||
|
"terms_of_service.upcoming_changes_on": "Mutationes venturae die {date}",
|
||||||
"time_remaining.days": "{number, plural, one {# die} other {# dies}} restant",
|
"time_remaining.days": "{number, plural, one {# die} other {# dies}} restant",
|
||||||
"time_remaining.hours": "{number, plural, one {# hora} other {# horae}} restant",
|
"time_remaining.hours": "{number, plural, one {# hora} other {# horae}} restant",
|
||||||
"time_remaining.minutes": "{number, plural, one {# minutum} other {# minuta}} restant",
|
"time_remaining.minutes": "{number, plural, one {# minutum} other {# minuta}} restant",
|
||||||
|
"time_remaining.moments": "Momenta reliqua",
|
||||||
"time_remaining.seconds": "{number, plural, one {# secundum} other {# secunda}} restant",
|
"time_remaining.seconds": "{number, plural, one {# secundum} other {# secunda}} restant",
|
||||||
"trends.counter_by_accounts": "{count, plural, one {{counter} persōna} other {{counter} persōnae}} in {days, plural, one {diē prīdiē} other {diēbus praeteritīs {days}}}",
|
"trends.counter_by_accounts": "{count, plural, one {{counter} persōna} other {{counter} persōnae}} in {days, plural, one {days} other {diēbus praeteritīs {days}}}",
|
||||||
|
"trends.trending_now": "Nunc in usu",
|
||||||
"ui.beforeunload": "Si Mastodon discesseris, tua epitome peribit.",
|
"ui.beforeunload": "Si Mastodon discesseris, tua epitome peribit.",
|
||||||
"units.short.billion": "{count} millia milionum",
|
"units.short.billion": "{count} millia milionum",
|
||||||
"units.short.million": "{count} milionum",
|
"units.short.million": "{count} milionum",
|
||||||
"units.short.thousand": "{count} millia",
|
"units.short.thousand": "{count} millia",
|
||||||
"upload_button.label": "Imaginēs, vīdeō aut fīle audītūs adde",
|
"upload_area.title": "Trahe et depone ad imponendum",
|
||||||
|
"upload_button.label": "Adde imagines, pelliculam, aut fasciculum sonorum.",
|
||||||
|
"upload_error.limit": "Limes onerationis superatus est.",
|
||||||
|
"upload_error.poll": "Nullis suffragiis licet fascicula imponere.",
|
||||||
|
"upload_error.quote": "Nullum oneramentum fasciculi cum citationibus permittitur.",
|
||||||
|
"upload_form.drag_and_drop.instructions": "Ad annexum mediorum tollendum, preme clavem \"Space\" aut \"Enter\". Dum traheis, utere clavibus sagittariis ad annexum mediorum in quamlibet partem movendum. Preme iterum \"Space\" aut \"Enter\" ad annexum mediorum in novo loco deponendum, aut preme \"Escape\" ad desinendum.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_cancel": "Tractatio revocata est. Adiunctum medium {item} demissum est.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_end": "Adhaesum medium {item} demissum est.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_over": "Adhaesum medium {item} motum est.",
|
||||||
|
"upload_form.drag_and_drop.on_drag_start": "Adhaesum medium {item} sublatum est.",
|
||||||
"upload_form.edit": "Recolere",
|
"upload_form.edit": "Recolere",
|
||||||
"upload_progress.label": "Uploading…"
|
"upload_progress.label": "Oneratur...",
|
||||||
|
"upload_progress.processing": "Processus…",
|
||||||
|
"username.taken": "Illud nomen usoris occupatum est. Aliud tenta.",
|
||||||
|
"video.close": "Pelliculam claude",
|
||||||
|
"video.download": "Prehendere fasciculus",
|
||||||
|
"video.exit_fullscreen": "Exitus ex plenum monitorium",
|
||||||
|
"video.expand": "Expande pelliculam",
|
||||||
|
"video.fullscreen": "Plenum monitorium",
|
||||||
|
"video.hide": "celare pellicula",
|
||||||
|
"video.mute": "Mutus",
|
||||||
|
"video.pause": "intermittere",
|
||||||
|
"video.play": "gignere",
|
||||||
|
"video.skip_backward": "Redire",
|
||||||
|
"video.skip_forward": "Progredi",
|
||||||
|
"video.unmute": "Sordes tollere",
|
||||||
|
"video.volume_down": "Volumen deminui",
|
||||||
|
"video.volume_up": "Volumen augete",
|
||||||
|
"visibility_modal.button_title": "Visibilitatem statuere",
|
||||||
|
"visibility_modal.direct_quote_warning.text": "Si praesentia configuramenta servaveris, sententia inserta in nexum convertetur.",
|
||||||
|
"visibility_modal.direct_quote_warning.title": "Citatio in mentitionibus privatis inseriri non possunt.",
|
||||||
|
"visibility_modal.header": "Visibilitas et interactio",
|
||||||
|
"visibility_modal.helper.direct_quoting": "Mentiones privatae in Mastodon scriptae ab aliis citari non possunt.",
|
||||||
|
"visibility_modal.helper.privacy_editing": "Visibilitas mutari non potest postquam nuntius publicatus est.",
|
||||||
|
"visibility_modal.helper.privacy_private_self_quote": "Citationes propriae nuntiorum privatorum publicari non possunt.",
|
||||||
|
"visibility_modal.helper.private_quoting": "Nuntii in Mastodon a sequacibus tantum scriptī ab aliis citari non possunt.",
|
||||||
|
"visibility_modal.helper.unlisted_quoting": "Cum te citant, eorum scriptum etiam ex indicibus popularibus celabitur.",
|
||||||
|
"visibility_modal.instructions": "Régula quis cum hoc scripto agere possit. Potes etiam ordinationes omnibus scriptis futuris adhibere, navigando ad <link>Praeferentias > Regulas scriptionis praedefinitas</link>.",
|
||||||
|
"visibility_modal.privacy_label": "Visibilitas",
|
||||||
|
"visibility_modal.quote_followers": "Sectatores tantum",
|
||||||
|
"visibility_modal.quote_label": "Quis citare potest",
|
||||||
|
"visibility_modal.quote_nobody": "Sicut me",
|
||||||
|
"visibility_modal.quote_public": "quisquis",
|
||||||
|
"visibility_modal.save": "Servare"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import { me, reduceMotion } from 'mastodon/initial_state';
|
|||||||
import ready from 'mastodon/ready';
|
import ready from 'mastodon/ready';
|
||||||
import { store } from 'mastodon/store';
|
import { store } from 'mastodon/store';
|
||||||
|
|
||||||
import { initializeEmoji } from './features/emoji';
|
|
||||||
import { isProduction, isDevelopment } from './utils/environment';
|
import { isProduction, isDevelopment } from './utils/environment';
|
||||||
|
|
||||||
function main() {
|
function main() {
|
||||||
@@ -30,6 +29,7 @@ function main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { initializeEmoji } = await import('./features/emoji/index');
|
||||||
initializeEmoji();
|
initializeEmoji();
|
||||||
|
|
||||||
const root = createRoot(mountNode);
|
const root = createRoot(mountNode);
|
||||||
|
|||||||
@@ -341,8 +341,8 @@ export const composeReducer = (state = initialState, action) => {
|
|||||||
const isDirect = state.get('privacy') === 'direct';
|
const isDirect = state.get('privacy') === 'direct';
|
||||||
return state
|
return state
|
||||||
.set('quoted_status_id', isDirect ? null : status.get('id'))
|
.set('quoted_status_id', isDirect ? null : status.get('id'))
|
||||||
.set('spoiler', status.get('sensitive'))
|
.update('spoiler', spoiler => (spoiler) || !!status.get('spoiler_text'))
|
||||||
.set('spoiler_text', status.get('spoiler_text'))
|
.update('spoiler_text', (spoiler_text) => spoiler_text || status.get('spoiler_text'))
|
||||||
.update('privacy', (visibility) => {
|
.update('privacy', (visibility) => {
|
||||||
if (['public', 'unlisted'].includes(visibility) && status.get('visibility') === 'private') {
|
if (['public', 'unlisted'].includes(visibility) && status.get('visibility') === 'private') {
|
||||||
return 'private';
|
return 'private';
|
||||||
|
|||||||
@@ -327,9 +327,9 @@ $content-width: 840px;
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
padding-bottom: 0;
|
padding-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: 0;
|
border-top: 0;
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -319,9 +319,9 @@ $content-width: 840px;
|
|||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--color-text-primary);
|
color: var(--color-text-primary);
|
||||||
text-transform: none;
|
text-transform: none;
|
||||||
padding-bottom: 0;
|
padding-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
border-bottom: 0;
|
border-top: 0;
|
||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
@@ -31,9 +31,10 @@ class IpBlock < ApplicationRecord
|
|||||||
|
|
||||||
after_commit :reset_cache
|
after_commit :reset_cache
|
||||||
|
|
||||||
def to_log_human_identifier
|
def to_cidr
|
||||||
"#{ip}/#{ip.prefix}"
|
"#{ip}/#{ip.prefix}"
|
||||||
end
|
end
|
||||||
|
alias to_log_human_identifier to_cidr
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
def blocked?(remote_ip)
|
def blocked?(remote_ip)
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ class REST::Admin::IpBlockSerializer < ActiveModel::Serializer
|
|||||||
end
|
end
|
||||||
|
|
||||||
def ip
|
def ip
|
||||||
"#{object.ip}/#{object.ip.prefix}"
|
object.to_cidr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
= f.check_box :ip_block_ids, { multiple: true, include_hidden: false }, ip_block.id
|
= f.check_box :ip_block_ids, { multiple: true, include_hidden: false }, ip_block.id
|
||||||
.batch-table__row__content.pending-account
|
.batch-table__row__content.pending-account
|
||||||
.pending-account__header
|
.pending-account__header
|
||||||
%samp= link_to "#{ip_block.ip}/#{ip_block.ip.prefix}", admin_accounts_path(ip: "#{ip_block.ip}/#{ip_block.ip.prefix}")
|
%samp= link_to ip_block.to_cidr, admin_accounts_path(ip: ip_block.to_cidr)
|
||||||
- if ip_block.comment.present?
|
- if ip_block.comment.present?
|
||||||
·
|
·
|
||||||
= ip_block.comment
|
= ip_block.comment
|
||||||
|
|||||||
@@ -477,7 +477,7 @@ da:
|
|||||||
no_file: Ingen fil valgt
|
no_file: Ingen fil valgt
|
||||||
export_domain_blocks:
|
export_domain_blocks:
|
||||||
import:
|
import:
|
||||||
description_html: En liste over domæneblokeringer er ved at blive importeret. Gennemgå listen meget nøje, især hvis man ikke selv har oprettet den.
|
description_html: Du er ved at importere en liste over domæneblokeringer. Gennemgå denne liste meget omhyggeligt, især hvis du ikke selv har udarbejdet den.
|
||||||
existing_relationships_warning: Eksisterende følge-relationer
|
existing_relationships_warning: Eksisterende følge-relationer
|
||||||
private_comment_description_html: 'For at man lettere kan holde styr på, hvorfra importerede blokeringer kommer, oprettes disse med flg. private kommentar: <q>%{comment}</q>'
|
private_comment_description_html: 'For at man lettere kan holde styr på, hvorfra importerede blokeringer kommer, oprettes disse med flg. private kommentar: <q>%{comment}</q>'
|
||||||
private_comment_template: Importeret fra %{source} d. %{date}
|
private_comment_template: Importeret fra %{source} d. %{date}
|
||||||
@@ -1186,7 +1186,7 @@ da:
|
|||||||
new_trending_statuses:
|
new_trending_statuses:
|
||||||
title: Indlæg, der trender
|
title: Indlæg, der trender
|
||||||
new_trending_tags:
|
new_trending_tags:
|
||||||
title: Hashtags, der trender
|
title: Populære hashtags
|
||||||
subject: Nye tendenser klar til gennemgang på %{instance}
|
subject: Nye tendenser klar til gennemgang på %{instance}
|
||||||
aliases:
|
aliases:
|
||||||
add_new: Opret alias
|
add_new: Opret alias
|
||||||
|
|||||||
@@ -1089,16 +1089,16 @@ de:
|
|||||||
tag_servers_measure: Server
|
tag_servers_measure: Server
|
||||||
tag_uses_measure: insgesamt
|
tag_uses_measure: insgesamt
|
||||||
description_html: Diese Hashtags werden derzeit in vielen Beiträgen verwendet, die dein Server sieht. Dies kann deinen Nutzer*innen helfen, herauszufinden, worüber die Leute im Moment am meisten schreiben. Hashtags werden erst dann öffentlich angezeigt, wenn du sie genehmigst.
|
description_html: Diese Hashtags werden derzeit in vielen Beiträgen verwendet, die dein Server sieht. Dies kann deinen Nutzer*innen helfen, herauszufinden, worüber die Leute im Moment am meisten schreiben. Hashtags werden erst dann öffentlich angezeigt, wenn du sie genehmigst.
|
||||||
listable: Kann vorgeschlagen werden
|
listable: Darf empfohlen werden
|
||||||
no_tag_selected: Keine Hashtags wurden geändert, da keine ausgewählt wurden
|
no_tag_selected: Keine Hashtags wurden geändert, da keine ausgewählt wurden
|
||||||
not_listable: Wird nicht vorgeschlagen
|
not_listable: Darf nicht vorgeschlagen werden
|
||||||
not_trendable: Wird in den Trends nicht angezeigt
|
not_trendable: In Trends nicht erlaubt
|
||||||
not_usable: Kann nicht verwendet werden
|
not_usable: In Beiträgen nicht erlaubt
|
||||||
peaked_on_and_decaying: In den Trends am %{date}, jetzt absteigend
|
peaked_on_and_decaying: In den Trends am %{date}, jetzt absteigend
|
||||||
title: Angesagte Hashtags
|
title: Angesagte Hashtags
|
||||||
trendable: Darf in den Trends erscheinen
|
trendable: In Trends erlaubt
|
||||||
trending_rank: Platz %{rank}
|
trending_rank: Platz %{rank}
|
||||||
usable: Darf verwendet werden
|
usable: In Beiträgen erlaubt
|
||||||
usage_comparison: Heute %{today}-mal und gestern %{yesterday}-mal verwendet
|
usage_comparison: Heute %{today}-mal und gestern %{yesterday}-mal verwendet
|
||||||
used_by_over_week:
|
used_by_over_week:
|
||||||
one: In den vergangenen 7 Tagen von einem Profil verwendet
|
one: In den vergangenen 7 Tagen von einem Profil verwendet
|
||||||
@@ -1122,7 +1122,7 @@ de:
|
|||||||
title: Neue Regel für Profilnamen erstellen
|
title: Neue Regel für Profilnamen erstellen
|
||||||
no_username_block_selected: Keine Regeln für Profilnamen wurden geändert, weil keine ausgewählt wurde(n)
|
no_username_block_selected: Keine Regeln für Profilnamen wurden geändert, weil keine ausgewählt wurde(n)
|
||||||
not_permitted: Nicht gestattet
|
not_permitted: Nicht gestattet
|
||||||
title: Regeln für Profilnamen
|
title: Profilnamen
|
||||||
updated_msg: Regel für Profilnamen erfolgreich aktualisiert
|
updated_msg: Regel für Profilnamen erfolgreich aktualisiert
|
||||||
warning_presets:
|
warning_presets:
|
||||||
add_new: Neu hinzufügen
|
add_new: Neu hinzufügen
|
||||||
@@ -1285,7 +1285,7 @@ de:
|
|||||||
new_confirmation_instructions_sent: In wenigen Minuten wirst du eine neue E-Mail mit dem Bestätigungslink erhalten!
|
new_confirmation_instructions_sent: In wenigen Minuten wirst du eine neue E-Mail mit dem Bestätigungslink erhalten!
|
||||||
title: Überprüfe dein E-Mail-Postfach
|
title: Überprüfe dein E-Mail-Postfach
|
||||||
sign_in:
|
sign_in:
|
||||||
preamble_html: Melde dich mit deinen Zugangsdaten für <strong>%{domain}</strong> an. Falls dein Konto auf einem anderen Server erstellt wurde, ist eine Anmeldung hier nicht möglich.
|
preamble_html: Melde dich mit deinen Zugangsdaten für <strong>%{domain}</strong> an. Falls dein Konto auf einem anderen Mastodon-Server erstellt wurde, ist eine Anmeldung hier nicht möglich.
|
||||||
title: Bei %{domain} anmelden
|
title: Bei %{domain} anmelden
|
||||||
sign_up:
|
sign_up:
|
||||||
manual_review: Registrierungen für den Server %{domain} werden manuell durch unsere Moderator*innen überprüft. Um uns dabei zu unterstützen, schreibe etwas über dich und sage uns, weshalb du ein Konto auf %{domain} anlegen möchtest.
|
manual_review: Registrierungen für den Server %{domain} werden manuell durch unsere Moderator*innen überprüft. Um uns dabei zu unterstützen, schreibe etwas über dich und sage uns, weshalb du ein Konto auf %{domain} anlegen möchtest.
|
||||||
|
|||||||
@@ -563,6 +563,7 @@ eu:
|
|||||||
create: Gehitu Moderazio Oharra
|
create: Gehitu Moderazio Oharra
|
||||||
created_msg: Instantziako moderazio oharra ongi sortu da!
|
created_msg: Instantziako moderazio oharra ongi sortu da!
|
||||||
description_html: Ikusi eta idatzi oharrak beste moderatzaileentzat eta zuretzat etorkizunerako
|
description_html: Ikusi eta idatzi oharrak beste moderatzaileentzat eta zuretzat etorkizunerako
|
||||||
|
title: Moderazio oharrak
|
||||||
private_comment: Iruzkin pribatua
|
private_comment: Iruzkin pribatua
|
||||||
public_comment: Iruzkin publikoa
|
public_comment: Iruzkin publikoa
|
||||||
purge: Ezabatu betiko
|
purge: Ezabatu betiko
|
||||||
@@ -771,6 +772,8 @@ eu:
|
|||||||
description_html: Gehienek erabilera baldintzak irakurri eta onartu dituztela baieztatzen badute ere, orokorrean arazoren bat dagoen arte ez dituzte irakurtzen. <strong>Zerbitzariaren arauak begirada batean ikustea errazteko buletadun zerrenda batean bildu.</strong> Saiatu arauak labur eta sinple idazten, baina elementu askotan banatu gabe.
|
description_html: Gehienek erabilera baldintzak irakurri eta onartu dituztela baieztatzen badute ere, orokorrean arazoren bat dagoen arte ez dituzte irakurtzen. <strong>Zerbitzariaren arauak begirada batean ikustea errazteko buletadun zerrenda batean bildu.</strong> Saiatu arauak labur eta sinple idazten, baina elementu askotan banatu gabe.
|
||||||
edit: Editatu araua
|
edit: Editatu araua
|
||||||
empty: Ez da zerbitzariko araurik definitu oraindik.
|
empty: Ez da zerbitzariko araurik definitu oraindik.
|
||||||
|
move_down: Behera mugitu
|
||||||
|
move_up: Mugitu gora
|
||||||
title: Zerbitzariaren arauak
|
title: Zerbitzariaren arauak
|
||||||
translation: Itzulpena
|
translation: Itzulpena
|
||||||
translations: Itzulpenak
|
translations: Itzulpenak
|
||||||
@@ -808,6 +811,14 @@ eu:
|
|||||||
all: Guztiei
|
all: Guztiei
|
||||||
disabled: Inori ez
|
disabled: Inori ez
|
||||||
users: Saioa hasita duten erabiltzaile lokalei
|
users: Saioa hasita duten erabiltzaile lokalei
|
||||||
|
feed_access:
|
||||||
|
modes:
|
||||||
|
public: Edonork
|
||||||
|
landing_page:
|
||||||
|
values:
|
||||||
|
about: Honi buruz
|
||||||
|
local_feed: Jario lokala
|
||||||
|
trends: Joerak
|
||||||
registrations:
|
registrations:
|
||||||
moderation_recommandation: Mesedez, ziurtatu moderazio-talde egokia eta erreaktiboa duzula erregistroak guztiei ireki aurretik!
|
moderation_recommandation: Mesedez, ziurtatu moderazio-talde egokia eta erreaktiboa duzula erregistroak guztiei ireki aurretik!
|
||||||
preamble: Kontrolatu nork sortu dezakeen kontua zerbitzarian.
|
preamble: Kontrolatu nork sortu dezakeen kontua zerbitzarian.
|
||||||
@@ -862,6 +873,7 @@ eu:
|
|||||||
original_status: Jatorrizko bidalketa
|
original_status: Jatorrizko bidalketa
|
||||||
quotes: Aipuak
|
quotes: Aipuak
|
||||||
reblogs: Bultzadak
|
reblogs: Bultzadak
|
||||||
|
replied_to_html: "%{acct_link}(r)i erantzuten"
|
||||||
status_changed: Bidalketa aldatuta
|
status_changed: Bidalketa aldatuta
|
||||||
status_title: "%{name} erabiltzailearen bidalketa"
|
status_title: "%{name} erabiltzailearen bidalketa"
|
||||||
trending: Joera
|
trending: Joera
|
||||||
|
|||||||
@@ -1672,6 +1672,7 @@ hu:
|
|||||||
disabled_account: A jelenlegi fiókod nem lesz teljesen használható ezután. Viszont elérhető lesz majd az adatexport funkció, valamint a reaktiválás is.
|
disabled_account: A jelenlegi fiókod nem lesz teljesen használható ezután. Viszont elérhető lesz majd az adatexport funkció, valamint a reaktiválás is.
|
||||||
followers: Ez a művelet az összes követődet a jelenlegi fiókról az újra fogja költöztetni
|
followers: Ez a művelet az összes követődet a jelenlegi fiókról az újra fogja költöztetni
|
||||||
only_redirect_html: Az is lehetséges, hogy <a href="%{path}">csak átirányítást raksz a profilodra</a>.
|
only_redirect_html: Az is lehetséges, hogy <a href="%{path}">csak átirányítást raksz a profilodra</a>.
|
||||||
|
other_data: Semmilyen más adat (beleértve a bejegyzéseket és a követett fiókokat) nem lesz automatikusan áthelyezve
|
||||||
redirect: A jelenlegi fiókod profiljára átirányításról szóló figyelmeztetést rakunk, valamint már nem fogjuk mutatni a keresésekben
|
redirect: A jelenlegi fiókod profiljára átirányításról szóló figyelmeztetést rakunk, valamint már nem fogjuk mutatni a keresésekben
|
||||||
moderation:
|
moderation:
|
||||||
title: Moderáció
|
title: Moderáció
|
||||||
@@ -1928,6 +1929,7 @@ hu:
|
|||||||
errors:
|
errors:
|
||||||
in_reply_not_found: Már nem létezik az a bejegyzés, melyre válaszolni szeretnél.
|
in_reply_not_found: Már nem létezik az a bejegyzés, melyre válaszolni szeretnél.
|
||||||
quoted_status_not_found: Már nem létezik az a bejegyzés, amelyből idézni szeretnél.
|
quoted_status_not_found: Már nem létezik az a bejegyzés, amelyből idézni szeretnél.
|
||||||
|
quoted_user_not_mentioned: Nem idézhet meg nem említett felhasználót egy privát említési bejegyzésben.
|
||||||
over_character_limit: túllépted a maximális %{max} karakteres keretet
|
over_character_limit: túllépted a maximális %{max} karakteres keretet
|
||||||
pin_errors:
|
pin_errors:
|
||||||
direct: A csak a megemlített felhasználók számára látható bejegyzések nem tűzhetők ki
|
direct: A csak a megemlített felhasználók számára látható bejegyzések nem tűzhetők ki
|
||||||
|
|||||||
@@ -928,6 +928,7 @@ ru:
|
|||||||
no_status_selected: Ничего не изменилось, так как ни один пост не был выделен
|
no_status_selected: Ничего не изменилось, так как ни один пост не был выделен
|
||||||
open: Открыть запись
|
open: Открыть запись
|
||||||
original_status: Оригинальный пост
|
original_status: Оригинальный пост
|
||||||
|
quotes: Цитаты
|
||||||
reblogs: Продвинули
|
reblogs: Продвинули
|
||||||
replied_to_html: Ответ пользователю %{acct_link}
|
replied_to_html: Ответ пользователю %{acct_link}
|
||||||
status_changed: Пост изменен
|
status_changed: Пост изменен
|
||||||
@@ -935,6 +936,7 @@ ru:
|
|||||||
title: Посты пользователя - @%{name}
|
title: Посты пользователя - @%{name}
|
||||||
trending: Популярное
|
trending: Популярное
|
||||||
view_publicly: Открыть по публичной ссылке
|
view_publicly: Открыть по публичной ссылке
|
||||||
|
view_quoted_post: Просмотр цитируемого сообщения
|
||||||
visibility: Видимость
|
visibility: Видимость
|
||||||
with_media: С файлами
|
with_media: С файлами
|
||||||
strikes:
|
strikes:
|
||||||
|
|||||||
@@ -374,7 +374,9 @@ cs:
|
|||||||
jurisdiction: Právní příslušnost
|
jurisdiction: Právní příslušnost
|
||||||
min_age: Věková hranice
|
min_age: Věková hranice
|
||||||
user:
|
user:
|
||||||
|
date_of_birth_1i: Rok
|
||||||
date_of_birth_2i: Měsíc
|
date_of_birth_2i: Měsíc
|
||||||
|
date_of_birth_3i: Den
|
||||||
role: Role
|
role: Role
|
||||||
time_zone: Časové pásmo
|
time_zone: Časové pásmo
|
||||||
user_role:
|
user_role:
|
||||||
|
|||||||
@@ -376,7 +376,9 @@ cy:
|
|||||||
jurisdiction: Awdurdodaeth gyfreithiol
|
jurisdiction: Awdurdodaeth gyfreithiol
|
||||||
min_age: Isafswm oedran
|
min_age: Isafswm oedran
|
||||||
user:
|
user:
|
||||||
|
date_of_birth_1i: Blwyddyn
|
||||||
date_of_birth_2i: Mis
|
date_of_birth_2i: Mis
|
||||||
|
date_of_birth_3i: Diwrnod
|
||||||
role: Rôl
|
role: Rôl
|
||||||
time_zone: Cylchfa amser
|
time_zone: Cylchfa amser
|
||||||
user_role:
|
user_role:
|
||||||
|
|||||||
@@ -353,10 +353,10 @@ de:
|
|||||||
indexable: Profilseite in Suchmaschinen einbeziehen
|
indexable: Profilseite in Suchmaschinen einbeziehen
|
||||||
show_application: App anzeigen, über die ich einen Beitrag veröffentlicht habe
|
show_application: App anzeigen, über die ich einen Beitrag veröffentlicht habe
|
||||||
tag:
|
tag:
|
||||||
listable: Erlaube, dass dieser Hashtag in Suchen und Empfehlungen erscheint
|
listable: Dieser Hashtag darf in Suchen und Empfehlungen erscheinen
|
||||||
name: Hashtag
|
name: Hashtag
|
||||||
trendable: Erlaube, dass dieser Hashtag in den Trends erscheint
|
trendable: Dieser Hashtag darf in den Trends erscheinen
|
||||||
usable: Beiträge dürfen diesen Hashtag lokal verwenden
|
usable: Dieser Hashtag darf lokal in Beiträgen verwendet werden
|
||||||
terms_of_service:
|
terms_of_service:
|
||||||
changelog: Was hat sich geändert?
|
changelog: Was hat sich geändert?
|
||||||
effective_date: Datum des Inkrafttretens
|
effective_date: Datum des Inkrafttretens
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ hu:
|
|||||||
activity_api_enabled: Helyi bejegyzések, aktív felhasználók és új regisztrációk száma heti bontásban
|
activity_api_enabled: Helyi bejegyzések, aktív felhasználók és új regisztrációk száma heti bontásban
|
||||||
app_icon: WEBP, PNG, GIF vagy JPG. Mobileszközökön az alkalmazás alapértelmezett ikonját felülírja egy egyéni ikonnal.
|
app_icon: WEBP, PNG, GIF vagy JPG. Mobileszközökön az alkalmazás alapértelmezett ikonját felülírja egy egyéni ikonnal.
|
||||||
backups_retention_period: A felhasználók archívumokat állíthatnak elő a bejegyzéseikből, hogy később letöltsék azokat. Ha pozitív értékre van állítva, akkor a megadott számú nap után automatikusan törölve lesznek a tárhelyedről.
|
backups_retention_period: A felhasználók archívumokat állíthatnak elő a bejegyzéseikből, hogy később letöltsék azokat. Ha pozitív értékre van állítva, akkor a megadott számú nap után automatikusan törölve lesznek a tárhelyedről.
|
||||||
|
bootstrap_timeline_accounts: Ezek a fiókok rögzítve lesznek az új felhasználók követési ajánlásai tetején. Add meg a fiókok vesszővel elválasztott listáját.
|
||||||
closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva
|
closed_registrations_message: Akkor jelenik meg, amikor a regisztráció le van zárva
|
||||||
content_cache_retention_period: Minden más kiszolgálóról származó bejegyzés (megtolásokkal és válaszokkal együtt) törölve lesz a megadott számú nap elteltével, függetlenül a helyi felhasználók ezekkel a bejegyzésekkel történő interakcióitól. Ebben azok a bejegyzések is benne vannak, melyeket a helyi felhasználó könyvjelzőzött vagy kedvencnek jelölt. A különböző kiszolgálók felhasználói közötti privát üzenetek is el fognak veszni visszaállíthatatlanul. Ennek a beállításnak a használata különleges felhasználási esetekre javasolt, mert számos felhasználói elvárás fog eltörni, ha általános céllal használják.
|
content_cache_retention_period: Minden más kiszolgálóról származó bejegyzés (megtolásokkal és válaszokkal együtt) törölve lesz a megadott számú nap elteltével, függetlenül a helyi felhasználók ezekkel a bejegyzésekkel történő interakcióitól. Ebben azok a bejegyzések is benne vannak, melyeket a helyi felhasználó könyvjelzőzött vagy kedvencnek jelölt. A különböző kiszolgálók felhasználói közötti privát üzenetek is el fognak veszni visszaállíthatatlanul. Ennek a beállításnak a használata különleges felhasználási esetekre javasolt, mert számos felhasználói elvárás fog eltörni, ha általános céllal használják.
|
||||||
custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat.
|
custom_css: A Mastodon webes verziójában használhatsz egyéni stílusokat.
|
||||||
@@ -371,7 +372,9 @@ hu:
|
|||||||
jurisdiction: Joghatóság
|
jurisdiction: Joghatóság
|
||||||
min_age: Minimális életkor
|
min_age: Minimális életkor
|
||||||
user:
|
user:
|
||||||
|
date_of_birth_1i: Év
|
||||||
date_of_birth_2i: Hónap
|
date_of_birth_2i: Hónap
|
||||||
|
date_of_birth_3i: Nap
|
||||||
role: Szerep
|
role: Szerep
|
||||||
time_zone: Időzóna
|
time_zone: Időzóna
|
||||||
user_role:
|
user_role:
|
||||||
|
|||||||
@@ -40,13 +40,15 @@ export function MastodonThemes(): Plugin {
|
|||||||
|
|
||||||
// Get all files mentioned in the themes.yml file.
|
// Get all files mentioned in the themes.yml file.
|
||||||
const themes = await loadThemesFromConfig(projectRoot);
|
const themes = await loadThemesFromConfig(projectRoot);
|
||||||
|
const allThemes = {
|
||||||
|
...themes,
|
||||||
|
default_theme_tokens: 'styles_new/application.scss',
|
||||||
|
'mastodon-light_theme_tokens': 'styles_new/mastodon-light.scss',
|
||||||
|
contrast_theme_tokens: 'styles_new/contrast.scss',
|
||||||
|
};
|
||||||
|
|
||||||
for (const [themeName, themePath] of Object.entries(themes)) {
|
for (const [themeName, themePath] of Object.entries(allThemes)) {
|
||||||
entrypoints[`themes/${themeName}`] = path.resolve(jsRoot, themePath);
|
entrypoints[`themes/${themeName}`] = path.resolve(jsRoot, themePath);
|
||||||
entrypoints[`themes/${themeName}_theme_tokens`] = path.resolve(
|
|
||||||
jsRoot,
|
|
||||||
themePath.replace('styles/', 'styles_new/'),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -107,9 +107,9 @@ module Mastodon::CLI
|
|||||||
IpBlock.severity_no_access.find_each do |ip_block|
|
IpBlock.severity_no_access.find_each do |ip_block|
|
||||||
case options[:format]
|
case options[:format]
|
||||||
when 'nginx'
|
when 'nginx'
|
||||||
say "deny #{ip_block.ip}/#{ip_block.ip.prefix};"
|
say "deny #{ip_block.to_cidr};"
|
||||||
else
|
else
|
||||||
say "#{ip_block.ip}/#{ip_block.ip.prefix}"
|
say ip_block.to_cidr
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -123,12 +123,12 @@ module Mastodon::CLI
|
|||||||
progress.log("Moving #{previous_path} to #{upgraded_path}") if options[:verbose]
|
progress.log("Moving #{previous_path} to #{upgraded_path}") if options[:verbose]
|
||||||
|
|
||||||
begin
|
begin
|
||||||
move_previous_to_upgraded
|
move_previous_to_upgraded(previous_path, upgraded_path)
|
||||||
rescue => e
|
rescue => e
|
||||||
progress.log(pastel.red("Error processing #{previous_path}: #{e}"))
|
progress.log(pastel.red("Error processing #{previous_path}: #{e}"))
|
||||||
success = false
|
success = false
|
||||||
|
|
||||||
remove_directory
|
remove_directory(upgraded_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -251,12 +251,12 @@ RSpec.describe Mastodon::CLI::IpBlocks do
|
|||||||
|
|
||||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}")
|
.to output_results("#{first_ip_range_block.to_cidr}\n#{second_ip_range_block.to_cidr}")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not export blocked IPs with different severities' do
|
it 'does not export blocked IPs with different severities' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to_not output_results("#{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}")
|
.to_not output_results(third_ip_range_block.to_cidr)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -265,19 +265,19 @@ RSpec.describe Mastodon::CLI::IpBlocks do
|
|||||||
|
|
||||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("deny #{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};\ndeny #{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix};")
|
.to output_results("deny #{first_ip_range_block.to_cidr};\ndeny #{second_ip_range_block.to_cidr};")
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'does not export blocked IPs with different severities' do
|
it 'does not export blocked IPs with different severities' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to_not output_results("deny #{third_ip_range_block.ip}/#{first_ip_range_block.ip.prefix};")
|
.to_not output_results("deny #{third_ip_range_block.to_cidr};")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when --format option is not provided' do
|
context 'when --format option is not provided' do
|
||||||
it 'exports blocked IPs in plain format by default' do
|
it 'exports blocked IPs in plain format by default' do
|
||||||
expect { subject }
|
expect { subject }
|
||||||
.to output_results("#{first_ip_range_block.ip}/#{first_ip_range_block.ip.prefix}\n#{second_ip_range_block.ip}/#{second_ip_range_block.ip.prefix}")
|
.to output_results("#{first_ip_range_block.to_cidr}\n#{second_ip_range_block.to_cidr}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -73,8 +73,6 @@ RSpec.describe Mastodon::RedisConfiguration do
|
|||||||
end
|
end
|
||||||
|
|
||||||
shared_examples 'sentinel support' do |prefix = nil|
|
shared_examples 'sentinel support' do |prefix = nil|
|
||||||
prefix = prefix ? "#{prefix}_" : ''
|
|
||||||
|
|
||||||
context 'when configuring sentinel support' do
|
context 'when configuring sentinel support' do
|
||||||
around do |example|
|
around do |example|
|
||||||
ClimateControl.modify "#{prefix}REDIS_PASSWORD": 'testpass1', "#{prefix}REDIS_HOST": 'redis2.example.com', "#{prefix}REDIS_SENTINELS": '192.168.0.1:3000,192.168.0.2:4000', "#{prefix}REDIS_SENTINEL_MASTER": 'mainsentinel' do
|
ClimateControl.modify "#{prefix}REDIS_PASSWORD": 'testpass1', "#{prefix}REDIS_HOST": 'redis2.example.com', "#{prefix}REDIS_SENTINELS": '192.168.0.1:3000,192.168.0.2:4000', "#{prefix}REDIS_SENTINEL_MASTER": 'mainsentinel' do
|
||||||
@@ -199,7 +197,7 @@ RSpec.describe Mastodon::RedisConfiguration do
|
|||||||
|
|
||||||
it_behaves_like 'secondary configuration', 'SIDEKIQ'
|
it_behaves_like 'secondary configuration', 'SIDEKIQ'
|
||||||
it_behaves_like 'setting a different driver'
|
it_behaves_like 'setting a different driver'
|
||||||
it_behaves_like 'sentinel support', 'SIDEKIQ'
|
it_behaves_like 'sentinel support', 'SIDEKIQ_'
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#cache' do
|
describe '#cache' do
|
||||||
@@ -225,6 +223,6 @@ RSpec.describe Mastodon::RedisConfiguration do
|
|||||||
|
|
||||||
it_behaves_like 'secondary configuration', 'CACHE'
|
it_behaves_like 'secondary configuration', 'CACHE'
|
||||||
it_behaves_like 'setting a different driver'
|
it_behaves_like 'setting a different driver'
|
||||||
it_behaves_like 'sentinel support', 'CACHE'
|
it_behaves_like 'sentinel support', 'CACHE_'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,6 +26,22 @@ RSpec.describe IpBlock do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#to_cidr' do
|
||||||
|
subject { Fabricate.build(:ip_block, ip:).to_cidr }
|
||||||
|
|
||||||
|
context 'with an IP and a specified prefix' do
|
||||||
|
let(:ip) { '192.168.1.0/24' }
|
||||||
|
|
||||||
|
it { is_expected.to eq('192.168.1.0/24') }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with an IP and a default prefix' do
|
||||||
|
let(:ip) { '192.168.1.0' }
|
||||||
|
|
||||||
|
it { is_expected.to eq('192.168.1.0/32') }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '.blocked?' do
|
describe '.blocked?' do
|
||||||
context 'when the IP is blocked' do
|
context 'when the IP is blocked' do
|
||||||
it 'returns true' do
|
it 'returns true' do
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ RSpec.describe 'IP Blocks' do
|
|||||||
|
|
||||||
expect(response.parsed_body)
|
expect(response.parsed_body)
|
||||||
.to include(
|
.to include(
|
||||||
ip: eq("#{ip_block.ip}/#{ip_block.ip.prefix}"),
|
ip: eq(ip_block.to_cidr),
|
||||||
severity: eq(ip_block.severity.to_s)
|
severity: eq(ip_block.severity.to_s)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@@ -216,7 +216,7 @@ RSpec.describe 'IP Blocks' do
|
|||||||
expect(response.content_type)
|
expect(response.content_type)
|
||||||
.to start_with('application/json')
|
.to start_with('application/json')
|
||||||
expect(response.parsed_body).to match(hash_including({
|
expect(response.parsed_body).to match(hash_including({
|
||||||
ip: "#{ip_block.ip}/#{ip_block.ip.prefix}",
|
ip: ip_block.to_cidr,
|
||||||
severity: 'sign_up_requires_approval',
|
severity: 'sign_up_requires_approval',
|
||||||
comment: 'Decreasing severity',
|
comment: 'Decreasing severity',
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -50,6 +50,21 @@ RSpec.describe 'API V1 Statuses Translations' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with a public status marked with the same language as the current locale when translation backend cannot do same-language translation' do
|
||||||
|
let(:status) { Fabricate(:status, account: user.account, text: 'Esto está en español pero está marcado como inglés.', language: 'en') }
|
||||||
|
|
||||||
|
it 'returns http forbidden with error message' do
|
||||||
|
subject
|
||||||
|
|
||||||
|
expect(response)
|
||||||
|
.to have_http_status(403)
|
||||||
|
expect(response.media_type)
|
||||||
|
.to eq('application/json')
|
||||||
|
expect(response.parsed_body)
|
||||||
|
.to include(error: /not allowed/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'with a private status' do
|
context 'with a private status' do
|
||||||
let(:status) { Fabricate(:status, visibility: :private, account: user.account, text: 'Hola', language: 'es') }
|
let(:status) { Fabricate(:status, visibility: :private, account: user.account, text: 'Hola', language: 'es') }
|
||||||
|
|
||||||
|
|||||||
64
yarn.lock
64
yarn.lock
@@ -97,39 +97,39 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.28.0, @babel/core@npm:^7.28.4":
|
"@babel/core@npm:^7.18.9, @babel/core@npm:^7.21.3, @babel/core@npm:^7.24.4, @babel/core@npm:^7.26.10, @babel/core@npm:^7.28.0, @babel/core@npm:^7.28.5":
|
||||||
version: 7.28.4
|
version: 7.28.5
|
||||||
resolution: "@babel/core@npm:7.28.4"
|
resolution: "@babel/core@npm:7.28.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame": "npm:^7.27.1"
|
"@babel/code-frame": "npm:^7.27.1"
|
||||||
"@babel/generator": "npm:^7.28.3"
|
"@babel/generator": "npm:^7.28.5"
|
||||||
"@babel/helper-compilation-targets": "npm:^7.27.2"
|
"@babel/helper-compilation-targets": "npm:^7.27.2"
|
||||||
"@babel/helper-module-transforms": "npm:^7.28.3"
|
"@babel/helper-module-transforms": "npm:^7.28.3"
|
||||||
"@babel/helpers": "npm:^7.28.4"
|
"@babel/helpers": "npm:^7.28.4"
|
||||||
"@babel/parser": "npm:^7.28.4"
|
"@babel/parser": "npm:^7.28.5"
|
||||||
"@babel/template": "npm:^7.27.2"
|
"@babel/template": "npm:^7.27.2"
|
||||||
"@babel/traverse": "npm:^7.28.4"
|
"@babel/traverse": "npm:^7.28.5"
|
||||||
"@babel/types": "npm:^7.28.4"
|
"@babel/types": "npm:^7.28.5"
|
||||||
"@jridgewell/remapping": "npm:^2.3.5"
|
"@jridgewell/remapping": "npm:^2.3.5"
|
||||||
convert-source-map: "npm:^2.0.0"
|
convert-source-map: "npm:^2.0.0"
|
||||||
debug: "npm:^4.1.0"
|
debug: "npm:^4.1.0"
|
||||||
gensync: "npm:^1.0.0-beta.2"
|
gensync: "npm:^1.0.0-beta.2"
|
||||||
json5: "npm:^2.2.3"
|
json5: "npm:^2.2.3"
|
||||||
semver: "npm:^6.3.1"
|
semver: "npm:^6.3.1"
|
||||||
checksum: 10c0/ef5a6c3c6bf40d3589b5593f8118cfe2602ce737412629fb6e26d595be2fcbaae0807b43027a5c42ec4fba5b895ff65891f2503b5918c8a3ea3542ab44d4c278
|
checksum: 10c0/535f82238027621da6bdffbdbe896ebad3558b311d6f8abc680637a9859b96edbf929ab010757055381570b29cf66c4a295b5618318d27a4273c0e2033925e72
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/generator@npm:^7.28.3":
|
"@babel/generator@npm:^7.28.5":
|
||||||
version: 7.28.3
|
version: 7.28.5
|
||||||
resolution: "@babel/generator@npm:7.28.3"
|
resolution: "@babel/generator@npm:7.28.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/parser": "npm:^7.28.3"
|
"@babel/parser": "npm:^7.28.5"
|
||||||
"@babel/types": "npm:^7.28.2"
|
"@babel/types": "npm:^7.28.5"
|
||||||
"@jridgewell/gen-mapping": "npm:^0.3.12"
|
"@jridgewell/gen-mapping": "npm:^0.3.12"
|
||||||
"@jridgewell/trace-mapping": "npm:^0.3.28"
|
"@jridgewell/trace-mapping": "npm:^0.3.28"
|
||||||
jsesc: "npm:^3.0.2"
|
jsesc: "npm:^3.0.2"
|
||||||
checksum: 10c0/0ff58bcf04f8803dcc29479b547b43b9b0b828ec1ee0668e92d79f9e90f388c28589056637c5ff2fd7bcf8d153c990d29c448d449d852bf9d1bc64753ca462bc
|
checksum: 10c0/9f219fe1d5431b6919f1a5c60db8d5d34fe546c0d8f5a8511b32f847569234ffc8032beb9e7404649a143f54e15224ecb53a3d11b6bb85c3203e573d91fca752
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -334,7 +334,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.3, @babel/parser@npm:^7.28.4":
|
"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.27.2, @babel/parser@npm:^7.28.5":
|
||||||
version: 7.28.5
|
version: 7.28.5
|
||||||
resolution: "@babel/parser@npm:7.28.5"
|
resolution: "@babel/parser@npm:7.28.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -1194,22 +1194,22 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.4":
|
"@babel/traverse@npm:^7.18.9, @babel/traverse@npm:^7.26.10, @babel/traverse@npm:^7.27.1, @babel/traverse@npm:^7.28.0, @babel/traverse@npm:^7.28.3, @babel/traverse@npm:^7.28.5":
|
||||||
version: 7.28.4
|
version: 7.28.5
|
||||||
resolution: "@babel/traverse@npm:7.28.4"
|
resolution: "@babel/traverse@npm:7.28.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/code-frame": "npm:^7.27.1"
|
"@babel/code-frame": "npm:^7.27.1"
|
||||||
"@babel/generator": "npm:^7.28.3"
|
"@babel/generator": "npm:^7.28.5"
|
||||||
"@babel/helper-globals": "npm:^7.28.0"
|
"@babel/helper-globals": "npm:^7.28.0"
|
||||||
"@babel/parser": "npm:^7.28.4"
|
"@babel/parser": "npm:^7.28.5"
|
||||||
"@babel/template": "npm:^7.27.2"
|
"@babel/template": "npm:^7.27.2"
|
||||||
"@babel/types": "npm:^7.28.4"
|
"@babel/types": "npm:^7.28.5"
|
||||||
debug: "npm:^4.3.1"
|
debug: "npm:^4.3.1"
|
||||||
checksum: 10c0/ee678fdd49c9f54a32e07e8455242390d43ce44887cea6567b233fe13907b89240c377e7633478a32c6cf1be0e17c2f7f3b0c59f0666e39c5074cc47b968489c
|
checksum: 10c0/f6c4a595993ae2b73f2d4cd9c062f2e232174d293edd4abe1d715bd6281da8d99e47c65857e8d0917d9384c65972f4acdebc6749a7c40a8fcc38b3c7fb3e706f
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.2, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5, @babel/types@npm:^7.4.4":
|
"@babel/types@npm:^7.0.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.25.4, @babel/types@npm:^7.26.10, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.4, @babel/types@npm:^7.28.5, @babel/types@npm:^7.4.4":
|
||||||
version: 7.28.5
|
version: 7.28.5
|
||||||
resolution: "@babel/types@npm:7.28.5"
|
resolution: "@babel/types@npm:7.28.5"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -3317,10 +3317,10 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@rolldown/pluginutils@npm:1.0.0-beta.43":
|
"@rolldown/pluginutils@npm:1.0.0-beta.47":
|
||||||
version: 1.0.0-beta.43
|
version: 1.0.0-beta.47
|
||||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.43"
|
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.47"
|
||||||
checksum: 10c0/1c17a0b16c277a0fdbab080fd22ef91e37c1f0d710ecfdacb6a080068062eb14ff030d0e9d2ec2325a1d4246dba0c49625755c82c0090f6cbf98d16e80183e02
|
checksum: 10c0/eb0cfa7334d66f090c47eaac612174936b05f26e789352428cb6e03575b590f355de30d26b42576ea4e613d8887b587119d19b2e4b3a8909ceb232ca1cf746c8
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
@@ -4815,18 +4815,18 @@ __metadata:
|
|||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"@vitejs/plugin-react@npm:^5.0.0":
|
"@vitejs/plugin-react@npm:^5.0.0":
|
||||||
version: 5.1.0
|
version: 5.1.1
|
||||||
resolution: "@vitejs/plugin-react@npm:5.1.0"
|
resolution: "@vitejs/plugin-react@npm:5.1.1"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/core": "npm:^7.28.4"
|
"@babel/core": "npm:^7.28.5"
|
||||||
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
|
"@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
|
||||||
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
|
"@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
|
||||||
"@rolldown/pluginutils": "npm:1.0.0-beta.43"
|
"@rolldown/pluginutils": "npm:1.0.0-beta.47"
|
||||||
"@types/babel__core": "npm:^7.20.5"
|
"@types/babel__core": "npm:^7.20.5"
|
||||||
react-refresh: "npm:^0.18.0"
|
react-refresh: "npm:^0.18.0"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||||
checksum: 10c0/e192a12e2b854df109eafb1d06c0bc848e8e2b162c686aa6b999b1048658983e72674b2068ccc37562fcce44d32ad92b65f3a4e1897a0cb7859c2ee69cc63eac
|
checksum: 10c0/e590efaea1eabfbb1beb6e8c9fac0742fd299808e3368e63b2825ce24740adb8a28fcb2668b14b7ca1bdb42890cfefe94d02dd358dcbbf8a27ddf377b9a82abf
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user