Merge remote-tracking branch 'parent/main' into upstream-20241209

This commit is contained in:
KMY 2024-12-09 17:49:49 +09:00
commit 6b6f145633
28 changed files with 571 additions and 324 deletions

2
.nvmrc
View file

@ -1 +1 @@
22.11
22.12

View file

@ -1,9 +1,5 @@
import api, { getLinks } from '../api';
export const HASHTAG_FETCH_REQUEST = 'HASHTAG_FETCH_REQUEST';
export const HASHTAG_FETCH_SUCCESS = 'HASHTAG_FETCH_SUCCESS';
export const HASHTAG_FETCH_FAIL = 'HASHTAG_FETCH_FAIL';
export const FOLLOWED_HASHTAGS_FETCH_REQUEST = 'FOLLOWED_HASHTAGS_FETCH_REQUEST';
export const FOLLOWED_HASHTAGS_FETCH_SUCCESS = 'FOLLOWED_HASHTAGS_FETCH_SUCCESS';
export const FOLLOWED_HASHTAGS_FETCH_FAIL = 'FOLLOWED_HASHTAGS_FETCH_FAIL';
@ -12,39 +8,6 @@ export const FOLLOWED_HASHTAGS_EXPAND_REQUEST = 'FOLLOWED_HASHTAGS_EXPAND_REQUES
export const FOLLOWED_HASHTAGS_EXPAND_SUCCESS = 'FOLLOWED_HASHTAGS_EXPAND_SUCCESS';
export const FOLLOWED_HASHTAGS_EXPAND_FAIL = 'FOLLOWED_HASHTAGS_EXPAND_FAIL';
export const HASHTAG_FOLLOW_REQUEST = 'HASHTAG_FOLLOW_REQUEST';
export const HASHTAG_FOLLOW_SUCCESS = 'HASHTAG_FOLLOW_SUCCESS';
export const HASHTAG_FOLLOW_FAIL = 'HASHTAG_FOLLOW_FAIL';
export const HASHTAG_UNFOLLOW_REQUEST = 'HASHTAG_UNFOLLOW_REQUEST';
export const HASHTAG_UNFOLLOW_SUCCESS = 'HASHTAG_UNFOLLOW_SUCCESS';
export const HASHTAG_UNFOLLOW_FAIL = 'HASHTAG_UNFOLLOW_FAIL';
export const fetchHashtag = name => (dispatch) => {
dispatch(fetchHashtagRequest());
api().get(`/api/v1/tags/${name}`).then(({ data }) => {
dispatch(fetchHashtagSuccess(name, data));
}).catch(err => {
dispatch(fetchHashtagFail(err));
});
};
export const fetchHashtagRequest = () => ({
type: HASHTAG_FETCH_REQUEST,
});
export const fetchHashtagSuccess = (name, tag) => ({
type: HASHTAG_FETCH_SUCCESS,
name,
tag,
});
export const fetchHashtagFail = error => ({
type: HASHTAG_FETCH_FAIL,
error,
});
export const fetchFollowedHashtags = () => (dispatch) => {
dispatch(fetchFollowedHashtagsRequest());
@ -116,57 +79,3 @@ export function expandFollowedHashtagsFail(error) {
error,
};
}
export const followHashtag = name => (dispatch) => {
dispatch(followHashtagRequest(name));
api().post(`/api/v1/tags/${name}/follow`).then(({ data }) => {
dispatch(followHashtagSuccess(name, data));
}).catch(err => {
dispatch(followHashtagFail(name, err));
});
};
export const followHashtagRequest = name => ({
type: HASHTAG_FOLLOW_REQUEST,
name,
});
export const followHashtagSuccess = (name, tag) => ({
type: HASHTAG_FOLLOW_SUCCESS,
name,
tag,
});
export const followHashtagFail = (name, error) => ({
type: HASHTAG_FOLLOW_FAIL,
name,
error,
});
export const unfollowHashtag = name => (dispatch) => {
dispatch(unfollowHashtagRequest(name));
api().post(`/api/v1/tags/${name}/unfollow`).then(({ data }) => {
dispatch(unfollowHashtagSuccess(name, data));
}).catch(err => {
dispatch(unfollowHashtagFail(name, err));
});
};
export const unfollowHashtagRequest = name => ({
type: HASHTAG_UNFOLLOW_REQUEST,
name,
});
export const unfollowHashtagSuccess = (name, tag) => ({
type: HASHTAG_UNFOLLOW_SUCCESS,
name,
tag,
});
export const unfollowHashtagFail = (name, error) => ({
type: HASHTAG_UNFOLLOW_FAIL,
name,
error,
});

View file

@ -0,0 +1,17 @@
import { apiGetTag, apiFollowTag, apiUnfollowTag } from 'mastodon/api/tags';
import { createDataLoadingThunk } from 'mastodon/store/typed_functions';
export const fetchHashtag = createDataLoadingThunk(
'tags/fetch',
({ tagId }: { tagId: string }) => apiGetTag(tagId),
);
export const followHashtag = createDataLoadingThunk(
'tags/follow',
({ tagId }: { tagId: string }) => apiFollowTag(tagId),
);
export const unfollowHashtag = createDataLoadingThunk(
'tags/unfollow',
({ tagId }: { tagId: string }) => apiUnfollowTag(tagId),
);

View file

@ -0,0 +1,11 @@
import { apiRequestPost, apiRequestGet } from 'mastodon/api';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
export const apiGetTag = (tagId: string) =>
apiRequestGet<ApiHashtagJSON>(`v1/tags/${tagId}`);
export const apiFollowTag = (tagId: string) =>
apiRequestPost<ApiHashtagJSON>(`v1/tags/${tagId}/follow`);
export const apiUnfollowTag = (tagId: string) =>
apiRequestPost<ApiHashtagJSON>(`v1/tags/${tagId}/unfollow`);

View file

@ -0,0 +1,13 @@
interface ApiHistoryJSON {
day: string;
accounts: string;
uses: string;
}
export interface ApiHashtagJSON {
id: string;
name: string;
url: string;
history: [ApiHistoryJSON, ...ApiHistoryJSON[]];
following?: boolean;
}

View file

@ -1,94 +0,0 @@
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import ImmutablePropTypes from 'react-immutable-proptypes';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import { Button } from 'mastodon/components/button';
import { ShortNumber } from 'mastodon/components/short_number';
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
import { withIdentity } from 'mastodon/identity_context';
import { PERMISSION_MANAGE_TAXONOMIES } from 'mastodon/permissions';
const messages = defineMessages({
followHashtag: { id: 'hashtag.follow', defaultMessage: 'Follow hashtag' },
unfollowHashtag: { id: 'hashtag.unfollow', defaultMessage: 'Unfollow hashtag' },
adminModeration: { id: 'hashtag.admin_moderation', defaultMessage: 'Open moderation interface for #{name}' },
});
const usesRenderer = (displayNumber, pluralReady) => (
<FormattedMessage
id='hashtag.counter_by_uses'
defaultMessage='{count, plural, one {{counter} post} other {{counter} posts}}'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
const peopleRenderer = (displayNumber, pluralReady) => (
<FormattedMessage
id='hashtag.counter_by_accounts'
defaultMessage='{count, plural, one {{counter} participant} other {{counter} participants}}'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
const usesTodayRenderer = (displayNumber, pluralReady) => (
<FormattedMessage
id='hashtag.counter_by_uses_today'
defaultMessage='{count, plural, one {{counter} post} other {{counter} posts}} today'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
export const HashtagHeader = withIdentity(injectIntl(({ tag, intl, disabled, onClick, identity }) => {
if (!tag) {
return null;
}
const { signedIn, permissions } = identity;
const menu = [];
if (signedIn && (permissions & PERMISSION_MANAGE_TAXONOMIES) === PERMISSION_MANAGE_TAXONOMIES ) {
menu.push({ text: intl.formatMessage(messages.adminModeration, { name: tag.get("name") }), href: `/admin/tags/${tag.get('id')}` });
}
const [uses, people] = tag.get('history').reduce((arr, day) => [arr[0] + day.get('uses') * 1, arr[1] + day.get('accounts') * 1], [0, 0]);
const dividingCircle = <span aria-hidden>{' · '}</span>;
return (
<div className='hashtag-header'>
<div className='hashtag-header__header'>
<h1>#{tag.get('name')}</h1>
<div className='hashtag-header__header__buttons'>
{ menu.length > 0 && <DropdownMenuContainer disabled={menu.length === 0} items={menu} icon='ellipsis-v' iconComponent={MoreHorizIcon} size={24} direction='right' /> }
<Button onClick={onClick} text={intl.formatMessage(tag.get('following') ? messages.unfollowHashtag : messages.followHashtag)} disabled={disabled} />
</div>
</div>
<div>
<ShortNumber value={uses} renderer={usesRenderer} />
{dividingCircle}
<ShortNumber value={people} renderer={peopleRenderer} />
{dividingCircle}
<ShortNumber value={tag.getIn(['history', 0, 'uses']) * 1} renderer={usesTodayRenderer} />
</div>
</div>
);
}));
HashtagHeader.propTypes = {
tag: ImmutablePropTypes.map,
disabled: PropTypes.bool,
onClick: PropTypes.func,
intl: PropTypes.object,
};

View file

@ -0,0 +1,188 @@
import { useCallback, useMemo, useState, useEffect } from 'react';
import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { isFulfilled } from '@reduxjs/toolkit';
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
import {
fetchHashtag,
followHashtag,
unfollowHashtag,
} from 'mastodon/actions/tags_typed';
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
import { Button } from 'mastodon/components/button';
import { ShortNumber } from 'mastodon/components/short_number';
import DropdownMenu from 'mastodon/containers/dropdown_menu_container';
import { useIdentity } from 'mastodon/identity_context';
import { PERMISSION_MANAGE_TAXONOMIES } from 'mastodon/permissions';
import { useAppDispatch } from 'mastodon/store';
const messages = defineMessages({
followHashtag: { id: 'hashtag.follow', defaultMessage: 'Follow hashtag' },
unfollowHashtag: {
id: 'hashtag.unfollow',
defaultMessage: 'Unfollow hashtag',
},
adminModeration: {
id: 'hashtag.admin_moderation',
defaultMessage: 'Open moderation interface for #{name}',
},
});
const usesRenderer = (displayNumber: React.ReactNode, pluralReady: number) => (
<FormattedMessage
id='hashtag.counter_by_uses'
defaultMessage='{count, plural, one {{counter} post} other {{counter} posts}}'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
const peopleRenderer = (
displayNumber: React.ReactNode,
pluralReady: number,
) => (
<FormattedMessage
id='hashtag.counter_by_accounts'
defaultMessage='{count, plural, one {{counter} participant} other {{counter} participants}}'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
const usesTodayRenderer = (
displayNumber: React.ReactNode,
pluralReady: number,
) => (
<FormattedMessage
id='hashtag.counter_by_uses_today'
defaultMessage='{count, plural, one {{counter} post} other {{counter} posts}} today'
values={{
count: pluralReady,
counter: <strong>{displayNumber}</strong>,
}}
/>
);
export const HashtagHeader: React.FC<{
tagId: string;
}> = ({ tagId }) => {
const intl = useIntl();
const { signedIn, permissions } = useIdentity();
const dispatch = useAppDispatch();
const [tag, setTag] = useState<ApiHashtagJSON>();
useEffect(() => {
void dispatch(fetchHashtag({ tagId })).then((result) => {
if (isFulfilled(result)) {
setTag(result.payload);
}
return '';
});
}, [dispatch, tagId, setTag]);
const menu = useMemo(() => {
const tmp = [];
if (
tag &&
signedIn &&
(permissions & PERMISSION_MANAGE_TAXONOMIES) ===
PERMISSION_MANAGE_TAXONOMIES
) {
tmp.push({
text: intl.formatMessage(messages.adminModeration, { name: tag.id }),
href: `/admin/tags/${tag.id}`,
});
}
return tmp;
}, [signedIn, permissions, intl, tag]);
const handleFollow = useCallback(() => {
if (!signedIn || !tag) {
return;
}
if (tag.following) {
setTag((hashtag) => hashtag && { ...hashtag, following: false });
void dispatch(unfollowHashtag({ tagId })).then((result) => {
if (isFulfilled(result)) {
setTag(result.payload);
}
return '';
});
} else {
setTag((hashtag) => hashtag && { ...hashtag, following: true });
void dispatch(followHashtag({ tagId })).then((result) => {
if (isFulfilled(result)) {
setTag(result.payload);
}
return '';
});
}
}, [dispatch, setTag, signedIn, tag, tagId]);
if (!tag) {
return null;
}
const [uses, people] = tag.history.reduce(
(arr, day) => [
arr[0] + parseInt(day.uses),
arr[1] + parseInt(day.accounts),
],
[0, 0],
);
const dividingCircle = <span aria-hidden>{' · '}</span>;
return (
<div className='hashtag-header'>
<div className='hashtag-header__header'>
<h1>#{tag.name}</h1>
<div className='hashtag-header__header__buttons'>
{menu.length > 0 && (
<DropdownMenu
disabled={menu.length === 0}
items={menu}
icon='ellipsis-v'
iconComponent={MoreHorizIcon}
size={24}
direction='right'
/>
)}
<Button
onClick={handleFollow}
text={intl.formatMessage(
tag.following ? messages.unfollowHashtag : messages.followHashtag,
)}
disabled={!signedIn}
/>
</div>
</div>
<div>
<ShortNumber value={uses} renderer={usesRenderer} />
{dividingCircle}
<ShortNumber value={people} renderer={peopleRenderer} />
{dividingCircle}
<ShortNumber
value={parseInt(tag.history[0].uses)}
renderer={usesTodayRenderer}
/>
</div>
</div>
);
};

View file

@ -5,7 +5,6 @@ import { FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { isEqual } from 'lodash';
@ -13,7 +12,6 @@ import { isEqual } from 'lodash';
import TagIcon from '@/material-icons/400-24px/tag.svg?react';
import { addColumn, removeColumn, moveColumn } from 'mastodon/actions/columns';
import { connectHashtagStream } from 'mastodon/actions/streaming';
import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/tags';
import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines';
import Column from 'mastodon/components/column';
import ColumnHeader from 'mastodon/components/column_header';
@ -26,7 +24,6 @@ import ColumnSettingsContainer from './containers/column_settings_container';
const mapStateToProps = (state, props) => ({
hasUnread: state.getIn(['timelines', `hashtag:${props.params.id}${props.params.local ? ':local' : ''}`, 'unread']) > 0,
tag: state.getIn(['tags', props.params.id]),
});
class HashtagTimeline extends PureComponent {
@ -38,7 +35,6 @@ class HashtagTimeline extends PureComponent {
columnId: PropTypes.string,
dispatch: PropTypes.func.isRequired,
hasUnread: PropTypes.bool,
tag: ImmutablePropTypes.map,
multiColumn: PropTypes.bool,
};
@ -130,7 +126,6 @@ class HashtagTimeline extends PureComponent {
this._subscribe(dispatch, id, tags, local);
dispatch(expandHashtagTimeline(id, { tags, local }));
dispatch(fetchHashtag(id));
}
componentDidMount () {
@ -162,27 +157,10 @@ class HashtagTimeline extends PureComponent {
dispatch(expandHashtagTimeline(id, { maxId, tags, local }));
};
handleFollow = () => {
const { dispatch, params, tag } = this.props;
const { id } = params;
const { signedIn } = this.props.identity;
if (!signedIn) {
return;
}
if (tag.get('following')) {
dispatch(unfollowHashtag(id));
} else {
dispatch(followHashtag(id));
}
};
render () {
const { hasUnread, columnId, multiColumn, tag } = this.props;
const { hasUnread, columnId, multiColumn } = this.props;
const { id, local } = this.props.params;
const pinned = !!columnId;
const { signedIn } = this.props.identity;
return (
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
@ -202,7 +180,7 @@ class HashtagTimeline extends PureComponent {
</ColumnHeader>
<StatusListContainer
prepend={pinned ? null : <HashtagHeader tag={tag} disabled={!signedIn} onClick={this.handleFollow} />}
prepend={pinned ? null : <HashtagHeader tagId={id} />}
alwaysPrepend
trackScroll={!pinned}
scrollKey={`hashtag_timeline-${columnId}`}

View file

@ -546,8 +546,8 @@
"notification.admin.report_statuses_other": "{name} denunciou a {target}",
"notification.admin.sign_up": "{name} rexistrouse",
"notification.admin.sign_up.name_and_others": "{name} e {count, plural, one {# máis} other {# máis}} crearon unha conta",
"notification.annual_report.message": "A #VidaEnMastodon de {year} agarda por ti! Desvela os momentos máis destacados e historias reseñables en Mastodon!",
"notification.annual_report.view": "Ver #VidaEnMastodon",
"notification.annual_report.message": "#Wrapstodon de {year} agarda por ti! Desvela os momentos máis destacados e historias reseñables en Mastodon!",
"notification.annual_report.view": "Ver #Wrapstodon",
"notification.favourite": "{name} marcou como favorita a túa publicación",
"notification.favourite.name_and_others_with_link": "{name} e <a>{count, plural, one {# máis} other {# máis}}</a> favoreceron a túa publicación",
"notification.follow": "{name} comezou a seguirte",

View file

@ -20,10 +20,13 @@
"account.block_short": "封鎖",
"account.blocked": "Hőng封鎖",
"account.cancel_follow_request": "取消跟tuè",
"account.copy": "Khóo-pih kàu個人資料ê連結",
"account.direct": "私人提起 @{name}",
"account.follow_back": "Tuè tńg去",
"annual_report.summary.percentile.text": "<topLabel>Tse 予lí變做 {domain} ê用戶ê </topLabel><percentage></percentage><bottomLabel></bottomLabel>",
"block_modal.show_less": "看khah少",
"compose.language.change": "換語言",
"confirmations.follow_to_list.confirm": "跟tuè加入kàu列單",
"search_popout.language_code": "ISO語言代碼"
"search_popout.language_code": "ISO語言代碼",
"status.translated_from_with": "用 {provider} 翻譯 {lang}"
}

View file

@ -0,0 +1,7 @@
import type { ApiHashtagJSON } from 'mastodon/api_types/tags';
export type Hashtag = ApiHashtagJSON;
export const createHashtag = (serverJSON: ApiHashtagJSON): Hashtag => ({
...serverJSON,
});

View file

@ -40,7 +40,6 @@ import settings from './settings';
import status_lists from './status_lists';
import statuses from './statuses';
import { suggestionsReducer } from './suggestions';
import tags from './tags';
import timelines from './timelines';
import trends from './trends';
import user_lists from './user_lists';
@ -83,7 +82,6 @@ const reducers = {
markers: markersReducer,
picture_in_picture: pictureInPictureReducer,
history,
tags,
followed_tags,
reaction_deck,
notificationPolicy: notificationPolicyReducer,

View file

@ -1,26 +0,0 @@
import { Map as ImmutableMap, fromJS } from 'immutable';
import {
HASHTAG_FETCH_SUCCESS,
HASHTAG_FOLLOW_REQUEST,
HASHTAG_FOLLOW_FAIL,
HASHTAG_UNFOLLOW_REQUEST,
HASHTAG_UNFOLLOW_FAIL,
} from 'mastodon/actions/tags';
const initialState = ImmutableMap();
export default function tags(state = initialState, action) {
switch(action.type) {
case HASHTAG_FETCH_SUCCESS:
return state.set(action.name, fromJS(action.tag));
case HASHTAG_FOLLOW_REQUEST:
case HASHTAG_UNFOLLOW_FAIL:
return state.setIn([action.name, 'following'], true);
case HASHTAG_FOLLOW_FAIL:
case HASHTAG_UNFOLLOW_REQUEST:
return state.setIn([action.name, 'following'], false);
default:
return state;
}
}

View file

@ -192,9 +192,11 @@ bg:
create_user_role: Създаване на роля
demote_user: Понижаване на потребител
destroy_announcement: Изтриване на оповестяване
destroy_canonical_email_block: Изтриване на блокиране за е-поща
destroy_custom_emoji: Изтриване на персонализирано емоджи
destroy_domain_allow: Изтриване на позволението за домейн
destroy_domain_block: Изтриване на блокирането за домейна
destroy_email_domain_block: Изтриване на блокиране на домейн на е-поща
destroy_instance: Чистка на домейна
destroy_ip_block: Изтриване на правило за IP
destroy_status: Изтриване на публикация

View file

@ -455,6 +455,7 @@ eo:
title: Bloki novan retpoŝtan domajnon
no_email_domain_block_selected: Neniuj domajn blokoj ŝanĝiĝis ĉar nenio estis elektita
not_permitted: Ne permesita
resolved_dns_records_hint_html: La nomo de la domajno almontras la sekvajn MX-domajnojn, kiuj estas fine responsaj por akcepti retpoŝton. Blokas MX-domajnon blokus enskribadojn el retpoŝtadreso ajn, kiu uzas la saman MX-domajnon, eĉ se la videbla domajnnomo estas malsama. <strong> Gardemu ne bloki maĵorajn provizistojn de retpoŝto.</strong>
resolved_through_html: Solvis tra %{domain}
title: Blokis retpoŝtajn domajnojn
export_domain_allows:
@ -483,6 +484,7 @@ eo:
instances:
audit_log:
title: Novaj Protokoloj Pri Ekzamenoj
view_all: Vidu la tutan protokolon de revizio
availability:
description_html:
one: Se sendo la domajno malsukcesis por <strong>%{count} dio</strong>, ne estas sendprovo plu escepte <em>de</em> la dojmano.
@ -609,6 +611,7 @@ eo:
resolve_description_html: Nenio okazotas al la raportita konto kaj la raporto fermotas.
silence_description_html: La konto estos videbla al nur personoj kiu jam sekvis ĝin au permane serĉo ĝin, ege limigante ĝian atingon. Malfermi ciujn raportojn kontra ĉi tiun konton.
suspend_description_html: La konto kaj ciuj ĝiaj enhavoj estos neatingebla kaj poŝte forigitas, kaj interagi per ĝi estos neebla. Malfermi ciujn raportojn kontra ĉi tiu konto.
actions_description_html: Elektu kiun agon fari por ripari ĉi tiun raporton. Se vi punus la raportitan uzanton, sciigon de retpoŝto sendos al ri, krom kiam la <strong>Spamo</strong> kategorio estas elektita.
actions_description_remote_html: Decidu kiun klopodon por solvi ĉi tiun raporton. Ĉi tiu efikas kiel nur <strong>via</strong> servilo komuniki per ĉi tiu fora konto kaj trakti ĝian enhavon.
actions_no_posts: Ĉi tiu raporto havas neniujn rilatajn afiŝojn por forigi
add_to_report: Aldoni pli al raporto
@ -630,6 +633,7 @@ eo:
created_at: Signalita
delete_and_resolve: Forigi afiŝojn
forwarded: Plusendita
forwarded_replies_explanation: Ĉi tiu raporto estas de malproksima uzanto kaj estas pri malproksima enhavo. Ĝi plusendis al vi ĉar la raportita enhavo estas rediraĵo je unu el viaj uzantoj.
forwarded_to: Plusendita al %{domain}
mark_as_resolved: Marki solvita
mark_as_sensitive: Marki kiel tiklan
@ -673,6 +677,7 @@ eo:
delete_data_html: Forigi profilon kaj enhavojn de <strong>@%{acct}</strong> post 30 tagoj se ili ne malsuspenditas dum la dauro
preview_preamble_html: "<strong>@%{acct}</strong> akiros averton kun ĉi tiuj enhavoj:"
record_strike_html: Rekordu admonon kontra <strong>@%{acct}</strong> por helpi vi plikontroli estontajn malobservojn de ĉi tiu konto
send_email_html: Sendu <strong>@%{acct}</strong> retpoŝto de averto
warning_placeholder: Nedeviga aldona kialo por la moderigadago.
target_origin: Origino de raportita konto
title: Signaloj
@ -712,6 +717,7 @@ eo:
manage_appeals: Administri Apelaciojn
manage_appeals_description: Rajtigas al uzantoj kontroli apelaciojn kontraǔ kontrolaj agoj
manage_blocks: Administri Blokojn
manage_blocks_description: Permesas uzantojn bloki provizistojn de retpoŝto kaj IP adresojn
manage_custom_emojis: Administri propajn emoĝiojn
manage_custom_emojis_description: Permesi uzantojn administri propajn emoĝiojn ĉe la servilo
manage_federation: Administri Federacion
@ -729,6 +735,7 @@ eo:
manage_taxonomies: Administri kategoriarojn
manage_taxonomies_description: Permesi uzantojn kontroli popularan enhavon kaj ĝisdatigi kradvortopciojn
manage_user_access: Administri uzantoaliron
manage_user_access_description: Permesas uzantojn invalidi la du-faktoran aŭtentigon de aliaj uzantoj, ŝanĝi siajn retpoŝtadresojn, kaj restarigi siajn pasvorton
manage_users: Administri uzantojn
manage_users_description: Permesi uzantaojn vidi detalojn de aliaj uzantoj kaj administri ilin
manage_webhooks: Administri rethokojn
@ -791,15 +798,19 @@ eo:
approved: Bezonas aprobi por aliĝi
none: Neniu povas aliĝi
open: Iu povas aliĝi
warning_hint: Ni rekomendas uzi "Konsento neprigas por enskribiĝi" krom se vi memcertas, ke via teamo de moderistoj povas ellabori spamon kaj malignajn registradojn rapide.
security:
authorized_fetch: Devigi aŭtentigon de frataraj serviloj
authorized_fetch_hint: Neprigante aŭtentigon por federataj serviloj permesas pli striktan devigon de ambaŭ uzanto-nivelaj kaj servilo-nivelaj blokoj. Tamen, ĉi tiu uzas pli risurcojn, reduktas la ĝisiradon de viaj respondoj, kaj povas enkonduki aferoj, pri kongruoj. Plu, ĉi tiu ne preventos homojn el alporti viajn afiŝojn kaj uzantojn.
authorized_fetch_overridden_hint: Vi nuntempe ne povas ŝanĝi ĉi tiun agordon ĉar ĝi estas anstataŭita de mediovariablo.
federation_authentication: Devigado de la aŭtentigo de la federacio
title: Agordoj de la servilo
site_uploads:
delete: Forigi elŝutitan dosieron
destroyed_msg: Reteja alŝuto sukcese forigita!
software_updates:
critical_update: Kritika — bonvolu ĝisdatiĝi rapide
description: Ni rekomendas ĝisdatigadi vian instalaĵon de Mastodon por deutili la plej ĵusajn riparojn kaj trajtojn. Plu, estas kelkajfoje grava ĝisdati Mastodon rapide por eviti problemojn pri sekureco. Tial, Mastodon kontrolas por ĝisdataĵoj ĉiuj 30 minutoj, kaj sciigos vin laŭ viaj agordoj pri retpoŝtaj sciigoj.
documentation_link: Lerni pli
release_notes: Eldono-notoj
title: Disponeblaj ĝisdatigoj
@ -815,6 +826,7 @@ eo:
back_to_account: Reveni al konta paĝo
back_to_report: Reveni al raportpaĝo
batch:
add_to_report: 'Aldoni al raporto #%{id}'
remove_from_report: Forigi de raporto
report: Raporti
contents: Enhavoj
@ -833,6 +845,7 @@ eo:
reblogs: Reblogaĵoj
replied_to_html: Respondis al %{acct_link}
status_changed: Afiŝo ŝanĝiĝis
status_title: Afiŝo de @%{name}
title: Afiŝoj de konto - @%{name}
trending: Popularaĵoj
view_publicly: Vidu publike
@ -853,10 +866,20 @@ eo:
system_checks:
database_schema_check:
message_html: Estas pritraktataj datumbazaj migradoj. Bonvolu ekzekuti ilin por certigi, ke la apliko kondutas kiel atendite
elasticsearch_health_red:
message_html: Elasticsearch peniko estas malsana (ruĝa statuso), trajtoj de serĉo malhaveblas
elasticsearch_health_yellow:
message_html: Peniko de Elasticsearch malsana (flava status), vi eble povas enketi la kialon
elasticsearch_index_mismatch:
message_html: Bildigoj de enhavtabelo de Elasticsearch posttempas. Bonvolu, rulu <code>tootctl search deploy --only=%{value}</code>
elasticsearch_preset:
action: Legi dokumentaron
message_html: Via peniko de Elasticsearch havas pli ol unu verticon, sed Mastodon ne estas agordita uzi ilin.
elasticsearch_preset_single_node:
action: Vidi dokumentadon
message_html: Via peniko de Elasticsearch havas nur unu verticon, <code>ES_PRESET</code> devus munti al <code>single_node_cluster</code>.
elasticsearch_reset_chewy:
message_html: Via enhavtabelo de la sistemo de Elasticsearch posttempas pro ŝanĝo de agordoj. Bonvolu, rulu <code>tootctl search deploy --reset-chewy</code> por ĝisdatigi ĝin.
elasticsearch_running_check:
message_html: Ne eblas konekti Elasticsearch. Bonvolu kontroli ke ĝi funkcias, aǔ malŝaltu plentekstan serĉon
elasticsearch_version_check:
@ -875,6 +898,7 @@ eo:
message_html: Grava ĝisdatigo de Mastodon disponeblas, bonvolu ĝisdatigi kiel eble plej rapide.
software_version_patch_check:
action: Vidi disponeblajn ĝisdatigojn
message_html: Ĝisdataĵo de Mastodon pri cimriparo haveblas.
upload_check_privacy_error:
action: Klaku ĉi tie por pliaj informoj
message_html: "<strong>Via retservilo estas misagordita. La privateco de viaj uzantoj estas en risko.</strong>"
@ -883,10 +907,13 @@ eo:
message_html: "<strong>Via objektostokado estas misagordita. La privateco de viaj uzantoj estas en risko.</strong>"
tags:
moderation:
not_trendable: Ne modebla
not_usable: Ne uzebla
pending_review: Pendata superrigardo
review_requested: Revizio petita
reviewed: Reviziita
title: Stato
trendable: Modebla
unreviewed: Nereviziita
usable: Uzebla
name: Nomo
@ -935,7 +962,9 @@ eo:
statuses:
allow: Permesi afiŝon
allow_account: Permesi aŭtoron
confirm_allow: Ĉu vi certas, ke vi volas permesi elektitajn statusojn?
confirm_allow_account: Ĉu vi certas, ke vi volas permesi elektitajn kontojn?
confirm_disallow: Ĉu vi certas, ke vi volas malpermesi elektitajn statusojn?
confirm_disallow_account: Ĉu vi certas, ke vi volas malpermesi elektitajn kontojn?
description_html: Oni multe diskonigas kaj stelumas ĉi tiujn mesaĝojn nuntempe laŭ via servilo. Tio povas helpi novajn kaj revenantajn uzantojn trovi pli da homoj por sekvi. Mesaĝo estas montrita publike nur se vi aprobis la aŭtoron kaj se la aŭtoro aprobis ke ties konto estu proponita al aliaj. Vi ankaŭ povas permesi aŭ malakcepti specifajn mesaĝojn.
disallow: Malpermesi afiŝon
@ -976,6 +1005,7 @@ eo:
delete: Forigi
edit_preset: Redakti avertan antaŭagordon
empty: Vi ankoraŭ ne difinis iun ajn antaŭagordon de averto.
title: Antaŭdifinoj de averto
webhooks:
add_new: Aldoni finpunkton
delete: Forigi
@ -997,6 +1027,9 @@ eo:
title: Rethokoj
webhook: Rethoko
admin_mailer:
auto_close_registrations:
body: Pro seneco de ĵusaj aktivaĵoj de moderistoj, enskribadojn en %{instance} aŭtomate ŝanĝis al mana superrigardo, por eviti %{instance} estas uzita por eblaj fiuloj. Vi povas reŝanĝi ĝin al malfermaj enskribadoj iam ajn.
subject: Enskribadoj por %{instance} aŭtomate ŝanĝis al mana konsento
new_appeal:
actions:
delete_statuses: por forigi iliajn afiŝojn
@ -1011,6 +1044,7 @@ eo:
subject: "%{username} apelacias kontroldecidon ĉe %{instance}"
new_critical_software_updates:
body: Novaj gravaj versioj de Mastodon estis publikigitaj, vi eble volas ĝisdatigi kiel eble plej baldaŭ!
subject: Sojlaj ĝisdataĵoj de Mastodon haveblas por %{instance}!
new_pending_account:
body: La detaloj de la nova konto estas ĉi-sube. Vi povas akcepti aŭ malakcepti tiun aliĝilon.
subject: Nova konto atendas por recenzo en %{instance} (%{username})
@ -1071,10 +1105,12 @@ eo:
hint_html: Nur unu plia afero! Ni devas konfirmi, ke vi estas homo (tio estas por ke ni povu konservi la spamon ekstere!). Solvu la CAPTCHA sube kaj alklaku "Daŭrigu".
title: Sekureckontrolo
confirmations:
awaiting_review: Via retpoŝtadreso estas konfirmita! La teamo de %{domain} nun superrigardas vian enskribiĝon. Vi ricevos retpoŝton, se ili aprobos vian konton!
awaiting_review_title: Via registriĝo estas reviziita
clicking_this_link: alklakante ĉi tiun ligilon
login_link: ensaluti
proceed_to_login_html: Vi nun povas iri al %{login_link}.
redirect_to_app_html: Vi devus sendigi al la <strong>%{app_name}</strong> aplikaĵo. Se tion ne okazis, provu %{clicking_this_link} aŭ mane reiras al la aplikaĵo.
registration_complete: Via registriĝo sur %{domain} nun finiĝis!
welcome_title: Bonvenon, %{name}!
wrong_email_hint: Se tiu retadreso ne estas ĝusta, vi povas ŝanĝi ĝin en kontagordoj.
@ -1120,6 +1156,8 @@ eo:
security: Sekureco
set_new_password: Elekti novan pasvorton
setup:
email_below_hint_html: Kontrolu vian spam-dosierujon aŭ petu novan. Se necese, vi povas korekti vian retadreson.
email_settings_hint_html: Enklaku la ligilon, ke ni sendis al vi por kontroli %{email}. Ni estos tien.
link_not_received: Ĉu vi ne ricevis ligilon?
new_confirmation_instructions_sent: Vi ricevos novan retpoŝton kun la konfirma ligilo post kelkaj minutoj!
title: Kontrolu vian retpoŝta enirkesto
@ -1127,13 +1165,16 @@ eo:
preamble_html: Ensalutu per via detaloj de <strong>%{domain}</strong>. Se via konto gastigantigas sur malsama servilo, vi ne povas ensaluti ĉi tie.
title: Saluti en %{domain}
sign_up:
manual_review: Enskriboj en %{domain} havas manan superrigardon, farita de niaj moderistoj. Por helpi nin por procezi vian enskribon, skribu ion pri vi mem, kaj kial vi volas konton en %{domain}.
preamble: Per konto ĉe ĉi tiu Mastodon-servilo, vi povas sekvi ajn personojn en la reto.
title: Ni pretigu vin ĉe %{domain}.
status:
account_status: Statuso de la konto
confirming: Atendante ke retpoŝta konfirmo estos kompletigita.
functional: Via konto estas tute funkcia.
pending: Via apliko estas superrigardata de niaj teamo. Ĉi tiu povas bezoni iom da tempo. Vi ricevos retpoŝton, se via apliko estas konsentita.
redirecting_to: Via konto estas neaktiva ĉar ĝi nun alidirektas al %{acct}.
self_destruct: Pro %{domain} ekfermas, vi povos nur havi malvastan atingon al via konto.
view_strikes: Vidi antauaj admonoj kontra via konto
too_fast: Formularo sendita tro rapide, klopodu denove.
use_security_key: Uzi sekurecan ŝlosilon
@ -1183,6 +1224,7 @@ eo:
data_removal: Viaj afiŝoj kaj aliaj informoj estos forigita por eterne
email_change_html: Vi povas <a href="%{path}">ŝanĝi vian retadreson</a> sen forigi vian konton
email_contact_html: Se ĝi ankoraŭ ne alvenas, vi povas retpoŝti al <a href="mailto:%{email}">%{email}</a> por helpo
email_reconfirmation_html: Se vi ne ricevas la konfirmretpoŝton, vi povas <a href="%{path}">denove peti</a>
irreversible: Vi ne povas regajni au reaktivigi vian konton
more_details_html: Por pli da detaloj, vidi la <a href="%{terms_path}">privatecan politikon</a>.
username_available: Via uzantnomo iĝos denove disponebla
@ -1219,6 +1261,7 @@ eo:
your_appeal_rejected: Via apelacio malakceptitas
edit_profile:
basic_information: Baza informo
hint_html: "<strong>Personigi, kion homoj vidi en via publika profilo kaj apud viaj afiŝoj. </strong> Aliaj homoj estas pli probable resekvi vin kaj interagi kun vi se vi havus finigitan profilon kaj profilan foton."
other: Alia
errors:
'400': La peto kiun vi sendis estas nevalida au malformas.
@ -1341,6 +1384,44 @@ eo:
merge_long: Konservi ekzistajn registrojn kaj aldoni novajn
overwrite: Anstataŭigi
overwrite_long: Anstataŭigi la nunajn registrojn per la novaj
overwrite_preambles:
blocking_html:
one: Vi tuj <strong>anstataŭas vian blokliston</strong>, kun ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>anstataŭas vian blokliston</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
bookmarks_html:
one: Vi tuj <strong>anstataŭas viajn legosignojn</strong> kun ĝis <strong>%{count} afiŝoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>anstataŭas viajn legosignojn</strong> kun ĝis <strong>%{count} afiŝoj</strong> de <strong>%{filename}</strong>.
domain_blocking_html:
one: Vi tuj <strong>anstataŭas vian domajnan blokliston</strong> kun ĝis <strong>%{count} domajnoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>anstataŭas vian domajnan blokliston</strong> kun ĝis <strong>%{count} domajnoj</strong> de <strong>%{filename}</strong>.
following_html:
one: Vi tuj <strong>sekvos</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong> kaj <strong>ĉesos sekvi iun alian</strong>.
other: Vi tuj <strong>sekvos</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong> kaj <strong>ĉesos sekvi iun alian</strong>.
lists_html:
one: Vi tuj <strong>anstataŭos viajn listojn</strong> kun enhavo de <strong>%{filename}</strong>. Ĝis <strong>%{count} kontoj</strong> estos aldonitaj al novaj listoj.
other: Vi tuj <strong>anstataŭos viajn listojn</strong> kun enhavo de <strong>%{filename}</strong>. Ĝis <strong>%{count} kontoj</strong> estos aldonitaj al novaj listoj.
muting_html:
one: Vi tuj <strong>anstataŭas viajn listojn de silentigitaj kontoj</strong> kun ĝis<strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>anstataŭas viajn listojn de silentigitaj kontoj</strong> kun ĝis<strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
preambles:
blocking_html:
one: Vi tuj <strong>blokas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>blokas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
bookmarks_html:
one: Vi tuj aldonas ĝis <strong>%{count} afiŝojn</strong> de <strong>%{filename}</strong> al viaj <strong>legosignoj</strong>.
other: Vi tuj aldonas ĝis <strong>%{count} afiŝojn</strong> de <strong>%{filename}</strong> al viaj <strong>legosignoj</strong>.
domain_blocking_html:
one: Vi tuj <strong>blokas</strong> ĝis <strong>%{count} domajnoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>blokas</strong> ĝis <strong>%{count} domajnoj</strong> de <strong>%{filename}</strong>.
following_html:
one: Vi tuj <strong>sekvas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj <strong>sekvas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
lists_html:
one: Vi tuj aldonas ĝis <strong>%{count} kontojn</strong> de <strong>%{filename}</strong> al viaj <strong>listoj</strong>. Novaj listoj estos kreitaj se ne estas listo por aldoni.
other: Vi tuj aldonas ĝis <strong>%{count} kontojn</strong> de <strong>%{filename}</strong> al viaj <strong>listoj</strong>. Novaj listoj estos kreitaj se ne estas listo por aldoni.
muting_html:
one: Vi tuj<strong>silentas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
other: Vi tuj<strong>silentas</strong> ĝis <strong>%{count} kontoj</strong> de <strong>%{filename}</strong>.
preface: Vi povas importi datumojn, kiujn vi eksportis el alia servilo, kiel liston de homoj, kiujn vi sekvas aŭ blokas.
recent_imports: Lastatempaj importoj
states:
@ -1352,6 +1433,9 @@ eo:
success: Viaj datumoj estis sukcese alŝutitaj kaj estos traktitaj kiel planite
time_started: Komencis je
titles:
blocking: Enportante blokitajn kontojn
bookmarks: Enportante legosignojn
domain_blocking: Enportante blokitajn domajnojn
following: Importado de sekvaj kontoj
lists: Importi listojn
muting: Importado de silentigitaj kontoj
@ -1408,13 +1492,21 @@ eo:
unsubscribe:
action: Jes, malabonu
complete: Malabonita
confirmation_html: Ĉu vi certas, ke vi volas malaboni je ricevi %{type} por Mastodon ĉe %{domain} al via retpoŝto ĉe %{email}? Vi ĉiam povas reaboni de viaj <a href="%{settings_path}">retpoŝtaj sciigaj agordoj</a>.
emails:
notification_emails:
favourite: sciigoj retpoŝtaj de ŝatataj
follow: sciigoj retpoŝtaj de sekvoj
follow_request: retpoŝtajn petoj de sekvado
mention: sciigoj retpoŝtaj de mencioj
reblog: sciigoj retpoŝtaj de stimuloj
resubscribe_html: Se vi malabonis erare, vi povas reaboni de viaj <a href="%{settings_path}">retpoŝtaj sciigaj agordoj</a>.
success_html: Vi ne plu ricevos %{type} por Mastodon ĉe %{domain} al via retpoŝto ĉe %{email}.
title: Malaboni
media_attachments:
validations:
images_and_video: Aldoni videon al mesaĝo, kiu jam havas bildojn ne eblas
not_found: Dosiero %{ids} ne trovis aŭ jam alteniĝis al alia afiŝo
not_ready: Ne povas aldoni dosieron kiu ne finas procezitis.
too_many: Aldoni pli ol 4 dosierojn ne eblas
migrations:
@ -1491,6 +1583,8 @@ eo:
update:
subject: "%{name} redaktis afiŝon"
notifications:
administration_emails: Sciigoj retpoŝtaj de administacio
email_events: Eventoj por retpoŝtaj sciigoj
email_events_hint: 'Elekti la eventojn pri kioj vi volas ricevi sciigojn:'
number:
human:
@ -1584,6 +1678,7 @@ eo:
scheduled_statuses:
over_daily_limit: Vi transpasis la limigon al %{limit} samtage planitaj mesaĝoj
over_total_limit: Vi transpasis la limigon al %{limit} planitaj mesaĝoj
too_soon: dato devas esti en la futuro
self_destruct:
lead_html: Bedaŭrinde, <strong>%{domain}</strong> konstante fermiĝas. Se vi havis konton tie, vi ne povos daŭrigi uzi ĝin, sed vi ankoraŭ povas peti sekurkopion de viaj datumoj.
title: Ĉi tiu servilo fermiĝas
@ -1652,6 +1747,7 @@ eo:
preferences: Preferoj
profile: Profilo
relationships: Sekvatoj kaj sekvantoj
severed_relationships: Finitaj rilatoj
statuses_cleanup: Automata mesaĝforigo
strikes: Kontroladmonoj
two_factor_authentication: Dufaktora aŭtentigo
@ -1659,8 +1755,13 @@ eo:
severed_relationships:
download: Elŝuti (%{count})
event_type:
account_suspension: Suspendado de konto (%{target_name})
domain_block: Suspendado de servilo (%{target_name})
user_domain_block: Vi blokis %{target_name}
lost_followers: Perditaj sekvantoj
lost_follows: Perditaj sekvantoj
preamble: Vi eble perdos sekvojn kaj sekvantojn, kiam vi blockus domajnon aŭ kiam viaj moderantoj elektus suspendi malproksiman servilon. Kiam tio okazas, vi povus elŝulti registrojn de finitaj rilatoj, por inspektiĝi kaj eble enporti en alia servilo.
purged: Informo pri ĉi tiu servilo foriĝis de la administracio de via servilo.
type: Evento
statuses:
attached:
@ -1775,19 +1876,24 @@ eo:
action: Konto-agordoj
explanation: La apelacio de la admono kontra via konto je %{strike_date} pri sendodato %{appeal_date} aprobitas.
subject: Via apelacio de %{date} aprobitas
subtitle: Via konto estas denove bone.
title: Apelacio estis aprobita
appeal_rejected:
explanation: La apelacio je %{strike_date} pri dato %{appeal_date} malakceptitas.
subject: Via apelacio de %{date} estis malaprobita
subtitle: Via revizio negiĝis.
title: Apelacio estis malaprobita
backup_ready:
explanation: Vi petis por tuta rezervo de via Mastodon-a konto.
extra: Estas nun preta por elŝuto!
subject: Via arkivo estas preta por elŝutado
title: Arkiva elŝuto
failed_2fa:
details: 'Jen detaloj de la provaĵo de ensaluti:'
explanation: Iu provis ensaluti al via konto sed provizis nevalidan duan aŭtentikigfaktoron.
further_actions_html: Se ĉi tio ne estis vi, ni rekomendas ke vi %{action} tuj ĉar ĝi povas esti endanĝerigita.
subject: Malsukceso dum la dua aŭtentikigfaktoro
title: Du-faktora aŭtentigo malsukcesis
suspicious_sign_in:
change_password: ŝanĝi vian pasvorton
details: 'Ĉi-sube estas detaloj pri la saluto:'
@ -1831,13 +1937,24 @@ eo:
apps_ios_action: Elŝutu ĉe la App Store
apps_step: Elŝutu niajn oficialajn aplikaĵojn.
apps_title: Aplikaĵoj de Mastodon
checklist_subtitle: 'Nin eku vin en ĉi tiu nova socia rando:'
checklist_title: Bonvenan Markolisto
edit_profile_action: Agordi
edit_profile_step: Plibonigi viajn interagojn per havas finitan profilon.
edit_profile_title: Agordi vian profilon
explanation: Jen kelkaj konsiloj por helpi vin komenci
feature_action: Lerni pli
feature_audience: Mastodon provizas vin per unika eblo por administri vian sekvantaron sen perantoj. Mastodon disponigita en via propra infrastrukturo ebligas al vi sekvi kaj esti sekvita de alia ajn Mastodon-servilo kaj estas tute sub via kontrolo nure.
feature_audience_title: Konstruu vian spektantaron memfide
feature_control: Vi scias plej bone, kion vi volas vidi en via hejmtemplinio. Neniaj algoritmoj nek reklamoj por malŝpari vian tempon. Sekvu iun ajn trans Mastodon-servilo ajn el unu konto kaj ricevu iliajn afiŝojn kronologie, kaj igu vian ejon de reto iom pli kiel vi.
feature_control_title: Havu la kontrolon de via propra templinio
feature_creativity: Mastodon subtenas aŭdaj, videajn kaj bildajn afiŝojn, priskribojn alireblecajn, enketojn, avertojn pri enhavo, animitajn bildetojn, personajn emoĝiojn, stucan kontrolon de bildetoj, kaj pli, por helpi al vi esprimi vin rete. Ĉu vi publikigas vian arton, vian muzikon, aŭ viajn podkastojn, Mastodon estas por vi.
feature_creativity_title: Senkompara kreemeco
feature_moderation: Mastodon denove donas al vi decidpovon. Ĉiu servilo kreas siajn proprajn regulojn kaj gvidliniojn, kiuj estas devigitaj loke kaj ne desupre kiel en firmaaj sociaj retejoj, igante ĝin la plej agordebla respondante al la bezonoj de malsamaj aroj de homoj. Aliĝu servilon kun la reguloj, kun kiuj vi konsentas, aŭ gastigu vian propran.
feature_moderation_title: Moderante kiel ĝi devus esti
follow_action: Sekvi
follow_step: Sekvi interesajn homojn estas pri kio Mastodon temas.
follow_title: Personigu vian hejmtemplinion
follows_subtitle: Sekvu konatajn kontojn
follows_title: Kiun sekvi
follows_view_more: Rigardu pli da homoj por sekvi
@ -1862,6 +1979,7 @@ eo:
invalid_otp_token: Nevalida kodo de dufaktora aŭtentigo
otp_lost_help_html: Se vi perdas aliron al ambaŭ, vi povas kontakti %{email}
rate_limited: Estas tro multaj aŭtentigaj provoj, reprovu poste.
seamless_external_login: Vi estas ensalutinta per ekstera servo, do pasvortaj kaj retpoŝtaj agordoj ne estas disponeblaj.
signed_in_as: 'Salutinta kiel:'
verification:
extra_instructions_html: <strong>Konsilo:</strong> La ligilo en via retejo povas esti nevidebla. La grava parto estas <code>rel="me"</code>, kiu evitas identoŝtelon en retejoj kun enhavo generita de uzantoj. Vi povas eĉ uzi <code>link</code>-etikedon en la <code>header</code> de la paĝo anstataŭ <code>a</code>, sed la HTML devas esti atingebla sen plenumado de JavaScript.

View file

@ -1069,11 +1069,11 @@ es-MX:
created_msg: El nuevo alias se ha creado correctamente. Ahora puedes empezar el traslado desde la cuenta antigua.
deleted_msg: Elimina el alias correctamente. El traslado de esa cuenta a esta ya no será posible.
empty: No tienes ningún alias.
hint_html: Si quieres migrar de otra cuenta a esta, aquí puedes crear un alias, es necesario proceder antes de empezar a mover seguidores de la cuenta anterior a esta. Esta acción por sí misma es <strong>inofensiva y reversible</strong>. <strong>La migración de la cuenta se inicia desde la cuenta antigua</strong>.
hint_html: Si deseas migrar de otra cuenta a esta, aquí puedes crear un alias, que es necesario para poder mover seguidores de la cuenta anterior a esta. Esta acción por sí misma es <strong>inofensiva y reversible</strong>. <strong>La migración de la cuenta se inicia desde la cuenta anterior</strong>.
remove: Desvincular alias
appearance:
advanced_web_interface: Interfaz web avanzada
advanced_web_interface_hint: 'Si quieres aprovechar todo el ancho de tu pantalla, la interfaz web avanzada te permite configurar muchas columnas diferentes para ver toda la información que quieras al mismo tiempo: Inicio, notificaciones, cronología federada, cualquier número de listas y etiquetas.'
advanced_web_interface_hint: 'Si deseas aprovechar todo el ancho de tu pantalla, la interfaz web avanzada te permite configurar muchas columnas diferentes para ver toda la información que quieras al mismo tiempo: inicio, notificaciones, cronología federada, cualquier número de listas y etiquetas.'
animations_and_accessibility: Animaciones y accesibilidad
confirmation_dialogs: Diálogos de confirmación
discovery: Descubrir

View file

@ -1 +1,16 @@
---
nan:
admin:
instances:
dashboard:
instance_languages_dimension: Tsia̍p用ê語言
statuses:
language: 語言
trends:
tags:
dashboard:
tag_languages_dimension: Tsia̍p用ê語言
scheduled_statuses:
too_soon: Tio̍h用未來ê日期。
statuses:
default_language: Kap界面ê語言sio kâng

View file

@ -60,6 +60,7 @@ eo:
setting_display_media_default: Kaŝi plurmediojn markitajn kiel tiklaj
setting_display_media_hide_all: Ĉiam kaŝi la plurmediojn
setting_display_media_show_all: Ĉiam montri la plurmediojn
setting_system_scrollbars_ui: Aplikas nur por surtablaj retumiloj baziĝas de Safari kaj Chrome
setting_use_blurhash: Transirojn estas bazita sur la koloroj de la kaŝitaj aŭdovidaĵoj sed ne montri iun ajn detalon
setting_use_pending_items: Kaŝi tempoliniajn ĝisdatigojn malantaŭ klako anstataŭ aŭtomate rulumi la fluon
username: Vi povas uzi literojn, ciferojn kaj substrekojn
@ -223,6 +224,7 @@ eo:
setting_hide_network: Kaŝi viajn sekvantojn kaj sekvatojn
setting_reduce_motion: Redukti la movecojn de la animacioj
setting_system_font_ui: Uzi la dekomencan tiparon de la sistemo
setting_system_scrollbars_ui: Uzu la defaŭltan rulumilon de la sistemo
setting_theme: Etoso de la retejo
setting_trends: Montri hodiaŭajn furoraĵojn
setting_unfollow_modal: Montri konfirman fenestron antaŭ ol ĉesi sekvi iun

View file

@ -16,43 +16,6 @@ def redirect_with_vary(path)
end
Rails.application.routes.draw do
# Paths of routes on the web app that to not require to be indexed or
# have alternative format representations requiring separate controllers
web_app_paths = %w(
/getting-started
/keyboard-shortcuts
/home
/public
/public/local
/public/local/fixed
/public/remote
/conversations
/lists/(*any)
/antennas/(*any)
/circles/(*any)
/links/(*any)
/notifications/(*any)
/notifications_v2/(*any)
/favourites
/emoji_reactions
/bookmarks
/bookmark_categories/(*any)
/pinned
/reaction_deck
/start/(*any)
/directory
/explore/(*any)
/search
/publish
/follow_requests
/blocks
/domain_blocks
/mutes
/followed_tags
/statuses/(*any)
/deck/(*any)
).freeze
root 'home#index'
mount LetterOpenerWeb::Engine, at: 'letter_opener' if Rails.env.development?
@ -236,9 +199,7 @@ Rails.application.routes.draw do
draw(:api)
web_app_paths.each do |path|
get path, to: 'home#index'
end
draw(:web_app)
get '/web/(*any)', to: redirect('/%{any}', status: 302), as: :web, defaults: { any: '' }, format: false
get '/about', to: 'about#show'

40
config/routes/web_app.rb Normal file
View file

@ -0,0 +1,40 @@
# frozen_string_literal: true
# Paths handled by the React application, which do not:
# - Require indexing
# - Have alternative format representations
%w(
/antennas/(*any)
/blocks
/bookmarks
/bookmark_categories/(*any)
/circles/(*any)
/conversations
/deck/(*any)
/directory
/domain_blocks
/emoji_reactions
/explore/(*any)
/favourites
/follow_requests
/followed_tags
/getting-started
/home
/keyboard-shortcuts
/links/(*any)
/lists/(*any)
/mutes
/notifications_v2/(*any)
/notifications/(*any)
/pinned
/public
/public/local
/public/local/fixed
/public/remote
/publish
/reaction_deck
/search
/start/(*any)
/statuses/(*any)
).each { |path| get path, to: 'home#index' }

View file

@ -8,6 +8,22 @@ class RemoveLegacyUserSettingsData < ActiveRecord::Migration[7.2]
thing_type IS NOT NULL
AND thing_id IS NOT NULL
SQL
# When running these migrations on mastodon.social, we saw 'notification_emails'
# and 'interactions' records that were not associated to a user and caused a
# migration issue.
# While I have not been able to pinpoint the exact cause of the issue, it is likely
# related to the settings system changes made in b11fdc3ae3f90731c01149a5a36dc64e065d4ea2.
# So, delete a few user settings that should already have been deleted.
connection.execute(<<~SQL.squish)
DELETE FROM settings
WHERE var IN (
'notification_emails', 'interactions', 'boost_modal', 'auto_play_gif',
'delete_modal', 'system_font_ui', 'default_sensitive', 'unfollow_modal',
'reduce_motion', 'display_sensitive_media', 'hide_network', 'expand_spoilers',
'display_media', 'aggregate_reblogs', 'show_application', 'advanced_layout',
'use_blurhash', 'use_pending_items')
SQL
end
def down

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
class AddMissingDeleteCascadeWebauthnCredentials < ActiveRecord::Migration[7.2]
def up
safety_assured do
execute <<~SQL.squish
ALTER TABLE webauthn_credentials
DROP CONSTRAINT fk_rails_a4355aef77,
ADD CONSTRAINT fk_rails_a4355aef77
FOREIGN KEY (user_id)
REFERENCES users(id)
ON DELETE CASCADE
SQL
end
end
def down
safety_assured do
execute <<~SQL.squish
ALTER TABLE webauthn_credentials
DROP CONSTRAINT fk_rails_a4355aef77,
ADD CONSTRAINT fk_rails_a4355aef77
FOREIGN KEY (user_id)
REFERENCES users(id)
SQL
end
end
end

View file

@ -0,0 +1,45 @@
# frozen_string_literal: true
class AddMissingDeleteCascadeAccountModerationNotes < ActiveRecord::Migration[7.2]
def up
safety_assured do
execute <<~SQL.squish
ALTER TABLE account_moderation_notes
DROP CONSTRAINT fk_rails_3f8b75089b,
ADD CONSTRAINT fk_rails_3f8b75089b
FOREIGN KEY (account_id)
REFERENCES accounts(id)
ON DELETE CASCADE
SQL
execute <<~SQL.squish
ALTER TABLE account_moderation_notes
DROP CONSTRAINT fk_rails_dd62ed5ac3,
ADD CONSTRAINT fk_rails_dd62ed5ac3
FOREIGN KEY (target_account_id)
REFERENCES accounts(id)
ON DELETE CASCADE
SQL
end
end
def down
safety_assured do
execute <<~SQL.squish
ALTER TABLE account_moderation_notes
DROP CONSTRAINT fk_rails_3f8b75089b,
ADD CONSTRAINT fk_rails_3f8b75089b
FOREIGN KEY (account_id)
REFERENCES accounts(id)
SQL
execute <<~SQL.squish
ALTER TABLE account_moderation_notes
DROP CONSTRAINT fk_rails_dd62ed5ac3,
ADD CONSTRAINT fk_rails_dd62ed5ac3
FOREIGN KEY (target_account_id)
REFERENCES accounts(id)
SQL
end
end
end

View file

@ -15,6 +15,22 @@ class RemoveLegacyUserSettingsColumns < ActiveRecord::Migration[7.2]
AND thing_id IS NOT NULL
SQL
# When running these migrations on mastodon.social, we saw 'notification_emails'
# and 'interactions' records that were not associated to a user and caused a
# migration issue.
# While I have not been able to pinpoint the exact cause of the issue, it is likely
# related to the settings system changes made in b11fdc3ae3f90731c01149a5a36dc64e065d4ea2.
# So, delete a few user settings that should already have been deleted.
connection.execute(<<~SQL.squish)
DELETE FROM settings
WHERE var IN (
'notification_emails', 'interactions', 'boost_modal', 'auto_play_gif',
'delete_modal', 'system_font_ui', 'default_sensitive', 'unfollow_modal',
'reduce_motion', 'display_sensitive_media', 'hide_network', 'expand_spoilers',
'display_media', 'aggregate_reblogs', 'show_application', 'advanced_layout',
'use_blurhash', 'use_pending_items')
SQL
add_index :settings, :var, unique: true, algorithm: :concurrently
remove_index :settings, [:thing_type, :thing_id, :var], name: :index_settings_on_thing_type_and_thing_id_and_var, unique: true

View file

@ -1606,8 +1606,8 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_08_232829) do
add_foreign_key "account_domain_blocks", "accounts", name: "fk_206c6029bd", on_delete: :cascade
add_foreign_key "account_migrations", "accounts", column: "target_account_id", on_delete: :nullify
add_foreign_key "account_migrations", "accounts", on_delete: :cascade
add_foreign_key "account_moderation_notes", "accounts"
add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id"
add_foreign_key "account_moderation_notes", "accounts", column: "target_account_id", on_delete: :cascade
add_foreign_key "account_moderation_notes", "accounts", on_delete: :cascade
add_foreign_key "account_notes", "accounts", column: "target_account_id", on_delete: :cascade
add_foreign_key "account_notes", "accounts", on_delete: :cascade
add_foreign_key "account_pins", "accounts", column: "target_account_id", on_delete: :cascade
@ -1764,7 +1764,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_08_232829) do
add_foreign_key "web_push_subscriptions", "oauth_access_tokens", column: "access_token_id", on_delete: :cascade
add_foreign_key "web_push_subscriptions", "users", on_delete: :cascade
add_foreign_key "web_settings", "users", name: "fk_11910667b2", on_delete: :cascade
add_foreign_key "webauthn_credentials", "users"
add_foreign_key "webauthn_credentials", "users", on_delete: :cascade
create_view "instances", materialized: true, sql_definition: <<-SQL
WITH domain_counts(domain, accounts_count) AS (

View file

@ -10,8 +10,14 @@ RSpec.describe 'Custom CSS' do
it 'returns empty stylesheet' do
get '/custom.css'
expect(response.content_type).to include('text/css')
expect(response.body.presence).to be_nil
expect(response)
.to have_http_status(200)
.and have_cacheable_headers
.and have_attributes(
content_type: match('text/css')
)
expect(response.body.presence)
.to be_nil
end
end
@ -23,8 +29,14 @@ RSpec.describe 'Custom CSS' do
it 'returns stylesheet from settings' do
get '/custom.css'
expect(response.content_type).to include('text/css')
expect(response.body.strip).to eq(expected_css)
expect(response)
.to have_http_status(200)
.and have_cacheable_headers
.and have_attributes(
content_type: match('text/css')
)
expect(response.body.strip)
.to eq(expected_css)
end
def expected_css
@ -44,8 +56,14 @@ RSpec.describe 'Custom CSS' do
it 'returns stylesheet from settings' do
get '/custom.css'
expect(response.content_type).to include('text/css')
expect(response.body.strip).to eq(expected_css)
expect(response)
.to have_http_status(200)
.and have_cacheable_headers
.and have_attributes(
content_type: match('text/css')
)
expect(response.body.strip)
.to eq(expected_css)
end
def expected_css

View file

@ -1,18 +0,0 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe 'Custom stylesheets' do
describe 'GET /custom.css' do
before { get '/custom.css' }
it 'returns http success' do
expect(response)
.to have_http_status(200)
.and have_cacheable_headers
.and have_attributes(
content_type: match('text/css')
)
end
end
end

View file

@ -1372,8 +1372,8 @@ __metadata:
linkType: hard
"@babel/preset-react@npm:^7.12.5, @babel/preset-react@npm:^7.22.3":
version: 7.25.9
resolution: "@babel/preset-react@npm:7.25.9"
version: 7.26.3
resolution: "@babel/preset-react@npm:7.26.3"
dependencies:
"@babel/helper-plugin-utils": "npm:^7.25.9"
"@babel/helper-validator-option": "npm:^7.25.9"
@ -1383,7 +1383,7 @@ __metadata:
"@babel/plugin-transform-react-pure-annotations": "npm:^7.25.9"
peerDependencies:
"@babel/core": ^7.0.0-0
checksum: 10c0/c294b475ee741f01f63ea0d828862811c453fabc6023f01814ce983bc316388e9d73290164d2b1384c2684db9c330803a3d4d2170285b105dcbacd483329eb93
checksum: 10c0/b470dcba11032ef6c832066f4af5c75052eaed49feb0f445227231ef1b5c42aacd6e216988c0bd469fd5728cd27b6b059ca307c9ecaa80c6bb5da4bf1c833e12
languageName: node
linkType: hard
@ -1972,8 +1972,8 @@ __metadata:
linkType: hard
"@dnd-kit/core@npm:^6.1.0":
version: 6.3.0
resolution: "@dnd-kit/core@npm:6.3.0"
version: 6.3.1
resolution: "@dnd-kit/core@npm:6.3.1"
dependencies:
"@dnd-kit/accessibility": "npm:^3.1.1"
"@dnd-kit/utilities": "npm:^3.2.2"
@ -1981,7 +1981,7 @@ __metadata:
peerDependencies:
react: ">=16.8.0"
react-dom: ">=16.8.0"
checksum: 10c0/7b6ebae619921ac27a367b5f168cf66729ab2f5041a5376bb05399cdfd05e03c8fac5d218632ee04fe7c1e049bde9222930c6e8ee1dbb0ca8bde38038f1a1a48
checksum: 10c0/196db95d81096d9dc248983533eab91ba83591770fa5c894b1ac776f42af0d99522b3fd5bb3923411470e4733fcfa103e6ee17adc17b9b7eb54c7fbec5ff7c52
languageName: node
linkType: hard
@ -8501,8 +8501,8 @@ __metadata:
linkType: hard
"express@npm:^4.17.1, express@npm:^4.18.2":
version: 4.21.1
resolution: "express@npm:4.21.1"
version: 4.21.2
resolution: "express@npm:4.21.2"
dependencies:
accepts: "npm:~1.3.8"
array-flatten: "npm:1.1.1"
@ -8523,7 +8523,7 @@ __metadata:
methods: "npm:~1.1.2"
on-finished: "npm:2.4.1"
parseurl: "npm:~1.3.3"
path-to-regexp: "npm:0.1.10"
path-to-regexp: "npm:0.1.12"
proxy-addr: "npm:~2.0.7"
qs: "npm:6.13.0"
range-parser: "npm:~1.2.1"
@ -8535,7 +8535,7 @@ __metadata:
type-is: "npm:~1.6.18"
utils-merge: "npm:1.0.1"
vary: "npm:~1.1.2"
checksum: 10c0/0c287867e5f6129d3def1edd9b63103a53c40d4dc8628839d4b6827e35eb8f0de5a4656f9d85f4457eba584f9871ebb2ad26c750b36bd75d9bbb8bcebdc4892c
checksum: 10c0/38168fd0a32756600b56e6214afecf4fc79ec28eca7f7a91c2ab8d50df4f47562ca3f9dee412da7f5cea6b1a1544b33b40f9f8586dbacfbdada0fe90dbb10a1f
languageName: node
linkType: hard
@ -13104,10 +13104,10 @@ __metadata:
languageName: node
linkType: hard
"path-to-regexp@npm:0.1.10":
version: 0.1.10
resolution: "path-to-regexp@npm:0.1.10"
checksum: 10c0/34196775b9113ca6df88e94c8d83ba82c0e1a2063dd33bfe2803a980da8d49b91db8104f49d5191b44ea780d46b8670ce2b7f4a5e349b0c48c6779b653f1afe4
"path-to-regexp@npm:0.1.12":
version: 0.1.12
resolution: "path-to-regexp@npm:0.1.12"
checksum: 10c0/1c6ff10ca169b773f3bba943bbc6a07182e332464704572962d277b900aeee81ac6aa5d060ff9e01149636c30b1f63af6e69dd7786ba6e0ddb39d4dee1f0645b
languageName: node
linkType: hard