mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-18 02:28:08 +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 'addressable', '~> 2.8'
|
||||
gem 'bootsnap', '~> 1.18.0', require: false
|
||||
gem 'bootsnap', '~> 1.19.0', require: false
|
||||
gem 'browser'
|
||||
gem 'charlock_holmes', '~> 0.7.7'
|
||||
gem 'chewy', '~> 7.3'
|
||||
|
||||
16
Gemfile.lock
16
Gemfile.lock
@@ -129,7 +129,7 @@ GEM
|
||||
binding_of_caller (1.0.1)
|
||||
debug_inspector (>= 1.2.0)
|
||||
blurhash (0.1.8)
|
||||
bootsnap (1.18.6)
|
||||
bootsnap (1.19.0)
|
||||
msgpack (~> 1.2)
|
||||
brakeman (7.1.1)
|
||||
racc
|
||||
@@ -349,7 +349,7 @@ GEM
|
||||
azure-blob (~> 0.5.2)
|
||||
hashie (~> 5.0)
|
||||
jmespath (1.6.2)
|
||||
json (2.15.2)
|
||||
json (2.16.0)
|
||||
json-canonicalization (1.0.0)
|
||||
json-jwt (1.17.0)
|
||||
activesupport (>= 4.2)
|
||||
@@ -446,7 +446,7 @@ GEM
|
||||
mime-types-data (3.2025.0924)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.9)
|
||||
minitest (5.26.0)
|
||||
minitest (5.26.1)
|
||||
msgpack (1.8.0)
|
||||
multi_json (1.17.0)
|
||||
mutex_m (0.3.0)
|
||||
@@ -759,7 +759,7 @@ GEM
|
||||
rubocop-ast (>= 1.47.1, < 2.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (>= 2.4.0, < 4.0)
|
||||
rubocop-ast (1.47.1)
|
||||
rubocop-ast (1.48.0)
|
||||
parser (>= 3.3.7.2)
|
||||
prism (~> 1.4)
|
||||
rubocop-capybara (2.22.1)
|
||||
@@ -778,10 +778,10 @@ GEM
|
||||
rack (>= 1.1)
|
||||
rubocop (>= 1.75.0, < 2.0)
|
||||
rubocop-ast (>= 1.44.0, < 2.0)
|
||||
rubocop-rspec (3.7.0)
|
||||
rubocop-rspec (3.8.0)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rspec_rails (2.31.0)
|
||||
rubocop (~> 1.81)
|
||||
rubocop-rspec_rails (2.32.0)
|
||||
lint_roller (~> 1.1)
|
||||
rubocop (~> 1.72, >= 1.72.1)
|
||||
rubocop-rspec (~> 3.5)
|
||||
@@ -941,7 +941,7 @@ DEPENDENCIES
|
||||
better_errors (~> 2.9)
|
||||
binding_of_caller (~> 1.0)
|
||||
blurhash (~> 0.1)
|
||||
bootsnap (~> 1.18.0)
|
||||
bootsnap (~> 1.19.0)
|
||||
brakeman (~> 7.0)
|
||||
browser
|
||||
bundler-audit (~> 0.9)
|
||||
|
||||
@@ -9,7 +9,7 @@ module Admin
|
||||
|
||||
@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
|
||||
|
||||
private
|
||||
|
||||
@@ -180,15 +180,15 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
||||
|
||||
if (shouldHandleEvent) {
|
||||
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;
|
||||
}[] = [];
|
||||
|
||||
(Object.keys(hotkeyMatcherMap) as HotkeyName[]).forEach(
|
||||
(handlerName) => {
|
||||
const handler = handlersRef.current[handlerName];
|
||||
|
||||
if (handler) {
|
||||
const hotkeyMatcher = hotkeyMatcherMap[handlerName];
|
||||
|
||||
const { isMatch, priority } = hotkeyMatcher(
|
||||
@@ -199,7 +199,6 @@ export function useHotkeys<T extends HTMLElement>(handlers: HandlerMap) {
|
||||
if (isMatch) {
|
||||
matchCandidates.push({ handler, priority });
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
|
||||
return (
|
||||
<Link
|
||||
className={classNames('mention hashtag', className)}
|
||||
to={`/tags/${hashtag}`}
|
||||
to={`/tags/${encodeURIComponent(hashtag)}`}
|
||||
rel='tag'
|
||||
data-menu-hashtag={hashtagAccountId}
|
||||
>
|
||||
@@ -71,7 +71,7 @@ export const HandledLink: FC<HandledLinkProps & ComponentProps<'a'>> = ({
|
||||
return (
|
||||
<a
|
||||
{...props}
|
||||
href={encodeURI(href)}
|
||||
href={href}
|
||||
title={href}
|
||||
className={classNames('unhandled-link', className)}
|
||||
target='_blank'
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
import { pasteLinkCompose } from 'mastodon/actions/compose_typed';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
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';
|
||||
|
||||
@@ -53,6 +54,7 @@ const mapStateToProps = state => ({
|
||||
quoteToPrivate:
|
||||
!!state.getIn(['compose', 'quoted_status_id'])
|
||||
&& 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]),
|
||||
isInReply: state.getIn(['compose', 'in_reply_to']) !== null,
|
||||
lang: state.getIn(['compose', 'language']),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { initialState } from '@/mastodon/initial_state';
|
||||
|
||||
import { toSupportedLocale } from './locale';
|
||||
import type { LocaleOrCustom } from './types';
|
||||
import { emojiLogger } from './utils';
|
||||
// eslint-disable-next-line import/default -- Importing via worker loader.
|
||||
import EmojiWorker from './worker?worker&inline';
|
||||
@@ -24,19 +25,17 @@ export function initializeEmoji() {
|
||||
}
|
||||
|
||||
if (worker) {
|
||||
// Assign worker to const to make TS happy inside the event listener.
|
||||
const thisWorker = worker;
|
||||
const timeoutId = setTimeout(() => {
|
||||
log('worker is not ready after timeout');
|
||||
worker = null;
|
||||
void fallbackLoad();
|
||||
}, WORKER_TIMEOUT);
|
||||
thisWorker.addEventListener('message', (event: MessageEvent<string>) => {
|
||||
worker.addEventListener('message', (event: MessageEvent<string>) => {
|
||||
const { data: message } = event;
|
||||
if (message === 'ready') {
|
||||
log('worker ready, loading data');
|
||||
clearTimeout(timeoutId);
|
||||
thisWorker.postMessage('custom');
|
||||
messageWorker('custom');
|
||||
void loadEmojiLocale(userLocale);
|
||||
// Load English locale as well, because people are still used to
|
||||
// using it from before we supported other locales.
|
||||
@@ -55,20 +54,35 @@ export function initializeEmoji() {
|
||||
async function fallbackLoad() {
|
||||
log('falling back to main thread for loading');
|
||||
const { importCustomEmojiData } = await import('./loader');
|
||||
await importCustomEmojiData();
|
||||
const emojis = await importCustomEmojiData();
|
||||
if (emojis) {
|
||||
log('loaded %d custom emojis', emojis.length);
|
||||
}
|
||||
await loadEmojiLocale(userLocale);
|
||||
if (userLocale !== 'en') {
|
||||
await loadEmojiLocale('en');
|
||||
}
|
||||
}
|
||||
|
||||
export async function loadEmojiLocale(localeString: string) {
|
||||
async function loadEmojiLocale(localeString: string) {
|
||||
const locale = toSupportedLocale(localeString);
|
||||
const { importEmojiData, localeToPath } = await import('./loader');
|
||||
|
||||
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 {
|
||||
const { importEmojiData } = await import('./loader');
|
||||
await importEmojiData(locale);
|
||||
const emojis = 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,
|
||||
} from './database';
|
||||
import { toSupportedLocale, toSupportedLocaleOrCustom } from './locale';
|
||||
import type { CustomEmojiData, LocaleOrCustom } from './types';
|
||||
import { emojiLogger } from './utils';
|
||||
import type { CustomEmojiData } from './types';
|
||||
|
||||
const log = emojiLogger('loader');
|
||||
|
||||
export async function importEmojiData(localeString: string) {
|
||||
export async function importEmojiData(localeString: string, path?: string) {
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
const flattenedEmojis: FlatCompactEmoji[] = flattenEmojiData(emojis);
|
||||
log('loaded %d for %s locale', flattenedEmojis.length, locale);
|
||||
await putEmojiData(flattenedEmojis, locale);
|
||||
return flattenedEmojis;
|
||||
}
|
||||
|
||||
export async function importCustomEmojiData() {
|
||||
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>('custom');
|
||||
const emojis = await fetchAndCheckEtag<CustomEmojiData[]>(
|
||||
'custom',
|
||||
'/api/v1/custom_emojis',
|
||||
);
|
||||
if (!emojis) {
|
||||
return;
|
||||
}
|
||||
log('loaded %d custom emojis', emojis.length);
|
||||
await putCustomEmojiData(emojis);
|
||||
return emojis;
|
||||
}
|
||||
|
||||
async function fetchAndCheckEtag<ResultType extends object[]>(
|
||||
localeOrCustom: LocaleOrCustom,
|
||||
const modules = import.meta.glob<string>(
|
||||
'../../../../../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> {
|
||||
const locale = toSupportedLocaleOrCustom(localeOrCustom);
|
||||
const locale = toSupportedLocaleOrCustom(localeString);
|
||||
|
||||
// Use location.origin as this script may be loaded from a CDN domain.
|
||||
const url = new URL(location.origin);
|
||||
if (locale === 'custom') {
|
||||
url.pathname = '/api/v1/custom_emojis';
|
||||
} else {
|
||||
const modulePath = await localeToPath(locale);
|
||||
url.pathname = modulePath;
|
||||
}
|
||||
const url = new URL(path, location.origin);
|
||||
|
||||
const oldEtag = await loadLatestEtag(locale);
|
||||
const response = await fetch(url, {
|
||||
@@ -60,38 +80,20 @@ async function fetchAndCheckEtag<ResultType extends object[]>(
|
||||
}
|
||||
if (!response.ok) {
|
||||
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;
|
||||
if (!Array.isArray(data)) {
|
||||
throw new Error(
|
||||
`Unexpected data format for ${localeOrCustom}: expected an array`,
|
||||
);
|
||||
throw new Error(`Unexpected data format for ${locale}: expected an array`);
|
||||
}
|
||||
|
||||
// Store the ETag for future requests
|
||||
const etag = response.headers.get('ETag');
|
||||
if (etag) {
|
||||
await putLatestEtag(etag, localeOrCustom);
|
||||
await putLatestEtag(etag, localeString);
|
||||
}
|
||||
|
||||
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
|
||||
.spyOn(db, 'loadEmojiByHexcode')
|
||||
.mockRejectedValue(new db.LocaleNotLoadedError('en'));
|
||||
vi.spyOn(loader, 'importEmojiData').mockResolvedValueOnce();
|
||||
vi.spyOn(loader, 'importEmojiData').mockResolvedValueOnce(undefined);
|
||||
const consoleCall = vi
|
||||
.spyOn(console, 'warn')
|
||||
.mockImplementationOnce(() => null);
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import { importEmojiData, importCustomEmojiData } from './loader';
|
||||
import { importCustomEmojiData, importEmojiData } from './loader';
|
||||
|
||||
addEventListener('message', handleMessage);
|
||||
self.postMessage('ready'); // After the worker is ready, notify the main thread
|
||||
|
||||
function handleMessage(event: MessageEvent<string>) {
|
||||
const { data: locale } = event;
|
||||
void loadData(locale);
|
||||
function handleMessage(event: MessageEvent<{ locale: string; path?: string }>) {
|
||||
const {
|
||||
data: { locale, path },
|
||||
} = event;
|
||||
void loadData(locale, path);
|
||||
}
|
||||
|
||||
async function loadData(locale: string) {
|
||||
if (locale !== 'custom') {
|
||||
await importEmojiData(locale);
|
||||
async function loadData(locale: string, path?: string) {
|
||||
let importCount: number | undefined;
|
||||
if (locale === 'custom') {
|
||||
importCount = (await importCustomEmojiData())?.length;
|
||||
} else if (path) {
|
||||
importCount = (await importEmojiData(locale, path))?.length;
|
||||
} 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 */
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useState, useRef, useCallback } from 'react';
|
||||
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -55,6 +55,8 @@ export const DetailedStatus: React.FC<{
|
||||
pictureInPicture: any;
|
||||
onToggleHidden?: (status: any) => void;
|
||||
onToggleMediaVisibility?: () => void;
|
||||
ancestors?: number;
|
||||
multiColumn?: boolean;
|
||||
}> = ({
|
||||
status,
|
||||
onOpenMedia,
|
||||
@@ -69,6 +71,8 @@ export const DetailedStatus: React.FC<{
|
||||
pictureInPicture,
|
||||
onToggleMediaVisibility,
|
||||
onToggleHidden,
|
||||
ancestors = 0,
|
||||
multiColumn = false,
|
||||
}) => {
|
||||
const properStatus = status?.get('reblog') ?? status;
|
||||
const [height, setHeight] = useState(0);
|
||||
@@ -123,6 +127,30 @@ export const DetailedStatus: React.FC<{
|
||||
if (onTranslate) 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) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -164,8 +164,6 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
componentDidMount () {
|
||||
attachFullscreenListener(this.onFullScreenChange);
|
||||
|
||||
this._scrollStatusIntoView();
|
||||
}
|
||||
|
||||
UNSAFE_componentWillReceiveProps (nextProps) {
|
||||
@@ -487,35 +485,11 @@ class Status extends ImmutablePureComponent {
|
||||
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) {
|
||||
const { status, ancestorsIds, descendantsIds } = this.props;
|
||||
const { status, descendantsIds } = this.props;
|
||||
|
||||
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
|
||||
if (prevProps.descendantsIds.length && isSameStatus) {
|
||||
const newRepliesIds = difference(descendantsIds, prevProps.descendantsIds);
|
||||
@@ -619,6 +593,8 @@ class Status extends ImmutablePureComponent {
|
||||
showMedia={this.state.showMedia}
|
||||
onToggleMediaVisibility={this.handleToggleMediaVisibility}
|
||||
pictureInPicture={pictureInPicture}
|
||||
ancestors={this.props.ancestorsIds.length}
|
||||
multiColumn={multiColumn}
|
||||
/>
|
||||
|
||||
<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.embed": "Získejte kód pro vložení",
|
||||
"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.history.created": "Uživatel {name} vytvořil {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.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_count": "{count, plural, one {{counter} citace} few {{counter} citace} many {{counter} citací} other {{counter} citací}}",
|
||||
"status.read_more": "Číst více",
|
||||
"status.reblog": "Boostnout",
|
||||
"status.reblog_or_quote": "Boostnout nebo citovat",
|
||||
"status.reblog_private": "Sdílejte znovu se svými sledujícími",
|
||||
"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_count": "{count, plural, one {{counter} boost} few {{counter} boosty} many {{counter} boostů} other {{counter} boostů}}",
|
||||
"status.redraft": "Smazat a přepsat",
|
||||
"status.remove_bookmark": "Odstranit ze záložek",
|
||||
"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.embed": "Cael y cod mewnblannu",
|
||||
"status.favourite": "Ffafrio",
|
||||
"status.favourites_count": "{count, plural, one {{counter} ffefryn} other {{counter} ffefryn}}",
|
||||
"status.filter": "Hidlo'r postiad hwn",
|
||||
"status.history.created": "Crëwyd 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.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_count": "{count, plural, one {{counter} dyfyniad} other {{counter} dyfyniad}}",
|
||||
"status.read_more": "Darllen rhagor",
|
||||
"status.reblog": "Hybu",
|
||||
"status.reblog_or_quote": "Hybu neu ddyfynnu",
|
||||
"status.reblog_private": "Rhannwch eto gyda'ch dilynwyr",
|
||||
"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_count": "{count, plural, one {{counter} hwb} other {{counter} hwb}}",
|
||||
"status.redraft": "Dileu ac ail lunio",
|
||||
"status.remove_bookmark": "Tynnu nod tudalen",
|
||||
"status.remove_favourite": "Tynnu o'r ffefrynnau",
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
"confirmations.delete_list.title": "Slet liste?",
|
||||
"confirmations.discard_draft.confirm": "Kassér og fortsæt",
|
||||
"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.post.cancel": "Genoptag udkast",
|
||||
"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.profile": "Åbn forfatters profil",
|
||||
"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.search": "Fokusér søgebjælke",
|
||||
"keyboard_shortcuts.spoilers": "Vis/skjul indholdsadvarsel-felt",
|
||||
@@ -675,7 +675,7 @@
|
||||
"notifications.column_settings.filter_bar.category": "Hurtigfiltreringsbjælke",
|
||||
"notifications.column_settings.follow": "Nye følgere:",
|
||||
"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.poll": "Afstemningsresultater:",
|
||||
"notifications.column_settings.push": "Push-notifikationer",
|
||||
@@ -764,7 +764,7 @@
|
||||
"privacy_policy.last_updated": "Senest opdateret {date}",
|
||||
"privacy_policy.title": "Privatlivspolitik",
|
||||
"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.quote": "Kun ét citat ad gangen er tilladt.",
|
||||
"quote_error.unauthorized": "Du har ikke tilladelse til at citere dette indlæg.",
|
||||
@@ -867,7 +867,7 @@
|
||||
"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.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.server_stats": "Serverstatstik:",
|
||||
"sign_in_banner.create_account": "Opret konto",
|
||||
@@ -902,7 +902,7 @@
|
||||
"status.edited": "Senest redigeret {date}",
|
||||
"status.edited_x_times": "Redigeret {count, plural, one {{count} gang} other {{count} gange}}",
|
||||
"status.embed": "Hent indlejringskode",
|
||||
"status.favourite": "Favorit",
|
||||
"status.favourite": "Favoritmarkér",
|
||||
"status.favourites_count": "{count, plural, one {{counter} favorit} other {{counter} favoritter}}",
|
||||
"status.filter": "Filtrér dette indlæg",
|
||||
"status.history.created": "{name} oprettet {date}",
|
||||
@@ -991,7 +991,7 @@
|
||||
"units.short.million": "{count} mio.",
|
||||
"units.short.thousand": "{count} tusind",
|
||||
"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.poll": "Filupload ikke tilladt for afstemninger.",
|
||||
"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.title": "Profil folgen?",
|
||||
"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.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.",
|
||||
@@ -584,8 +584,8 @@
|
||||
"navigation_bar.follows_and_followers": "Follower und Folge ich",
|
||||
"navigation_bar.import_export": "Importieren und exportieren",
|
||||
"navigation_bar.lists": "Listen",
|
||||
"navigation_bar.live_feed_local": "Live-Feed (lokal)",
|
||||
"navigation_bar.live_feed_public": "Live-Feed (öffentlich)",
|
||||
"navigation_bar.live_feed_local": "Live-Feed (Dieser Server)",
|
||||
"navigation_bar.live_feed_public": "Live-Feed (Alle Server)",
|
||||
"navigation_bar.logout": "Abmelden",
|
||||
"navigation_bar.moderation": "Moderation",
|
||||
"navigation_bar.more": "Mehr",
|
||||
|
||||
@@ -233,7 +233,7 @@
|
||||
"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.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.title": "Hylätäänkö luonnosjulkaisusi?",
|
||||
"confirmations.discard_edit_media.confirm": "Hylkää",
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
"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}.",
|
||||
"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}}",
|
||||
"lists.add_member": "Ajouter",
|
||||
"lists.add_to_list": "Ajouter à la liste",
|
||||
|
||||
@@ -528,7 +528,7 @@
|
||||
"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}.",
|
||||
"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}}",
|
||||
"lists.add_member": "Ajouter",
|
||||
"lists.add_to_list": "Ajouter à la liste",
|
||||
|
||||
@@ -189,7 +189,7 @@
|
||||
"notification.update": "{name} nuntium correxit",
|
||||
"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_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.polls": "Eventus electionis",
|
||||
"notifications.group": "{count} Notificātiōnēs",
|
||||
@@ -246,19 +246,102 @@
|
||||
"status.history.created": "{name} creatum {date}",
|
||||
"status.history.edited": "{name} correxit {date}",
|
||||
"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.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.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.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.hours": "{number, plural, one {# hora} other {# horae}} 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",
|
||||
"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.",
|
||||
"units.short.billion": "{count} millia milionum",
|
||||
"units.short.million": "{count} milionum",
|
||||
"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_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 { store } from 'mastodon/store';
|
||||
|
||||
import { initializeEmoji } from './features/emoji';
|
||||
import { isProduction, isDevelopment } from './utils/environment';
|
||||
|
||||
function main() {
|
||||
@@ -30,6 +29,7 @@ function main() {
|
||||
});
|
||||
}
|
||||
|
||||
const { initializeEmoji } = await import('./features/emoji/index');
|
||||
initializeEmoji();
|
||||
|
||||
const root = createRoot(mountNode);
|
||||
|
||||
@@ -341,8 +341,8 @@ export const composeReducer = (state = initialState, action) => {
|
||||
const isDirect = state.get('privacy') === 'direct';
|
||||
return state
|
||||
.set('quoted_status_id', isDirect ? null : status.get('id'))
|
||||
.set('spoiler', status.get('sensitive'))
|
||||
.set('spoiler_text', status.get('spoiler_text'))
|
||||
.update('spoiler', spoiler => (spoiler) || !!status.get('spoiler_text'))
|
||||
.update('spoiler_text', (spoiler_text) => spoiler_text || status.get('spoiler_text'))
|
||||
.update('privacy', (visibility) => {
|
||||
if (['public', 'unlisted'].includes(visibility) && status.get('visibility') === 'private') {
|
||||
return 'private';
|
||||
|
||||
@@ -327,9 +327,9 @@ $content-width: 840px;
|
||||
font-weight: 700;
|
||||
color: $primary-text-color;
|
||||
text-transform: none;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
border-top: 0;
|
||||
|
||||
.comment {
|
||||
display: block;
|
||||
|
||||
@@ -319,9 +319,9 @@ $content-width: 840px;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
text-transform: none;
|
||||
padding-bottom: 0;
|
||||
padding-top: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
border-top: 0;
|
||||
|
||||
.comment {
|
||||
display: block;
|
||||
|
||||
@@ -31,9 +31,10 @@ class IpBlock < ApplicationRecord
|
||||
|
||||
after_commit :reset_cache
|
||||
|
||||
def to_log_human_identifier
|
||||
def to_cidr
|
||||
"#{ip}/#{ip.prefix}"
|
||||
end
|
||||
alias to_log_human_identifier to_cidr
|
||||
|
||||
class << self
|
||||
def blocked?(remote_ip)
|
||||
|
||||
@@ -9,6 +9,6 @@ class REST::Admin::IpBlockSerializer < ActiveModel::Serializer
|
||||
end
|
||||
|
||||
def ip
|
||||
"#{object.ip}/#{object.ip.prefix}"
|
||||
object.to_cidr
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
= f.check_box :ip_block_ids, { multiple: true, include_hidden: false }, ip_block.id
|
||||
.batch-table__row__content.pending-account
|
||||
.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?
|
||||
·
|
||||
= ip_block.comment
|
||||
|
||||
@@ -477,7 +477,7 @@ da:
|
||||
no_file: Ingen fil valgt
|
||||
export_domain_blocks:
|
||||
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
|
||||
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}
|
||||
@@ -1186,7 +1186,7 @@ da:
|
||||
new_trending_statuses:
|
||||
title: Indlæg, der trender
|
||||
new_trending_tags:
|
||||
title: Hashtags, der trender
|
||||
title: Populære hashtags
|
||||
subject: Nye tendenser klar til gennemgang på %{instance}
|
||||
aliases:
|
||||
add_new: Opret alias
|
||||
|
||||
@@ -1089,16 +1089,16 @@ de:
|
||||
tag_servers_measure: Server
|
||||
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.
|
||||
listable: Kann vorgeschlagen werden
|
||||
listable: Darf empfohlen werden
|
||||
no_tag_selected: Keine Hashtags wurden geändert, da keine ausgewählt wurden
|
||||
not_listable: Wird nicht vorgeschlagen
|
||||
not_trendable: Wird in den Trends nicht angezeigt
|
||||
not_usable: Kann nicht verwendet werden
|
||||
not_listable: Darf nicht vorgeschlagen werden
|
||||
not_trendable: In Trends nicht erlaubt
|
||||
not_usable: In Beiträgen nicht erlaubt
|
||||
peaked_on_and_decaying: In den Trends am %{date}, jetzt absteigend
|
||||
title: Angesagte Hashtags
|
||||
trendable: Darf in den Trends erscheinen
|
||||
trendable: In Trends erlaubt
|
||||
trending_rank: Platz %{rank}
|
||||
usable: Darf verwendet werden
|
||||
usable: In Beiträgen erlaubt
|
||||
usage_comparison: Heute %{today}-mal und gestern %{yesterday}-mal verwendet
|
||||
used_by_over_week:
|
||||
one: In den vergangenen 7 Tagen von einem Profil verwendet
|
||||
@@ -1122,7 +1122,7 @@ de:
|
||||
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)
|
||||
not_permitted: Nicht gestattet
|
||||
title: Regeln für Profilnamen
|
||||
title: Profilnamen
|
||||
updated_msg: Regel für Profilnamen erfolgreich aktualisiert
|
||||
warning_presets:
|
||||
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!
|
||||
title: Überprüfe dein E-Mail-Postfach
|
||||
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
|
||||
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.
|
||||
|
||||
@@ -563,6 +563,7 @@ eu:
|
||||
create: Gehitu Moderazio Oharra
|
||||
created_msg: Instantziako moderazio oharra ongi sortu da!
|
||||
description_html: Ikusi eta idatzi oharrak beste moderatzaileentzat eta zuretzat etorkizunerako
|
||||
title: Moderazio oharrak
|
||||
private_comment: Iruzkin pribatua
|
||||
public_comment: Iruzkin publikoa
|
||||
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.
|
||||
edit: Editatu araua
|
||||
empty: Ez da zerbitzariko araurik definitu oraindik.
|
||||
move_down: Behera mugitu
|
||||
move_up: Mugitu gora
|
||||
title: Zerbitzariaren arauak
|
||||
translation: Itzulpena
|
||||
translations: Itzulpenak
|
||||
@@ -808,6 +811,14 @@ eu:
|
||||
all: Guztiei
|
||||
disabled: Inori ez
|
||||
users: Saioa hasita duten erabiltzaile lokalei
|
||||
feed_access:
|
||||
modes:
|
||||
public: Edonork
|
||||
landing_page:
|
||||
values:
|
||||
about: Honi buruz
|
||||
local_feed: Jario lokala
|
||||
trends: Joerak
|
||||
registrations:
|
||||
moderation_recommandation: Mesedez, ziurtatu moderazio-talde egokia eta erreaktiboa duzula erregistroak guztiei ireki aurretik!
|
||||
preamble: Kontrolatu nork sortu dezakeen kontua zerbitzarian.
|
||||
@@ -862,6 +873,7 @@ eu:
|
||||
original_status: Jatorrizko bidalketa
|
||||
quotes: Aipuak
|
||||
reblogs: Bultzadak
|
||||
replied_to_html: "%{acct_link}(r)i erantzuten"
|
||||
status_changed: Bidalketa aldatuta
|
||||
status_title: "%{name} erabiltzailearen bidalketa"
|
||||
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.
|
||||
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>.
|
||||
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
|
||||
moderation:
|
||||
title: Moderáció
|
||||
@@ -1928,6 +1929,7 @@ hu:
|
||||
errors:
|
||||
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_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
|
||||
pin_errors:
|
||||
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: Ничего не изменилось, так как ни один пост не был выделен
|
||||
open: Открыть запись
|
||||
original_status: Оригинальный пост
|
||||
quotes: Цитаты
|
||||
reblogs: Продвинули
|
||||
replied_to_html: Ответ пользователю %{acct_link}
|
||||
status_changed: Пост изменен
|
||||
@@ -935,6 +936,7 @@ ru:
|
||||
title: Посты пользователя - @%{name}
|
||||
trending: Популярное
|
||||
view_publicly: Открыть по публичной ссылке
|
||||
view_quoted_post: Просмотр цитируемого сообщения
|
||||
visibility: Видимость
|
||||
with_media: С файлами
|
||||
strikes:
|
||||
|
||||
@@ -374,7 +374,9 @@ cs:
|
||||
jurisdiction: Právní příslušnost
|
||||
min_age: Věková hranice
|
||||
user:
|
||||
date_of_birth_1i: Rok
|
||||
date_of_birth_2i: Měsíc
|
||||
date_of_birth_3i: Den
|
||||
role: Role
|
||||
time_zone: Časové pásmo
|
||||
user_role:
|
||||
|
||||
@@ -376,7 +376,9 @@ cy:
|
||||
jurisdiction: Awdurdodaeth gyfreithiol
|
||||
min_age: Isafswm oedran
|
||||
user:
|
||||
date_of_birth_1i: Blwyddyn
|
||||
date_of_birth_2i: Mis
|
||||
date_of_birth_3i: Diwrnod
|
||||
role: Rôl
|
||||
time_zone: Cylchfa amser
|
||||
user_role:
|
||||
|
||||
@@ -353,10 +353,10 @@ de:
|
||||
indexable: Profilseite in Suchmaschinen einbeziehen
|
||||
show_application: App anzeigen, über die ich einen Beitrag veröffentlicht habe
|
||||
tag:
|
||||
listable: Erlaube, dass dieser Hashtag in Suchen und Empfehlungen erscheint
|
||||
listable: Dieser Hashtag darf in Suchen und Empfehlungen erscheinen
|
||||
name: Hashtag
|
||||
trendable: Erlaube, dass dieser Hashtag in den Trends erscheint
|
||||
usable: Beiträge dürfen diesen Hashtag lokal verwenden
|
||||
trendable: Dieser Hashtag darf in den Trends erscheinen
|
||||
usable: Dieser Hashtag darf lokal in Beiträgen verwendet werden
|
||||
terms_of_service:
|
||||
changelog: Was hat sich geändert?
|
||||
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
|
||||
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.
|
||||
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
|
||||
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.
|
||||
@@ -371,7 +372,9 @@ hu:
|
||||
jurisdiction: Joghatóság
|
||||
min_age: Minimális életkor
|
||||
user:
|
||||
date_of_birth_1i: Év
|
||||
date_of_birth_2i: Hónap
|
||||
date_of_birth_3i: Nap
|
||||
role: Szerep
|
||||
time_zone: Időzóna
|
||||
user_role:
|
||||
|
||||
@@ -40,13 +40,15 @@ export function MastodonThemes(): Plugin {
|
||||
|
||||
// Get all files mentioned in the themes.yml file.
|
||||
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}_theme_tokens`] = path.resolve(
|
||||
jsRoot,
|
||||
themePath.replace('styles/', 'styles_new/'),
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -107,9 +107,9 @@ module Mastodon::CLI
|
||||
IpBlock.severity_no_access.find_each do |ip_block|
|
||||
case options[:format]
|
||||
when 'nginx'
|
||||
say "deny #{ip_block.ip}/#{ip_block.ip.prefix};"
|
||||
say "deny #{ip_block.to_cidr};"
|
||||
else
|
||||
say "#{ip_block.ip}/#{ip_block.ip.prefix}"
|
||||
say ip_block.to_cidr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -123,12 +123,12 @@ module Mastodon::CLI
|
||||
progress.log("Moving #{previous_path} to #{upgraded_path}") if options[:verbose]
|
||||
|
||||
begin
|
||||
move_previous_to_upgraded
|
||||
move_previous_to_upgraded(previous_path, upgraded_path)
|
||||
rescue => e
|
||||
progress.log(pastel.red("Error processing #{previous_path}: #{e}"))
|
||||
success = false
|
||||
|
||||
remove_directory
|
||||
remove_directory(upgraded_path)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -251,12 +251,12 @@ RSpec.describe Mastodon::CLI::IpBlocks do
|
||||
|
||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||
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
|
||||
|
||||
it 'does not export blocked IPs with different severities' do
|
||||
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
|
||||
|
||||
@@ -265,19 +265,19 @@ RSpec.describe Mastodon::CLI::IpBlocks do
|
||||
|
||||
it 'exports blocked IPs with "no_access" severity in plain format' do
|
||||
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
|
||||
|
||||
it 'does not export blocked IPs with different severities' do
|
||||
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
|
||||
|
||||
context 'when --format option is not provided' do
|
||||
it 'exports blocked IPs in plain format by default' do
|
||||
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
|
||||
|
||||
@@ -73,8 +73,6 @@ RSpec.describe Mastodon::RedisConfiguration do
|
||||
end
|
||||
|
||||
shared_examples 'sentinel support' do |prefix = nil|
|
||||
prefix = prefix ? "#{prefix}_" : ''
|
||||
|
||||
context 'when configuring sentinel support' do
|
||||
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
|
||||
@@ -199,7 +197,7 @@ RSpec.describe Mastodon::RedisConfiguration do
|
||||
|
||||
it_behaves_like 'secondary configuration', 'SIDEKIQ'
|
||||
it_behaves_like 'setting a different driver'
|
||||
it_behaves_like 'sentinel support', 'SIDEKIQ'
|
||||
it_behaves_like 'sentinel support', 'SIDEKIQ_'
|
||||
end
|
||||
|
||||
describe '#cache' do
|
||||
@@ -225,6 +223,6 @@ RSpec.describe Mastodon::RedisConfiguration do
|
||||
|
||||
it_behaves_like 'secondary configuration', 'CACHE'
|
||||
it_behaves_like 'setting a different driver'
|
||||
it_behaves_like 'sentinel support', 'CACHE'
|
||||
it_behaves_like 'sentinel support', 'CACHE_'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -26,6 +26,22 @@ RSpec.describe IpBlock do
|
||||
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
|
||||
context 'when the IP is blocked' do
|
||||
it 'returns true' do
|
||||
|
||||
@@ -97,7 +97,7 @@ RSpec.describe 'IP Blocks' do
|
||||
|
||||
expect(response.parsed_body)
|
||||
.to include(
|
||||
ip: eq("#{ip_block.ip}/#{ip_block.ip.prefix}"),
|
||||
ip: eq(ip_block.to_cidr),
|
||||
severity: eq(ip_block.severity.to_s)
|
||||
)
|
||||
end
|
||||
@@ -216,7 +216,7 @@ RSpec.describe 'IP Blocks' do
|
||||
expect(response.content_type)
|
||||
.to start_with('application/json')
|
||||
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',
|
||||
comment: 'Decreasing severity',
|
||||
}))
|
||||
|
||||
@@ -50,6 +50,21 @@ RSpec.describe 'API V1 Statuses Translations' do
|
||||
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
|
||||
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
|
||||
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":
|
||||
version: 7.28.4
|
||||
resolution: "@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.5
|
||||
resolution: "@babel/core@npm:7.28.5"
|
||||
dependencies:
|
||||
"@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-module-transforms": "npm:^7.28.3"
|
||||
"@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/traverse": "npm:^7.28.4"
|
||||
"@babel/types": "npm:^7.28.4"
|
||||
"@babel/traverse": "npm:^7.28.5"
|
||||
"@babel/types": "npm:^7.28.5"
|
||||
"@jridgewell/remapping": "npm:^2.3.5"
|
||||
convert-source-map: "npm:^2.0.0"
|
||||
debug: "npm:^4.1.0"
|
||||
gensync: "npm:^1.0.0-beta.2"
|
||||
json5: "npm:^2.2.3"
|
||||
semver: "npm:^6.3.1"
|
||||
checksum: 10c0/ef5a6c3c6bf40d3589b5593f8118cfe2602ce737412629fb6e26d595be2fcbaae0807b43027a5c42ec4fba5b895ff65891f2503b5918c8a3ea3542ab44d4c278
|
||||
checksum: 10c0/535f82238027621da6bdffbdbe896ebad3558b311d6f8abc680637a9859b96edbf929ab010757055381570b29cf66c4a295b5618318d27a4273c0e2033925e72
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@babel/generator@npm:^7.28.3":
|
||||
version: 7.28.3
|
||||
resolution: "@babel/generator@npm:7.28.3"
|
||||
"@babel/generator@npm:^7.28.5":
|
||||
version: 7.28.5
|
||||
resolution: "@babel/generator@npm:7.28.5"
|
||||
dependencies:
|
||||
"@babel/parser": "npm:^7.28.3"
|
||||
"@babel/types": "npm:^7.28.2"
|
||||
"@babel/parser": "npm:^7.28.5"
|
||||
"@babel/types": "npm:^7.28.5"
|
||||
"@jridgewell/gen-mapping": "npm:^0.3.12"
|
||||
"@jridgewell/trace-mapping": "npm:^0.3.28"
|
||||
jsesc: "npm:^3.0.2"
|
||||
checksum: 10c0/0ff58bcf04f8803dcc29479b547b43b9b0b828ec1ee0668e92d79f9e90f388c28589056637c5ff2fd7bcf8d153c990d29c448d449d852bf9d1bc64753ca462bc
|
||||
checksum: 10c0/9f219fe1d5431b6919f1a5c60db8d5d34fe546c0d8f5a8511b32f847569234ffc8032beb9e7404649a143f54e15224ecb53a3d11b6bb85c3203e573d91fca752
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -334,7 +334,7 @@ __metadata:
|
||||
languageName: node
|
||||
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
|
||||
resolution: "@babel/parser@npm:7.28.5"
|
||||
dependencies:
|
||||
@@ -1194,22 +1194,22 @@ __metadata:
|
||||
languageName: node
|
||||
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":
|
||||
version: 7.28.4
|
||||
resolution: "@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.5
|
||||
resolution: "@babel/traverse@npm:7.28.5"
|
||||
dependencies:
|
||||
"@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/parser": "npm:^7.28.4"
|
||||
"@babel/parser": "npm:^7.28.5"
|
||||
"@babel/template": "npm:^7.27.2"
|
||||
"@babel/types": "npm:^7.28.4"
|
||||
"@babel/types": "npm:^7.28.5"
|
||||
debug: "npm:^4.3.1"
|
||||
checksum: 10c0/ee678fdd49c9f54a32e07e8455242390d43ce44887cea6567b233fe13907b89240c377e7633478a32c6cf1be0e17c2f7f3b0c59f0666e39c5074cc47b968489c
|
||||
checksum: 10c0/f6c4a595993ae2b73f2d4cd9c062f2e232174d293edd4abe1d715bd6281da8d99e47c65857e8d0917d9384c65972f4acdebc6749a7c40a8fcc38b3c7fb3e706f
|
||||
languageName: node
|
||||
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
|
||||
resolution: "@babel/types@npm:7.28.5"
|
||||
dependencies:
|
||||
@@ -3317,10 +3317,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rolldown/pluginutils@npm:1.0.0-beta.43":
|
||||
version: 1.0.0-beta.43
|
||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.43"
|
||||
checksum: 10c0/1c17a0b16c277a0fdbab080fd22ef91e37c1f0d710ecfdacb6a080068062eb14ff030d0e9d2ec2325a1d4246dba0c49625755c82c0090f6cbf98d16e80183e02
|
||||
"@rolldown/pluginutils@npm:1.0.0-beta.47":
|
||||
version: 1.0.0-beta.47
|
||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.47"
|
||||
checksum: 10c0/eb0cfa7334d66f090c47eaac612174936b05f26e789352428cb6e03575b590f355de30d26b42576ea4e613d8887b587119d19b2e4b3a8909ceb232ca1cf746c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -4815,18 +4815,18 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"@vitejs/plugin-react@npm:^5.0.0":
|
||||
version: 5.1.0
|
||||
resolution: "@vitejs/plugin-react@npm:5.1.0"
|
||||
version: 5.1.1
|
||||
resolution: "@vitejs/plugin-react@npm:5.1.1"
|
||||
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-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"
|
||||
react-refresh: "npm:^0.18.0"
|
||||
peerDependencies:
|
||||
vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
|
||||
checksum: 10c0/e192a12e2b854df109eafb1d06c0bc848e8e2b162c686aa6b999b1048658983e72674b2068ccc37562fcce44d32ad92b65f3a4e1897a0cb7859c2ee69cc63eac
|
||||
checksum: 10c0/e590efaea1eabfbb1beb6e8c9fac0742fd299808e3368e63b2825ce24740adb8a28fcb2668b14b7ca1bdb42890cfefe94d02dd358dcbbf8a27ddf377b9a82abf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user